* src/vmcore/loader.c (load_class_from_classbuffer_intern): Also call
[cacao.git] / src / vmcore / loader.c
index 4d547f5753c7608ab81d8ef0c371a36571709409..1c0efb1e6cc7f2354f7f333a24279bb019779208 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vmcore/loader.c - class loader functions
 
-   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
-   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
-   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
-   J. Wenninger, Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
@@ -22,8 +20,6 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: loader.c 7921 2007-05-20 23:14:11Z michi $
-
 */
 
 
@@ -37,6 +33,8 @@
 
 #include "mm/memory.h"
 
+#include "native/llni.h"
+
 #include "threads/lock-common.h"
 
 #include "toolbox/hashtable.h"
@@ -45,6 +43,9 @@
 #include "vm/builtin.h"
 #include "vm/exceptions.h"
 #include "vm/global.h"
+#include "vm/package.h"
+#include "vm/primitive.h"
+#include "vm/resolve.h"
 #include "vm/stringlocal.h"
 #include "vm/vm.h"
 
 #endif
 
 #include "vmcore/classcache.h"
+#include "vmcore/field.h"
 #include "vmcore/linker.h"
 #include "vmcore/loader.h"
+#include "vmcore/method.h"
 #include "vmcore/options.h"
 #include "vmcore/rt-timing.h"
 
 static hashtable *hashtable_classloader;
 
 
-/* loader_init *****************************************************************
+/* loader_preinit **************************************************************
+
+   Initializes the classpath list and loads classes required for the
+   primitive table.
 
-   Initializes all lists and loads all classes required for the system
-   or the compiler.
+   NOTE: Exceptions thrown during VM initialization are caught in the
+         exception functions themselves.
 
 *******************************************************************************/
  
-bool loader_init(void)
+void loader_preinit(void)
 {
 #if defined(ENABLE_THREADS)
        list_classpath_entry *lce;
+#endif
+
+       TRACESUBSYSTEMINITIALIZATION("loader_preinit");
 
+#if defined(ENABLE_THREADS)
        /* 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
 
        /* initialize classloader hashtable, 10 entries should be enough */
@@ -106,131 +117,139 @@ bool loader_init(void)
        hashtable_classloader = NEW(hashtable);
        hashtable_create(hashtable_classloader, 10);
 
-       /* load some important classes */
+       /* Load the most basic classes. */
 
-       if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object)))
-               return false;
+       assert(vm_initializing == true);
 
-       if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String)))
-               return false;
+       class_java_lang_Object     = load_class_bootstrap(utf_java_lang_Object);
 
 #if defined(ENABLE_JAVASE)
-       if (!(class_java_lang_Cloneable =
-                 load_class_bootstrap(utf_java_lang_Cloneable)))
-               return false;
-
-       if (!(class_java_io_Serializable =
-                 load_class_bootstrap(utf_java_io_Serializable)))
-               return false;
-#endif
-
-       /* load classes for wrapping primitive types */
-
-#if defined(ENABLE_JAVASE)
-       if (!(class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void)))
-               return false;
+       class_java_lang_Cloneable  = load_class_bootstrap(utf_java_lang_Cloneable);
+       class_java_io_Serializable = load_class_bootstrap(utf_java_io_Serializable);
 #endif
+}
 
-       if (!(class_java_lang_Boolean =
-                 load_class_bootstrap(utf_java_lang_Boolean)))
-               return false;
 
-       if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte)))
-               return false;
+/* loader_init *****************************************************************
 
-       if (!(class_java_lang_Character =
-                 load_class_bootstrap(utf_java_lang_Character)))
-               return false;
+   Loads all classes required in the VM.
 
-       if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short)))
-               return false;
+   NOTE: Exceptions thrown during VM initialization are caught in the
+         exception functions themselves.
 
-       if (!(class_java_lang_Integer =
-                 load_class_bootstrap(utf_java_lang_Integer)))
-               return false;
+*******************************************************************************/
+void loader_init(void)
+{
+       TRACESUBSYSTEMINITIALIZATION("loader_init");
 
-       if (!(class_java_lang_Long = load_class_bootstrap(utf_java_lang_Long)))
-               return false;
+       /* Load primitive-type wrapping classes. */
 
-       if (!(class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float)))
-               return false;
+       assert(vm_initializing == true);
 
-       if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double)))
-               return false;
+#if defined(ENABLE_JAVASE)
+       class_java_lang_Void       = load_class_bootstrap(utf_java_lang_Void);
+#endif
 
+       class_java_lang_Boolean    = load_class_bootstrap(utf_java_lang_Boolean);
+       class_java_lang_Byte       = load_class_bootstrap(utf_java_lang_Byte);
+       class_java_lang_Character  = load_class_bootstrap(utf_java_lang_Character);
+       class_java_lang_Short      = load_class_bootstrap(utf_java_lang_Short);
+       class_java_lang_Integer    = load_class_bootstrap(utf_java_lang_Integer);
+       class_java_lang_Long       = load_class_bootstrap(utf_java_lang_Long);
+       class_java_lang_Float      = load_class_bootstrap(utf_java_lang_Float);
+       class_java_lang_Double     = load_class_bootstrap(utf_java_lang_Double);
 
-       /* load some other important classes */
+       /* Load important system classes. */
 
-       if (!(class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class)))
-               return false;
+       class_java_lang_Class      = load_class_bootstrap(utf_java_lang_Class);
+       class_java_lang_String     = load_class_bootstrap(utf_java_lang_String);
 
 #if defined(ENABLE_JAVASE)
-       if (!(class_java_lang_ClassLoader =
-                 load_class_bootstrap(utf_java_lang_ClassLoader)))
-               return false;
+       class_java_lang_ClassLoader =
+               load_class_bootstrap(utf_java_lang_ClassLoader);
 
-       if (!(class_java_lang_SecurityManager =
-                 load_class_bootstrap(utf_java_lang_SecurityManager)))
-               return false;
+       class_java_lang_SecurityManager =
+               load_class_bootstrap(utf_java_lang_SecurityManager);
 #endif
 
-       if (!(class_java_lang_System = load_class_bootstrap(utf_java_lang_System)))
-               return false;
+       class_java_lang_System     =
+               load_class_bootstrap(utf_new_char("java/lang/System"));
 
-       if (!(class_java_lang_Thread =
-                 load_class_bootstrap(utf_new_char("java/lang/Thread"))))
-               return false;
+       class_java_lang_Thread     =
+               load_class_bootstrap(utf_new_char("java/lang/Thread"));
 
 #if defined(ENABLE_JAVASE)
