OSDN Git Service

+ 2000-04-22 Anthony Green <green@cygnus.com>
[pf3gnuchains/gcc-fork.git] / libjava / boehm.cc
1 // boehm.cc - interface between libjava and Boehm GC.
2
3 /* Copyright (C) 1998, 1999, 2000  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 #include <config.h>
12
13 #include <stdio.h>
14
15 #include <jvm.h>
16 #include <gcj/cni.h>
17
18 #include <java/lang/Class.h>
19 #include <java-interp.h>
20
21 // More nastiness: the GC wants to define TRUE and FALSE.  We don't
22 // need the Java definitions (themselves a hack), so we undefine them.
23 #undef TRUE
24 #undef FALSE
25
26 extern "C"
27 {
28 #include <gc_priv.h>
29 #include <gc_mark.h>
30
31   // These aren't declared in any Boehm GC header.
32   void GC_finalize_all (void);
33   ptr_t GC_debug_generic_malloc (size_t size, int k, GC_EXTRA_PARAMS);
34 };
35
36 // FIXME: this should probably be defined in some GC header.
37 #ifdef GC_DEBUG
38 #  define GC_GENERIC_MALLOC(Size, Type) \
39     GC_debug_generic_malloc (Size, Type, GC_EXTRAS)
40 #else
41 #  define GC_GENERIC_MALLOC(Size, Type) GC_generic_malloc (Size, Type)
42 #endif
43
44 // We must check for plausibility ourselves.
45 #define MAYBE_MARK(Obj, Top, Limit, Source, Exit)  \
46       if ((ptr_t) (Obj) >= GC_least_plausible_heap_addr \
47           && (ptr_t) (Obj) <= GC_greatest_plausible_heap_addr) \
48         PUSH_CONTENTS (Obj, Top, Limit, Source, Exit)
49
50 #define ObjectClass _CL_Q34java4lang6Object
51 extern java::lang::Class ObjectClass;
52 #define ClassClass _CL_Q34java4lang5Class
53 extern java::lang::Class ClassClass;
54
55 \f
56
57 // Nonzero if this module has been initialized.
58 static int initialized = 0;
59
60 // `kind' index used when allocating Java objects.
61 static int obj_kind_x;
62
63 // `kind' index used when allocating Java arrays.
64 static int array_kind_x;
65
66 // Freelist used for Java objects.
67 static ptr_t *obj_free_list;
68
69 // Freelist used for Java arrays.
70 static ptr_t *array_free_list;
71
72 // Lock used to protect access to Boehm's GC_enable/GC_disable functions.
73 static _Jv_Mutex_t disable_gc_mutex;
74
75 \f
76
77 // This is called by the GC during the mark phase.  It marks a Java
78 // object.  We use `void *' arguments and return, and not what the
79 // Boehm GC wants, to avoid pollution in our headers.
80 void *
81 _Jv_MarkObj (void *addr, void *msp, void *msl, void * /*env*/)
82 {
83   mse *mark_stack_ptr = (mse *) msp;
84   mse *mark_stack_limit = (mse *) msl;
85   jobject obj = (jobject) addr;
86
87   _Jv_VTable *dt = *(_Jv_VTable **) addr;
88   // We check this in case a GC occurs before the vtbl is set.  FIXME:
89   // should use allocation lock while initializing object.
90   if (__builtin_expect (! dt, 0))
91     return mark_stack_ptr;
92   jclass klass = dt->clas;
93
94   // Every object has a sync_info pointer.
95   ptr_t p = (ptr_t) obj->sync_info;
96   MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, o1label);
97   // Mark the object's class.
98   p = (ptr_t) klass;
99   MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, o2label);
100
101   if (__builtin_expect (klass == &ClassClass, 0))
102     {
103       jclass c = (jclass) addr;
104
105 #if 0
106       // The next field should probably not be marked, since this is
107       // only used in the class hash table.  Marking this field
108       // basically prohibits class unloading. --Kresten
109       p = (ptr_t) c->next;
110       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c2label);
111 #endif
112
113       p = (ptr_t) c->name;
114       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c3label);
115       p = (ptr_t) c->superclass;
116       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c4label);
117       for (int i = 0; i < c->constants.size; ++i)
118         {
119           /* FIXME: We could make this more precise by using the tags -KKT */
120           p = (ptr_t) c->constants.data[i].p;
121           MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5label);
122         }
123
124 #ifdef INTERPRETER
125       if (_Jv_IsInterpretedClass (c))
126         {
127           p = (ptr_t) c->constants.tags;
128           MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5alabel);
129           p = (ptr_t) c->constants.data;
130           MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5blabel);
131         }
132 #endif
133
134       // If the class is an array, then the methods field holds a
135       // pointer to the element class.  If the class is primitive,
136       // then the methods field holds a pointer to the array class.
137       p = (ptr_t) c->methods;
138       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c6label);
139
140
141       if (! c->isArray() && ! c->isPrimitive())
142         {
143           // Scan each method in the cases where `methods' really
144           // points to a methods structure.
145           for (int i = 0; i < c->method_count; ++i)
146             {
147               p = (ptr_t) c->methods[i].name;
148               MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c,
149                              cm1label);
150               p = (ptr_t) c->methods[i].signature;
151               MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c,
152                              cm2label);
153
154               // FIXME: `ncode' entry?
155
156 #ifdef INTERPRETER
157               // The interpreter installs a heap-allocated
158               // trampoline here, so we'll mark it. 
159               if (_Jv_IsInterpretedClass (c))
160                   {
161                       p = (ptr_t) c->methods[i].ncode;
162                       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c,
163                                   cm3label);
164                   }
165 #endif
166             }
167         }
168
169       // Mark all the fields.
170       p = (ptr_t) c->fields;
171       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8label);
172       for (int i = 0; i < c->field_count; ++i)
173         {
174           _Jv_Field* field = &c->fields[i];
175
176 #ifndef COMPACT_FIELDS
177           p = (ptr_t) field->name;
178           MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8alabel);
179 #endif
180           p = (ptr_t) field->type;
181           MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8blabel);
182
183           // For the interpreter, we also need to mark the memory
184           // containing static members
185           if (field->flags & 0x0008)
186             {
187               p = (ptr_t) field->u.addr;
188               MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8clabel);
189
190               // also, if the static member is a reference,
191               // mark also the value pointed to.  We check for isResolved
192               // since marking can happen before memory is allocated for
193               // static members.
194               if (JvFieldIsRef (field) && field->isResolved()) 
195                 {
196                   jobject val = *(jobject*) field->u.addr;
197                   p = (ptr_t) val;
198                   MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit,
199                               c, c8elabel);
200                 }
201             }
202         }
203
204       p = (ptr_t) c->vtable;
205       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c9label);
206       p = (ptr_t) c->interfaces;
207       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cAlabel);
208       for (int i = 0; i < c->interface_count; ++i)
209         {
210           p = (ptr_t) c->interfaces[i];
211           MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cClabel);
212         }
213       p = (ptr_t) c->loader;
214       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cBlabel);
215
216 #ifdef INTERPRETER
217       if (_Jv_IsInterpretedClass (c))
218         {
219           _Jv_InterpClass* ic = (_Jv_InterpClass*)c;
220
221           p = (ptr_t) ic->interpreted_methods;
222           MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, cElabel);
223
224           for (int i = 0; i < c->method_count; i++)
225             {
226               p = (ptr_t) ic->interpreted_methods[i];
227               MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, \
228                           cFlabel);
229             }
230
231           p = (ptr_t) ic->field_initializers;
232           MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, cGlabel);
233           
234         }
235 #endif
236
237     }
238   else
239     {
240       // NOTE: each class only holds information about the class
241       // itself.  So we must do the marking for the entire inheritance
242       // tree in order to mark all fields.  FIXME: what about
243       // interfaces?  We skip Object here, because Object only has a
244       // sync_info, and we handled that earlier.
245       // Note: occasionally `klass' can be null.  For instance, this
246       // can happen if a GC occurs between the point where an object
247       // is allocated and where the vtbl slot is set.
248       while (klass && klass != &ObjectClass)
249         {
250           jfieldID field = JvGetFirstInstanceField (klass);
251           jint max = JvNumInstanceFields (klass);
252
253           for (int i = 0; i < max; ++i)
254             {
255               if (JvFieldIsRef (field))
256                 {
257                   jobject val = JvGetObjectField (obj, field);
258                   p = (ptr_t) val;
259                   MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit,
260                               obj, elabel);
261                 }
262               field = field->getNextField ();
263             }
264           klass = klass->getSuperclass();
265         }
266     }
267
268   return mark_stack_ptr;
269 }
270
271 // This is called by the GC during the mark phase.  It marks a Java
272 // array (of objects).  We use `void *' arguments and return, and not
273 // what the Boehm GC wants, to avoid pollution in our headers.
274 void *
275 _Jv_MarkArray (void *addr, void *msp, void *msl, void * /*env*/)
276 {
277   mse *mark_stack_ptr = (mse *) msp;
278   mse *mark_stack_limit = (mse *) msl;
279   jobjectArray array = (jobjectArray) addr;
280
281   _Jv_VTable *dt = *(_Jv_VTable **) addr;
282   // We check this in case a GC occurs before the vtbl is set.  FIXME:
283   // should use allocation lock while initializing object.
284   if (__builtin_expect (! dt, 0))
285     return mark_stack_ptr;
286   jclass klass = dt->clas;
287
288   // Every object has a sync_info pointer.
289   ptr_t p = (ptr_t) array->sync_info;
290   MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array, e1label);
291   // Mark the object's class.
292   p = (ptr_t) klass;
293   MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, o2label);
294
295   for (int i = 0; i < JvGetArrayLength (array); ++i)
296     {
297       jobject obj = elements (array)[i];
298       p = (ptr_t) obj;
299       MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array, e2label);
300     }
301
302   return mark_stack_ptr;
303 }
304
305 // Allocate space for a new Java object.  FIXME: this might be the
306 // wrong interface; we might prefer to pass in the object type as
307 // well.  It isn't important for this collector, but it might be for
308 // other collectors.
309 void *
310 _Jv_AllocObj (jsize size)
311 {
312   return GC_GENERIC_MALLOC (size, obj_kind_x);
313 }
314
315 // Allocate space for a new Java array.  FIXME: again, this might be
316 // the wrong interface.
317 void *
318 _Jv_AllocArray (jsize size)
319 {
320   return GC_GENERIC_MALLOC (size, array_kind_x);
321 }
322
323 // Allocate some space that is known to be pointer-free.
324 void *
325 _Jv_AllocBytes (jsize size)
326 {
327   void *r = GC_GENERIC_MALLOC (size, PTRFREE);
328   // We have to explicitly zero memory here, as the GC doesn't
329   // guarantee that PTRFREE allocations are zeroed.  Note that we
330   // don't have to do this for other allocation types because we set
331   // the `ok_init' flag in the type descriptor.
332   if (__builtin_expect (r != NULL, !NULL))
333     memset (r, 0, size);
334   return r;
335 }
336
337 static void
338 call_finalizer (GC_PTR obj, GC_PTR client_data)
339 {
340   _Jv_FinalizerFunc *fn = (_Jv_FinalizerFunc *) client_data;
341   jobject jobj = (jobject) obj;
342
343   (*fn) (jobj);
344 }
345
346 void
347 _Jv_RegisterFinalizer (void *object, _Jv_FinalizerFunc *meth)
348 {
349   GC_REGISTER_FINALIZER_NO_ORDER (object, call_finalizer, (GC_PTR) meth,
350                                   NULL, NULL);
351 }
352
353 void
354 _Jv_RunFinalizers (void)
355 {
356   GC_invoke_finalizers ();
357 }
358
359 void
360 _Jv_RunAllFinalizers (void)
361 {
362   GC_finalize_all ();
363 }
364
365 void
366 _Jv_RunGC (void)
367 {
368   GC_gcollect ();
369 }
370
371 long
372 _Jv_GCTotalMemory (void)
373 {
374   return GC_get_heap_size ();
375 }
376
377 long
378 _Jv_GCFreeMemory (void)
379 {
380   return GC_get_free_bytes ();
381 }
382
383 void
384 _Jv_GCSetInitialHeapSize (size_t size)
385 {
386   size_t current = GC_get_heap_size ();
387   if (size > current)
388     GC_expand_hp (size - current);
389 }
390
391 void
392 _Jv_GCSetMaximumHeapSize (size_t size)
393 {
394   GC_set_max_heap_size ((GC_word) size);
395 }
396
397 // From boehm's misc.c 
398 extern "C" void GC_enable();
399 extern "C" void GC_disable();
400
401 void
402 _Jv_DisableGC (void)
403 {
404   _Jv_MutexLock (&disable_gc_mutex); 
405   GC_disable();
406   _Jv_MutexUnlock (&disable_gc_mutex); 
407 }
408
409 void
410 _Jv_EnableGC (void)
411 {
412   _Jv_MutexLock (&disable_gc_mutex); 
413   GC_enable();
414   _Jv_MutexUnlock (&disable_gc_mutex); 
415 }
416
417 void
418 _Jv_InitGC (void)
419 {
420   int proc;
421   DCL_LOCK_STATE;
422
423   DISABLE_SIGNALS ();
424   LOCK ();
425
426   if (initialized)
427     {
428       UNLOCK ();
429       ENABLE_SIGNALS ();
430       return;
431     }
432   initialized = 1;
433
434   GC_java_finalization = 1;
435
436   // Set up state for marking and allocation of Java objects.
437   obj_free_list = (ptr_t *) GC_generic_malloc_inner ((MAXOBJSZ + 1)
438                                                      * sizeof (ptr_t),
439                                                      PTRFREE);
440   memset (obj_free_list, 0, (MAXOBJSZ + 1) * sizeof (ptr_t));
441
442   proc = GC_n_mark_procs++;
443   GC_mark_procs[proc] = (mark_proc) _Jv_MarkObj;
444
445   obj_kind_x = GC_n_kinds++;
446   GC_obj_kinds[obj_kind_x].ok_freelist = obj_free_list;
447   GC_obj_kinds[obj_kind_x].ok_reclaim_list = 0;
448   GC_obj_kinds[obj_kind_x].ok_descriptor = MAKE_PROC (proc, 0);
449   GC_obj_kinds[obj_kind_x].ok_relocate_descr = FALSE;
450   GC_obj_kinds[obj_kind_x].ok_init = TRUE;
451
452   // Set up state for marking and allocation of arrays of Java
453   // objects.
454   array_free_list = (ptr_t *) GC_generic_malloc_inner ((MAXOBJSZ + 1)
455                                                        * sizeof (ptr_t),
456                                                        PTRFREE);
457   memset (array_free_list, 0, (MAXOBJSZ + 1) * sizeof (ptr_t));
458
459   proc = GC_n_mark_procs++;
460   GC_mark_procs[proc] = (mark_proc) _Jv_MarkArray;
461
462   array_kind_x = GC_n_kinds++;
463   GC_obj_kinds[array_kind_x].ok_freelist = array_free_list;
464   GC_obj_kinds[array_kind_x].ok_reclaim_list = 0;
465   GC_obj_kinds[array_kind_x].ok_descriptor = MAKE_PROC (proc, 0);
466   GC_obj_kinds[array_kind_x].ok_relocate_descr = FALSE;
467   GC_obj_kinds[array_kind_x].ok_init = TRUE;
468
469   _Jv_MutexInit (&disable_gc_mutex);
470
471   UNLOCK ();
472   ENABLE_SIGNALS ();
473 }