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>
17 #define GC_I_HIDE_POINTERS
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 %s\n", 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 object_register_finalizer (obj, run_finalize);
83 * to speedup, at class init time, check if a class or struct
84 * have fields that need to be finalized and set a flag.
87 finalize_fields (MonoClass *class, char *data, gboolean instance, GHashTable *todo) {
89 MonoClassField *field;
93 g_print ("Finalize statics on on %s\n", class->name);*/
94 if (instance && class->valuetype)
95 data -= sizeof (MonoObject);
97 for (i = 0; i < class->field.count; ++i) {
98 field = &class->fields [i];
100 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
103 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
106 switch (field->type->type) {
107 case MONO_TYPE_OBJECT:
108 case MONO_TYPE_CLASS:
109 obj = *((MonoObject**)(data + field->offset));
111 if (mono_object_class (obj)->has_finalize) {
112 /* disable the registered finalizer */
113 object_register_finalizer (obj, NULL);
114 run_finalize (obj, NULL);
117 * if the type doesn't have a finalizer, we finalize
118 * the fields ourselves just like we do for structs.
119 * Disabled for now: how do we handle loops?
121 /*finalize_fields (mono_object_class (obj), obj, TRUE, todo);*/
125 case MONO_TYPE_VALUETYPE: {
126 MonoClass *fclass = mono_class_from_mono_type (field->type);
127 if (fclass->enumtype)
129 /*finalize_fields (fclass, data + field->offset, TRUE, todo);*/
132 case MONO_TYPE_ARRAY:
133 case MONO_TYPE_SZARRAY:
134 /* FIXME: foreach item... */
140 class = class->parent;
145 finalize_static_data (MonoClass *class, MonoVTable *vtable, GHashTable *todo) {
147 if (class->enumtype || !vtable->data)
149 finalize_fields (class, vtable->data, FALSE, todo);
153 mono_domain_finalize (MonoDomain *domain) {
155 GHashTable *todo = g_hash_table_new (NULL, NULL);
159 mono_g_hash_table_foreach (domain->class_vtable_hash, (GHFunc)finalize_static_data, todo);
160 /* FIXME: finalize objects in todo... */
161 g_hash_table_destroy (todo);
165 ves_icall_System_GC_InternalCollect (int generation)
173 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
178 return GC_get_heap_size ();
185 ves_icall_System_GC_KeepAlive (MonoObject *obj)
193 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
195 object_register_finalizer (obj, run_finalize);
199 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
201 object_register_finalizer (obj, NULL);
205 ves_icall_System_GC_WaitForPendingFinalizers (void)
209 /*static CRITICAL_SECTION handle_section;*/
210 static guint32 next_handle = 0;
211 static gpointer *gc_handles = NULL;
212 static guint32 array_size = 0;
215 * The handle type is encoded in the lower two bits of the handle value:
222 * FIXME: make thread safe and reuse the array entries.
225 ves_icall_System_GCHandle_GetTarget (guint32 handle)
230 obj = gc_handles [handle >> 2];
231 if ((handle & 0x3) > 1)
232 return REVEAL_POINTER (obj);
239 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
242 guint32 h, idx = next_handle++;
244 if (idx >= array_size) {
249 new_array = GC_malloc (sizeof (gpointer) * (array_size * 2));
252 memcpy (new_array, gc_handles, sizeof (gpointer) * array_size);
253 /* need to re-register links for weak refs. test if GC_realloc needs the same */
254 for (i = 0; i < array_size; ++i) {
255 if (((gulong)new_array [i]) & 0x1) { /* all and only disguised pointers have it set */
256 GC_general_register_disappearing_link (&(new_array [i]), REVEAL_POINTER (new_array [i]));
261 gc_handles = new_array;
263 g_error ("No GCHandle support built-in");
268 /* resuse the type from the old target */
275 gc_handles [idx] = val;
279 val = (gpointer)HIDE_POINTER (val);
280 gc_handles [idx] = val;
282 GC_general_register_disappearing_link (&(gc_handles [idx]), obj);
284 g_error ("No weakref support");
292 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
294 gc_handles [handle >> 2] = (gpointer)-1;
298 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
303 obj = gc_handles [handle >> 2];
304 if ((handle & 0x3) > 1)
305 return REVEAL_POINTER (obj);