-       if (!(class_java_lang_ThreadGroup =
-                 load_class_bootstrap(utf_java_lang_ThreadGroup)))
-               return false;
+       class_java_lang_ThreadGroup =
+               load_class_bootstrap(utf_java_lang_ThreadGroup);
 #endif
 
+       class_java_lang_Throwable  = load_class_bootstrap(utf_java_lang_Throwable);
+
 #if defined(WITH_CLASSPATH_GNU)
-       if (!(class_java_lang_VMSystem =
-                 load_class_bootstrap(utf_new_char("java/lang/VMSystem"))))
+       class_java_lang_VMSystem   =
+               load_class_bootstrap(utf_new_char("java/lang/VMSystem"));
 
-               return false;
+       class_java_lang_VMThread   =
+               load_class_bootstrap(utf_new_char("java/lang/VMThread"));
 
-       if (!(class_java_lang_VMThread =
-                 load_class_bootstrap(utf_new_char("java/lang/VMThread"))))
-               return false;
+       class_java_lang_VMThrowable =
+               load_class_bootstrap(utf_new_char("java/lang/VMThrowable"));
 #endif
 
+       /* Important system exceptions. */
+
+       class_java_lang_Exception  = load_class_bootstrap(utf_java_lang_Exception);
 
-       /* some classes which may be used more often */
+       class_java_lang_ClassNotFoundException =
+               load_class_bootstrap(utf_java_lang_ClassNotFoundException);
+
+       class_java_lang_RuntimeException =
+               load_class_bootstrap(utf_java_lang_RuntimeException);
+
+       /* Some classes which may be used often. */
 
 #if defined(ENABLE_JAVASE)
-       if (!(class_java_lang_StackTraceElement =
-                 load_class_bootstrap(utf_java_lang_StackTraceElement)))
-               return false;
+       class_java_lang_StackTraceElement =
+               load_class_bootstrap(utf_java_lang_StackTraceElement);
 
-       if (!(class_java_lang_reflect_Constructor =
-                 load_class_bootstrap(utf_java_lang_reflect_Constructor)))
-               return false;
+       class_java_lang_reflect_Constructor =
+               load_class_bootstrap(utf_java_lang_reflect_Constructor);
 
-       if (!(class_java_lang_reflect_Field =
-                 load_class_bootstrap(utf_java_lang_reflect_Field)))
-               return false;
+       class_java_lang_reflect_Field =
+               load_class_bootstrap(utf_java_lang_reflect_Field);
 
-       if (!(class_java_lang_reflect_Method =
-                 load_class_bootstrap(utf_java_lang_reflect_Method)))
-               return false;
+       class_java_lang_reflect_Method =
+               load_class_bootstrap(utf_java_lang_reflect_Method);
 
-       if (!(class_java_security_PrivilegedAction =
-                 load_class_bootstrap(utf_new_char("java/security/PrivilegedAction"))))
-               return false;
+       class_java_security_PrivilegedAction =
+               load_class_bootstrap(utf_new_char("java/security/PrivilegedAction"));
 
-       if (!(class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector)))
-               return false;
+       class_java_util_HashMap = 
+               load_class_bootstrap(utf_new_char("java/util/HashMap"));
 
-       if (!(arrayclass_java_lang_Object =
-                 load_class_bootstrap(utf_new_char("[Ljava/lang/Object;"))))
-               return false;
-#endif
+       class_java_util_Vector     = load_class_bootstrap(utf_java_util_Vector);
 
-       return true;
+# if defined(WITH_CLASSPATH_SUN)
+       class_sun_reflect_MagicAccessorImpl =
+               load_class_bootstrap(utf_new_char("sun/reflect/MagicAccessorImpl"));
+# endif
+
+       arrayclass_java_lang_Object =
+               load_class_bootstrap(utf_new_char("[Ljava/lang/Object;"));
+
+# if defined(ENABLE_ANNOTATIONS)
+       /* needed by annotation support */
+       class_sun_reflect_ConstantPool =
+               load_class_bootstrap(utf_new_char("sun/reflect/ConstantPool"));
+
+#  if defined(WITH_CLASSPATH_GNU)
+       /* needed by GNU Classpaths annotation support */
+       class_sun_reflect_annotation_AnnotationParser =
+               load_class_bootstrap(utf_new_char("sun/reflect/annotation/AnnotationParser"));
+#  endif
+# endif
+#endif
 }
 
 
@@ -242,7 +261,7 @@ bool loader_init(void)
 
 *******************************************************************************/
 
