OSDN Git Service

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