X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=libjava%2Fboehm.cc;h=2e382959ee40d64b4bb9becd12ea81f55b0f1ca8;hb=1e26d88a08a00f3ab609a0d07aad48c3f1bcdfd9;hp=af26c2b7b36efeda49177e2f7ab716487b1d6aed;hpb=cbbf0e3ce1b0416b8a85ca267b7b32a7b1010a86;p=pf3gnuchains%2Fgcc-fork.git diff --git a/libjava/boehm.cc b/libjava/boehm.cc index af26c2b7b36..2e382959ee4 100644 --- a/libjava/boehm.cc +++ b/libjava/boehm.cc @@ -1,6 +1,6 @@ // boehm.cc - interface between libjava and Boehm GC. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation This file is part of libgcj. @@ -26,6 +26,18 @@ details. */ #undef TRUE #undef FALSE +// We include two autoconf headers. Avoid multiple definition warnings. +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#ifdef HAVE_DLFCN_H +#undef _GNU_SOURCE +#define _GNU_SOURCE +#include +#endif + extern "C" { #include @@ -58,6 +70,8 @@ static int array_kind_x; // Freelist used for Java arrays. static void **array_free_list; +static int _Jv_GC_has_static_roots (const char *filename, void *, size_t); + // This is called by the GC during the mark phase. It marks a Java @@ -85,14 +99,14 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void *env) jclass klass = dt->clas; GC_PTR p; + p = (GC_PTR) dt; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj); + # ifndef JV_HASH_SYNCHRONIZATION // Every object has a sync_info pointer. p = (GC_PTR) obj->sync_info; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj); # endif - // Mark the object's class. - p = (GC_PTR) klass; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj); if (__builtin_expect (klass == &java::lang::Class::class$, false)) { @@ -114,25 +128,10 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void *env) MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->superclass; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - for (int i = 0; i < c->constants.size; ++i) - { - /* FIXME: We could make this more precise by using the tags -KKT */ - p = (GC_PTR) c->constants.data[i].p; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - } - -#ifdef INTERPRETER - if (_Jv_IsInterpretedClass (c)) - { - p = (GC_PTR) c->constants.tags; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - p = (GC_PTR) c->constants.data; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - } -#endif - // The vtable might be allocated even for compiled code. - p = (GC_PTR) c->vtable; + p = (GC_PTR) c->constants.tags; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); + p = (GC_PTR) c->constants.data; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); // If the class is an array, then the methods field holds a @@ -141,97 +140,24 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void *env) p = (GC_PTR) c->methods; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - // The vtable might have been set, but the rest of the class - // could still be uninitialized. If this is the case, then - // c.isArray will SEGV. We check for this, and if it is the - // case we just return. - if (__builtin_expect (c->name == NULL, false)) - return mark_stack_ptr; - - if (! c->isArray() && ! c->isPrimitive()) - { - // Scan each method in the cases where `methods' really - // points to a methods structure. - for (int i = 0; i < c->method_count; ++i) - { - p = (GC_PTR) c->methods[i].name; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - p = (GC_PTR) c->methods[i].signature; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - - // Note that we don't have to mark each individual throw - // separately, as these are stored in the constant pool. - p = (GC_PTR) c->methods[i].throws; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - } - } - - // Mark all the fields. p = (GC_PTR) c->fields; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - for (int i = 0; i < c->field_count; ++i) - { - _Jv_Field* field = &c->fields[i]; - - p = (GC_PTR) field->name; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - p = (GC_PTR) field->type; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - - // For the interpreter, we also need to mark the memory - // containing static members - if ((field->flags & java::lang::reflect::Modifier::STATIC)) - { - p = (GC_PTR) field->u.addr; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - - // also, if the static member is a reference, - // mark also the value pointed to. We check for isResolved - // since marking can happen before memory is allocated for - // static members. - // Note that field->u.addr may be null if the class c is - // JV_STATE_LOADED but not JV_STATE_PREPARED (initialized). - if (JvFieldIsRef (field) && p && field->isResolved()) - { - jobject val = *(jobject*) p; - p = (GC_PTR) val; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - } - } - } + // The vtable might be allocated even for compiled code. p = (GC_PTR) c->vtable; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); + p = (GC_PTR) c->interfaces; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - for (int i = 0; i < c->interface_count; ++i) - { - p = (GC_PTR) c->interfaces[i]; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - } p = (GC_PTR) c->loader; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); // The dispatch tables can be allocated at runtime. p = (GC_PTR) c->ancestors; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - if (c->idt) - { - p = (GC_PTR) c->idt; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - if (c->isInterface()) - { - p = (GC_PTR) c->idt->iface.ioffsets; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c->idt); - } - else if (! c->isPrimitive()) - { - // This field is only valid for ordinary classes. - p = (GC_PTR) c->idt->cls.itable; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c->idt); - } - } + p = (GC_PTR) c->idt; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->arrayclass; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); @@ -242,72 +168,10 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void *env) p = (GC_PTR) c->aux_info; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); -#ifdef INTERPRETER - if (_Jv_IsInterpretedClass (c) && c->aux_info) - { - _Jv_InterpClass* ic = (_Jv_InterpClass*) c->aux_info; - - p = (GC_PTR) ic->interpreted_methods; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); - - p = (GC_PTR) ic->source_file_name; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); - - for (int i = 0; i < c->method_count; i++) - { - // The interpreter installs a heap-allocated trampoline - // here, so we'll mark it. - p = (GC_PTR) c->methods[i].ncode; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); - - using namespace java::lang::reflect; - - // Mark the direct-threaded code. Note a subtlety here: - // when we add Miranda methods to a class, we don't - // resize its interpreted_methods array. If we try to - // reference one of these methods, we may crash. - // However, we know these are all abstract, and we know - // that abstract methods have nothing useful in this - // array. So, we skip all abstract methods to avoid the - // problem. FIXME: this is pretty obscure, it may be - // better to add a methods to the execution engine and - // resize the array. - if ((c->methods[i].accflags & Modifier::ABSTRACT) != 0) - continue; - - p = (GC_PTR) ic->interpreted_methods[i]; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); - - if ((c->methods[i].accflags & Modifier::NATIVE) != 0) - { - _Jv_JNIMethod *jm - = (_Jv_JNIMethod *) ic->interpreted_methods[i]; - if (jm) - { - p = (GC_PTR) jm->jni_arg_types; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, p); - } - } - else - { - _Jv_InterpMethod *im - = (_Jv_InterpMethod *) ic->interpreted_methods[i]; - if (im) - { - p = (GC_PTR) im->line_table; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); - p = (GC_PTR) im->prepared; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); - } - } - } - - p = (GC_PTR) ic->field_initializers; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); - - } -#endif - + // The class chain must be marked for runtime-allocated Classes + // loaded by the bootstrap ClassLoader. + p = (GC_PTR) c->next_or_version; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); } else { @@ -360,17 +224,16 @@ _Jv_MarkArray (void *addr, void *msp, void *msl, void *env) // we may need to round up the size. if (__builtin_expect (! dt || !(dt -> get_finalizer()), false)) return mark_stack_ptr; - jclass klass = dt->clas; GC_PTR p; + p = (GC_PTR) dt; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array); + # ifndef JV_HASH_SYNCHRONIZATION // Every object has a sync_info pointer. p = (GC_PTR) array->sync_info; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array); # endif - // Mark the object's class. - p = (GC_PTR) klass; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, &(dt -> clas)); for (int i = 0; i < JvGetArrayLength (array); ++i) { @@ -511,7 +374,7 @@ _Jv_AllocArray (jsize size, jclass klass) void * _Jv_AllocRawObj (jsize size) { - return (void *) GC_MALLOC (size); + return (void *) GC_MALLOC (size ? size : 1); } static void @@ -618,10 +481,21 @@ void _Jv_InitGC (void) { int proc; + static bool gc_initialized; + + if (gc_initialized) + return; + + gc_initialized = 1; // Ignore pointers that do not point to the start of an object. GC_all_interior_pointers = 0; +#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR) + // Tell the collector to ask us before scanning DSOs. + GC_register_has_static_roots_callback (_Jv_GC_has_static_roots); +#endif + // Configure the collector to use the bitmap marking descriptors that we // stash in the class vtable. // We always use mark proc descriptor 0, since the compiler knows @@ -709,3 +583,134 @@ _Jv_GCCanReclaimSoftReference (jobject) // For now, always reclaim soft references. FIXME. return true; } + + + +#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR) + +// We keep a store of the filenames of DSOs that need to be +// conservatively scanned by the garbage collector. During collection +// the gc calls _Jv_GC_has_static_roots() to see if the data segment +// of a DSO should be scanned. +typedef struct filename_node +{ + char *name; + struct filename_node *link; +} filename_node; + +#define FILENAME_STORE_SIZE 17 +static filename_node *filename_store[FILENAME_STORE_SIZE]; + +// Find a filename in filename_store. +static filename_node ** +find_file (const char *filename) +{ + int index = strlen (filename) % FILENAME_STORE_SIZE; + filename_node **node = &filename_store[index]; + + while (*node) + { + if (strcmp ((*node)->name, filename) == 0) + return node; + node = &(*node)->link; + } + + return node; +} + +// Print the store of filenames of DSOs that need collection. +void +_Jv_print_gc_store (void) +{ + for (int i = 0; i < FILENAME_STORE_SIZE; i++) + { + filename_node *node = filename_store[i]; + while (node) + { + fprintf (stderr, "%s\n", node->name); + node = node->link; + } + } +} + +// Create a new node in the store of libraries to collect. +static filename_node * +new_node (const char *filename) +{ + filename_node *node = (filename_node*)_Jv_Malloc (sizeof (filename_node)); + node->name = (char *)_Jv_Malloc (strlen (filename) + 1); + node->link = NULL; + strcpy (node->name, filename); + + return node; +} + +// Nonzero if the gc should scan this lib. +static int +_Jv_GC_has_static_roots (const char *filename, void *, size_t) +{ + if (filename == NULL || strlen (filename) == 0) + // No filename; better safe than sorry. + return 1; + + filename_node **node = find_file (filename); + if (*node) + return 1; + + return 0; +} + +#endif + +// Register the DSO that contains p for collection. +void +_Jv_RegisterLibForGc (const void *p __attribute__ ((__unused__))) +{ +#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR) + Dl_info info; + + if (dladdr (const_cast(p), &info) != 0) + { + filename_node **node = find_file (info.dli_fname); + if (! *node) + *node = new_node (info.dli_fname); + } +#endif +} + +void +_Jv_SuspendThread (_Jv_Thread_t *thread) +{ +#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ + && !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS) + GC_suspend_thread (_Jv_GetPlatformThreadID (thread)); +#endif +} + +void +_Jv_ResumeThread (_Jv_Thread_t *thread) +{ +#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ + && !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS) + GC_resume_thread (_Jv_GetPlatformThreadID (thread)); +#endif +} + +void +_Jv_GCAttachThread () +{ + // The registration interface is only defined on posixy systems and + // only actually works if pthread_getattr_np is defined. + // FIXME: until gc7 it is simpler to disable this on solaris. +#if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(GC_SOLARIS_THREADS) + GC_register_my_thread (); +#endif +} + +void +_Jv_GCDetachThread () +{ +#if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(GC_SOLARIS_THREADS) + GC_unregister_my_thread (); +#endif +}