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>
20 #define HIDE_POINTER(v) (v)
21 #define REVEAL_POINTER(v) (v)
24 static int finalize_slot = -1;
27 * actually, we might want to queue the finalize requests in a separate thread,
28 * but we need to be careful about the execution domain of the thread...
31 run_finalize (void *obj, void *data)
33 MonoObject *exc = NULL;
35 o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
37 if (finalize_slot < 0) {
39 for (i = 0; i < mono_defaults.object_class->vtable_size; ++i) {
40 MonoMethod *cm = mono_defaults.object_class->vtable [i];
42 if (!strcmp (cm->name, "Finalize")) {
48 /* speedup later... and use a timeout */
49 /*g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name);*/
50 mono_runtime_invoke (o->vtable->klass->vtable [finalize_slot], o, NULL, &exc);
53 /* fixme: do something useful */
58 * Some of our objects may point to a different address than the address returned by GC_malloc()
59 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
60 * This also means that in the callback we need to adjust the pointer to get back the real
62 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer,
63 * since that, too, can cause the underlying pointer to be offset.
66 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
71 g_assert (GC_base (obj) == (char*)obj - offset);
72 GC_register_finalizer ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
77 mono_object_register_finalizer (MonoObject *obj)
79 /*g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name);*/
80 object_register_finalizer (obj, run_finalize);
84 * to speedup, at class init time, check if a class or struct
85 * have fields that need to be finalized and set a flag.
88 finalize_fields (MonoClass *class, char *data, gboolean instance, GHashTable *todo) {
90 MonoClassField *field;
94 g_print ("Finalize statics on on %s\n", class->name);*/
95 if (instance && class->valuetype)
96 data -= sizeof (MonoObject);
98 for (i = 0; i < class->field.count; ++i) {
99 field = &class->fields [i];
101 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
104 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
107 switch (field->type->type) {
108 case MONO_TYPE_OBJECT:
109 case MONO_TYPE_CLASS:
110 obj = *((MonoObject**)(data + field->offset));
112 if (mono_object_class (obj)->has_finalize) {
113 /* disable the registered finalizer */
114 object_register_finalizer (obj, NULL);
115 run_finalize (obj, NULL);
118 * if the type doesn't have a finalizer, we finalize
119 * the fields ourselves just like we do for structs.
120 * Disabled for now: how do we handle loops?
122 /*finalize_fields (mono_object_class (obj), obj, TRUE, todo);*/
126 case MONO_TYPE_VALUETYPE: {
127 MonoClass *fclass = mono_class_from_mono_type (field->type);
128 if (fclass->enumtype)
130 /*finalize_fields (fclass, data + field->offset, TRUE, todo);*/
133 case MONO_TYPE_ARRAY:
134 case MONO_TYPE_SZARRAY:
135 /* FIXME: foreach item... */
141 class = class->parent;
146 finalize_static_data (MonoClass *class, MonoVTable *vtable, GHashTable *todo) {
148 if (class->enumtype || !vtable->data)
150 finalize_fields (class, vtable->data, FALSE, todo);
154 mono_domain_finalize (MonoDomain *domain) {
156 GHashTable *todo = g_hash_table_new (NULL, NULL);
160 mono_g_hash_table_foreach (domain->class_vtable_hash, (GHFunc)finalize_static_data, todo);
161 /* FIXME: finalize objects in todo... */
162 g_hash_table_destroy (todo);
166 ves_icall_System_GC_InternalCollect (int generation)
174 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
179 return GC_get_heap_size ();
186 ves_icall_System_GC_KeepAlive (MonoObject *obj)
194 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
196 object_register_finalizer (obj, run_finalize);
200 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
202 object_register_finalizer (obj, NULL);
206 ves_icall_System_GC_WaitForPendingFinalizers (void)
210 /*static CRITICAL_SECTION handle_section;*/
211 static guint32 next_handle = 0;
212 static gpointer *gc_handles = NULL;
213 static guint8 *gc_handle_types = NULL;
214 static guint32 array_size = 0;
217 * The handle type is encoded in the lower two bits of the handle value:
231 * FIXME: make thread safe and reuse the array entries.
234 ves_icall_System_GCHandle_GetTarget (guint32 handle)
241 g_assert (type == gc_handle_types [handle >> 2]);
242 obj = gc_handles [handle >> 2];
246 if ((type == HANDLE_WEAK) || (type == HANDLE_WEAK_TRACK))
247 return REVEAL_POINTER (obj);
255 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
258 guint32 h, idx = next_handle++;
260 if (idx >= array_size) {
263 guint8 *new_type_array;
266 new_array = GC_malloc (sizeof (gpointer) * (array_size * 2));
267 new_type_array = GC_malloc (sizeof (guint8) * (array_size * 2));
270 memcpy (new_array, gc_handles, sizeof (gpointer) * array_size);
271 memcpy (new_type_array, gc_handle_types, sizeof (guint8) * array_size);
272 /* need to re-register links for weak refs. test if GC_realloc needs the same */
273 for (i = 0; i < array_size; ++i) {
274 if ((gc_handle_types[i] == HANDLE_WEAK) || (gc_handle_types[i] == HANDLE_WEAK_TRACK)) { /* all and only disguised pointers have it set */
275 if (gc_handles [i] != (gpointer)-1)
276 GC_unregister_disappearing_link (&(gc_handles [i]));
277 if (new_array [i] != (gpointer)-1)
278 GC_general_register_disappearing_link (&(new_array [i]), REVEAL_POINTER (new_array [i]));
283 gc_handles = new_array;
284 gc_handle_types = new_type_array;
286 g_error ("No GCHandle support built-in");
290 /* resuse the type from the old target */
293 h = (idx << 2) | type;
296 case HANDLE_WEAK_TRACK:
297 val = (gpointer)HIDE_POINTER (val);
298 gc_handles [idx] = val;
299 gc_handle_types [idx] = type;
301 if (gc_handles [idx] != (gpointer)-1)
302 GC_general_register_disappearing_link (&(gc_handles [idx]), obj);
304 g_error ("No weakref support");
308 gc_handles [idx] = val;
309 gc_handle_types [idx] = type;
316 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
318 int idx = handle >> 2;
319 int type = handle & 0x3;
322 g_assert (type == gc_handle_types [idx]);
323 if ((type == HANDLE_WEAK) || (type == HANDLE_WEAK_TRACK)) {
324 if (gc_handles [idx] != (gpointer)-1)
325 GC_unregister_disappearing_link (&(gc_handles [idx]));
328 g_error ("No GCHandle support");
331 gc_handles [idx] = (gpointer)-1;
332 gc_handle_types [idx] = (guint8)-1;
336 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
339 int type = handle & 0x3;
342 obj = gc_handles [handle >> 2];
343 g_assert (gc_handle_types [handle >> 2] == type);
344 if ((type == HANDLE_WEAK) || (type == HANDLE_WEAK_TRACK)) {
345 obj = REVEAL_POINTER (obj);
346 if (obj == (MonoObject *) -1)