* src/mm/cacao-gc/heap.c (heap_alloc_intern) [!NDEBUG]: Added sanity check.
[cacao.git] / src / vmcore / loader.c
index 26447947c10ce9ef8c82854f5ded7bb33482f19c..d7b90d98737ae5b6ea28af05a7aa09be1c043742 100644 (file)
@@ -22,8 +22,6 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: loader.c 8249 2007-07-31 12:59:03Z panzi $
-
 */
 
 
 
 #include "mm/memory.h"
 
+#include "native/llni.h"
+
 #include "threads/lock-common.h"
 
+#include "toolbox/hashtable.h"
 #include "toolbox/logging.h"
 
 #include "vm/builtin.h"
 #include "vm/exceptions.h"
 #include "vm/global.h"
+#include "vm/primitive.h"
 #include "vm/stringlocal.h"
 #include "vm/vm.h"
 
@@ -60,7 +62,6 @@
 #include "vmcore/loader.h"
 #include "vmcore/method.h"
 #include "vmcore/options.h"
-#include "vmcore/primitive.h"
 #include "vmcore/rt-timing.h"
 
 #if defined(ENABLE_STATISTICS)
 #endif
 
 
-/* loader_init *****************************************************************
+/* global variables ***********************************************************/
+
+static hashtable *hashtable_classloader;
+
 
-   Initializes all lists and loads all classes required for the system
-   or the compiler.
+/* loader_preinit **************************************************************
+
+   Initializes the classpath list and loads classes required for the
+   primitive table.
 
 *******************************************************************************/
  
-bool loader_init(void)
+void loader_preinit(void)
 {
 #if defined(ENABLE_THREADS)
        list_classpath_entry *lce;
@@ -93,101 +99,115 @@ bool loader_init(void)
        /* Initialize the monitor pointer for zip/jar file locking. */
 
        for (lce = list_first(list_classpath_entries); lce != NULL;
-                lce = list_next(list_classpath_entries, lce))
+                lce = list_next(list_classpath_entries, lce)) {
                if (lce->type == CLASSPATH_ARCHIVE)
                        LOCK_INIT_OBJECT_LOCK(lce);
+       }
 #endif
 
-       /* load some important classes */
+       /* initialize classloader hashtable, 10 entries should be enough */
 
-       if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object)))
-               return false;
+       hashtable_classloader = NEW(hashtable);
+       hashtable_create(hashtable_classloader, 10);
 
-       if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String)))
-               return false;
+       /* Load the most basic class. */
+
+       if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object)))
+               vm_abort("loader_preinit: loading java/lang/Object failed");
 
 #if defined(ENABLE_JAVASE)
        if (!(class_java_lang_Cloneable =
                  load_class_bootstrap(utf_java_lang_Cloneable)))
-               return false;
+               vm_abort("loader_preinit: loading java/lang/Cloneable failed");
 
        if (!(class_java_io_Serializable =
                  load_class_bootstrap(utf_java_io_Serializable)))
-               return false;
+               vm_abort("loader_preinit: loading java/io/Serializable failed");
 #endif
+}
+
 
-       /* load classes for wrapping primitive types */
+/* loader_init *****************************************************************
+
+   Loads all classes required in the VM.
+
+*******************************************************************************/
+void loader_init(void)
+{
+       /* Load primitive-type wrapping classes. */
 
 #if defined(ENABLE_JAVASE)
        if (!(class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void)))
-               return false;
+               vm_abort("loader_init: loading failed");
 #endif
 
        if (!(class_java_lang_Boolean =
                  load_class_bootstrap(utf_java_lang_Boolean)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_Character =
                  load_class_bootstrap(utf_java_lang_Character)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_Integer =
                  load_class_bootstrap(utf_java_lang_Integer)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_Long = load_class_bootstrap(utf_java_lang_Long)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double)))
-               return false;
-
+               vm_abort("loader_init: loading failed");
 
-       /* load some other important classes */
+       /* Load important system classes. */
 
        if (!(class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class)))
-               return false;
+               vm_abort("loader_init: loading failed");
+
+       if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String)))
+               vm_abort("loader_init: loading failed");
 
 #if defined(ENABLE_JAVASE)
        if (!(class_java_lang_ClassLoader =
                  load_class_bootstrap(utf_java_lang_ClassLoader)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_SecurityManager =
                  load_class_bootstrap(utf_java_lang_SecurityManager)))