-classloader *loader_hashtable_classloader_add(java_objectheader *cl)
+classloader *loader_hashtable_classloader_add(java_handle_t *cl)
 {
        hashtable_classloader_entry *cle;
        u4   key;
@@ -253,28 +272,26 @@ classloader *loader_hashtable_classloader_add(java_objectheader *cl)
 
        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(cl) >> 4;
-#else
-       key  = ((u4) (ptrint) cl) >> 4;
-#endif
-
+       key  = heap_hashcode(LLNI_DIRECT(cl)) >> 4;
        slot = key & (hashtable_classloader->size - 1);
        cle  = hashtable_classloader->ptr[slot];
 
        /* search hashchain for existing entry */
-       /* XXX no GC collection is allowed here, make this a critical section */
 
        while (cle) {
-               if (cle->object == cl)
+               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) {
@@ -283,10 +300,22 @@ classloader *loader_hashtable_classloader_add(java_objectheader *cl)
 #if defined(ENABLE_GC_CACAO)
                /* register the classloader object with the GC */
 
-               gc_reference_register(&(cle->object));
+               gc_reference_register(&(cle->object), GC_REFTYPE_CLASSLOADER);
 #endif
 
-               cle->object = cl;
+               LLNI_CRITICAL_START;
+
+               cle->object = LLNI_DIRECT(cl);
+
+               LLNI_CRITICAL_END;
+
+/*#define LOADER_DEBUG_CLASSLOADER*/
+#ifdef LOADER_DEBUG_CLASSLOADER
+               printf("CLASSLOADER: adding new classloader entry %p for %p: ", cle, cl);
+               class_print(LLNI_vftbl_direct(cl)->class);
+               printf("\n");
+               fflush(stdout);
+#endif
 
                /* insert entry into hashtable */
 
@@ -301,7 +330,11 @@ classloader *loader_hashtable_classloader_add(java_objectheader *cl)
 
        LOCK_MONITOR_EXIT(hashtable_classloader->header);
 
+#if defined(ENABLE_HANDLES)
        return cle;
+#else
+       return cl;
+#endif
 }
 
 
@@ -311,7 +344,7 @@ classloader *loader_hashtable_classloader_add(java_objectheader *cl)
 
 *******************************************************************************/
 
-classloader *loader_hashtable_classloader_find(java_objectheader *cl)
+classloader *loader_hashtable_classloader_find(java_handle_t *cl)
 {
        hashtable_classloader_entry *cle;
        u4   key;
@@ -320,29 +353,40 @@ classloader *loader_hashtable_classloader_find(java_objectheader *cl)
        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(cl) >> 4;
-#else
-       key  = ((u4) (ptrint) cl) >> 4;
-#endif
-
+       key  = heap_hashcode(LLNI_DIRECT(cl)) >> 4;
        slot = key & (hashtable_classloader->size - 1);
        cle  = hashtable_classloader->ptr[slot];
 
        /* search hashchain for existing entry */
-       /* XXX no GC collection is allowed here, make this a critical section */
 
        while (cle) {
-               if (cle->object == cl)
+               if (cle->object == LLNI_DIRECT(cl))
                        break;
 
                cle = cle->hashlink;
        }
 
+#ifdef LOADER_DEBUG_CLASSLOADER
+       if (cle == NULL) {
+               printf("CLASSLOADER: unable to find classloader entry for %p: ", cl);
+               class_print(LLNI_vftbl_direct(cl)->class);
+               printf("\n");
+               fflush(stdout);
+       }
+#endif
+
+       LLNI_CRITICAL_END;
+
+#if defined(ENABLE_HANDLES)
        return cle;
+#else
+       return cl;
+#endif
 }
 
 
@@ -769,17 +813,6 @@ static bool load_constantpool(classbuffer *cb, descriptor_pool *descpool)
 
                cptags[forward_classes->thisindex] = CONSTANT_Class;
 
-               if (opt_eager) {
-                       classinfo *tc;
-
-                       if (!(tc = load_class_bootstrap(name)))
-                               return false;
-
-                       /* link the class later, because we cannot link the class currently
-                          loading */
-                       list_add_first(&unlinkedclasses, tc);
-               }
-
                /* the classref is created later */
                cpinfos[forward_classes->thisindex] = name;
 
@@ -928,633 +961,16 @@ bool loader_load_attribute_signature(classbuffer *cb, utf **signature)
                return false;
        }
 
