2002-07-15 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / metadata / gc.c
1 /*
2  * metadata/gc.c: GC icalls.
3  *
4  * Author: Paolo Molaro <lupus@ximian.com>
5  *
6  * (C) 2002 Ximian, Inc.
7  */
8
9 #include <config.h>
10 #include <glib.h>
11 #include <string.h>
12
13 #include <mono/metadata/gc.h>
14 #include <mono/metadata/threads.h>
15 #if HAVE_BOEHM_GC
16 #define GC_I_HIDE_POINTERS
17 #include <gc/gc.h>
18 #else
19 #define HIDE_POINTER(v) (v)
20 #define REVEAL_POINTER(v) (v)
21 #endif
22
23 static int finalize_slot = -1;
24
25 /* 
26  * actually, we might want to queue the finalize requests in a separate thread,
27  * but we need to be careful about the execution domain of the thread...
28  */
29 static void
30 run_finalize (void *obj, void *data)
31 {
32         MonoObject *exc = NULL;
33         MonoObject *o;
34         o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
35
36         if (finalize_slot < 0) {
37                 int i;
38                 for (i = 0; i < mono_defaults.object_class->vtable_size; ++i) {
39                         MonoMethod *cm = mono_defaults.object_class->vtable [i];
40                
41                         if (!strcmp (cm->name, "Finalize")) {
42                                 finalize_slot = i;
43                                 break;
44                         }
45                 }
46         }
47         /* speedup later... */
48         /* g_print ("Finalize run on %s\n", mono_object_class (o)->name); */
49         mono_runtime_invoke (o->vtable->klass->vtable [finalize_slot], o, NULL, &exc);
50
51         if (exc) {
52                 /* fixme: do something useful */
53         }
54 }
55
56 /*
57  * Some of our objects may point to a different address than the address returned by GC_malloc()
58  * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
59  * This also means that in the callback we need to adjust the pointer to get back the real
60  * MonoObject*.
61  * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, 
62  * since that, too, can cause the underlying pointer to be offset.
63  */
64 static void
65 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
66 {
67 #if HAVE_BOEHM_GC
68         guint offset = 0;
69
70         g_assert (GC_base (obj) == (char*)obj - offset);
71         GC_register_finalizer ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
72 #endif
73 }
74
75 void
76 mono_object_register_finalizer (MonoObject *obj)
77 {
78         object_register_finalizer (obj, run_finalize);
79 }
80
81 void
82 ves_icall_System_GC_InternalCollect (int generation)
83 {
84 #if HAVE_BOEHM_GC
85         GC_gcollect ();
86 #endif
87 }
88
89 gint64
90 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
91 {
92 #if HAVE_BOEHM_GC
93         if (forceCollection)
94                 GC_gcollect ();
95         return GC_get_heap_size ();
96 #else
97         return 0;
98 #endif
99 }
100
101 void
102 ves_icall_System_GC_KeepAlive (MonoObject *obj)
103 {
104         /*
105          * Does nothing.
106          */
107 }
108
109 void
110 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
111 {
112         object_register_finalizer (obj, run_finalize);
113 }
114
115 void
116 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
117 {
118         object_register_finalizer (obj, NULL);
119 }
120
121 void
122 ves_icall_System_GC_WaitForPendingFinalizers (void)
123 {
124 }
125
126 /*static CRITICAL_SECTION handle_section;*/
127 static guint32 next_handle = 0;
128 static gpointer *gc_handles = NULL;
129 static guint32 array_size = 0;
130
131 /*
132  * The handle type is encoded in the lower two bits of the handle value:
133  * 0 -> normal
134  * 1 -> pinned
135  * 2 -> weak
136  */
137
138 /*
139  * FIXME: make thread safe and reuse the array entries.
140  */
141 MonoObject *
142 ves_icall_System_GCHandle_GetTarget (guint32 handle)
143 {
144         MonoObject *obj;
145
146         if (gc_handles) {
147                 obj = gc_handles [handle >> 2];
148                 if ((handle & 0x3) > 1)
149                         return REVEAL_POINTER (obj);
150                 return obj;
151         }
152         return NULL;
153 }
154
155 guint32
156 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
157 {
158         gpointer val = obj;
159         guint32 h, idx = next_handle++;
160
161         if (idx >= array_size) {
162 #if HAVE_BOEHM_GC
163                 gpointer *new_array;
164                 if (!array_size)
165                         array_size = 16;
166                 new_array = GC_malloc (sizeof (gpointer) * (array_size * 2));
167                 if (gc_handles) {
168                         int i;
169                         memcpy (new_array, gc_handles, sizeof (gpointer) * array_size);
170                         /* need to re-register links for weak refs. test if GC_realloc needs the same */
171                         for (i = 0; i < array_size; ++i) {
172                                 if (((gulong)new_array [i]) & 0x1) { /* all and only disguised pointers have it set */
173                                         GC_general_register_disappearing_link (&(new_array [i]), REVEAL_POINTER (new_array [i]));
174                                 }
175                         }
176                 }
177                 array_size *= 2;
178                 gc_handles = new_array;
179 #else
180                 g_error ("No GCHandle support built-in");
181 #endif
182         }
183         h = idx << 2;
184
185         /* resuse the type from the old target */
186         if (type == -1)
187                 type =  handle & 0x3;
188         switch (type) {
189         case 0:
190         case 1:
191                 h |= type;
192                 gc_handles [idx] = val;
193                 break;
194         default:
195                 h |= 2;
196                 val = (gpointer)HIDE_POINTER (val);
197                 gc_handles [idx] = val;
198 #if HAVE_BOEHM_GC
199                 GC_general_register_disappearing_link (&(gc_handles [idx]), obj);
200 #else
201                 g_error ("No weakref support");
202 #endif
203                 break;
204         }
205         return h;
206 }
207
208 void
209 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
210 {
211         gc_handles [handle >> 2] = (gpointer)-1;
212 }
213
214 gpointer
215 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
216 {
217         MonoObject *obj;
218
219         if (gc_handles) {
220                 obj = gc_handles [handle >> 2];
221                 if ((handle & 0x3) > 1)
222                         return REVEAL_POINTER (obj);
223                 return obj;
224         }
225         return NULL;
226 }
227
228