-               return false;
+               vm_abort("loader_init: loading failed");
 #endif
 
        if (!(class_java_lang_System = load_class_bootstrap(utf_java_lang_System)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_Thread =
                  load_class_bootstrap(utf_new_char("java/lang/Thread"))))
-               return false;
+               vm_abort("loader_init: loading failed");
 
 #if defined(ENABLE_JAVASE)
        if (!(class_java_lang_ThreadGroup =
                  load_class_bootstrap(utf_java_lang_ThreadGroup)))
-               return false;
+               vm_abort("loader_init: loading failed");
 #endif
 
 #if defined(WITH_CLASSPATH_GNU)
        if (!(class_java_lang_VMSystem =
                  load_class_bootstrap(utf_new_char("java/lang/VMSystem"))))
-
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_VMThread =
                  load_class_bootstrap(utf_new_char("java/lang/VMThread"))))
-               return false;
+               vm_abort("loader_init: loading failed");
 #endif
 
 
@@ -196,54 +216,173 @@ bool loader_init(void)
 #if defined(ENABLE_JAVASE)
        if (!(class_java_lang_StackTraceElement =
                  load_class_bootstrap(utf_java_lang_StackTraceElement)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_reflect_Constructor =
                  load_class_bootstrap(utf_java_lang_reflect_Constructor)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_reflect_Field =
                  load_class_bootstrap(utf_java_lang_reflect_Field)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_lang_reflect_Method =
                  load_class_bootstrap(utf_java_lang_reflect_Method)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_security_PrivilegedAction =
                  load_class_bootstrap(utf_new_char("java/security/PrivilegedAction"))))
-               return false;
+               vm_abort("loader_init: loading failed");
 
        if (!(class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector)))
-               return false;
+               vm_abort("loader_init: loading failed");
 
 # if defined(WITH_CLASSPATH_SUN)
        if (!(class_sun_reflect_MagicAccessorImpl =
                  load_class_bootstrap(utf_new_char("sun/reflect/MagicAccessorImpl"))))
-               return false;
+               vm_abort("loader_init: loading failed");
 # endif
 
        if (!(arrayclass_java_lang_Object =
                  load_class_bootstrap(utf_new_char("[Ljava/lang/Object;"))))
-               return false;
+               vm_abort("loader_init: loading failed");
 
-#if defined(ENABLE_ANNOTATIONS)
+# if defined(ENABLE_ANNOTATIONS)
        /* needed by annotation support */
        if (!(class_sun_reflect_ConstantPool = 
-                 load_class_bootstrap(utf_sun_reflect_ConstantPool)))
-               return false;
+                 load_class_bootstrap(utf_new_char("sun/reflect/ConstantPool"))))
+               vm_abort("loader_init: loading failed");
 
-#if defined(WITH_CLASSPATH_GNU)
+#  if defined(WITH_CLASSPATH_GNU)
        /* needed by GNU Classpaths annotation support */
        if (!(class_sun_reflect_annotation_AnnotationParser = 
-                 load_class_bootstrap(utf_sun_reflect_annotation_AnnotationParser)))
-               return false;
+                 load_class_bootstrap(utf_new_char("sun/reflect/annotation/AnnotationParser"))))
+               vm_abort("loader_init: loading failed");
+#  endif
+# endif
 #endif