-       /* get signature */
-
-       signature_index = suck_u2(cb);
-
-       if (!(*signature = class_getconstant(c, signature_index, CONSTANT_Utf8)))
-               return false;
-
-       return true;
-}
-#endif /* defined(ENABLE_JAVASE) */
-
-
-/* load_field ******************************************************************
-
-   Load everything about a class field from the class file and fill a
-   'fieldinfo' structure. For static fields, space in the data segment
-   is allocated.
-
-*******************************************************************************/
-
-#define field_load_NOVALUE  0xffffffff /* must be bigger than any u2 value! */
-
-static bool load_field(classbuffer *cb, fieldinfo *f, descriptor_pool *descpool)
-{
-       classinfo *c;
-       u4 attrnum, i;
-       u4 jtype;
-       u4 pindex = field_load_NOVALUE;     /* constantvalue_index */
-       utf *u;
-
-       c = cb->class;
-
-       if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
-               return false;
-
-       f->flags = suck_u2(cb);
-
-       if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
-               return false;
-
-       f->name = u;
-
-       if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
-               return false;
-
-       f->descriptor = u;
-       f->parseddesc = NULL;
-
-       if (!descriptor_pool_add(descpool, u, NULL))
-               return false;
-
-       /* descriptor_pool_add accepts method descriptors, so we have to check  */
-       /* against them here before the call of descriptor_to_basic_type below. */
-       if (u->text[0] == '(') {
-               exceptions_throw_classformaterror(c, "Method descriptor used for field");
-               return false;
-       }
-
-#ifdef ENABLE_VERIFIER
-       if (opt_verify) {
-               /* check name */
-               if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') {
-                       exceptions_throw_classformaterror(c,
-                                                                                         "Illegal Field name \"%s\"",
-                                                                                         f->name->text);
-                       return false;
-               }
-
-               /* check flag consistency */
-               i = f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED);
-
-               if ((i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) ||
-                       ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE))) {
-                       exceptions_throw_classformaterror(c,
-                                                                                         "Illegal field modifiers: 0x%X",
-                                                                                         f->flags);
-                       return false;
-               }
-
-               if (c->flags & ACC_INTERFACE) {
-                       if (((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
-                               != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) ||
-                               f->flags & ACC_TRANSIENT) {
-                               exceptions_throw_classformaterror(c,
-                                                                                                 "Illegal field modifiers: 0x%X",
-                                                                                                 f->flags);
-                               return false;
-                       }
-               }
-       }
-#endif /* ENABLE_VERIFIER */
-
-       f->type   = jtype = descriptor_to_basic_type(f->descriptor); /* data type */
-       f->offset = 0;                             /* offset from start of object */
-       f->class  = c;
-
-       switch (f->type) {
-       case TYPE_INT:
-               f->value.i = 0;
-               break;
-
-       case TYPE_FLT:
-               f->value.f = 0.0;
-               break;
-
-       case TYPE_DBL:
-               f->value.d = 0.0;
-               break;
-
-       case TYPE_ADR:
-               f->value.a = NULL;
-               if (!(f->flags & ACC_STATIC))
-                       c->flags |= ACC_CLASS_HAS_POINTERS;
-               break;
-
-       case TYPE_LNG:
-#if U8_AVAILABLE
-               f->value.l = 0;
-#else
-               f->value.l.low  = 0;
-               f->value.l.high = 0;
-#endif
-               break;
-       }
-
-       /* read attributes */
-       if (!suck_check_classbuffer_size(cb, 2))
-               return false;
-
-       attrnum = suck_u2(cb);
-       for (i = 0; i < attrnum; i++) {
-               if (!suck_check_classbuffer_size(cb, 2))
-                       return false;
-
-               if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
-                       return false;
-
-               if (u == utf_ConstantValue) {
-                       if (!suck_check_classbuffer_size(cb, 4 + 2))
-                               return false;
-
-                       /* check attribute length */
-
-                       if (suck_u4(cb) != 2) {
-                               exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute");
-                               return false;
-                       }
-                       
-                       /* constant value attribute */
-
-                       if (pindex != field_load_NOVALUE) {
-                               exceptions_throw_classformaterror(c, "Multiple ConstantValue attributes");
-                               return false;
-                       }
-                       
-                       /* index of value in constantpool */
-
-                       pindex = suck_u2(cb);
-               
-                       /* initialize field with value from constantpool */             
-                       switch (jtype) {
-                       case TYPE_INT: {
-                               constant_integer *ci; 
-
-                               if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer)))
-                                       return false;
-
-                               f->value.i = ci->value;
-                       }
-                       break;
-                                       
-                       case TYPE_LNG: {
-                               constant_long *cl; 
-
-                               if (!(cl = class_getconstant(c, pindex, CONSTANT_Long)))
-                                       return false;
-
-                               f->value.l = cl->value;
-                       }
-                       break;
-
-                       case TYPE_FLT: {
-                               constant_float *cf;
-
-                               if (!(cf = class_getconstant(c, pindex, CONSTANT_Float)))
-                                       return false;
-
-                               f->value.f = cf->value;
-                       }
-                       break;
-                                                                                       
-                       case TYPE_DBL: {
-                               constant_double *cd;
-
-                               if (!(cd = class_getconstant(c, pindex, CONSTANT_Double)))
-                                       return false;
-
-                               f->value.d = cd->value;
-                       }
-                       break;
-                                               
-                       case TYPE_ADR:
-                               if (!(u = class_getconstant(c, pindex, CONSTANT_String)))
-                                       return false;
-
-                               /* create javastring from compressed utf8-string */
-                               f->value.a = literalstring_new(u);
-                               break;
-       
-                       default: 
-                               log_text("Invalid Constant - Type");
-                       }
-               }
-#if defined(ENABLE_JAVASE)
-               else if (u == utf_Signature) {
-                       /* Signature */
-
-                       if (!loader_load_attribute_signature(cb, &(f->signature)))
-                               return false;
-               }
-#endif
-               else {
-                       /* unknown attribute */
-
-                       if (!loader_skip_attribute_body(cb))
-                               return false;
-               }
-       }
-
-       /* everything was ok */
-
-       return true;
-}
-
-
-/* loader_load_method **********************************************************
-
-   Loads a method from the class file and fills an existing
-   'methodinfo' structure. For native methods, the function pointer
-   field is set to the real function pointer, for JavaVM methods a
-   pointer to the compiler is used preliminarily.
-
-   method_info {
-       u2 access_flags;
-          u2 name_index;
-          u2 descriptor_index;
-          u2 attributes_count;
-          attribute_info attributes[attribute_count];
-   }
-
-   attribute_info {
-       u2 attribute_name_index;
-          u4 attribute_length;
-          u1 info[attribute_length];
-   }
-
-   LineNumberTable_attribute {
-       u2 attribute_name_index;
-          u4 attribute_length;
-          u2 line_number_table_length;
-          {
-              u2 start_pc;
-                  u2 line_number;
-          } line_number_table[line_number_table_length];
-   }
-
-*******************************************************************************/
-
-static bool loader_load_method(classbuffer *cb, methodinfo *m,
-                                                          descriptor_pool *descpool)
-{
-       classinfo *c;
-       int argcount;
-       s4         i, j, k, l;
-       utf       *u;
-       u2         name_index;
-       u2         descriptor_index;
-       u2         attributes_count;
-       u2         attribute_name_index;
-       utf       *attribute_name;
-       u2         code_attributes_count;
-       u2         code_attribute_name_index;
-       utf       *code_attribute_name;
-
-       /* get classinfo */
-
-       c = cb->class;
-
-#if defined(ENABLE_THREADS)
-       lock_init_object_lock(&m->header);
-#endif
-
-#if defined(ENABLE_STATISTICS)
-       if (opt_stat)
-               count_all_methods++;
-#endif
-
-       /* all fields of m have been zeroed in load_class_from_classbuffer */
-
-       m->class = c;
-       
-       if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
-               return false;
-
-       /* access flags */
-
-       m->flags = suck_u2(cb);
-
-       /* name */
-
-       name_index = suck_u2(cb);
-
-       if (!(u = class_getconstant(c, name_index, CONSTANT_Utf8)))
-               return false;
-
-       m->name = u;
-
-       /* descriptor */
-
-       descriptor_index = suck_u2(cb);
-
-       if (!(u = class_getconstant(c, descriptor_index, CONSTANT_Utf8)))
-               return false;
-
-       m->descriptor = u;
-
-       if (!descriptor_pool_add(descpool, u, &argcount))
-               return false;
-
-#ifdef ENABLE_VERIFIER
-       if (opt_verify) {
-               if (!is_valid_name_utf(m->name)) {
-                       exceptions_throw_classformaterror(c, "Method with invalid name");
-                       return false;
-               }
-
-               if (m->name->text[0] == '<' &&
-                       m->name != utf_init && m->name != utf_clinit) {
-                       exceptions_throw_classformaterror(c, "Method with invalid special name");
-                       return false;
-               }
-       }
-#endif /* ENABLE_VERIFIER */
-       
-       if (!(m->flags & ACC_STATIC))
-               argcount++; /* count the 'this' argument */
-
-#ifdef ENABLE_VERIFIER
-       if (opt_verify) {
-               if (argcount > 255) {
-                       exceptions_throw_classformaterror(c, "Too many arguments in signature");
-                       return false;
-               }
-
-               /* check flag consistency */
-               if (m->name != utf_clinit) {
-                       i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
-
-                       if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) {
-                               exceptions_throw_classformaterror(c,
-                                                                                                 "Illegal method modifiers: 0x%X",
-                                                                                                 m->flags);
-                               return false;
-                       }
-
-                       if (m->flags & ACC_ABSTRACT) {
-                               if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE |
-                                                                ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) {
-                                       exceptions_throw_classformaterror(c,
-                                                                                                         "Illegal method modifiers: 0x%X",
-                                                                                                         m->flags);
-                                       return false;
-                               }
-                       }
-
-                       if (c->flags & ACC_INTERFACE) {
-                               if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) != (ACC_ABSTRACT | ACC_PUBLIC)) {
-                                       exceptions_throw_classformaterror(c,
-                                                                                                         "Illegal method modifiers: 0x%X",
-                                                                                                         m->flags);
-                                       return false;
-                               }
-                       }
-
-                       if (m->name == utf_init) {
-                               if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
-                                                               ACC_NATIVE | ACC_ABSTRACT)) {
-                                       exceptions_throw_classformaterror(c, "Instance initialization method has invalid flags set");
-                                       return false;
-                               }
-                       }
-               }
-       }
-#endif /* ENABLE_VERIFIER */
-
-       /* mark the method as monomorphic until further notice */
-
-       m->flags |= ACC_METHOD_MONOMORPHIC;
-
-       /* non-abstract methods have an implementation in this class */
-
-       if (!(m->flags & ACC_ABSTRACT))
-               m->flags |= ACC_METHOD_IMPLEMENTED;
-               
-       if (!suck_check_classbuffer_size(cb, 2))
-               return false;
-
-       /* attributes count */
-
-       attributes_count = suck_u2(cb);
-
-       for (i = 0; i < attributes_count; i++) {
-               if (!suck_check_classbuffer_size(cb, 2))
-                       return false;
-
-               /* attribute name index */
-
-               attribute_name_index = suck_u2(cb);
-
-               if (!(attribute_name = class_getconstant(c, attribute_name_index, CONSTANT_Utf8)))
-                       return false;
-
-               if (attribute_name == utf_Code) {
-                       /* Code */
-                       if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
-                               exceptions_throw_classformaterror(c, "Code attribute in native or abstract methods");
-                               return false;
-                       }
-                       
-                       if (m->jcode) {
-                               exceptions_throw_classformaterror(c, "Multiple Code attributes");
-                               return false;
-                       }
-
-                       if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
-                               return false;
-
-                       suck_u4(cb);
-                       m->maxstack = suck_u2(cb);
-                       m->maxlocals = suck_u2(cb);
-
-                       if (m->maxlocals < argcount) {
-                               exceptions_throw_classformaterror(c, "Arguments can't fit into locals");
-                               return false;
-                       }
-                       
-                       if (!suck_check_classbuffer_size(cb, 4))
-                               return false;
-
-                       m->jcodelength = suck_u4(cb);
-
-                       if (m->jcodelength == 0) {
-                               exceptions_throw_classformaterror(c, "Code of a method has length 0");
-                               return false;
-                       }
-                       
-                       if (m->jcodelength > 65535) {
-                               exceptions_throw_classformaterror(c, "Code of a method longer than 65535 bytes");
-                               return false;
-                       }
-
-                       if (!suck_check_classbuffer_size(cb, m->jcodelength))
-                               return false;
-
-                       m->jcode = MNEW(u1, m->jcodelength);
-                       suck_nbytes(m->jcode, cb, m->jcodelength);
-
-                       if (!suck_check_classbuffer_size(cb, 2))
-                               return false;
-
-                       m->rawexceptiontablelength = suck_u2(cb);
-                       if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->rawexceptiontablelength))
-                               return false;
-
-                       m->rawexceptiontable = MNEW(raw_exception_entry, m->rawexceptiontablelength);
-
-#if defined(ENABLE_STATISTICS)
-                       if (opt_stat) {
-                               count_vmcode_len += m->jcodelength + 18;
-                               count_extable_len +=
-                                       m->rawexceptiontablelength * sizeof(raw_exception_entry);
-                       }
-#endif
-
-                       for (j = 0; j < m->rawexceptiontablelength; j++) {
-                               u4 idx;
-                               m->rawexceptiontable[j].startpc = suck_u2(cb);
-                               m->rawexceptiontable[j].endpc = suck_u2(cb);
-                               m->rawexceptiontable[j].handlerpc = suck_u2(cb);
-
-                               idx = suck_u2(cb);
-                               if (!idx) {
-                                       m->rawexceptiontable[j].catchtype.any = NULL;
-
-                               } else {
-                                       /* the classref is created later */
-                                       if (!(m->rawexceptiontable[j].catchtype.any =
-                                                 (utf*)class_getconstant(c, idx, CONSTANT_Class)))
-                                               return false;
-                               }
-                       }
-
-                       if (!suck_check_classbuffer_size(cb, 2))
-                               return false;
-
-                       /* code attributes count */
-
-                       code_attributes_count = suck_u2(cb);
-
-                       for (k = 0; k < code_attributes_count; k++) {
-                               if (!suck_check_classbuffer_size(cb, 2))
-                                       return false;
-
-                               /* code attribute name index */
-
-                               code_attribute_name_index = suck_u2(cb);
-
-                               if (!(code_attribute_name = class_getconstant(c, code_attribute_name_index, CONSTANT_Utf8)))
-                                       return false;
-
-                               /* check which code attribute */
-
-                               if (code_attribute_name == utf_LineNumberTable) {
-                                       /* LineNumberTable */
-                                       if (!suck_check_classbuffer_size(cb, 4 + 2))
-                                               return false;
-
-                                       /* attribute length */
-
-                                       (void) suck_u4(cb);
-
-                                       /* line number table length */
-
-                                       m->linenumbercount = suck_u2(cb);
-
-                                       if (!suck_check_classbuffer_size(cb,
-                                                                                               (2 + 2) * m->linenumbercount))
-                                               return false;
-
-                                       m->linenumbers = MNEW(lineinfo, m->linenumbercount);
-
-#if defined(ENABLE_STATISTICS)
-                                       if (opt_stat)
-                                               size_lineinfo += sizeof(lineinfo) * m->linenumbercount;
-#endif
-                                       
-                                       for (l = 0; l < m->linenumbercount; l++) {
-                                               m->linenumbers[l].start_pc    = suck_u2(cb);
-                                               m->linenumbers[l].line_number = suck_u2(cb);
-                                       }
-                               }
-#if defined(ENABLE_JAVASE)
-                               else if (code_attribute_name == utf_StackMapTable) {
-                                       /* StackTableMap */
-
-                                       if (!stackmap_load_attribute_stackmaptable(cb, m))
-                                               return false;
-                               }
-#endif
-                               else {
-                                       /* unknown code attribute */
-
-                                       if (!loader_skip_attribute_body(cb))
-                                               return false;
-                               }
-                       }
-               }
-               else if (attribute_name == utf_Exceptions) {
-                       /* Exceptions */
-
-                       if (m->thrownexceptions != NULL) {
-                               exceptions_throw_classformaterror(c, "Multiple Exceptions attributes");
-                               return false;
-                       }
-
-                       if (!suck_check_classbuffer_size(cb, 4 + 2))
-                               return false;
-
-                       /* attribute length */
-
-                       (void) suck_u4(cb);
-
-                       m->thrownexceptionscount = suck_u2(cb);
-
-                       if (!suck_check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
-                               return false;
-
-                       m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount);
-
-                       for (j = 0; j < m->thrownexceptionscount; j++) {
-                               /* the classref is created later */
-                               if (!((m->thrownexceptions)[j].any =
-                                         (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
-                                       return false;
-                       }
-               }
-#if defined(ENABLE_JAVASE)
-               else if (attribute_name == utf_Signature) {
-                       /* Signature */
-
-                       if (!loader_load_attribute_signature(cb, &(m->signature)))
-                               return false;
-               }
-#endif
-               else {
-                       /* unknown attribute */
-
-                       if (!loader_skip_attribute_body(cb))
-                               return false;
-               }
-       }
-
-       if ((m->jcode == NULL) && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
-               exceptions_throw_classformaterror(c, "Missing Code attribute");
-               return false;
-       }
-
-       /* initialize the hit countdown field */
+       /* get signature */
 
-#if defined(ENABLE_REPLACEMENT)
-       m->hitcountdown = METHOD_INITIAL_HIT_COUNTDOWN;
-#endif
+       signature_index = suck_u2(cb);
 
-       /* everything was ok */
+       if (!(*signature = class_getconstant(c, signature_index, CONSTANT_Utf8)))
+               return false;
 
        return true;
 }
+#endif /* defined(ENABLE_JAVASE) */
 
 
 /* load_class_from_sysloader ***************************************************
@@ -1572,10 +988,10 @@ static bool loader_load_method(classbuffer *cb, methodinfo *m,
 
 classinfo *load_class_from_sysloader(utf *name)
 {
-       methodinfo        *m;
-       java_objectheader *clo;
-       classloader       *cl;
-       classinfo         *c;
+       methodinfo    *m;
+       java_handle_t *clo;
+       classloader   *cl;
+       classinfo     *c;
 
        assert(class_java_lang_Object);
        assert(class_java_lang_ClassLoader);
@@ -1619,10 +1035,10 @@ classinfo *load_class_from_sysloader(utf *name)
 
 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;
@@ -1661,7 +1077,7 @@ classinfo *load_class_from_classloader(utf *name, classloader *cl)
                        case 'L':
                                /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */
                                if (namelen < 4 || text[2] == '[' || text[namelen - 1] != ';') {
-                                       exceptions_throw_noclassdeffounderror(name);
+                                       exceptions_throw_classnotfoundexception(name);
                                        return false;
                                }
 
@@ -1714,16 +1130,27 @@ classinfo *load_class_from_classloader(utf *name, classloader *cl)
                                return c;
                        }
                }
