2 * metadata/gc.c: GC icalls.
4 * Author: Paolo Molaro <lupus@ximian.com>
6 * (C) 2002 Ximian, Inc.
13 #include <mono/metadata/gc.h>
14 #include <mono/metadata/threads.h>
15 #include <mono/metadata/tabledefs.h>
16 #define GC_I_HIDE_POINTERS
17 #include <mono/os/gc_wrapper.h>
19 static int finalize_slot = -1;
22 * actually, we might want to queue the finalize requests in a separate thread,
23 * but we need to be careful about the execution domain of the thread...
26 run_finalize (void *obj, void *data)
28 MonoObject *exc = NULL;
30 o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
32 if (finalize_slot < 0) {
34 for (i = 0; i < mono_defaults.object_class->vtable_size; ++i) {
35 MonoMethod *cm = mono_defaults.object_class->vtable [i];
37 if (!strcmp (cm->name, "Finalize")) {
43 /* speedup later... and use a timeout */
44 /*g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name);*/
45 mono_runtime_invoke (o->vtable->klass->vtable [finalize_slot], o, NULL, &exc);
48 /* fixme: do something useful */
53 * Some of our objects may point to a different address than the address returned by GC_malloc()
54 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
55 * This also means that in the callback we need to adjust the pointer to get back the real
57 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer,
58 * since that, too, can cause the underlying pointer to be offset.
61 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
66 g_assert (GC_base (obj) == (char*)obj - offset);
67 GC_register_finalizer ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
72 mono_object_register_finalizer (MonoObject *obj)
74 /*g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name);*/
75 object_register_finalizer (obj, run_finalize);
79 * to speedup, at class init time, check if a class or struct
80 * have fields that need to be finalized and set a flag.
83 finalize_fields (MonoClass *class, char *data, gboolean instance, GHashTable *todo) {
85 MonoClassField *field;
89 g_print ("Finalize statics on on %s\n", class->name);*/
90 if (instance && class->valuetype)
91 data -= sizeof (MonoObject);
93 for (i = 0; i < class->field.count; ++i) {
94 field = &class->fields [i];
96 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
99 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
102 switch (field->type->type) {
103 case MONO_TYPE_OBJECT:
104 case MONO_TYPE_CLASS:
105 obj = *((MonoObject**)(data + field->offset));
107 if (mono_object_class (obj)->has_finalize) {
108 /* disable the registered finalizer */
109 object_register_finalizer (obj, NULL);
110 run_finalize (obj, NULL);
113 * if the type doesn't have a finalizer, we finalize
114 * the fields ourselves just like we do for structs.
115 * Disabled for now: how do we handle loops?
117 /*finalize_fields (mono_object_class (obj), obj, TRUE, todo);*/
121 case MONO_TYPE_VALUETYPE: {
122 MonoClass *fclass = mono_class_from_mono_type (field->type);
123 if (fclass->enumtype)
125 /*finalize_fields (fclass, data + field->offset, TRUE, todo);*/
128 case MONO_TYPE_ARRAY:
129 case MONO_TYPE_SZARRAY:
130 /* FIXME: foreach item... */
136 class = class->parent;
141 finalize_static_data (MonoClass *class, MonoVTable *vtable, GHashTable *todo) {
143 if (class->enumtype || !vtable->data)
145 finalize_fields (class, vtable->data, FALSE, todo);
149 mono_domain_finalize (MonoDomain *domain) {
151 GHashTable *todo = g_hash_table_new (NULL, NULL);
155 mono_g_hash_table_foreach (domain->class_vtable_hash, (GHFunc)finalize_static_data, todo);
156 /* FIXME: finalize objects in todo... */
157 g_hash_table_destroy (todo);
161 ves_icall_System_GC_InternalCollect (int generation)
169 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
174 return GC_get_heap_size ();
181 ves_icall_System_GC_KeepAlive (MonoObject *obj)
189 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
191 object_register_finalizer (obj, run_finalize);
195 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
197 object_register_finalizer (obj, NULL);
201 ves_icall_System_GC_WaitForPendingFinalizers (void)
205 /*static CRITICAL_SECTION handle_section;*/
206 static guint32 next_handle = 0;
207 static gpointer *gc_handles = NULL;
208 static guint32 array_size = 0;
211 * The handle type is encoded in the lower two bits of the handle value:
218 * FIXME: make thread safe and reuse the array entries.
221 ves_icall_System_GCHandle_GetTarget (guint32 handle)
226 obj = gc_handles [handle >> 2];
227 if ((handle & 0x3) > 1)
228 return REVEAL_POINTER (obj);
242 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
245 guint32 h, idx = next_handle++;
247 if (idx >= array_size) {
252 new_array = GC_malloc (sizeof (gpointer) * (array_size * 2));
255 memcpy (new_array, gc_handles, sizeof (gpointer) * array_size);
256 /* need to re-register links for weak refs. test if GC_realloc needs the same */
257 for (i = 0; i < array_size; ++i) {
258 if (((gulong)new_array [i]) & 0x1) { /* all and only disguised pointers have it set */
259 GC_general_register_disappearing_link (&(new_array [i]), REVEAL_POINTER (new_array [i]));
264 gc_handles = new_array;
266 g_error ("No GCHandle support built-in");
271 /* resuse the type from the old target */
276 case HANDLE_WEAK_TRACK:
278 val = (gpointer)HIDE_POINTER (val);
279 gc_handles [idx] = val;
281 GC_general_register_disappearing_link (&(gc_handles [idx]), obj);
283 g_error ("No weakref support");
288 gc_handles [idx] = val;
295 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
297 gc_handles [handle >> 2] = (gpointer)-1;
301 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
306 obj = gc_handles [handle >> 2];
307 if ((handle & 0x3) > 1)
308 return REVEAL_POINTER (obj);