+}
+
+
+/* loader_hashtable_classloader_add ********************************************
+
+   Adds an entry to the classloader hashtable.
+
+   REMEMBER: Also use this to register native loaders!
+
+*******************************************************************************/
+
+classloader *loader_hashtable_classloader_add(java_handle_t *cl)
+{
+       hashtable_classloader_entry *cle;
+       u4   key;
+       u4   slot;
+
+       if (cl == NULL)
+               return NULL;
+
+       LOCK_MONITOR_ENTER(hashtable_classloader->header);
+
+       LLNI_CRITICAL_START;
+
+       /* key for entry is the hashcode of the classloader;
+          aligned to 16-byte boundaries */
+
+#if defined(ENABLE_GC_CACAO)
+       key  = heap_get_hashcode(LLNI_DIRECT(cl)) >> 4;
+#else
+       key  = ((u4) (ptrint) cl) >> 4;
 #endif
+
+       slot = key & (hashtable_classloader->size - 1);
+       cle  = hashtable_classloader->ptr[slot];
+
+       /* search hashchain for existing entry */
+
+       while (cle) {
+               if (cle->object == LLNI_DIRECT(cl))
+                       break;
+
+               cle = cle->hashlink;
+       }
+
+       LLNI_CRITICAL_END;
+
+       /* if no classloader was found, we create a new entry here */
+
+       if (cle == NULL) {
+               cle = NEW(hashtable_classloader_entry);
+
+#if defined(ENABLE_GC_CACAO)
+               /* register the classloader object with the GC */
+
+               gc_reference_register(&(cle->object), GC_REFTYPE_CLASSLOADER);
 #endif
 
+               LLNI_CRITICAL_START;
 
-       return true;
+               cle->object = LLNI_DIRECT(cl);
+
+               LLNI_CRITICAL_END;
+
+               /* insert entry into hashtable */
+
+               cle->hashlink = hashtable_classloader->ptr[slot];
+               hashtable_classloader->ptr[slot] = cle;
+
+               /* update number of entries */
+
+               hashtable_classloader->entries++;
+       }
+
+
+       LOCK_MONITOR_EXIT(hashtable_classloader->header);
+
+       return cle;
+}
+
+
+/* loader_hashtable_classloader_find *******************************************
+
+   Find an entry in the classloader hashtable.
+
+*******************************************************************************/
+
+classloader *loader_hashtable_classloader_find(java_handle_t *cl)
+{
+       hashtable_classloader_entry *cle;
+       u4   key;
+       u4   slot;
+
+       if (cl == NULL)
+               return NULL;
+
+       LLNI_CRITICAL_START;
+
+       /* key for entry is the hashcode of the classloader;
+          aligned to 16-byte boundaries */
+
+#if defined(ENABLE_GC_CACAO)
+       key  = heap_get_hashcode(LLNI_DIRECT(cl)) >> 4;
+#else
+       key  = ((u4) (ptrint) cl) >> 4;
+#endif
+
+       slot = key & (hashtable_classloader->size - 1);
+       cle  = hashtable_classloader->ptr[slot];
+
+       /* search hashchain for existing entry */
+
+       while (cle) {
+               if (cle->object == LLNI_DIRECT(cl))
+                       break;
+
+               cle = cle->hashlink;
+       }
+
+       LLNI_CRITICAL_END;
+
+       return cle;
 }
 
 
@@ -845,9 +984,10 @@ bool loader_load_attribute_signature(classbuffer *cb, utf **signature)
 
 classinfo *load_class_from_sysloader(utf *name)
 {
-       methodinfo        *m;
-       java_objectheader *cl;
-       classinfo         *c;
+       methodinfo    *m;
+       java_handle_t *clo;
+       classloader   *cl;
+       classinfo     *c;
 
        assert(class_java_lang_Object);
        assert(class_java_lang_ClassLoader);
@@ -862,11 +1002,13 @@ classinfo *load_class_from_sysloader(utf *name)
        if (!m)
                return false;
 
-       cl = vm_call_method(m, NULL);
+       clo = vm_call_method(m, NULL);
 
-       if (!cl)
+       if (!clo)
                return false;
 
+       cl = loader_hashtable_classloader_add(clo);
+
        c = load_class_from_classloader(name, cl);
 
        return c;
@@ -887,12 +1029,12 @@ classinfo *load_class_from_sysloader(utf *name)
 
 *******************************************************************************/
 
-classinfo *load_class_from_classloader(utf *name, java_objectheader *cl)
+classinfo *load_class_from_classloader(utf *name, classloader *cl)
 {
-       java_objectheader *o;
-       classinfo         *c;
-       classinfo         *tmpc;
-       java_objectheader *string;
+       java_handle_t *o;
+       classinfo     *c;
+       classinfo     *tmpc;
+       java_handle_t *string;
 #if defined(ENABLE_RT_TIMING)
        struct timespec time_start, time_lookup, time_prepare, time_java, 
                                        time_cache;
@@ -985,15 +1127,24 @@ classinfo *load_class_from_classloader(utf *name, java_objectheader *cl)
                        }
                }
                
-               assert(class_java_lang_Object);
+#if defined(WITH_CLASSPATH_SUN)
+               /* OpenJDK uses this internal function because it's
+                  synchronized. */
 