-               
-               assert(class_java_lang_Object);
 
-               lc = class_resolveclassmethod(cl->object->vftbl->class,
+               LLNI_class_get(cl, c);
+
+#if defined(WITH_CLASSPATH_SUN)
+               /* OpenJDK uses this internal function because it's
+                  synchronized. */
+
+               lc = class_resolveclassmethod(c,
+                                                                         utf_loadClassInternal,
+                                                                         utf_java_lang_String__java_lang_Class,
+                                                                         NULL,
+                                                                         true);
+#else
+               lc = class_resolveclassmethod(c,
                                                                          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* */
@@ -1732,11 +1159,11 @@ classinfo *load_class_from_classloader(utf *name, classloader *cl)
 
                RT_TIMING_GET_TIME(time_prepare);
 
-               o = vm_call_method(lc, cl->object, string);
+               o = vm_call_method(lc, (java_handle_t *) cl, string);
 
                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
@@ -1755,18 +1182,6 @@ classinfo *load_class_from_classloader(utf *name, classloader *cl)
                        }
 
                        c = tmpc;
-
-               } else {
-                       /* loadClass has thrown an exception.  We must convert
-                          ClassNotFoundException into
-                          NoClassDefFoundException. */
-
-                       /* XXX Maybe we should have a flag that avoids this
-                          conversion for calling load_class_from_classloader from
-                          Class.forName.  Currently we do a double conversion in
-                          these cases.  */
-
-                       classnotfoundexception_to_noclassdeffounderror();
                }
 
                RT_TIMING_GET_TIME(time_cache);
@@ -1833,8 +1248,9 @@ classinfo *load_class_bootstrap(utf *name)
 
        /* lookup if this class has already been loaded */
 
-       if ((r = classcache_lookup(NULL, name))) {
+       r = classcache_lookup(NULL, name);
 
+       if (r != NULL) {
                RT_TIMING_GET_TIME(time_lookup);
                RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_BOOT_LOOKUP);
                
@@ -1852,8 +1268,10 @@ classinfo *load_class_bootstrap(utf *name)
 
        if (name->text[0] == '[') {
                c = load_newly_created_array(c, NULL);
+
                if (c == NULL)
                        return NULL;
+
                assert(c->state & CLASS_LOADED);
 
                RT_TIMING_GET_TIME(time_array);
@@ -1877,13 +1295,7 @@ classinfo *load_class_bootstrap(utf *name)
        cb = suck_start(c);
 
        if (cb == NULL) {
-               /* this normally means, the classpath was not set properly */
-
-               if (name == utf_java_lang_Object)
-                       vm_abort("java/lang/NoClassDefFoundError: java/lang/Object");
-
-               exceptions_throw_noclassdeffounderror(name);
-
+               exceptions_throw_classnotfoundexception(name);
                return NULL;
        }
 
@@ -1895,22 +1307,27 @@ classinfo *load_class_bootstrap(utf *name)
 
        RT_TIMING_GET_TIME(time_load);
        
-       if (!r) {
+       if (r == NULL) {
                /* the class could not be loaded, free the classinfo struct */
 
                class_free(c);
-
-       else {
+       }
+       else {
                /* Store this class in the loaded class cache this step also
-               checks the loading constraints. If the class has been loaded
-               before, the earlier loaded class is returned. */
+                  checks the loading constraints. If the class has been
+                  loaded before, the earlier loaded class is returned. */
 
                classinfo *res = classcache_store(NULL, c, true);
 
-               if (!res) {
+               if (res == NULL) {
                        /* exception */
                        class_free(c);
                }
+               else {
+                       /* Add the package name to the boot packages. */
+
+                       package_add(c->packagename);
+               }
 
                r = res;
        }
@@ -1948,30 +1365,30 @@ 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.
+   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.
 
-   The super class and the interfaces implemented by this class need
-   not be loaded. The link is set later by the function 'class_link'.
-
-   The loaded class is removed from the list 'unloadedclasses' and
-   added to the list 'unlinkedclasses'.
-       
    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;
+       classinfo          *c;
+       classinfo          *tc;
+       utf                *name;
+       utf                *supername;
+       utf               **interfacesnames;
+       utf                *u;
+       constant_classref  *cr;
+       int16_t             index;
+
        u4 i,j;
        u4 ma, mi;
-       s4 dumpsize;
        descriptor_pool *descpool;
 #if defined(ENABLE_STATISTICS)
        u4 classrefsize;
@@ -1986,44 +1403,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 */
@@ -2033,7 +1424,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);
@@ -2047,14 +1438,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. */
@@ -2075,7 +1466,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) {
@@ -2087,18 +1478,20 @@ 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 */
+       /* This class. */
 
-       i = suck_u2(cb);
+       index = suck_u2(cb);
 
-       if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class)))
-               goto return_exception;
+       name = (utf *) class_getconstant(c, index, CONSTANT_Class);
+
+       if (name == NULL)
+               return false;
 
        if (c->name == utf_not_named_yet) {
                /* we finally have a name for this class */
@@ -2107,92 +1500,112 @@ 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 */
+       /* Retrieve superclass. */
+
+       c->super = NULL;
+
+       index = suck_u2(cb);
+
+       if (index == 0) {
+               supername = NULL;
+
+               /* This is only allowed for java.lang.Object. */
 
-       c->super.any = NULL;
+               if (c->name != utf_java_lang_Object) {
+                       exceptions_throw_classformaterror(c, "Bad superclass index");
+                       return false;
+               }
+       }
+       else {
+               supername = (utf *) class_getconstant(c, index, CONSTANT_Class);
 
-       if ((i = suck_u2(cb))) {
-               if (!(supername = (utf *) class_getconstant(c, i, CONSTANT_Class)))
-                       goto return_exception;
+               if (supername == NULL)
+                       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. */
+               /* Detect circularity. */
 
-               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;
+               if (supername == c->name) {
+                       exceptions_throw_classcircularityerror(c);
+                       return false;
                }
 
-       } else {
-               supername = NULL;
-
-               /* This is only allowed for java.lang.Object. */
+               /* Interfaces must have java.lang.Object as super class. */
 
-               if (c->name != utf_java_lang_Object) {
-                       exceptions_throw_classformaterror(c, "Bad superclass index");
-                       goto return_exception;
+               if ((c->flags & ACC_INTERFACE) && (supername != utf_java_lang_Object)) {
+                       exceptions_throw_classformaterror(c, "Interfaces must have java.lang.Object as superclass");
+                       return false;
                }
        }
 
-       /* retrieve interfaces */
+       /* Parse the super 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(classinfo*, c->interfacescount);
+
+       /* Get the names of the super interfaces. */
+
+       interfacesnames = DMNEW(utf*, c->interfacescount);
 
-       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;
+               index = suck_u2(cb);
+
+               u = (utf *) class_getconstant(c, index, CONSTANT_Class);
+
+               if (u == NULL)
+                       return false;
+
+               interfacesnames[i] = u;
        }
 
        RT_TIMING_GET_TIME(time_setup);
 
-       /* load fields */
+       /* Parse 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 (!load_field(cb, &(c->fields[i]),descpool))
-                       goto return_exception;
+               if (!field_load(cb, &(c->fields[i]), descpool))
+                       return false;
        }
 
        RT_TIMING_GET_TIME(time_fields);
 
-       /* load methods */
+       /* Parse 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 (!loader_load_method(cb, &(c->methods[i]), descpool))
-                       goto return_exception;
+               if (!method_load(cb, &(c->methods[i]), descpool))
+                       return false;
        }
 
        RT_TIMING_GET_TIME(time_methods);
@@ -2221,6 +1634,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
        RT_TIMING_GET_TIME(time_descs);
 
        /* put the classrefs in the constant pool */
+
        for (i = 0; i < c->cpcount; i++) {
                if (c->cptags[i] == CONSTANT_Class) {
                        utf *name = (utf *) c->cpinfos[i];
@@ -2228,34 +1642,87 @@ classinfo *load_class_from_classbuffer(classbuffer *cb)
                }
        }
 
-       /* set the super class reference */
+       /* Resolve the super class. */
+
+       if (supername != NULL) {
+               cr = descriptor_pool_lookup_classref(descpool, supername);
+
+               if (cr == NULL)
+                       return false;
+
+               /* XXX This should be done better. */
+               tc = resolve_classref_or_classinfo_eager(CLASSREF_OR_CLASSINFO(cr), false);
+
+               if (tc == NULL) {
+                       resolve_handle_pending_exception(true);
+                       return false;
+               }
+
+               /* Interfaces are not allowed as super classes. */
+
+               if (tc->flags & ACC_INTERFACE) {
+                       exceptions_throw_incompatibleclasschangeerror(c, "class %s has interface %s as super class");
+                       return false;
+               }
+
+               /* Don't allow extending final classes */
+
+               if (tc->flags & ACC_FINAL) {
+                       exceptions_throw_verifyerror(NULL,
+                                                                                "Cannot inherit from final class");
+                       return false;
+               }
+
+               /* Store the super class. */
 
-       if (supername) {
-               c->super.ref = descriptor_pool_lookup_classref(descpool, supername);
-               if (!c->super.ref)
-                       goto return_exception;
+               c->super = tc;
        }
 
-       /* set the super interfaces references */
+       /* Resolve the super interfaces. */
 
        for (i = 0; i < c->interfacescount; i++) {
-               c->interfaces[i].ref =
-                       descriptor_pool_lookup_classref(descpool,
-                                                                                       (utf *) c->interfaces[i].any);
-               if (!c->interfaces[i].ref)
-                       goto return_exception;
+               u  = interfacesnames[i];
+               cr = descriptor_pool_lookup_classref(descpool, u);
+
+               if (cr == NULL)
+                       return false;
+
+               /* XXX This should be done better. */
+               tc = resolve_classref_or_classinfo_eager(CLASSREF_OR_CLASSINFO(cr), false);
+
+               if (tc == NULL) {
+                       resolve_handle_pending_exception(true);
+                       return false;
+               }
+
+               /* Detect circularity. */
+
+               if (tc == c) {
+                       exceptions_throw_classcircularityerror(c);
+                       return false;
+               }
+
+               if (!(tc->flags & ACC_INTERFACE)) {
+                       exceptions_throw_incompatibleclasschangeerror(tc,
+                                                                                                                 "Implementing class");
+                       return false;
+               }
+
+               /* Store the super interface. */
+
+               c->interfaces[i] = tc;
        }
 
        RT_TIMING_GET_TIME(time_setrefs);
 
-       /* parse field descriptors */
+       /* Parse the field descriptors. */
 
        for (i = 0; i < c->fieldscount; i++) {
                c->fields[i].parseddesc =
                        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);
@@ -2268,23 +1735,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;
                }
        }
 
@@ -2303,13 +1772,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:
@@ -2319,14 +1789,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;
                }
        }