-               lc = class_resolveclassmethod(cl->vftbl->class,
+               lc = class_resolveclassmethod(cl->object->vftbl->class,
+                                                                         utf_loadClassInternal,
+                                                                         utf_java_lang_String__java_lang_Class,
+                                                                         NULL,
+                                                                         true);
+#else
+               lc = class_resolveclassmethod(cl->object->vftbl->class,
                                                                          utf_loadClass,
                                                                          utf_java_lang_String__java_lang_Class,
-                                                                         class_java_lang_Object,
+                                                                         NULL,
                                                                          true);
+#endif
 
-               if (!lc)
+               if (lc == NULL)
                        return false; /* exception */
 
                /* move return value into `o' and cast it afterwards to a classinfo* */
@@ -1002,11 +1153,15 @@ classinfo *load_class_from_classloader(utf *name, java_objectheader *cl)
 
                RT_TIMING_GET_TIME(time_prepare);
 
-               o = vm_call_method(lc, cl, string);
+#if defined(ENABLE_HANDLES)
+               o = vm_call_method(lc, (java_handle_t *) cl, string);
+#else
+               o = vm_call_method(lc, cl->object, string);
+#endif
 
                RT_TIMING_GET_TIME(time_java);
 
-               c = (classinfo *) o;
+               c = LLNI_classinfo_unwrap(o);
 
                if (c != NULL) {
                        /* Store this class in the loaded class cache. If another
@@ -1209,27 +1364,24 @@ classinfo *load_class_bootstrap(utf *name)
 }
 
 
-/* load_class_from_classbuffer *************************************************
+/* load_class_from_classbuffer_intern ******************************************
        
-   Loads everything interesting about a class from the class file. The
-   'classinfo' structure must have been allocated previously.
-
-   The super class and the interfaces implemented by this class need
-   not be loaded. The link is set later by the function 'class_link'.
+   Loads a class from a classbuffer into a given classinfo structure.
+   Super-classes are also loaded at this point and some verfication
+   checks are done.
 
    SYNCHRONIZATION:
        This function is NOT synchronized!
    
 *******************************************************************************/
 
-classinfo *load_class_from_classbuffer(classbuffer *cb)
+static bool load_class_from_classbuffer_intern(classbuffer *cb)
 {
        classinfo *c;
        utf *name;
        utf *supername;
        u4 i,j;
        u4 ma, mi;
-       s4 dumpsize;
        descriptor_pool *descpool;
 #if defined(ENABLE_STATISTICS)
        u4 classrefsize;
@@ -1244,44 +1396,18 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
 
        RT_TIMING_GET_TIME(time_start);
 
-       /* get the classbuffer's class */
+       /* Get the classbuffer's class. */
 
        c = cb->class;
 
-       /* the class is already loaded */
-
-       if (c->state & CLASS_LOADED)
-               return c;
-
-#if defined(ENABLE_STATISTICS)
-       if (opt_stat)
-               count_class_loads++;
-#endif
-
-#if !defined(NDEBUG)
-       /* output for debugging purposes */
-
-       if (loadverbose)
-               log_message_class("Loading class: ", c);
-#endif
-
-       /* mark start of dump memory area */
-
-       dumpsize = dump_size();
-
-       /* class is currently loading */
-
-       c->state |= CLASS_LOADING;
-
        if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
-               goto return_exception;
+               return false;
 
        /* check signature */
 
        if (suck_u4(cb) != MAGIC) {
                exceptions_throw_classformaterror(c, "Bad magic number");
-
-               goto return_exception;
+               return false;
        }
 
        /* check version */
@@ -1291,7 +1417,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
 
        if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) {
                exceptions_throw_unsupportedclassversionerror(c, ma, mi);
-               goto return_exception;
+               return false;
        }
 
        RT_TIMING_GET_TIME(time_checks);
@@ -1305,14 +1431,14 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
        /* load the constant pool */
 
        if (!load_constantpool(cb, descpool))
-               goto return_exception;
+               return false;
 
        RT_TIMING_GET_TIME(time_cpool);
 
        /* ACC flags */
 
        if (!suck_check_classbuffer_size(cb, 2))
-               goto return_exception;
+               return false;
 
        /* We OR the flags here, as we set already some flags in
           class_create_classinfo. */
@@ -1333,7 +1459,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                        exceptions_throw_classformaterror(c,
                                                                                          "Illegal class modifiers: 0x%X",
                                                                                          c->flags);
-                       goto return_exception;
+                       return false;
                }
 
                if (c->flags & ACC_SUPER) {
@@ -1345,18 +1471,18 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                exceptions_throw_classformaterror(c,
                                                                                  "Illegal class modifiers: 0x%X",
                                                                                  c->flags);
-               goto return_exception;
+               return false;
        }
 
        if (!suck_check_classbuffer_size(cb, 2 + 2))
-               goto return_exception;
+               return false;
 
        /* this class */
 
        i = suck_u2(cb);
 
        if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class)))