@@ -2382,7 +1852,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]));
                        }
@@ -2399,13 +1869,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;
@@ -2413,7 +1876,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]));
                        }
@@ -2437,12 +1900,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 */
@@ -2450,32 +1912,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);
@@ -2492,16 +1934,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;
+       bool       result;
+       int32_t    dumpmarker;
+
+       /* 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. */
+
+       DMARKER;
+
+       /* Class is currently loading. */
+
+       c->state |= CLASS_LOADING;
+
+       /* Parse the classbuffer. */
+
+       result = load_class_from_classbuffer_intern(cb);
+
+       /* Release dump area. */
+
+       DRELEASE;
+
+       /* An error occurred. */
+
+       if (result == false) {
+               /* Revert loading state. */
+
+               c->state = (c->state & ~CLASS_LOADING);
 
-return_exception:
-       /* release dump area */
+               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 */
 
-       dump_release(dumpsize);
+       if (jvmti)
+               jvmti_ClassLoadPrepare(true, c);
+#endif
 
-       /* an exception has been thrown */
+#if !defined(NDEBUG)
+       if (loadverbose)
+               log_message_class("Loading done class: ", c);
+#endif
 
-       return NULL;
+       return c;
 }
 
 
@@ -2533,13 +2046,13 @@ classinfo *load_newly_created_array(classinfo *c, classloader *loader)
        s4                 namelen;
        utf               *u;
 
-       text = c->name->text;
+       text    = c->name->text;
        namelen = c->name->blength;
 
        /* Check array class name */
 
        if ((namelen < 2) || (text[0] != '[')) {
-               exceptions_throw_noclassdeffounderror(c->name);
+               exceptions_throw_classnotfoundexception(c->name);
                return NULL;
        }
 
@@ -2550,15 +2063,14 @@ classinfo *load_newly_created_array(classinfo *c, classloader *loader)
                /* c is an array of arrays. We have to create the component class. */
 
                u = utf_new(text + 1, namelen - 1);
-               if (!(comp = load_class_from_classloader(u, loader)))
+
+               comp = load_class_from_classloader(u, loader);
+
+               if (comp == NULL)
                        return NULL;
 
                assert(comp->state & CLASS_LOADED);
 
-               if (opt_eager)
-                       if (!link_class(c))
-                               return NULL;
-
                /* the array's flags are that of the component class */
                c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT;
                c->classloader = comp->classloader;
@@ -2569,7 +2081,7 @@ classinfo *load_newly_created_array(classinfo *c, classloader *loader)
 
                /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */
                if ((namelen < 4) || (text[2] == '[') || (text[namelen - 1] != ';')) {
-                       exceptions_throw_noclassdeffounderror(c->name);
+                       exceptions_throw_classnotfoundexception(c->name);
                        return NULL;
                }
 
@@ -2580,10 +2092,6 @@ classinfo *load_newly_created_array(classinfo *c, classloader *loader)
 
                assert(comp->state & CLASS_LOADED);
 
-               if (opt_eager)
-                       if (!link_class(c))
-                               return NULL;
-
                /* the array's flags are that of the component class */
                c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT;
                c->classloader = comp->classloader;
@@ -2592,9 +2100,11 @@ classinfo *load_newly_created_array(classinfo *c, classloader *loader)
        default:
                /* c is an array of a primitive type */
 
-               /* check for cases like `[II' */
-               if (namelen > 2) {
-                       exceptions_throw_noclassdeffounderror(c->name);
+               /* check for cases like `[II' and whether the character is a
+                  valid primitive type */
+
+               if ((namelen > 2) || (primitive_class_get_by_char(text[1]) == NULL)) {
+                       exceptions_throw_classnotfoundexception(c->name);
                        return NULL;
                }
 
@@ -2609,43 +2119,33 @@ classinfo *load_newly_created_array(classinfo *c, classloader *loader)
        assert(class_java_io_Serializable);
 #endif
 
-       /* setup the array class */
+       /* Setup the array class. */
 
-       c->super.cls = class_java_lang_Object;
+       c->super = class_java_lang_Object;
 
 #if defined(ENABLE_JAVASE)
-       c->interfacescount = 2;
-    c->interfaces      = MNEW(classref_or_classinfo, 2);
-
-       if (opt_eager) {
-               classinfo *tc;
 
-               tc = class_java_lang_Cloneable;
-               assert(tc->state & CLASS_LOADED);
-               list_add_first(&unlinkedclasses, tc);
-               c->interfaces[0].cls = tc;
+       c->interfacescount = 2;
+    c->interfaces      = MNEW(classinfo*, 2);
+       c->interfaces[0]   = class_java_lang_Cloneable;
+       c->interfaces[1]   = class_java_io_Serializable;
 
-               tc = class_java_io_Serializable;
-               assert(tc->state & CLASS_LOADED);
-               list_add_first(&unlinkedclasses, tc);
-               c->interfaces[1].cls = tc;
-       }
-       else {
-               c->interfaces[0].cls = class_java_lang_Cloneable;
-               c->interfaces[1].cls = class_java_io_Serializable;
-       }
 #elif defined(ENABLE_JAVAME_CLDC1_1)
+
        c->interfacescount = 0;
        c->interfaces      = NULL;
+
 #else
-#error unknow Java configuration
+# error unknow Java configuration
 #endif
 
        c->methodscount = 1;
-       c->methods = MNEW(methodinfo, c->methodscount);
+       c->methods      = MNEW(methodinfo, c->methodscount);
+
        MZERO(c->methods, methodinfo, c->methodscount);
 
        classrefs = MNEW(constant_classref, 2);
+
        CLASSREF_INIT(classrefs[0], c, c->name);
        CLASSREF_INIT(classrefs[1], c, utf_java_lang_Object);