-               goto return_exception;
+               return false;
 
        if (c->name == utf_not_named_yet) {
                /* we finally have a name for this class */
@@ -1365,7 +1491,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
        }
        else if (name != c->name) {
                exceptions_throw_noclassdeffounderror_wrong_name(c, name);
-               goto return_exception;
+               return false;
        }
 
        /* retrieve superclass */
@@ -1374,83 +1500,83 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
 
        if ((i = suck_u2(cb))) {
                if (!(supername = (utf *) class_getconstant(c, i, CONSTANT_Class)))
-                       goto return_exception;
+                       return false;
 
                /* java.lang.Object may not have a super class. */
 
                if (c->name == utf_java_lang_Object) {
                        exceptions_throw_classformaterror(NULL, "java.lang.Object with superclass");
-                       goto return_exception;
+                       return false;
                }
 
                /* Interfaces must have java.lang.Object as super class. */
 
                if ((c->flags & ACC_INTERFACE) && (supername != utf_java_lang_Object)) {
                        exceptions_throw_classformaterror(c, "Interfaces must have java.lang.Object as superclass");
-                       goto return_exception;
+                       return false;
                }
-
-       else {
+       }
+       else {
                supername = NULL;
 
                /* This is only allowed for java.lang.Object. */
 
                if (c->name != utf_java_lang_Object) {
                        exceptions_throw_classformaterror(c, "Bad superclass index");
-                       goto return_exception;
+                       return false;
                }
        }
 
        /* retrieve interfaces */
 
        if (!suck_check_classbuffer_size(cb, 2))
-               goto return_exception;
+               return false;
 
        c->interfacescount = suck_u2(cb);
 
        if (!suck_check_classbuffer_size(cb, 2 * c->interfacescount))
-               goto return_exception;
+               return false;
 
        c->interfaces = MNEW(classref_or_classinfo, c->interfacescount);
+
        for (i = 0; i < c->interfacescount; i++) {
                /* the classrefs are created later */
                if (!(c->interfaces[i].any = (utf *) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
-                       goto return_exception;
+                       return false;
        }
 
        RT_TIMING_GET_TIME(time_setup);
 
        /* load fields */
+
        if (!suck_check_classbuffer_size(cb, 2))
-               goto return_exception;
+               return false;
 
        c->fieldscount = suck_u2(cb);
-#if defined(ENABLE_GC_CACAO)
-       c->fields = MNEW(fieldinfo, c->fieldscount);
+       c->fields      = MNEW(fieldinfo, c->fieldscount);
+
        MZERO(c->fields, fieldinfo, c->fieldscount);
-#else
-       c->fields = GCNEW_UNCOLLECTABLE(fieldinfo, c->fieldscount);
-#endif
 
        for (i = 0; i < c->fieldscount; i++) {
                if (!field_load(cb, &(c->fields[i]), descpool))
-                       goto return_exception;
+                       return false;
        }
 
        RT_TIMING_GET_TIME(time_fields);
 
        /* load methods */
+
        if (!suck_check_classbuffer_size(cb, 2))
-               goto return_exception;
+               return false;
 
        c->methodscount = suck_u2(cb);
-       c->methods = MNEW(methodinfo, c->methodscount);
+       c->methods      = MNEW(methodinfo, c->methodscount);
 
        MZERO(c->methods, methodinfo, c->methodscount);
        
        for (i = 0; i < c->methodscount; i++) {
                if (!method_load(cb, &(c->methods[i]), descpool))
-                       goto return_exception;
+                       return false;
        }
 
        RT_TIMING_GET_TIME(time_methods);
@@ -1491,7 +1617,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
        if (supername) {
                c->super.ref = descriptor_pool_lookup_classref(descpool, supername);
                if (!c->super.ref)
-                       goto return_exception;
+                       return false;
        }
 
        /* set the super interfaces references */
@@ -1501,7 +1627,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                        descriptor_pool_lookup_classref(descpool,
                                                                                        (utf *) c->interfaces[i].any);
                if (!c->interfaces[i].ref)
-                       goto return_exception;
+                       return false;
        }
 
        RT_TIMING_GET_TIME(time_setrefs);
@@ -1513,7 +1639,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                        descriptor_pool_parse_field_descriptor(descpool,
                                                                                                   c->fields[i].descriptor);
                if (!c->fields[i].parseddesc)
-                       goto return_exception;
+                       return false;
        }
 
        RT_TIMING_GET_TIME(time_parsefds);
@@ -1526,23 +1652,25 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                        descriptor_pool_parse_method_descriptor(descpool, m->descriptor,
                                                                                                        m->flags, class_get_self_classref(m->class));
                if (!m->parseddesc)
-                       goto return_exception;
+                       return false;
 
                for (j = 0; j < m->rawexceptiontablelength; j++) {
                        if (!m->rawexceptiontable[j].catchtype.any)
                                continue;
+
                        if ((m->rawexceptiontable[j].catchtype.ref =
                                 descriptor_pool_lookup_classref(descpool,
                                                (utf *) m->rawexceptiontable[j].catchtype.any)) == NULL)
-                               goto return_exception;
+                               return false;
                }
 
                for (j = 0; j < m->thrownexceptionscount; j++) {
                        if (!m->thrownexceptions[j].any)
                                continue;
+
                        if ((m->thrownexceptions[j].ref = descriptor_pool_lookup_classref(descpool,
                                                (utf *) m->thrownexceptions[j].any)) == NULL)
-                               goto return_exception;
+                               return false;
                }
        }
 
@@ -1561,13 +1689,14 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                                descriptor_pool_parse_field_descriptor(descpool,
                                                                                                           fmi->descriptor);
                        if (!fmi->parseddesc.fd)
-                               goto return_exception;
+                               return false;
+
                        index = fmi->p.index;
                        fmi->p.classref =
                                (constant_classref *) class_getconstant(c, index,
                                                                                                                CONSTANT_Class);
                        if (!fmi->p.classref)
-                               goto return_exception;
+                               return false;
                        break;
                case CONSTANT_Methodref:
                case CONSTANT_InterfaceMethodref:
@@ -1577,14 +1706,14 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                                (constant_classref *) class_getconstant(c, index,
                                                                                                                CONSTANT_Class);
                        if (!fmi->p.classref)
-                               goto return_exception;
+                               return false;
                        fmi->parseddesc.md =
                                descriptor_pool_parse_method_descriptor(descpool,
                                                                                                                fmi->descriptor,
                                                                                                                ACC_UNDEF,
                                                                                                                fmi->p.classref);
                        if (!fmi->parseddesc.md)
-                               goto return_exception;
+                               return false;
                        break;
                }
        }
@@ -1640,7 +1769,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                                        if (c->fields[old].name == fi->name &&
                                                c->fields[old].descriptor == fi->descriptor) {
                                                exceptions_throw_classformaterror(c, "Repetitive field name/signature");
-                                               goto return_exception;
+                                               return false;
                                        }
                                } while ((old = next[old]));
                        }
@@ -1657,13 +1786,6 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                        index = ((((size_t) mi->name) +
                                          ((size_t) mi->descriptor)) >> shift) % hashlen;
 
-                       /*{ JOWENN
-                               int dbg;
-                               for (dbg=0;dbg<hashlen+hashlen/5;++dbg){
-                                       printf("Hash[%d]:%d\n",dbg,hashtab[dbg]);
-                               }
-                       }*/
-
                        if ((old = hashtab[index])) {
                                old--;
                                next[i] = old;
@@ -1671,7 +1793,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                                        if (c->methods[old].name == mi->name &&
                                                c->methods[old].descriptor == mi->descriptor) {
                                                exceptions_throw_classformaterror(c, "Repetitive method name/signature");
-                                               goto return_exception;
+                                               return false;
                                        }
                                } while ((old = next[old]));
                        }
@@ -1695,12 +1817,11 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
        /* load attribute structures */
 
        if (!class_load_attributes(cb))
-               goto return_exception;
+               return false;
 
-       /* Pre Java 1.5 version don't check this. This implementation is like
-          Java 1.5 do it: for class file version 45.3 we don't check it, older
-          versions are checked.
-        */
+       /* Pre Java 1.5 version don't check this. This implementation is
+          like Java 1.5 do it: for class file version 45.3 we don't check
+          it, older versions are checked. */
 
        if (((ma == 45) && (mi > 3)) || (ma > 45)) {
                /* check if all data has been read */
@@ -1708,32 +1829,12 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
 
                if (classdata_left > 0) {
                        exceptions_throw_classformaterror(c, "Extra bytes at the end of class file");
-                       goto return_exception;
+                       return false;
                }
        }
 
        RT_TIMING_GET_TIME(time_attrs);
 
-       /* release dump area */
-
-       dump_release(dumpsize);
-
-       /* revert loading state and class is loaded */
-
-       c->state = (c->state & ~CLASS_LOADING) | CLASS_LOADED;
-
-#if defined(ENABLE_JVMTI)
-       /* fire Class Prepare JVMTI event */
-
-       if (jvmti)
-               jvmti_ClassLoadPrepare(true, c);
-#endif
-
-#if !defined(NDEBUG)
-       if (loadverbose)
-               log_message_class("Loading done class: ", c);
-#endif
-
        RT_TIMING_TIME_DIFF(time_start     , time_checks    , RT_TIMING_LOAD_CHECKS);
        RT_TIMING_TIME_DIFF(time_checks    , time_ndpool    , RT_TIMING_LOAD_NDPOOL);
        RT_TIMING_TIME_DIFF(time_ndpool    , time_cpool     , RT_TIMING_LOAD_CPOOL);
@@ -1750,16 +1851,87 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
        RT_TIMING_TIME_DIFF(time_verify    , time_attrs     , RT_TIMING_LOAD_ATTRS);
        RT_TIMING_TIME_DIFF(time_start     , time_attrs     , RT_TIMING_LOAD_TOTAL);
 
-       return c;
+       return true;
+}
+
+
+/* load_class_from_classbuffer *************************************************
+
+   Convenience wrapper for load_class_from_classbuffer.
+
+   SYNCHRONIZATION:
+       This function is NOT synchronized!
+   
+*******************************************************************************/
+
+classinfo *load_class_from_classbuffer(classbuffer *cb)
+{
+       classinfo *c;
+       int32_t    dumpsize;
+       bool       result;
+
+       /* Get the classbuffer's class. */
+
+       c = cb->class;
+
+       /* Check if the class is already loaded. */
+
+       if (c->state & CLASS_LOADED)
+               return c;
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               count_class_loads++;
+#endif
+
+#if !defined(NDEBUG)
+       if (loadverbose)
+               log_message_class("Loading class: ", c);
+#endif
+
+       /* Mark start of dump memory area. */
+
+       dumpsize = dump_size();
 
-return_exception:
-       /* release dump area */
+       /* Class is currently loading. */
+
+       c->state |= CLASS_LOADING;
+
+       /* Parse the classbuffer. */
+
+       result = load_class_from_classbuffer_intern(cb);
+
+       /* Release dump area. */
 
        dump_release(dumpsize);
 
-       /* an exception has been thrown */
+       /* An error occurred. */
 
-       return NULL;
+       if (result == false) {
+               /* Revert loading state. */
+
+               c->state = (c->state & ~CLASS_LOADING);
+
+               return NULL;
+       }
+
+       /* Revert loading state and set loaded. */
+
+       c->state = (c->state & ~CLASS_LOADING) | CLASS_LOADED;
+
+#if defined(ENABLE_JVMTI)
+       /* fire Class Prepare JVMTI event */
+
+       if (jvmti)
+               jvmti_ClassLoadPrepare(true, c);
+#endif
+
+#if !defined(NDEBUG)
+       if (loadverbose)
+               log_message_class("Loading done class: ", c);
+#endif
+
+       return c;
 }
 
 
@@ -1781,7 +1953,7 @@ return_exception:
 
 *******************************************************************************/
 
-classinfo *load_newly_created_array(classinfo *c, java_objectheader *loader)
+classinfo *load_newly_created_array(classinfo *c, classloader *loader)
 {
        classinfo         *comp = NULL;
        methodinfo        *clone;