Calling convention fixes.
[cacao.git] / src / vm / loader.c
index 5538c668d0aedd86d7cd8aa9f600b3b3555ce218..2a4681af59d61a9e554dc78ed3b8a0762f6fb612 100644 (file)
@@ -1,9 +1,9 @@
-/* loader.c - class loader functions
+/* vm/loader.c - class loader functions
 
 
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
-   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
-   P. Tomsich, J. Wenninger
+   Copyright (C) 1996-2005 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
 
    This file is part of CACAO.
 
 
    This file is part of CACAO.
 
    Contact: cacao@complang.tuwien.ac.at
 
    Authors: Reinhard Grafl
    Contact: cacao@complang.tuwien.ac.at
 
    Authors: Reinhard Grafl
+
    Changes: Andreas Krall
             Roman Obermaiser
             Mark Probst
    Changes: Andreas Krall
             Roman Obermaiser
             Mark Probst
-                       Edwin Steiner
+            Edwin Steiner
+            Christian Thalinger
 
 
-   $Id: loader.c 775 2003-12-14 12:57:05Z edwin $
+   $Id: loader.c 1936 2005-02-10 11:04:10Z twisti $
 
 */
 
 
 
 */
 
 
+#include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 #include <sys/stat.h>
 #include <string.h>
 #include <assert.h>
 #include <sys/stat.h>
-#include "global.h"
-#include "loader.h"
-#include "main.h"
-#include "native.h"
-#include "tables.h"
-#include "builtin.h"
-#include "jit.h"
-#include "asmpart.h"
-#include "toolbox/memory.h"
-#include "toolbox/loging.h"
-#include "threads/thread.h"
-#include "threads/locks.h"
-#include <sys/stat.h>
 
 
-#ifdef USE_ZLIB
-#include "unzip.h"
+#include "mm/memory.h"
+#include "native/native.h"
+#include "native/include/java_lang_Throwable.h"
+
+#if defined(USE_THREADS)
+# if defined(NATIVE_THREADS)
+#  include "threads/native/threads.h"
+# else
+#  include "threads/green/threads.h"
+#  include "threads/green/locks.h"
+# endif
 #endif
 
 #endif
 
-#undef JOWENN_DEBUG
-#undef JOWENN_DEBUG1
-#undef JOWENN_DEBUG2
-
-/* global variables ***********************************************************/
-
-int count_class_infos = 0;      /* variables for measurements                 */
-int count_const_pool_len = 0;
-int count_vftbl_len = 0;
-int count_all_methods = 0;
-int count_vmcode_len = 0;
-int count_extable_len = 0;
-int count_class_loads = 0;
-int count_class_inits = 0;
-
-static s4 interfaceindex;       /* sequential numbering of interfaces         */ 
-
-list unloadedclasses;       /* list of all referenced but not loaded classes  */
-list unlinkedclasses;       /* list of all loaded but not linked classes      */
-list linkedclasses;         /* list of all completely linked classes          */
-
-
-/* utf-symbols for pointer comparison of frequently used strings */
-
-static utf *utf_innerclasses;          /* InnerClasses            */
-static utf *utf_constantvalue;                 /* ConstantValue           */
-static utf *utf_code;                      /* Code                    */
-static utf *utf_finalize;                  /* finalize                */
-static utf *utf_fidesc;                    /* ()V changed             */
-static utf *utf_clinit;                    /* <clinit>                */
-static utf *utf_initsystemclass;       /* initializeSystemClass   */
-static utf *utf_systemclass;           /* java/lang/System        */
-static utf *utf_vmclassloader;      /* java/lang/VMClassLoader */
-static utf *utf_vmclass;            /* java/lang/VMClassLoader */
-static utf *utf_initialize;
-static utf *utf_initializedesc;
-
-
-#ifdef USE_ZLIB
-static unzFile uf = 0;
+#include "toolbox/logging.h"
+#include "vm/exceptions.h"
+#include "vm/builtin.h"
+#include "vm/global.h"
+#include "vm/loader.h"
+#include "vm/options.h"
+#include "vm/statistics.h"
+#include "vm/stringlocal.h"
+#include "vm/tables.h"
+
+#if defined(USE_ZLIB)
+# include "vm/unzip.h"
 #endif
 
 #endif
 
+#include "vm/jit/asmpart.h"
+#include "vm/jit/jit.h"
 
 
-utf* clinit_desc(){
-       return utf_fidesc;
-}
-utf* clinit_name(){
-       return utf_clinit;
-}
 
 
+#undef JOWENN_DEBUG
+#undef JOWENN_DEBUG1
+#undef JOWENN_DEBUG2
 
 
-/* important system classes ***************************************************/
+/* global variables ***********************************************************/
 
 
-classinfo *class_java_lang_Object;
-classinfo *class_java_lang_String;
+static s4 interfaceindex;       /* sequential numbering of interfaces         */
+static s4 classvalue;
 
 
-classinfo *class_java_lang_Throwable;
-classinfo *class_java_lang_Cloneable;
-classinfo *class_java_io_Serializable;
 
 
-/* Pseudo classes for the typechecker */
-classinfo *pseudo_class_Arraystub = NULL;
-classinfo *pseudo_class_Null = NULL;
-classinfo *pseudo_class_New = NULL;
-vftbl *pseudo_class_Arraystub_vftbl = NULL;
+vftbl_t *pseudo_class_Arraystub_vftbl = NULL;
 
 
-/* stefan */
-/* These are made static so they cannot be used for throwing in native */
-/* functions.                                                          */
-static classinfo *class_java_lang_ClassCastException;
-static classinfo *class_java_lang_NullPointerException;
-static classinfo *class_java_lang_ArrayIndexOutOfBoundsException;
-static classinfo *class_java_lang_NegativeArraySizeException;
-static classinfo *class_java_lang_OutOfMemoryError;
-static classinfo *class_java_lang_ArithmeticException;
-static classinfo *class_java_lang_ArrayStoreException;
-static classinfo *class_java_lang_ThreadDeath;
 
 
-static methodinfo method_clone_array;
+/********************************************************************
+   list of classpath entries (either filesystem directories or 
+   ZIP/JAR archives
+********************************************************************/
 
 
-static int loader_inited = 0;
+static classpath_info *classpath_entries = NULL;
 
 
 /******************************************************************************
 
 
 /******************************************************************************
@@ -151,26 +106,17 @@ static int loader_inited = 0;
  * by the ARRAYTYPE_ constants (expcept ARRAYTYPE_OBJECT).
  */
 primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT] = { 
  * by the ARRAYTYPE_ constants (expcept ARRAYTYPE_OBJECT).
  */
 primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT] = { 
-               { NULL, NULL, "java/lang/Integer",   'I', "int"     , "[I", NULL, NULL },
-               { NULL, NULL, "java/lang/Long",      'J', "long"    , "[J", NULL, NULL },
-               { NULL, NULL, "java/lang/Float",     'F', "float"   , "[F", NULL, NULL },
-               { NULL, NULL, "java/lang/Double",    'D', "double"  , "[D", NULL, NULL },
-               { NULL, NULL, "java/lang/Byte",      'B', "byte"    , "[B", NULL, NULL },
-               { NULL, NULL, "java/lang/Character", 'C', "char"    , "[C", NULL, NULL },
-               { NULL, NULL, "java/lang/Short",     'S', "short"   , "[S", NULL, NULL },
-               { NULL, NULL, "java/lang/Boolean",   'Z', "boolean" , "[Z", NULL, NULL },
-               { NULL, NULL, "java/lang/Void",      'V', "void"    , NULL, NULL, NULL }};
-
-/* instances of important system classes **************************************/
-
-java_objectheader *proto_java_lang_ClassCastException;
-java_objectheader *proto_java_lang_NullPointerException;
-java_objectheader *proto_java_lang_ArrayIndexOutOfBoundsException;
-java_objectheader *proto_java_lang_NegativeArraySizeException;
-java_objectheader *proto_java_lang_OutOfMemoryError;
-java_objectheader *proto_java_lang_ArithmeticException;
-java_objectheader *proto_java_lang_ArrayStoreException;
-java_objectheader *proto_java_lang_ThreadDeath;
+       { NULL, NULL, "java/lang/Integer",   'I', "int"     , "[I", NULL, NULL },
+       { NULL, NULL, "java/lang/Long",      'J', "long"    , "[J", NULL, NULL },
+       { NULL, NULL, "java/lang/Float",     'F', "float"   , "[F", NULL, NULL },
+       { NULL, NULL, "java/lang/Double",    'D', "double"  , "[D", NULL, NULL },
+       { NULL, NULL, "java/lang/Byte",      'B', "byte"    , "[B", NULL, NULL },
+       { NULL, NULL, "java/lang/Character", 'C', "char"    , "[C", NULL, NULL },
+       { NULL, NULL, "java/lang/Short",     'S', "short"   , "[S", NULL, NULL },
+       { NULL, NULL, "java/lang/Boolean",   'Z', "boolean" , "[Z", NULL, NULL },
+       { NULL, NULL, "java/lang/Void",      'V', "void"    , NULL, NULL, NULL }
+};
+
 
 /************* functions for reading classdata *********************************
 
 
 /************* functions for reading classdata *********************************
 
@@ -179,104 +125,151 @@ java_objectheader *proto_java_lang_ThreadDeath;
 
 *******************************************************************************/
 
 
 *******************************************************************************/
 
-static char *classpath    = "";     /* searchpath for classfiles              */
-static u1 *classbuffer    = NULL;   /* pointer to buffer with classfile-data  */
-static u1 *classbuf_pos;            /* current position in classfile buffer   */
-static int classbuffer_size;        /* size of classfile-data                 */
+/* check_classbuffer_size ******************************************************
+
+   assert that at least <len> bytes are left to read
+   <len> is limited to the range of non-negative s4 values
+
+*******************************************************************************/
+
+static inline bool check_classbuffer_size(classbuffer *cb, s4 len)
+{
+       if (len < 0 || ((cb->data + cb->size) - cb->pos - 1) < len) {
+               *exceptionptr =
+                       new_classformaterror((cb)->class, "Truncated class file");
+
+               return false;
+       }
+
+       return true;
+}
+
+
+/* suck_nbytes *****************************************************************
+
+   transfer block of classfile data into a buffer
+
+*******************************************************************************/
+
+inline void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len)
+{
+       memcpy(buffer, cb->pos + 1, len);
+       cb->pos += len;
+}
 
 
-/* assert that at least <len> bytes are left to read */
-/* <len> is limited to the range of non-negative s4 values */
-#define ASSERT_LEFT(len)                                                                                               \
-       do {if ( ((s4)(len)) < 0                                                                                        \
-                        || ((classbuffer + classbuffer_size) - classbuf_pos - 1) < (len)) \
-                       panic("Unexpected end of classfile"); } while(0)
 
 
-/* transfer block of classfile data into a buffer */
+/* skip_nbytes ****************************************************************
 
 
-#define suck_nbytes(buffer,len)                                                \
-       do {ASSERT_LEFT(len);                                                   \
-               memcpy(buffer,classbuf_pos+1,len);                      \
-               classbuf_pos+=len;} while (0)
+   skip block of classfile data
+
+*******************************************************************************/
 
 
-/* skip block of classfile data */
+inline void skip_nbytes(classbuffer *cb, s4 len)
+{
+       cb->pos += len;
+}
 
 
-#define skip_nbytes(len)                                               \
-       do {ASSERT_LEFT(len);                                           \
-               classbuf_pos+=len;} while(0)
 
 
-inline u1 suck_u1()
+inline u1 suck_u1(classbuffer *cb)
 {
 {
-       ASSERT_LEFT(1);
-       return *++classbuf_pos;
+       return *++(cb->pos);
 }
 }
-inline u2 suck_u2()
+
+
+inline u2 suck_u2(classbuffer *cb)
 {
 {
-       u1 a=suck_u1(), b=suck_u1();
-       return ((u2)a<<8)+(u2)b;
+       u1 a = suck_u1(cb);
+       u1 b = suck_u1(cb);
+       return ((u2) a << 8) + (u2) b;
 }
 }
-inline u4 suck_u4()
+
+
+inline u4 suck_u4(classbuffer *cb)
 {
 {
-       u1 a=suck_u1(), b=suck_u1(), c=suck_u1(), d=suck_u1();
-       return ((u4)a<<24)+((u4)b<<16)+((u4)c<<8)+(u4)d;
+       u1 a = suck_u1(cb);
+       u1 b = suck_u1(cb);
+       u1 c = suck_u1(cb);
+       u1 d = suck_u1(cb);
+       return ((u4) a << 24) + ((u4) b << 16) + ((u4) c << 8) + (u4) d;
 }
 }
-#define suck_s8() (s8) suck_u8()
-#define suck_s2() (s2) suck_u2()
-#define suck_s4() (s4) suck_u4()
-#define suck_s1() (s1) suck_u1()
 
 
 /* get u8 from classfile data */
 
 
 /* get u8 from classfile data */
-static u8 suck_u8()
+static u8 suck_u8(classbuffer *cb)
 {
 #if U8_AVAILABLE
        u8 lo, hi;
 {
 #if U8_AVAILABLE
        u8 lo, hi;
-       hi = suck_u4();
-       lo = suck_u4();
+       hi = suck_u4(cb);
+       lo = suck_u4(cb);
        return (hi << 32) + lo;
 #else
        u8 v;
        return (hi << 32) + lo;
 #else
        u8 v;
-       v.high = suck_u4();
-       v.low = suck_u4();
+       v.high = suck_u4(cb);
+       v.low = suck_u4(cb);
        return v;
 #endif
 }
 
 
        return v;
 #endif
 }
 
 
+#define suck_s8(a) (s8) suck_u8((a))
+#define suck_s2(a) (s2) suck_u2((a))
+#define suck_s4(a) (s4) suck_u4((a))
+#define suck_s1(a) (s1) suck_u1((a))
+
+
 /* get float from classfile data */
 /* get float from classfile data */
-static float suck_float()
+static float suck_float(classbuffer *cb)
 {
        float f;
 
 #if !WORDS_BIGENDIAN 
 {
        float f;
 
 #if !WORDS_BIGENDIAN 
-               u1 buffer[4];
-               u2 i;
-               for (i = 0; i < 4; i++) buffer[3 - i] = suck_u1();
-               memcpy((u1*) (&f), buffer, 4);
-#else 
-               suck_nbytes((u1*) (&f), 4);
+       u1 buffer[4];
+       u2 i;
+
+       for (i = 0; i < 4; i++)
+               buffer[3 - i] = suck_u1(cb);
+
+       memcpy((u1*) (&f), buffer, 4);
+#else
+       suck_nbytes((u1*) (&f), cb, 4);
 #endif
 
 #endif
 
-       PANICIF (sizeof(float) != 4, "Incompatible float-format");
+       if (sizeof(float) != 4) {
+               *exceptionptr = new_exception_message(string_java_lang_InternalError,
+                                                                                         "Incompatible float-format");
+
+               /* XXX should we exit in such a case? */
+               throw_exception_exit();
+       }
        
        return f;
 }
 
 
 /* get double from classfile data */
        
        return f;
 }
 
 
 /* get double from classfile data */
-static double suck_double()
+static double suck_double(classbuffer *cb)
 {
        double d;
 
 #if !WORDS_BIGENDIAN 
 {
        double d;
 
 #if !WORDS_BIGENDIAN 
-               u1 buffer[8];
-               u2 i;   
-               for (i = 0; i < 8; i++) buffer[7 - i] = suck_u1 ();
-               memcpy((u1*) (&d), buffer, 8);
+       u1 buffer[8];
+       u2 i;   
+
+       for (i = 0; i < 8; i++)
+               buffer[7 - i] = suck_u1(cb);
+
+       memcpy((u1*) (&d), buffer, 8);
 #else 
 #else 
-               suck_nbytes((u1*) (&d), 8);
+       suck_nbytes((u1*) (&d), cb, 8);
 #endif
 
 #endif
 
-       PANICIF (sizeof(double) != 8, "Incompatible double-format" );
+       if (sizeof(double) != 8) {
+               *exceptionptr = new_exception_message(string_java_lang_InternalError,
+                                                                                         "Incompatible double-format");
+
+               /* XXX should we exit in such a case? */
+               throw_exception_exit();
+       }
        
        return d;
 }
        
        return d;
 }
@@ -288,10 +281,128 @@ static double suck_double()
 
 *******************************************************************************/
 
 
 *******************************************************************************/
 
-void suck_init(char *cpath)
+void suck_init(char *classpath)
+{
+       char *start;
+       char *end;
+       char *filename;
+       s4 filenamelen;
+       bool is_zip;
+       classpath_info *cpi;
+       classpath_info *lastcpi;
+
+       /* search for last classpath entry (only if there already some) */
+
+       if ((lastcpi = classpath_entries)) {
+               while (lastcpi->next)
+                       lastcpi = lastcpi->next;
+       }
+
+       for (start = classpath; (*start) != '\0';) {
+
+               /* search for ':' delimiter to get the end of the current entry */
+               for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
+
+               if (start != end) {
+                       is_zip = false;
+                       filenamelen = end - start;
+
+                       if (filenamelen > 3) {
+                               if (strncasecmp(end - 3, "zip", 3) == 0 ||
+                                       strncasecmp(end - 3, "jar", 3) == 0) {
+                                       is_zip = true;
+                               }
+                       }
+
+                       /* allocate memory for filename and fill it */
+
+                       filename = MNEW(char, filenamelen + 2);  /* 2 = "/\0" */
+                       strncpy(filename, start, filenamelen);
+                       filename[filenamelen + 1] = '\0';
+                       cpi = NULL;
+
+                       if (is_zip) {
+#if defined(USE_ZLIB)
+                               unzFile uf = unzOpen(filename);
+
+                               if (uf) {
+                                       cpi = NEW(classpath_info);
+                                       cpi->type = CLASSPATH_ARCHIVE;
+                                       cpi->uf = uf;
+                                       cpi->next = NULL;
+                                       cpi->pd = NULL; /* ProtectionDomain not set yet */
+                                       cpi->path = filename;
+                               }
+
+#else
+                               throw_cacao_exception_exit(string_java_lang_InternalError,
+                                                                                  "zip/jar files not supported");
+#endif
+                               
+                       } else {
+                               cpi = NEW(classpath_info);
+                               cpi->type = CLASSPATH_PATH;
+                               cpi->next = NULL;
+                               cpi->pd = NULL; /* ProtectionDomain not set yet */
+
+                               if (filename[filenamelen - 1] != '/') {/*PERHAPS THIS SHOULD BE READ FROM A GLOBAL CONFIGURATION */
+                                       filename[filenamelen] = '/';
+                                       filename[filenamelen + 1] = '\0';
+                                       filenamelen++;
+                               }
+
+                               cpi->path = filename;
+                               cpi->pathlen = filenamelen;
+                       }
+
+                       /* attach current classpath entry */
+
+                       if (cpi) {
+                               if (!classpath_entries)
+                                       classpath_entries = cpi;
+                               else
+                                       lastcpi->next = cpi;
+
+                               lastcpi = cpi;
+                       }
+               }
+
+               /* goto next classpath entry, skip ':' delimiter */
+
+               if ((*end) == ':') {
+                       start = end + 1;
+
+               } else {
+                       start = end;
+               }
+       }
+}
+
+
+void create_all_classes()
 {
 {
-       classpath   = cpath;
-       classbuffer = NULL;
+       classpath_info *cpi;
+
+       for (cpi = classpath_entries; cpi != 0; cpi = cpi->next) {
+#if defined(USE_ZLIB)
+               if (cpi->type == CLASSPATH_ARCHIVE) {
+                       cacao_entry_s *ce;
+                       unz_s *s;
+
+                       s = (unz_s *) cpi->uf;
+                       ce = s->cacao_dir_list;
+                               
+                       while (ce) {
+                               (void) class_new(ce->name);
+                               ce = ce->next;
+                       }
+
+               } else {
+#endif
+#if defined(USE_ZLIB)
+               }
+#endif
+       }
 }
 
 
 }
 
 
@@ -304,130 +415,132 @@ void suck_init(char *cpath)
        
 *******************************************************************************/
 
        
 *******************************************************************************/
 
-bool suck_start(utf *classname)
+classbuffer *suck_start(classinfo *c)
 {
 {
-
-#define MAXFILENAME 1000               /* maximum length of a filename           */
-       
-       char filename[MAXFILENAME+10];  /* room for '.class'                      */    
-       char *pathpos;                  /* position in searchpath                 */
-       char c, *utf_ptr;               /* pointer to the next utf8-character     */
+       classpath_info *cpi;
+/*     char *utf_ptr; */
+/*     char ch; */
+       char *filename;
+       s4    filenamelen;
+       char *path;
        FILE *classfile;
        FILE *classfile;
-       int  filenamelen, err;
+       bool found;
+       s4 len;
        struct stat buffer;
        struct stat buffer;
-       int isZip;
+       classbuffer *cb;
 
 
-       if (classbuffer)                /* classbuffer is already valid */
-               return true;
+       /* initialize return value */
 
 
-       pathpos = classpath;
-       
-       while (*pathpos) {
+       found = false;
+       cb = NULL;
 
 
-               /* skip path separator */
+       filenamelen = utf_strlen(c->name) + 7;  /* 7 = ".class\0" */
+       filename = MNEW(char, filenamelen);
 
 
-               while (*pathpos == ':')
-                       pathpos++;
-               /* extract directory from searchpath */
+       utf_sprint(filename, c->name);
+       strcat(filename, ".class");
 
 
-               filenamelen = 0;
-               while ((*pathpos) && (*pathpos != ':')) {
-                   PANICIF (filenamelen >= MAXFILENAME, "Filename too long");
-                       filename[filenamelen++] = *(pathpos++);
-                       }
+       /* walk through all classpath entries */
 
 
-               isZip = 0;
-               if (filenamelen > 4) {
-                       if ( ((filename[filenamelen - 1] == 'p') || (filename[filenamelen - 1] == 'P')) &
-                            ((filename[filenamelen - 2] == 'i') || (filename[filenamelen - 2] == 'I')) &
-                                ((filename[filenamelen - 3] == 'z') || (filename[filenamelen - 3] == 'Z')) ) {
-                               isZip = 1;
-                       }
-               }
+       for (cpi = classpath_entries; cpi != NULL && cb == NULL; cpi = cpi->next) {
+#if defined(USE_ZLIB)
+               if (cpi->type == CLASSPATH_ARCHIVE) {
 
 
-               if (isZip) {
-#ifdef USE_ZLIB
-                       filename[filenamelen++] = '\0';
-                       if (uf == 0) uf = unzOpen(filename);
-                       if (uf != 0) {
-                               utf_ptr = classname->text;
-                               filenamelen = 0;
-                               while (utf_ptr < utf_end(classname)) {
-                                       PANICIF (filenamelen >= MAXFILENAME, "Filename too long");
-                                       c = *utf_ptr++;
-                                       if ((c <= ' ' || c > 'z') && (c != '/'))     /* invalid character */ 
-                                               c = '?'; 
-                                       filename[filenamelen++] = c;    
-                               }
-                               strcpy(filename + filenamelen, ".class");
-                               if (cacao_locate(uf,classname) == UNZ_OK) {
-                                       unz_file_info file_info;
-                                       log_text("Class found in zip file");
-                                       if (unzGetCurrentFileInfo(uf, &file_info, filename,
-                                                                                                 sizeof(filename), NULL, 0, NULL, 0) == UNZ_OK) {
-                                               if (unzOpenCurrentFile(uf) == UNZ_OK) {
-                                                       classbuffer_size = file_info.uncompressed_size;                         
-                                                       classbuffer      = MNEW(u1, classbuffer_size);
-                                                       classbuf_pos     = classbuffer - 1;
-                                                       /*printf("classfile size: %d\n",file_info.uncompressed_size);*/
-                                                       if (unzReadCurrentFile(uf, classbuffer, classbuffer_size) == classbuffer_size) {
-                                                               unzCloseCurrentFile(uf);
-                                                               return true;
-                                                       } else {
-                                                               MFREE(classbuffer, u1, classbuffer_size);
-                                                               log_text("Error while unzipping");
-                                                       }
-                                               } else log_text("Error while opening file in archive");
-                                       } else log_text("Error while retrieving fileinfo");
-                               }
-                               unzCloseCurrentFile(uf);
+#if defined(USE_THREADS)
+                       /* enter a monitor on zip/jar archives */
 
 
-                       }
-#endif                 
-               } else {
-                       filename[filenamelen++] = '/';  
-   
-                       /* add classname to filename */
-
-                       utf_ptr = classname->text;
-                       while (utf_ptr < utf_end(classname)) {
-                               PANICIF (filenamelen >= MAXFILENAME, "Filename too long");
-                               c = *utf_ptr++;
-                               if ((c <= ' ' || c > 'z') && (c != '/'))     /* invalid character */ 
-                                       c = '?'; 
-                               filename[filenamelen++] = c;    
-                       }
-       
-                       /* add suffix */
+                       builtin_monitorenter((java_objectheader *) cpi);
+#endif
 
 
-                       strcpy(filename + filenamelen, ".class");
+                       if (cacao_locate(cpi->uf, c->name) == UNZ_OK) {
+                               unz_file_info file_info;
+
+                               if (unzGetCurrentFileInfo(cpi->uf, &file_info, filename,
+                                                                                 sizeof(filename), NULL, 0, NULL, 0) == UNZ_OK) {
+                                       if (unzOpenCurrentFile(cpi->uf) == UNZ_OK) {
+                                               cb = NEW(classbuffer);
+                                               cb->class = c;
+                                               cb->size = file_info.uncompressed_size;
+                                               cb->data = MNEW(u1, cb->size);
+                                               cb->pos = cb->data - 1;
+                                               /* We need this later in use_class_as_object to set a */
+                                               /* correct ProtectionDomain and CodeSource.           */
+                                               c->pd = (struct java_security_ProtectionDomain *) cpi; 
+
+                                               len = unzReadCurrentFile(cpi->uf, cb->data, cb->size);
+
+                                               if (len != cb->size) {
+                                                       suck_stop(cb);
+                                                       log_text("Error while unzipping");
+
+                                               } else {
+                                                       found = true;
+                                               }
 
 
-                       classfile = fopen(filename, "r");
-                       if (classfile) {                                       /* file exists */
+                                       } else {
+                                               log_text("Error while opening file in archive");
+                                       }
 
 
-                               /* determine size of classfile */
+                               } else {
+                                       log_text("Error while retrieving fileinfo");
+                               }
+                       }
+                       unzCloseCurrentFile(cpi->uf);
 
 
-                               /* dolog("File: %s",filename); */
+#if defined(USE_THREADS)
+                       /* leave the monitor */
 
 
-                               err = stat(filename, &buffer);
+                       builtin_monitorexit((java_objectheader *) cpi);
+#endif
 
 
-                               if (!err) {                                /* read classfile data */                            
-                                       classbuffer_size = buffer.st_size;                              
-                                       classbuffer      = MNEW(u1, classbuffer_size);
-                                       classbuf_pos     = classbuffer - 1;
-                                       fread(classbuffer, 1, classbuffer_size, classfile);
-                                       fclose(classfile);
-                                       return true;
+               } else {
+#endif /* USE_ZLIB */
+                       
+                       path = MNEW(char, cpi->pathlen + filenamelen + 1);
+                       strcpy(path, cpi->path);
+                       strcat(path, filename);
+
+                       classfile = fopen(path, "r");
+
+                       if (classfile) {                                   /* file exists */
+                               if (!stat(path, &buffer)) {            /* read classfile data */
+                                       cb = NEW(classbuffer);
+                                       cb->class = c;
+                                       cb->size = buffer.st_size;
+                                       cb->data = MNEW(u1, cb->size);
+                                       cb->pos = cb->data - 1;
+                                       /* We need this later in use_class_as_object to set a     */
+                                       /* correct ProtectionDomain and CodeSource.               */
+                                       c->pd = (struct java_security_ProtectionDomain *) cpi; 
+
+                                       /* read class data */
+                                       len = fread(cb->data, 1, cb->size, classfile);
+
+                                       if (len != buffer.st_size) {
+                                               suck_stop(cb);
+/*                                             if (ferror(classfile)) { */
+/*                                             } */
+
+                                       } else {
+                                               found = true;
+                                       }
                                }
                        }
                                }
                        }
+
+                       MFREE(path, char, cpi->pathlen + filenamelen + 1);
+#if defined(USE_ZLIB)
                }
                }
+#endif
        }
        }
-       if (verbose) {
-               dolog("Warning: Can not open class file '%s'", filename);
+
+       if (opt_verbose) {
+               if (!found)
+                       dolog("Warning: Can not open class file '%s'", filename);
        }
 
        }
 
-       return false;
+       MFREE(filename, char, filenamelen);
+
+       return cb;
 }
 
 
 }
 
 
@@ -439,23 +552,12 @@ bool suck_start(utf *classname)
        
 *******************************************************************************/
 
        
 *******************************************************************************/
 
-void suck_stop()
+void suck_stop(classbuffer *cb)
 {
 {
-       /* determine amount of classdata not retrieved by suck-operations         */
-
-       int classdata_left = ((classbuffer + classbuffer_size) - classbuf_pos - 1);
-
-       if (classdata_left > 0) {
-               /* surplus */           
-               dolog("There are %d access bytes at end of classfile",
-                               classdata_left);
-               /* XXX panic? */
-       }
-
        /* free memory */
 
        /* free memory */
 
-       MFREE(classbuffer, u1, classbuffer_size);
-       classbuffer = NULL;
+       MFREE(cb->data, u1, cb->size);
+       FREE(cb, classbuffer);
 }
 
 
 }
 
 
@@ -463,8 +565,6 @@ void suck_stop()
 /******************* Some support functions ***********************************/
 /******************************************************************************/
 
 /******************* Some support functions ***********************************/
 /******************************************************************************/
 
-
-
 void fprintflags (FILE *fp, u2 f)
 {
    if ( f & ACC_PUBLIC )       fprintf (fp," PUBLIC");
 void fprintflags (FILE *fp, u2 f)
 {
    if ( f & ACC_PUBLIC )       fprintf (fp," PUBLIC");
@@ -480,8 +580,10 @@ void fprintflags (FILE *fp, u2 f)
    if ( f & ACC_ABSTRACT )     fprintf (fp," ABSTRACT");
 }
 
    if ( f & ACC_ABSTRACT )     fprintf (fp," ABSTRACT");
 }
 
+
 /********** internal function: printflags  (only for debugging) ***************/
 /********** internal function: printflags  (only for debugging) ***************/
-void printflags (u2 f)
+
+void printflags(u2 f)
 {
    if ( f & ACC_PUBLIC )       printf (" PUBLIC");
    if ( f & ACC_PRIVATE )      printf (" PRIVATE");
 {
    if ( f & ACC_PUBLIC )       printf (" PUBLIC");
    if ( f & ACC_PRIVATE )      printf (" PRIVATE");
@@ -497,20 +599,6 @@ void printflags (u2 f)
 }
 
 
 }
 
 
-/************************* Function: skipattribute *****************************
-
-       skips a (1) 'attribute' structure in the class file
-
-*******************************************************************************/
-
-static void skipattribute ()
-{
-       u4 len;
-       suck_u2 ();
-       len = suck_u4();
-       skip_nbytes(len);       
-}
-
 /********************** Function: skipattributebody ****************************
 
        skips an attribute after the 16 bit reference to attribute_name has already
 /********************** Function: skipattributebody ****************************
 
        skips an attribute after the 16 bit reference to attribute_name has already
@@ -518,37 +606,85 @@ static void skipattribute ()
        
 *******************************************************************************/
 
        
 *******************************************************************************/
 
-static void skipattributebody ()
+static bool skipattributebody(classbuffer *cb)
 {
        u4 len;
 {
        u4 len;
-       len = suck_u4();
-       skip_nbytes(len);
+
+       if (!check_classbuffer_size(cb, 4))
+               return false;
+
+       len = suck_u4(cb);
+
+       if (!check_classbuffer_size(cb, len))
+               return false;
+
+       skip_nbytes(cb, len);
+
+       return true;
 }
 
 }
 
+
 /************************* Function: skipattributes ****************************
 
        skips num attribute structures
        
 *******************************************************************************/
 
 /************************* Function: skipattributes ****************************
 
        skips num attribute structures
        
 *******************************************************************************/
 
-static void skipattributes (u4 num)
+static bool skipattributes(classbuffer *cb, u4 num)
 {
        u4 i;
 {
        u4 i;
-       for (i = 0; i < num; i++)
-               skipattribute();
+       u4 len;
+
+       for (i = 0; i < num; i++) {
+               if (!check_classbuffer_size(cb, 2 + 4))
+                       return false;
+
+               suck_u2(cb);
+               len = suck_u4(cb);
+
+               if (!check_classbuffer_size(cb, len))
+                       return false;
+
+               skip_nbytes(cb, len);
+       }
+
+       return true;
+}
+
+
+/******************** function:: class_getconstant *****************************
+
+       retrieves the value at position 'pos' of the constantpool of a class
+       if the type of the value is other than 'ctype' the system is stopped
+
+*******************************************************************************/
+
+voidptr class_getconstant(classinfo *c, u4 pos, u4 ctype)
+{
+       /* check index and type of constantpool entry */
+       /* (pos == 0 is caught by type comparison) */
+       if (pos >= c->cpcount || c->cptags[pos] != ctype) {
+               *exceptionptr = new_classformaterror(c, "Illegal constant pool index");
+               return NULL;
+       }
+
+       return c->cpinfos[pos];
 }
 
 }
 
+
 /******************** function: innerclass_getconstant ************************
 
 /******************** function: innerclass_getconstant ************************
 
-    like class_getconstant, but if cptags is ZERO null is returned                                      
+    like class_getconstant, but if cptags is ZERO null is returned
        
 *******************************************************************************/
 
        
 *******************************************************************************/
 
-voidptr innerclass_getconstant (classinfo *c, u4 pos, u4 ctype) 
+voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype)
 {
        /* invalid position in constantpool */
 {
        /* invalid position in constantpool */
-       if (pos >= c->cpcount) 
-               panic ("Attempt to access constant outside range");
+       if (pos >= c->cpcount) {
+               *exceptionptr = new_classformaterror(c, "Illegal constant pool index");
+               return NULL;
+       }
 
        /* constantpool entry of type 0 */      
        if (!c->cptags[pos])
 
        /* constantpool entry of type 0 */      
        if (!c->cptags[pos])
@@ -556,58 +692,121 @@ voidptr innerclass_getconstant (classinfo *c, u4 pos, u4 ctype)
 
        /* check type of constantpool entry */
        if (c->cptags[pos] != ctype) {
 
        /* check type of constantpool entry */
        if (c->cptags[pos] != ctype) {
-               error ("Type mismatch on constant: %d requested, %d here (innerclass_getconstant)",
-                (int) ctype, (int) c->cptags[pos] );
-               }
+               *exceptionptr = new_classformaterror(c, "Illegal constant pool index");
+               return NULL;
+       }
                
        return c->cpinfos[pos];
 }
 
                
        return c->cpinfos[pos];
 }
 
+
+/********************* Function: class_constanttype ****************************
+
+       Determines the type of a class entry in the ConstantPool
+       
+*******************************************************************************/
+
+u4 class_constanttype(classinfo *c, u4 pos)
+{
+       if (pos <= 0 || pos >= c->cpcount) {
+               *exceptionptr = new_classformaterror(c, "Illegal constant pool index");
+               return 0;
+       }
+
+       return c->cptags[pos];
+}
+
+
 /************************ function: attribute_load ****************************
 
     read attributes from classfile
        
 *******************************************************************************/
 
 /************************ function: attribute_load ****************************
 
     read attributes from classfile
        
 *******************************************************************************/
 
-static void attribute_load (u4 num, classinfo *c)
+static bool attribute_load(classbuffer *cb, classinfo *c, u4 num)
 {
 {
-       u4 i,j;
+       utf *aname;
+       u4 i, j;
 
        for (i = 0; i < num; i++) {
 
        for (i = 0; i < num; i++) {
-               /* retrieve attribute name */   
-               utf *aname = class_getconstant (c, suck_u2(), CONSTANT_Utf8);
+               /* retrieve attribute name */
+               if (!check_classbuffer_size(cb, 2))
+                       return false;
 
 
-               if ( aname == utf_innerclasses)  {                      
+               if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+                       return false;
+
+               if (aname == utf_InnerClasses) {
                        /* innerclasses attribute */
                        /* innerclasses attribute */
+                       if (c->innerclass) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Multiple InnerClasses attributes");
+                               return false;
+                       }
                                
                                
-                       /* skip attribute length */                                             
-                       suck_u4(); 
+                       if (!check_classbuffer_size(cb, 4 + 2))
+                               return false;
+
+                       /* skip attribute length */
+                       suck_u4(cb);
+
                        /* number of records */
                        /* number of records */
-                       c->innerclasscount = suck_u2();
-                       /* allocate memory for innerclass structure */
-                       c->innerclass = MNEW (innerclassinfo, c->innerclasscount);
+                       c->innerclasscount = suck_u2(cb);
 
 
-                       for (j=0;j<c->innerclasscount;j++) {
-                               
-                               /*  The innerclass structure contains a class with an encoded name, 
-                                   its defining scope, its simple name  and a bitmask of the access flags. 
-                                   If an inner class is not a member, its outer_class is NULL, 
-                                   if a class is anonymous, its name is NULL.                              */
+                       if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount))
+                               return false;
+
+                       /* allocate memory for innerclass structure */
+                       c->innerclass = MNEW(innerclassinfo, c->innerclasscount);
+
+                       for (j = 0; j < c->innerclasscount; j++) {
+                               /* The innerclass structure contains a class with an encoded
+                                  name, its defining scope, its simple name and a bitmask of
+                                  the access flags. If an inner class is not a member, its
+                                  outer_class is NULL, if a class is anonymous, its name is
+                                  NULL. */
                                                                
                                innerclassinfo *info = c->innerclass + j;
 
                                                                
                                innerclassinfo *info = c->innerclass + j;
 
-                               info->inner_class = innerclass_getconstant(c, suck_u2(), CONSTANT_Class); /* CONSTANT_Class_info index */
-                               info->outer_class = innerclass_getconstant(c, suck_u2(), CONSTANT_Class); /* CONSTANT_Class_info index */
-                               info->name  = innerclass_getconstant(c, suck_u2(), CONSTANT_Utf8);        /* CONSTANT_Utf8_info index  */
-                               info->flags = suck_u2 ();                                                 /* access_flags bitmask      */
+                               info->inner_class =
+                                       innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class);
+                               info->outer_class =
+                                       innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class);
+                               info->name =
+                                       innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
+                               info->flags = suck_u2(cb);
+                       }
+
+               } else if (aname == utf_SourceFile) {
+                       if (!check_classbuffer_size(cb, 4 + 2))
+                               return false;
+
+                       if (suck_u4(cb) != 2) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Wrong size for VALUE attribute");
+                               return false;
+                       }
+
+                       if (c->sourcefile) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Multiple SourceFile attributes");
+                               return false;
                        }
                        }
+
+                       if (!(c->sourcefile = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+                               return false;
+
                } else {
                        /* unknown attribute */
                } else {
                        /* unknown attribute */
-                       skipattributebody ();
+                       if (!skipattributebody(cb))
+                               return false;
                }
        }
                }
        }
+
+       return true;
 }
 
 }
 
+
 /******************* function: checkfielddescriptor ****************************
 
        checks whether a field-descriptor is valid and aborts otherwise
 /******************* function: checkfielddescriptor ****************************
 
        checks whether a field-descriptor is valid and aborts otherwise
@@ -622,6 +821,8 @@ static void checkfielddescriptor (char *utf_ptr, char *end_pos)
                                                  | CLASSLOAD_NULLPRIMITIVE
                                                  | CLASSLOAD_NOVOID
                                                  | CLASSLOAD_CHECKEND);
                                                  | CLASSLOAD_NULLPRIMITIVE
                                                  | CLASSLOAD_NOVOID
                                                  | CLASSLOAD_CHECKEND);
+       
+       /* XXX use the following if -noverify */
 #if 0
        char *tstart;  /* pointer to start of classname */
        char ch;
 #if 0
        char *tstart;  /* pointer to start of classname */
        char ch;
@@ -659,35 +860,62 @@ static void checkfielddescriptor (char *utf_ptr, char *end_pos)
 
     checks whether a method-descriptor is valid and aborts otherwise.
     All referenced classes are inserted into the list of unloaded classes.
 
     checks whether a method-descriptor is valid and aborts otherwise.
     All referenced classes are inserted into the list of unloaded classes.
+
+    The number of arguments is returned. A long or double argument is counted
+    as two arguments.
        
 *******************************************************************************/
 
        
 *******************************************************************************/
 
-static void checkmethoddescriptor (utf *d)
+static int checkmethoddescriptor(classinfo *c, utf *descriptor)
 {
 {
-       char *utf_ptr = d->text;     /* current position in utf text   */
-       char *end_pos = utf_end(d);  /* points behind utf string       */
+       char *utf_ptr;                      /* current position in utf text       */
+       char *end_pos;                      /* points behind utf string           */
+       s4 argcount = 0;                    /* number of arguments                */
+
+       utf_ptr = descriptor->text;
+       end_pos = utf_end(descriptor);
 
        /* method descriptor must start with parenthesis */
 
        /* method descriptor must start with parenthesis */
-       if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+       if (utf_ptr == end_pos || *utf_ptr++ != '(')
+               panic ("Missing '(' in method descriptor");
 
     /* check arguments */
     while (utf_ptr != end_pos && *utf_ptr != ')') {
 
     /* check arguments */
     while (utf_ptr != end_pos && *utf_ptr != ')') {
+               /* We cannot count the this argument here because
+                * we don't know if the method is static. */
+               if (*utf_ptr == 'J' || *utf_ptr == 'D')
+                       argcount+=2;
+               else
+                       argcount++;
                class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
                                                          CLASSLOAD_NEW
                                                          | CLASSLOAD_NULLPRIMITIVE
                                                          | CLASSLOAD_NOVOID);
        }
 
                class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
                                                          CLASSLOAD_NEW
                                                          | CLASSLOAD_NULLPRIMITIVE
                                                          | CLASSLOAD_NOVOID);
        }
 
-       if (utf_ptr == end_pos) panic("Missing return type in method descriptor");
+       if (utf_ptr == end_pos)
+               panic("Missing ')' in method descriptor");
+
     utf_ptr++; /* skip ')' */
 
     utf_ptr++; /* skip ')' */
 
-       class_from_descriptor(utf_ptr,end_pos,NULL,
-                                                 CLASSLOAD_NEW
-                                                 | CLASSLOAD_NULLPRIMITIVE
-                                                 | CLASSLOAD_CHECKEND);
-       
+       class_from_descriptor(utf_ptr,
+                                                 end_pos,
+                                                 NULL,
+                                                 CLASSLOAD_NEW |
+                                                 CLASSLOAD_NULLPRIMITIVE |
+                                                 CLASSLOAD_CHECKEND);
+
+       if (argcount > 255) {
+               *exceptionptr =
+                       new_classformaterror(c, "Too many arguments in signature");
+
+               return 0;
+       }
+
+       return argcount;
+
+       /* XXX use the following if -noverify */
 #if 0
 #if 0
-       /* XXX check length */
        /* check arguments */
        while ((c = *utf_ptr++) != ')') {
                start = utf_ptr-1;
        /* check arguments */
        while ((c = *utf_ptr++) != ')') {
                start = utf_ptr-1;
@@ -769,115 +997,191 @@ void print_arraydescriptor(FILE *file, arraydescriptor *desc)
 /******************************************************************************/
 
 
 /******************************************************************************/
 
 
-/************************ Function: field_load *********************************
+/* field_load ******************************************************************
 
 
-       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.
+   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.
 
 *******************************************************************************/
 
 
 *******************************************************************************/
 
-static void field_load (fieldinfo *f, classinfo *c)
+#define field_load_NOVALUE  0xffffffff /* must be bigger than any u2 value! */
+
+static bool field_load(classbuffer *cb, classinfo *c, fieldinfo *f)
 {
 {
-       u4 attrnum,i;
+       u4 attrnum, i;
        u4 jtype;
        u4 jtype;
+       u4 pindex = field_load_NOVALUE;     /* constantvalue_index */
+       utf *u;
+
+       if (!check_classbuffer_size(cb, 2 + 2 + 2))
+               return false;
+
+       f->flags = suck_u2(cb);
 
 
-       f -> flags = suck_u2 ();                                           /* ACC flags                   */
-       f -> name = class_getconstant (c, suck_u2(), CONSTANT_Utf8);       /* name of field               */
-       f -> descriptor = class_getconstant (c, suck_u2(), CONSTANT_Utf8); /* JavaVM descriptor           */
-       f -> type = jtype = desc_to_type (f->descriptor);                  /* data type                   */
-       f -> offset = 0;                                                   /* offset from start of object */
-       f -> class = c;
+       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;
+
+       if (opt_verify) {
+               /* check name */
+               if (!is_valid_name_utf(f->name) || f->name->text[0] == '<')
+                       panic("Field with invalid name");
+               
+               /* 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))) {
+                       *exceptionptr =
+                               new_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) {
+                               *exceptionptr =
+                                       new_classformaterror(c,
+                                                                                "Illegal field modifiers: 0x%X",
+                                                                                f->flags);
+                               return false;
+                       }
+               }
+
+               /* check descriptor */
+               checkfielddescriptor(f->descriptor->text, utf_end(f->descriptor));
+       }
+               
+       f->type = jtype = desc_to_type(f->descriptor);    /* data type            */
+       f->offset = 0;                             /* offset from start of object */
+       f->class = c;
        f->xta = NULL;
        
        switch (f->type) {
        f->xta = NULL;
        
        switch (f->type) {
-       case TYPE_INT:        f->value.i = 0; break;
-       case TYPE_FLOAT:      f->value.f = 0.0; break;
-       case TYPE_DOUBLE:     f->value.d = 0.0; break;
-       case TYPE_ADDRESS:    f->value.a = NULL;                              
-/*                           heap_addreference (&(f->value.a));           /* make global reference (GC)  */
-                             break;
+       case TYPE_INT:     f->value.i = 0; break;
+       case TYPE_FLOAT:   f->value.f = 0.0; break;
+       case TYPE_DOUBLE:  f->value.d = 0.0; break;
+       case TYPE_ADDRESS: f->value.a = NULL; break;
        case TYPE_LONG:
 #if U8_AVAILABLE
                f->value.l = 0; break;
 #else
                f->value.l.low = 0; f->value.l.high = 0; break;
        case TYPE_LONG:
 #if U8_AVAILABLE
                f->value.l = 0; break;
 #else
                f->value.l.low = 0; f->value.l.high = 0; break;
-#endif 
+#endif
        }
 
        /* read attributes */
        }
 
        /* read attributes */
-       attrnum = suck_u2();
-       for (i=0; i<attrnum; i++) {
-               u4 pindex;
-               utf *aname;
+       if (!check_classbuffer_size(cb, 2))
+               return false;
 
 
-               aname = class_getconstant (c, suck_u2(), CONSTANT_Utf8);
-               
-               if ( aname != utf_constantvalue ) {
-                       /* unknown attribute */
-                       skipattributebody ();
+       attrnum = suck_u2(cb);
+       for (i = 0; i < attrnum; i++) {
+               if (!check_classbuffer_size(cb, 2))
+                       return false;
+
+               if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+                       return false;
+
+               if (u == utf_ConstantValue) {
+                       if (!check_classbuffer_size(cb, 4 + 2))
+                               return false;
+
+                       /* check attribute length */
+                       if (suck_u4(cb) != 2) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Wrong size for VALUE attribute");
+                               return false;
                        }
                        }
-               else {
+                       
                        /* constant value attribute */
                        /* constant value attribute */
+                       if (pindex != field_load_NOVALUE) {
+                               *exceptionptr =
+                                       new_classformaterror(c,
+                                                                                "Multiple ConstantValue attributes");
+                               return false;
+                       }
                        
                        
-                       /* skip attribute length */
-                       suck_u4();
                        /* index of value in constantpool */            
                        /* index of value in constantpool */            
-                       pindex = suck_u2();
+                       pindex = suck_u2(cb);
                
                        /* initialize field with value from constantpool */             
                        switch (jtype) {
                
                        /* initialize field with value from constantpool */             
                        switch (jtype) {
-                               case TYPE_INT: {
-                                       constant_integer *ci = 
-                                               class_getconstant(c, pindex, CONSTANT_Integer);
-                                       f->value.i = ci -> value;
-                                       }
-                                       break;
+                       case TYPE_INT: {
+                               constant_integer *ci; 
+
+                               if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer)))
+                                       return false;
+
+                               f->value.i = ci->value;
+                       }
+                       break;
                                        
                                        
-                               case TYPE_LONG: {
-                                       constant_long *cl = 
-                                          class_getconstant(c, pindex, CONSTANT_Long);
-       
-                                       f->value.l = cl -> value;
-                                       }
-                                       break;
+                       case TYPE_LONG: {
+                               constant_long *cl; 
 
 
-                               case TYPE_FLOAT: {
-                                       constant_float *cf = 
-                                           class_getconstant(c, pindex, CONSTANT_Float);
-       
-                                       f->value.f = cf->value;
-                                       }
-                                       break;
+                               if (!(cl = class_getconstant(c, pindex, CONSTANT_Long)))
+                                       return false;
+
+                               f->value.l = cl->value;
+                       }
+                       break;
+
+                       case TYPE_FLOAT: {
+                               constant_float *cf;
+
+                               if (!(cf = class_getconstant(c, pindex, CONSTANT_Float)))
+                                       return false;
+
+                               f->value.f = cf->value;
+                       }
+                       break;
                                                                                        
                                                                                        
-                               case TYPE_DOUBLE: {
-                                       constant_double *cd = 
-                                           class_getconstant(c, pindex, CONSTANT_Double);
-       
-                                       f->value.d = cd->value;
-                                       }
-                                       break;
-                                               
-                               case TYPE_ADDRESS: { 
-                                       utf *u = class_getconstant(c, pindex, CONSTANT_String);
-                                       /* create javastring from compressed utf8-string */                                     
-                                       f->value.a = literalstring_new(u);
-                                       }
-                                       break;
-       
-                               default: 
-                                       log_text ("Invalid Constant - Type");
+                       case TYPE_DOUBLE: {
+                               constant_double *cd;
 
 
-                               }
+                               if (!(cd = class_getconstant(c, pindex, CONSTANT_Double)))
+                                       return false;
+
+                               f->value.d = cd->value;
+                       }
+                       break;
+                                               
+                       case TYPE_ADDRESS:
+                               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");
                        }
                        }
+
+               } else {
+                       /* unknown attribute */
+                       if (!skipattributebody(cb))
+                               return false;
                }
                }
+       }
+
+       /* everything was ok */
+
+       return true;
 }
 
 
 /********************** function: field_free **********************************/
 
 }
 
 
 /********************** function: field_free **********************************/
 
-static void field_free (fieldinfo *f)
+static void field_free(fieldinfo *f)
 {
        /* empty */
 }
 {
        /* empty */
 }
@@ -898,39 +1202,129 @@ void field_display(fieldinfo *f)
 
 
 /******************************************************************************/
 
 
 /******************************************************************************/
-/************************* Functions for methods ******************************/ 
+/************************* Functions for methods ******************************/
 /******************************************************************************/
 
 
 /******************************************************************************/
 
 
-/*********************** Function: method_load *********************************
+/* method_load *****************************************************************
 
 
-       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.
+   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.
        
 *******************************************************************************/
 
        
 *******************************************************************************/
 
-static void method_load(methodinfo *m, classinfo *c)
+static bool method_load(classbuffer *cb, classinfo *c, methodinfo *m)
 {
 {
-       u4 attrnum, i, e;
-       
+       s4 argcount;
+       s4 i, j;
+       u4 attrnum;
+       u4 codeattrnum;
+       utf *u;
+
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+       initObjectLock(&m->header);
+#endif
+
 #ifdef STATISTICS
 #ifdef STATISTICS
-       count_all_methods++;
+       if (opt_stat)
+               count_all_methods++;
 #endif
 
 #endif
 
+       m->thrownexceptionscount = 0;
+       m->linenumbercount = 0;
+       m->linenumbers = 0;
        m->class = c;
        m->class = c;
+       m->nativelyoverloaded = false;
        
        
-       m->flags = suck_u2();
-       m->name = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
-       m->descriptor = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
-       checkmethoddescriptor(m->descriptor);
+       if (!check_classbuffer_size(cb, 2 + 2 + 2))
+               return false;
+
+       m->flags = suck_u2(cb);
+
+       if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+               return false;
+       m->name = u;
+
+       if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+               return false;
+       m->descriptor = u;
+
+       if (opt_verify) {
+               if (!is_valid_name_utf(m->name))
+                       panic("Method with invalid name");
+
+               if (m->name->text[0] == '<'
+                       && m->name != utf_init && m->name != utf_clinit)
+                       panic("Method with invalid special name");
+       }
        
        
+       argcount = checkmethoddescriptor(c, m->descriptor);
+
+       if (!(m->flags & ACC_STATIC))
+               argcount++; /* count the 'this' argument */
+
+       if (opt_verify) {
+               if (argcount > 255) {
+                       *exceptionptr =
+                               new_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) {
+                               *exceptionptr =
+                                       new_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))) {
+                                       *exceptionptr =
+                                               new_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)) {
+                                       *exceptionptr =
+                                               new_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))
+                                       panic("Instance initialization method has invalid flags set");
+                       }
+               }
+       }
+               
        m->jcode = NULL;
        m->jcode = NULL;
+       m->basicblockcount = 0;
+       m->basicblocks = NULL;
+       m->basicblockindex = NULL;
+       m->instructioncount = 0;
+       m->instructions = NULL;
+       m->stackcount = 0;
+       m->stack = NULL;
        m->exceptiontable = NULL;
        m->exceptiontable = NULL;
-       m->entrypoint = NULL;
-       m->mcode = NULL;
        m->stubroutine = NULL;
        m->stubroutine = NULL;
+       m->mcode = NULL;
+       m->entrypoint = NULL;
        m->methodUsed = NOTUSED;    
        m->monoPoly = MONO;    
        m->subRedefs = 0;
        m->methodUsed = NOTUSED;    
        m->monoPoly = MONO;    
        m->subRedefs = 0;
@@ -942,67 +1336,209 @@ static void method_load(methodinfo *m, classinfo *c)
                m->stubroutine = createcompilerstub(m);
 
        } else {
                m->stubroutine = createcompilerstub(m);
 
        } else {
+               /*if (useinlining) {
+                       log_text("creating native stub:");
+                       method_display(m);
+               }*/
                functionptr f = native_findfunction(c->name, m->name, m->descriptor, 
                functionptr f = native_findfunction(c->name, m->name, m->descriptor, 
-                                                                                       (m->flags & ACC_STATIC) != 0);
-               if (f) {
+                                                       (m->flags & ACC_STATIC) != 0);
+#ifdef STATIC_CLASSPATH
+               if (f) 
+#endif
+                {
                        m->stubroutine = createnativestub(f, m);
                }
        }
        
                        m->stubroutine = createnativestub(f, m);
                }
        }
        
+       if (!check_classbuffer_size(cb, 2))
+               return false;
        
        
-       attrnum = suck_u2();
+       attrnum = suck_u2(cb);
        for (i = 0; i < attrnum; i++) {
                utf *aname;
 
        for (i = 0; i < attrnum; i++) {
                utf *aname;
 
-               aname = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
+               if (!check_classbuffer_size(cb, 2))
+                       return false;
 
 
-               if (aname != utf_code) {
-                       skipattributebody();
+               if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+                       return false;
 
 
-               } else {
-                       u4 codelen;
-                       if (m->jcode)
-                               panic("Two code-attributes for one method!");
+               if (aname == utf_Code) {
+                       if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
+                                       *exceptionptr =
+                                               new_classformaterror(c,
+                                                                                        "Code attribute in native or abstract methods");
+
+                                       return false;
+                       }
                        
                        
-                       suck_u4();
-                       m->maxstack = suck_u2();
-                       m->maxlocals = suck_u2();
-                       codelen = suck_u4();
-                       if (codelen == 0)
-                               panic("bytecode has zero length");
-                       if (codelen > 65536)
-                               panic("bytecode too long");
-                       m->jcodelength = codelen;
+                       if (m->jcode) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Multiple Code attributes");
+
+                               return false;
+                       }
+
+                       if (!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) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Arguments can't fit into locals");
+
+                               return false;
+                       }
+                       
+                       if (!check_classbuffer_size(cb, 4))
+                               return false;
+
+                       m->jcodelength = suck_u4(cb);
+
+                       if (m->jcodelength == 0) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Code of a method has length 0");
+
+                               return false;
+                       }
+                       
+                       if (m->jcodelength > 65535) {
+                               *exceptionptr =
+                                       new_classformaterror(c,
+                                                                                "Code of a method longer than 65535 bytes");
+
+                               return false;
+                       }
+
+                       if (!check_classbuffer_size(cb, m->jcodelength))
+                               return false;
+
                        m->jcode = MNEW(u1, m->jcodelength);
                        m->jcode = MNEW(u1, m->jcodelength);
-                       suck_nbytes(m->jcode, m->jcodelength);
-                       m->exceptiontablelength = suck_u2();
-                       m->exceptiontable = 
-                               MNEW(exceptiontable, m->exceptiontablelength);
+                       suck_nbytes(m->jcode, cb, m->jcodelength);
 
 
-#ifdef STATISTICS
-                       count_vmcode_len += m->jcodelength + 18;
-                       count_extable_len += 8 * m->exceptiontablelength;
+                       if (!check_classbuffer_size(cb, 2))
+                               return false;
+
+                       m->exceptiontablelength = suck_u2(cb);
+                       if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->exceptiontablelength))
+                               return false;
+
+                       m->exceptiontable = MNEW(exceptiontable, m->exceptiontablelength);
+
+#if defined(STATISTICS)
+                       if (opt_stat) {
+                               count_vmcode_len += m->jcodelength + 18;
+                               count_extable_len += 8 * m->exceptiontablelength;
+                       }
 #endif
 
 #endif
 
-                       for (e = 0; e < m->exceptiontablelength; e++) {
+                       for (j = 0; j < m->exceptiontablelength; j++) {
                                u4 idx;
                                u4 idx;
-                               m->exceptiontable[e].startpc = suck_u2();
-                               m->exceptiontable[e].endpc = suck_u2();
-                               m->exceptiontable[e].handlerpc = suck_u2();
+                               m->exceptiontable[j].startpc = suck_u2(cb);
+                               m->exceptiontable[j].endpc = suck_u2(cb);
+                               m->exceptiontable[j].handlerpc = suck_u2(cb);
 
 
-                               idx = suck_u2();
+                               idx = suck_u2(cb);
                                if (!idx) {
                                if (!idx) {
-                                       m->exceptiontable[e].catchtype = NULL;
+                                       m->exceptiontable[j].catchtype = NULL;
 
                                } else {
 
                                } else {
-                                       m->exceptiontable[e].catchtype = 
-                                     class_getconstant(c, idx, CONSTANT_Class);
+                                       if (!(m->exceptiontable[j].catchtype =
+                                                 class_getconstant(c, idx, CONSTANT_Class)))
+                                               return false;
                                }
                                }
-                       }                       
+                       }
+
+                       if (!check_classbuffer_size(cb, 2))
+                               return false;
+
+                       codeattrnum = suck_u2(cb);
+
+                       for (; codeattrnum > 0; codeattrnum--) {
+                               utf *caname;
+
+                               if (!check_classbuffer_size(cb, 2))
+                                       return false;
+
+                               if (!(caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
+                                       return false;
+
+                               if (caname == utf_LineNumberTable) {
+                                       u2 lncid;
+
+                                       if (!check_classbuffer_size(cb, 4 + 2))
+                                               return false;
+
+                                       suck_u4(cb);
+                                       m->linenumbercount = suck_u2(cb);
 
 
-                       skipattributes(suck_u2());
+                                       if (!check_classbuffer_size(cb,
+                                                                                               (2 + 2) * m->linenumbercount))
+                                               return false;
+
+                                       m->linenumbers = MNEW(lineinfo, m->linenumbercount);
+                                       
+                                       for (lncid = 0; lncid < m->linenumbercount; lncid++) {
+                                               m->linenumbers[lncid].start_pc = suck_u2(cb);
+                                               m->linenumbers[lncid].line_number = suck_u2(cb);
+                                       }
+                                       codeattrnum--;
+
+                                       if (!skipattributes(cb, codeattrnum))
+                                               return false;
+                                       
+                                       break;
+
+                               } else {
+                                       if (!skipattributebody(cb))
+                                               return false;
+                               }
+                       }
+
+               } else if (aname == utf_Exceptions) {
+                       s4 j;
+
+                       if (m->thrownexceptions) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Multiple Exceptions attributes");
+                               return false;
+                       }
+
+                       if (!check_classbuffer_size(cb, 4 + 2))
+                               return false;
+
+                       suck_u4(cb); /* length */
+                       m->thrownexceptionscount = suck_u2(cb);
+
+                       if (!check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
+                               return false;
+
+                       m->thrownexceptions = MNEW(classinfo*, m->thrownexceptionscount);
+
+                       for (j = 0; j < m->thrownexceptionscount; j++) {
+                               if (!((m->thrownexceptions)[j] =
+                                         class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
+                                       return false;
+                       }
+                               
+               } else {
+                       if (!skipattributebody(cb))
+                               return false;
                }
        }
                }
        }
+
+       if (!m->jcode && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
+               *exceptionptr = new_classformaterror(c, "Missing Code attribute");
+
+               return false;
+       }
+
+       /* everything was ok */
+
+       return true;
 }
 
 
 }
 
 
@@ -1047,67 +1583,51 @@ void method_display(methodinfo *m)
        printf("\n");
 }
 
        printf("\n");
 }
 
+/************** Function: method_display_w_class  (debugging only) **************/
 
 
-/******************** Function: method_canoverwrite ****************************
-
-       Check if m and old are identical with respect to type and name. This means
-       that old can be overwritten with m.
-       
-*******************************************************************************/  
-
-static bool method_canoverwrite (methodinfo *m, methodinfo *old)
+void method_display_w_class(methodinfo *m)
 {
 {
-       if (m->name != old->name) return false;
-       if (m->descriptor != old->descriptor) return false;
-       if (m->flags & ACC_STATIC) return false;
-       return true;
+        printflags(m->class->flags);
+        printf(" "); fflush(stdout);
+        utf_display(m->class->name);
+        printf(".");fflush(stdout);
+
+        printf("   ");
+        printflags(m->flags);
+        printf(" "); fflush(stdout);
+        utf_display(m->name);
+        printf(" "); fflush(stdout);
+        utf_display(m->descriptor);
+        printf("\n"); fflush(stdout);
 }
 
 }
 
+/************** Function: method_display_flags_last  (debugging only) **************/
 
 
-
-
-/******************************************************************************/
-/************************ Functions for class *********************************/
-/******************************************************************************/
-
-
-/******************** function:: class_getconstant ******************************
-
-       retrieves the value at position 'pos' of the constantpool of a class
-       if the type of the value is other than 'ctype' the system is stopped
-
-*******************************************************************************/
-
-voidptr class_getconstant(classinfo *c, u4 pos, u4 ctype)
+void method_display_flags_last(methodinfo *m)
 {
 {
-       /* invalid position in constantpool */  
-       if (pos >= c->cpcount)
-               panic("Attempt to access constant outside range");
-
-       /* check type of constantpool entry */
-
-       if (c->cptags[pos] != ctype) {
-               class_showconstantpool(c);
-               error("Type mismatch on constant: %d requested, %d here (class_getconstant)",
-                         (int) ctype, (int) c->cptags[pos]);
-       }
-               
-       return c->cpinfos[pos];
+        printf(" ");
+        utf_display(m->name);
+        printf(" ");
+        utf_display(m->descriptor);
+        printf("   ");
+        printflags(m->flags);
+        printf("\n");
 }
 
 
 }
 
 
-/********************* Function: class_constanttype ****************************
+/******************** Function: method_canoverwrite ****************************
 
 
-       Determines the type of a class entry in the ConstantPool
+       Check if m and old are identical with respect to type and name. This means
+       that old can be overwritten with m.
        
 *******************************************************************************/
 
        
 *******************************************************************************/
 
-u4 class_constanttype(classinfo *c, u4 pos)
+static bool method_canoverwrite(methodinfo *m, methodinfo *old)
 {
 {
-       if (pos >= c->cpcount)
-               panic("Attempt to access constant outside range");
-
-       return c->cptags[pos];
+       if (m->name != old->name) return false;
+       if (m->descriptor != old->descriptor) return false;
+       if (m->flags & ACC_STATIC) return false;
+       return true;
 }
 
 
 }
 
 
@@ -1120,7 +1640,7 @@ u4 class_constanttype(classinfo *c, u4 pos)
 
 *******************************************************************************/
 
 
 *******************************************************************************/
 
-static void class_loadcpool(classinfo *c)
+static bool class_loadcpool(classbuffer *cb, classinfo *c)
 {
 
        /* The following structures are used to save information which cannot be 
 {
 
        /* The following structures are used to save information which cannot be 
@@ -1128,17 +1648,17 @@ static void class_loadcpool(classinfo *c)
           been traversed the references can be resolved. 
           (only in specific order)                                                */
        
           been traversed the references can be resolved. 
           (only in specific order)                                                */
        
-       /* CONSTANT_Class_info entries */
-       typedef struct forward_class {      
-               struct forward_class *next; 
-               u2 thisindex;               
-               u2 name_index;              
-       } forward_class;                    
-                                        
-       /* CONSTANT_String */                                      
-       typedef struct forward_string { 
-               struct forward_string *next; 
-               u2 thisindex;                
+       /* CONSTANT_Class entries */
+       typedef struct forward_class {
+               struct forward_class *next;
+               u2 thisindex;
+               u2 name_index;
+       } forward_class;
+
+       /* CONSTANT_String */
+       typedef struct forward_string {
+               struct forward_string *next;
+               u2 thisindex;
                u2 string_index;
        } forward_string;
 
                u2 string_index;
        } forward_string;
 
@@ -1151,7 +1671,7 @@ static void class_loadcpool(classinfo *c)
        } forward_nameandtype;
 
        /* CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref */
        } forward_nameandtype;
 
        /* CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref */
-       typedef struct forward_fieldmethint {   
+       typedef struct forward_fieldmethint {
                struct forward_fieldmethint *next;
                u2 thisindex;
                u1 tag;
                struct forward_fieldmethint *next;
                u2 thisindex;
                u1 tag;
@@ -1161,288 +1681,393 @@ static void class_loadcpool(classinfo *c)
 
 
        u4 idx;
 
 
        u4 idx;
-       long int dumpsize = dump_size ();
 
        forward_class *forward_classes = NULL;
        forward_string *forward_strings = NULL;
        forward_nameandtype *forward_nameandtypes = NULL;
        forward_fieldmethint *forward_fieldmethints = NULL;
 
 
        forward_class *forward_classes = NULL;
        forward_string *forward_strings = NULL;
        forward_nameandtype *forward_nameandtypes = NULL;
        forward_fieldmethint *forward_fieldmethints = NULL;
 
-       /* number of entries in the constant_pool table  */
-       u4 cpcount       = c -> cpcount = suck_u2();
+       forward_class *nfc;
+       forward_string *nfs;
+       forward_nameandtype *nfn;
+       forward_fieldmethint *nff;
+
+       u4 cpcount;
+       u1 *cptags;
+       voidptr *cpinfos;
+
+       /* number of entries in the constant_pool table plus one */
+       if (!check_classbuffer_size(cb, 2))
+               return false;
+
+       cpcount = c->cpcount = suck_u2(cb);
+
        /* allocate memory */
        /* allocate memory */
-       u1 *cptags       = c -> cptags  = MNEW (u1, cpcount);
-       voidptr *cpinfos = c -> cpinfos = MNEW (voidptr, cpcount);
+       cptags  = c->cptags  = MNEW(u1, cpcount);
+       cpinfos = c->cpinfos = MNEW(voidptr, cpcount);
 
 
-#ifdef STATISTICS
-       count_const_pool_len += (sizeof(voidptr) + 1) * cpcount;
+       if (cpcount < 1) {
+               *exceptionptr = new_classformaterror(c, "Illegal constant pool size");
+               return false;
+       }
+       
+#if defined(STATISTICS)
+       if (opt_stat)
+               count_const_pool_len += (sizeof(voidptr) + 1) * cpcount;
 #endif
        
        /* initialize constantpool */
 #endif
        
        /* initialize constantpool */
-       for (idx=0; idx<cpcount; idx++) {
+       for (idx = 0; idx < cpcount; idx++) {
                cptags[idx] = CONSTANT_UNUSED;
                cpinfos[idx] = NULL;
                cptags[idx] = CONSTANT_UNUSED;
                cpinfos[idx] = NULL;
-               }
+       }
 
                        
 
                        
-               /******* first pass *******/
-               /* entries which cannot be resolved now are written into 
-                  temporary structures and traversed again later        */
+       /******* first pass *******/
+       /* entries which cannot be resolved now are written into 
+          temporary structures and traversed again later        */
                   
        idx = 1;
        while (idx < cpcount) {
                   
        idx = 1;
        while (idx < cpcount) {
+               u4 t;
+
                /* get constant type */
                /* get constant type */
-               u4 t = suck_u1 (); 
-               switch ( t ) {
+               if (!check_classbuffer_size(cb, 1))
+                       return false;
 
 
-                       case CONSTANT_Class: { 
-                               forward_class *nfc = DNEW(forward_class);
+               t = suck_u1(cb);
 
 
-                               nfc -> next = forward_classes;                                                                                  
-                               forward_classes = nfc;
+               switch (t) {
+               case CONSTANT_Class:
+                       nfc = NEW(forward_class);
 
 
-                               nfc -> thisindex = idx;
-                               /* reference to CONSTANT_NameAndType */
-                               nfc -> name_index = suck_u2 (); 
+                       nfc->next = forward_classes;
+                       forward_classes = nfc;
 
 
-                               idx++;
-                               break;
-                               }
+                       nfc->thisindex = idx;
+                       /* reference to CONSTANT_NameAndType */
+                       if (!check_classbuffer_size(cb, 2))
+                               return false;
+
+                       nfc->name_index = suck_u2(cb);
+
+                       idx++;
+                       break;
                        
                        
-                       case CONSTANT_Fieldref:
-                       case CONSTANT_Methodref:
-                       case CONSTANT_InterfaceMethodref: { 
-                               forward_fieldmethint *nff = DNEW (forward_fieldmethint);
-                               
-                               nff -> next = forward_fieldmethints;
-                               forward_fieldmethints = nff;
-
-                               nff -> thisindex = idx;
-                               /* constant type */
-                               nff -> tag = t;
-                               /* class or interface type that contains the declaration of the field or method */
-                               nff -> class_index = suck_u2 (); 
-                               /* name and descriptor of the field or method */
-                               nff -> nameandtype_index = suck_u2 ();
-
-                               idx ++;
-                               break;
-                               }
-                               
-                       case CONSTANT_String: {
-                               forward_string *nfs = DNEW (forward_string);
+               case CONSTANT_String:
+                       nfs = NEW(forward_string);
                                
                                
-                               nfs -> next = forward_strings;
-                               forward_strings = nfs;
+                       nfs->next = forward_strings;
+                       forward_strings = nfs;
                                
                                
-                               nfs -> thisindex = idx;
-                               /* reference to CONSTANT_Utf8_info with string characters */
-                               nfs -> string_index = suck_u2 ();
+                       nfs->thisindex = idx;
+
+                       /* reference to CONSTANT_Utf8_info with string characters */
+                       if (!check_classbuffer_size(cb, 2))
+                               return false;
+
+                       nfs->string_index = suck_u2(cb);
                                
                                
-                               idx ++;
-                               break;
-                               }
+                       idx++;
+                       break;
 
 
-                       case CONSTANT_NameAndType: {
-                               forward_nameandtype *nfn = DNEW (forward_nameandtype);
+               case CONSTANT_NameAndType:
+                       nfn = NEW(forward_nameandtype);
                                
                                
-                               nfn -> next = forward_nameandtypes;
-                               forward_nameandtypes = nfn;
+                       nfn->next = forward_nameandtypes;
+                       forward_nameandtypes = nfn;
                                
                                
-                               nfn -> thisindex = idx;
-                               /* reference to CONSTANT_Utf8_info containing simple name */
-                               nfn -> name_index = suck_u2 ();
-                               /* reference to CONSTANT_Utf8_info containing field or method descriptor */
-                               nfn -> sig_index = suck_u2 ();
+                       nfn->thisindex = idx;
+
+                       if (!check_classbuffer_size(cb, 2 + 2))
+                               return false;
+
+                       /* reference to CONSTANT_Utf8_info containing simple name */
+                       nfn->name_index = suck_u2(cb);
+
+                       /* reference to CONSTANT_Utf8_info containing field or method
+                          descriptor */
+                       nfn->sig_index = suck_u2(cb);
                                
                                
-                               idx ++;
-                               break;
-                               }
+                       idx++;
+                       break;
 
 
-                       case CONSTANT_Integer: {
-                               constant_integer *ci = NEW (constant_integer);
+               case CONSTANT_Fieldref:
+               case CONSTANT_Methodref:
+               case CONSTANT_InterfaceMethodref:
+                       nff = NEW(forward_fieldmethint);
+                       
+                       nff->next = forward_fieldmethints;
+                       forward_fieldmethints = nff;
 
 
-#ifdef STATISTICS
-       count_const_pool_len += sizeof(constant_integer);
-#endif
+                       nff->thisindex = idx;
+                       /* constant type */
+                       nff->tag = t;
+
+                       if (!check_classbuffer_size(cb, 2 + 2))
+                               return false;
+
+                       /* class or interface type that contains the declaration of the
+                          field or method */
+                       nff->class_index = suck_u2(cb);
 
 
-                               ci -> value = suck_s4 ();
-                               cptags [idx] = CONSTANT_Integer;
-                               cpinfos [idx] = ci;
-                               idx ++;
+                       /* name and descriptor of the field or method */
+                       nff->nameandtype_index = suck_u2(cb);
+
+                       idx++;
+                       break;
                                
                                
-                               break;
-                               }
+               case CONSTANT_Integer: {
+                       constant_integer *ci = NEW(constant_integer);
+
+#if defined(STATISTICS)
+                       if (opt_stat)
+                               count_const_pool_len += sizeof(constant_integer);
+#endif
+
+                       if (!check_classbuffer_size(cb, 4))
+                               return false;
+
+                       ci->value = suck_s4(cb);
+                       cptags[idx] = CONSTANT_Integer;
+                       cpinfos[idx] = ci;
+
+                       idx++;
+                       break;
+               }
                                
                                
-                       case CONSTANT_Float: {
-                               constant_float *cf = NEW (constant_float);
+               case CONSTANT_Float: {
+                       constant_float *cf = NEW(constant_float);
 
 
-#ifdef STATISTICS
-       count_const_pool_len += sizeof(constant_float);
+#if defined(STATISTICS)
+                       if (opt_stat)
+                               count_const_pool_len += sizeof(constant_float);
 #endif
 
 #endif
 
-                               cf -> value = suck_float ();
-                               cptags [idx] = CONSTANT_Float;
-                               cpinfos[idx] = cf;
-                               idx ++;
-                               break;
-                               }
+                       if (!check_classbuffer_size(cb, 4))
+                               return false;
+
+                       cf->value = suck_float(cb);
+                       cptags[idx] = CONSTANT_Float;
+                       cpinfos[idx] = cf;
+
+                       idx++;
+                       break;
+               }
                                
                                
-                       case CONSTANT_Long: {
-                               constant_long *cl = NEW(constant_long);
+               case CONSTANT_Long: {
+                       constant_long *cl = NEW(constant_long);
                                        
                                        
-#ifdef STATISTICS
-       count_const_pool_len += sizeof(constant_long);
+#if defined(STATISTICS)
+                       if (opt_stat)
+                               count_const_pool_len += sizeof(constant_long);
 #endif
 
 #endif
 
-                               cl -> value = suck_s8 ();
-                               cptags [idx] = CONSTANT_Long;
-                               cpinfos [idx] = cl;
-                               idx += 2;
-                               break;
-                               }
+                       if (!check_classbuffer_size(cb, 8))
+                               return false;
+
+                       cl->value = suck_s8(cb);
+                       cptags[idx] = CONSTANT_Long;
+                       cpinfos[idx] = cl;
+                       idx += 2;
+                       if (idx > cpcount) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Invalid constant pool entry");
+                               return false;
+                       }
+                       break;
+               }
                        
                        
-                       case CONSTANT_Double: {
-                               constant_double *cd = NEW(constant_double);
+               case CONSTANT_Double: {
+                       constant_double *cd = NEW(constant_double);
                                
                                
-#ifdef STATISTICS
-       count_const_pool_len += sizeof(constant_double);
+#if defined(STATISTICS)
+                       if (opt_stat)
+                               count_const_pool_len += sizeof(constant_double);
 #endif
 
 #endif
 
-                               cd -> value = suck_double ();
-                               cptags [idx] = CONSTANT_Double;
-                               cpinfos [idx] = cd;
-                               idx += 2;
-                               break;
-                               }
+                       if (!check_classbuffer_size(cb, 8))
+                               return false;
+
+                       cd->value = suck_double(cb);
+                       cptags[idx] = CONSTANT_Double;
+                       cpinfos[idx] = cd;
+                       idx += 2;
+                       if (idx > cpcount) {
+                               *exceptionptr =
+                                       new_classformaterror(c, "Invalid constant pool entry");
+                               return false;
+                       }
+                       break;
+               }
                                
                                
-                       case CONSTANT_Utf8: { 
-
-                               /* number of bytes in the bytes array (not string-length) */
-                               u4 length = suck_u2();
-                               cptags [idx]  = CONSTANT_Utf8;
-                               /* validate the string */
-                               ASSERT_LEFT(length);
-                               if (!is_valid_utf(classbuf_pos+1, classbuf_pos+1+length))
-                                       panic("Invalid UTF-8 string"); 
-                               /* insert utf-string into the utf-symboltable */
-                               cpinfos [idx] = utf_new(classbuf_pos+1, length);
-                               /* skip bytes of the string */
-                               skip_nbytes(length);
-                               idx++;
-                               break;
-                               }
+               case CONSTANT_Utf8: { 
+                       u4 length;
+
+                       /* number of bytes in the bytes array (not string-length) */
+                       if (!check_classbuffer_size(cb, 2))
+                               return false;
+
+                       length = suck_u2(cb);
+                       cptags[idx] = CONSTANT_Utf8;
+
+                       /* validate the string */
+                       if (!check_classbuffer_size(cb, length))
+                               return false;
+
+                       if (opt_verify &&
+                               !is_valid_utf((char *) (cb->pos + 1),
+                                                         (char *) (cb->pos + 1 + length))) {
+                               dolog("Invalid UTF-8 string (constant pool index %d)",idx);
+                               panic("Invalid UTF-8 string");
+                       }
+                       /* insert utf-string into the utf-symboltable */
+                       cpinfos[idx] = utf_new_intern((char *) (cb->pos + 1), length);
+
+                       /* skip bytes of the string (buffer size check above) */
+                       skip_nbytes(cb, length);
+                       idx++;
+                       break;
+               }
                                                                                
                                                                                
-                       default:
-                               error ("Unkown constant type: %d",(int) t);
-               
-                       }  /* end switch */
-                       
-               } /* end while */
-               
+               default:
+                       *exceptionptr =
+                               new_classformaterror(c, "Illegal constant pool type");
+                       return false;
+               }  /* end switch */
+       } /* end while */
 
 
 
 
-          /* resolve entries in temporary structures */
+       /* resolve entries in temporary structures */
 
        while (forward_classes) {
                utf *name =
 
        while (forward_classes) {
                utf *name =
-                 class_getconstant (c, forward_classes -> name_index, CONSTANT_Utf8);
+                       class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8);
+
+               if (opt_verify && !is_valid_name_utf(name))
+                       panic("Class reference with invalid name");
 
 
-               cptags  [forward_classes -> thisindex] = CONSTANT_Class;
+               cptags[forward_classes->thisindex] = CONSTANT_Class;
                /* retrieve class from class-table */
                /* retrieve class from class-table */
-               cpinfos [forward_classes -> thisindex] = class_new (name);
+               if (opt_eager) {
+                       classinfo *tc;
+                       tc = class_new_intern(name);
 
 
-               forward_classes = forward_classes -> next;
-               
+                       if (!class_load(tc))
+                               return false;
+
+                       /* link the class later, because we cannot link the class currently
+                          loading */
+                       list_addfirst(&unlinkedclasses, tc);
+
+                       cpinfos[forward_classes->thisindex] = tc;
+
+               } else {
+                       cpinfos[forward_classes->thisindex] = class_new(name);
                }
 
                }
 
+               nfc = forward_classes;
+               forward_classes = forward_classes->next;
+               FREE(nfc, forward_class);
+       }
+
        while (forward_strings) {
        while (forward_strings) {
-               utf *text = 
-                 class_getconstant (c, forward_strings -> string_index, CONSTANT_Utf8);
-/*
-               log_text("forward_string:");
-               printf( "classpoolid: %d\n",forward_strings -> thisindex);
-               utf_display(text);
-               log_text("\n------------------"); */
-               /* resolve utf-string */                
-               cptags   [forward_strings -> thisindex] = CONSTANT_String;
-               cpinfos  [forward_strings -> thisindex] = text;
+               utf *text =
+                       class_getconstant(c, forward_strings->string_index, CONSTANT_Utf8);
+
+               /* resolve utf-string */
+               cptags[forward_strings->thisindex] = CONSTANT_String;
+               cpinfos[forward_strings->thisindex] = text;
                
                
-               forward_strings = forward_strings -> next;
-               }       
+               nfs = forward_strings;
+               forward_strings = forward_strings->next;
+               FREE(nfs, forward_string);
+       }
 
        while (forward_nameandtypes) {
 
        while (forward_nameandtypes) {
-               constant_nameandtype *cn = NEW (constant_nameandtype);  
+               constant_nameandtype *cn = NEW(constant_nameandtype);   
 
 
-#ifdef STATISTICS
-               count_const_pool_len += sizeof(constant_nameandtype);
+#if defined(STATISTICS)
+               if (opt_stat)
+                       count_const_pool_len += sizeof(constant_nameandtype);
 #endif
 
                /* resolve simple name and descriptor */
 #endif
 
                /* resolve simple name and descriptor */
-               cn -> name = class_getconstant 
-                  (c, forward_nameandtypes -> name_index, CONSTANT_Utf8);
-               cn -> descriptor = class_getconstant
-                  (c, forward_nameandtypes -> sig_index, CONSTANT_Utf8);
-                
-               cptags   [forward_nameandtypes -> thisindex] = CONSTANT_NameAndType;
-               cpinfos  [forward_nameandtypes -> thisindex] = cn;
-               
-               forward_nameandtypes = forward_nameandtypes -> next;
+               cn->name = class_getconstant(c,
+                                                                        forward_nameandtypes->name_index,
+                                                                        CONSTANT_Utf8);
+
+               cn->descriptor = class_getconstant(c,
+                                                                                  forward_nameandtypes->sig_index,
+                                                                                  CONSTANT_Utf8);
+
+               if (opt_verify) {
+                       /* check name */
+                       if (!is_valid_name_utf(cn->name)) {
+                               *exceptionptr =
+                                       new_exception_utfmessage(string_java_lang_InternalError,
+                                                                                        cn->name);
+                               return false;
+                       }
+
+                       /* disallow referencing <clinit> among others */
+                       if (cn->name->text[0] == '<' && cn->name != utf_init) {
+                               *exceptionptr =
+                                       new_exception_utfmessage(string_java_lang_InternalError,
+                                                                                        cn->name);
+                               return false;
+                       }
                }
 
                }
 
+               cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType;
+               cpinfos[forward_nameandtypes->thisindex] = cn;
+
+               nfn = forward_nameandtypes;
+               forward_nameandtypes = forward_nameandtypes->next;
+               FREE(nfn, forward_nameandtype);
+       }
 
 
-       while (forward_fieldmethints)  {
+       while (forward_fieldmethints) {
                constant_nameandtype *nat;
                constant_nameandtype *nat;
-               constant_FMIref *fmi = NEW (constant_FMIref);
+               constant_FMIref *fmi = NEW(constant_FMIref);
 
 
-#ifdef STATISTICS
-               count_const_pool_len += sizeof(constant_FMIref);
+#if defined(STATISTICS)
+               if (opt_stat)
+                       count_const_pool_len += sizeof(constant_FMIref);
 #endif
                /* resolve simple name and descriptor */
 #endif
                /* resolve simple name and descriptor */
-               nat = class_getconstant
-                       (c, forward_fieldmethints -> nameandtype_index, CONSTANT_NameAndType);
-
-#ifdef JOWENN_DEBUG
-               log_text("trying to resolve:");
-               log_text(nat->name->text);
-               switch(forward_fieldmethints ->tag) {
-               case CONSTANT_Fieldref: 
-                               log_text("CONSTANT_Fieldref");
-                               break;
-               case CONSTANT_InterfaceMethodref: 
-                               log_text("CONSTANT_InterfaceMethodref");
-                               break;
-               case CONSTANT_Methodref: 
-                               log_text("CONSTANT_Methodref");
-                               break;
-               }
-#endif
-               fmi -> class = class_getconstant 
-                       (c, forward_fieldmethints -> class_index, CONSTANT_Class);
-               fmi -> name = nat -> name;
-               fmi -> descriptor = nat -> descriptor;
-
-               cptags [forward_fieldmethints -> thisindex] = forward_fieldmethints -> tag;
-               cpinfos [forward_fieldmethints -> thisindex] = fmi;
+               nat = class_getconstant(c,
+                                                               forward_fieldmethints->nameandtype_index,
+                                                               CONSTANT_NameAndType);
+
+               fmi->class = class_getconstant(c,
+                                                                          forward_fieldmethints->class_index,
+                                                                          CONSTANT_Class);
+               fmi->name = nat->name;
+               fmi->descriptor = nat->descriptor;
+
+               cptags[forward_fieldmethints->thisindex] = forward_fieldmethints->tag;
+               cpinfos[forward_fieldmethints->thisindex] = fmi;
        
        
-               switch (forward_fieldmethints -> tag) {
+               switch (forward_fieldmethints->tag) {
                case CONSTANT_Fieldref:  /* check validity of descriptor */
                case CONSTANT_Fieldref:  /* check validity of descriptor */
-                                        checkfielddescriptor (fmi->descriptor->text,utf_end(fmi->descriptor));
-                                        break;
-               case CONSTANT_InterfaceMethodref: 
+                       checkfielddescriptor(fmi->descriptor->text,
+                                                                utf_end(fmi->descriptor));
+                       break;
+               case CONSTANT_InterfaceMethodref:
                case CONSTANT_Methodref: /* check validity of descriptor */
                case CONSTANT_Methodref: /* check validity of descriptor */
-                       /* XXX check special names (<init>) */
-                                        checkmethoddescriptor (fmi->descriptor);
-                                        break;
-               }               
-       
-               forward_fieldmethints = forward_fieldmethints -> next;
-
+                       checkmethoddescriptor(c, fmi->descriptor);
+                       break;
                }
                }
+       
+               nff = forward_fieldmethints;
+               forward_fieldmethints = forward_fieldmethints->next;
+               FREE(nff, forward_fieldmethint);
+       }
 
 
-/*     class_showconstantpool(c); */
+       /* everything was ok */
 
 
-       dump_release (dumpsize);
+       return true;
 }
 
 
 }
 
 
@@ -1459,40 +2084,141 @@ static void class_loadcpool(classinfo *c)
        
 *******************************************************************************/
 
        
 *******************************************************************************/
 
-static int class_load(classinfo *c)
+classinfo *class_load_intern(classbuffer *cb);
+
+classinfo *class_load(classinfo *c)
 {
 {
-       u4 i;
-       u4 mi,ma;
+       classbuffer *cb;
+       classinfo *r;
 
 
-#ifdef STATISTICS
-       count_class_loads++;
+#if defined(USE_THREADS)
+       /* enter a monitor on the class */
+
+       builtin_monitorenter((java_objectheader *) c);
 #endif
 
 #endif
 
-       /* output for debugging purposes */
-       if (loadverbose) {              
-               char logtext[MAXLOGTEXT];
-               sprintf(logtext, "Loading class: ");
-               utf_sprint(logtext + strlen(logtext), c->name);
-               log_text(logtext);
+       /* maybe the class is already loaded */
+       if (c->loaded) {
+#if defined(USE_THREADS)
+               builtin_monitorexit((java_objectheader *) c);
+#endif
+
+               return c;
        }
        }
-       
+
+       /* measure time */
+
+       if (getcompilingtime)
+               compilingtime_stop();
+
+       if (getloadingtime)
+               loadingtime_start();
+
        /* load classdata, throw exception on error */
 
        /* load classdata, throw exception on error */
 
-       if (!suck_start(c->name)) {
-               throw_noclassdeffounderror_message(c->name);
-               return false;
+       if ((cb = suck_start(c)) == NULL) {
+               /* this means, the classpath was not set properly */
+               if (c->name == utf_java_lang_Object)
+                       throw_cacao_exception_exit(string_java_lang_NoClassDefFoundError,
+                                                                          "java/lang/Object");
+
+               *exceptionptr =
+                       new_exception_utfmessage(string_java_lang_NoClassDefFoundError,
+                                                                        c->name);
+
+#if defined(USE_THREADS)
+               builtin_monitorexit((java_objectheader *) c);
+#endif
+
+               return NULL;
        }
        
        }
        
-       /* check signature */           
-       if (suck_u4() != MAGIC) panic("Can not find class-file signature");     
+       /* call the internal function */
+       r = class_load_intern(cb);
+
+       /* if return value is NULL, we had a problem and the class is not loaded */
+       if (!r) {
+               c->loaded = false;
+
+               /* now free the allocated memory, otherwise we could ran into a DOS */
+               class_remove(c);
+       }
+
+       /* free memory */
+       suck_stop(cb);
+
+       /* measure time */
+
+       if (getloadingtime)
+               loadingtime_stop();
+
+       if (getcompilingtime)
+               compilingtime_start();
+
+#if defined(USE_THREADS)
+       /* leave the monitor */
+
+       builtin_monitorexit((java_objectheader *) c);
+#endif
+
+       return r;
+}
+
+
+classinfo *class_load_intern(classbuffer *cb)
+{
+       classinfo *c;
+       classinfo *tc;
+       u4 i;
+       u4 ma, mi;
+       char msg[MAXLOGTEXT];               /* maybe we get an exception */
+
+       /* get the classbuffer's class */
+       c = cb->class;
+
+       /* maybe the class is already loaded */
+       if (c->loaded)
+               return c;
+
+#if defined(STATISTICS)
+       if (opt_stat)
+               count_class_loads++;
+#endif
+
+       /* output for debugging purposes */
+       if (loadverbose)
+               log_message_class("Loading class: ", c);
+       
+       /* class is somewhat loaded */
+       c->loaded = true;
+
+       if (!check_classbuffer_size(cb, 4 + 2 + 2))
+               return NULL;
+
+       /* check signature */
+       if (suck_u4(cb) != MAGIC) {
+               *exceptionptr = new_classformaterror(c, "Bad magic number");
+
+               return NULL;
+       }
+
        /* check version */
        /* check version */
-       mi = suck_u2(); 
-       ma = suck_u2();
-       if (ma != MAJOR_VERSION && (ma != MAJOR_VERSION+1 || mi != 0)) {
-               error("File version %d.%d is not supported", (int) ma, (int) mi);
+       mi = suck_u2(cb);
+       ma = suck_u2(cb);
+
+       if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) {
+               *exceptionptr =
+                       new_unsupportedclassversionerror(c,
+                                                                                        "Unsupported major.minor version %d.%d",
+                                                                                        ma, mi);
+
+               return NULL;
        }
 
        }
 
-       class_loadcpool(c);
+       /* load the constant pool */
+       if (!class_loadcpool(cb, c))
+               return NULL;
+
        /*JOWENN*/
        c->erroneous_state = 0;
        c->initializing_thread = 0;     
        /*JOWENN*/
        c->erroneous_state = 0;
        c->initializing_thread = 0;     
@@ -1501,70 +2227,271 @@ static int class_load(classinfo *c)
        c->impldBy = NULL;
 
        /* ACC flags */
        c->impldBy = NULL;
 
        /* ACC flags */
-       c->flags = suck_u2(); 
+       if (!check_classbuffer_size(cb, 2))
+               return NULL;
+
+       c->flags = suck_u2(cb);
        /*if (!(c->flags & ACC_PUBLIC)) { log_text("CLASS NOT PUBLIC"); } JOWENN*/
 
        /*if (!(c->flags & ACC_PUBLIC)) { log_text("CLASS NOT PUBLIC"); } JOWENN*/
 
+       /* check ACC flags consistency */
+       if (c->flags & ACC_INTERFACE) {
+               if (!(c->flags & ACC_ABSTRACT)) {
+                       /* We work around this because interfaces in JDK 1.1 are
+                        * not declared abstract. */
+
+                       c->flags |= ACC_ABSTRACT;
+                       /* panic("Interface class not declared abstract"); */
+               }
+
+               if (c->flags & ACC_FINAL) {
+                       *exceptionptr =
+                               new_classformaterror(c,
+                                                                        "Illegal class modifiers: 0x%X", c->flags);
+
+                       return NULL;
+               }
+
+               if (c->flags & ACC_SUPER) {
+                       c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */
+               }
+       }
+
+       if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) {
+               *exceptionptr =
+                       new_classformaterror(c, "Illegal class modifiers: 0x%X", c->flags);
+
+               return NULL;
+       }
+
+       if (!check_classbuffer_size(cb, 2 + 2))
+               return NULL;
+
        /* this class */
        /* this class */
-       suck_u2();       
+       i = suck_u2(cb);
+       if (!(tc = class_getconstant(c, i, CONSTANT_Class)))
+               return NULL;
+
+       if (tc != c) {
+               utf_sprint(msg, c->name);
+               sprintf(msg + strlen(msg), " (wrong name: ");
+               utf_sprint(msg + strlen(msg), tc->name);
+               sprintf(msg + strlen(msg), ")");
+
+               *exceptionptr =
+                       new_exception_message(string_java_lang_NoClassDefFoundError, msg);
+
+               return NULL;
+       }
        
        /* retrieve superclass */
        
        /* retrieve superclass */
-       if ((i = suck_u2())) {
-               c->super = class_getconstant(c, i, CONSTANT_Class);
+       if ((i = suck_u2(cb))) {
+               if (!(c->super = class_getconstant(c, i, CONSTANT_Class)))
+                       return NULL;
+
+               /* java.lang.Object may not have a super class. */
+               if (c->name == utf_java_lang_Object) {
+                       *exceptionptr =
+                               new_exception_message(string_java_lang_ClassFormatError,
+                                                                         "java.lang.Object with superclass");
+
+                       return NULL;
+               }
+
+               /* Interfaces must have java.lang.Object as super class. */
+               if ((c->flags & ACC_INTERFACE) &&
+                       c->super->name != utf_java_lang_Object) {
+                       *exceptionptr =
+                               new_exception_message(string_java_lang_ClassFormatError,
+                                                                         "Interfaces must have java.lang.Object as superclass");
+
+                       return NULL;
+               }
 
        } else {
                c->super = NULL;
 
        } else {
                c->super = NULL;
+
+               /* This is only allowed for java.lang.Object. */
+               if (c->name != utf_java_lang_Object) {
+                       *exceptionptr = new_classformaterror(c, "Bad superclass index");
+
+                       return NULL;
+               }
        }
                         
        /* retrieve interfaces */
        }
                         
        /* retrieve interfaces */
-       c->interfacescount = suck_u2();
+       if (!check_classbuffer_size(cb, 2))
+               return NULL;
+
+       c->interfacescount = suck_u2(cb);
+
+       if (!check_classbuffer_size(cb, 2 * c->interfacescount))
+               return NULL;
+
        c->interfaces = MNEW(classinfo*, c->interfacescount);
        for (i = 0; i < c->interfacescount; i++) {
        c->interfaces = MNEW(classinfo*, c->interfacescount);
        for (i = 0; i < c->interfacescount; i++) {
-               c->interfaces [i] = 
-                       class_getconstant(c, suck_u2(), CONSTANT_Class);
+               if (!(c->interfaces[i] = class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
+                       return NULL;
        }
 
        /* load fields */
        }
 
        /* load fields */
-       c->fieldscount = suck_u2();
-/*     utf_display(c->name);
-       printf(" ,Fieldscount: %d\n",c->fieldscount);*/
+       if (!check_classbuffer_size(cb, 2))
+               return NULL;
 
 
+       c->fieldscount = suck_u2(cb);
        c->fields = GCNEW(fieldinfo, c->fieldscount);
        c->fields = GCNEW(fieldinfo, c->fieldscount);
+/*     c->fields = MNEW(fieldinfo, c->fieldscount); */
        for (i = 0; i < c->fieldscount; i++) {
        for (i = 0; i < c->fieldscount; i++) {
-               field_load(&(c->fields[i]), c);
+               if (!field_load(cb, c, &(c->fields[i])))
+                       return NULL;
        }
 
        /* load methods */
        }
 
        /* load methods */
-       c->methodscount = suck_u2();
-       c->methods = MNEW(methodinfo, c->methodscount);
+       if (!check_classbuffer_size(cb, 2))
+               return NULL;
+
+       c->methodscount = suck_u2(cb);
+       c->methods = GCNEW(methodinfo, c->methodscount);
+/*     c->methods = MNEW(methodinfo, c->methodscount); */
        for (i = 0; i < c->methodscount; i++) {
        for (i = 0; i < c->methodscount; i++) {
-               method_load(&(c->methods[i]), c);
+               if (!method_load(cb, c, &(c->methods[i])))
+                       return NULL;
        }
 
        }
 
-#ifdef STATISTICS
-       count_class_infos += sizeof(classinfo*) * c->interfacescount;
-       count_class_infos += sizeof(fieldinfo) * c->fieldscount;
-       count_class_infos += sizeof(methodinfo) * c->methodscount;
+       /* Check if all fields and methods can be uniquely
+        * identified by (name,descriptor). */
+       if (opt_verify) {
+               /* We use a hash table here to avoid making the
+                * average case quadratic in # of methods, fields.
+                */
+               static int shift = 0;
+               u2 *hashtab;
+               u2 *next; /* for chaining colliding hash entries */
+               size_t len;
+               size_t hashlen;
+               u2 index;
+               u2 old;
+
+               /* Allocate hashtable */
+               len = c->methodscount;
+               if (len < c->fieldscount) len = c->fieldscount;
+               hashlen = 5 * len;
+               hashtab = MNEW(u2,(hashlen + len));
+               next = hashtab + hashlen;
+
+               /* Determine bitshift (to get good hash values) */
+               if (!shift) {
+                       len = sizeof(utf);
+                       while (len) {
+                               len >>= 1;
+                               shift++;
+                       }
+               }
+
+               /* Check fields */
+               memset(hashtab, 0, sizeof(u2) * (hashlen + len));
+
+               for (i = 0; i < c->fieldscount; ++i) {
+                       fieldinfo *fi = c->fields + i;
+
+                       /* It's ok if we lose bits here */
+                       index = ((((size_t) fi->name) +
+                                         ((size_t) fi->descriptor)) >> shift) % hashlen;
+
+                       if ((old = hashtab[index])) {
+                               old--;
+                               next[i] = old;
+                               do {
+                                       if (c->fields[old].name == fi->name &&
+                                               c->fields[old].descriptor == fi->descriptor) {
+                                               *exceptionptr =
+                                                       new_classformaterror(c,
+                                                                                                "Repetitive field name/signature");
+
+                                               return NULL;
+                                       }
+                               } while ((old = next[old]));
+                       }
+                       hashtab[index] = i + 1;
+               }
+               
+               /* Check methods */
+               memset(hashtab, 0, sizeof(u2) * (hashlen + hashlen/5));
+
+               for (i = 0; i < c->methodscount; ++i) {
+                       methodinfo *mi = c->methods + i;
+
+                       /* It's ok if we lose bits here */
+                       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;
+                               do {
+                                       if (c->methods[old].name == mi->name &&
+                                               c->methods[old].descriptor == mi->descriptor) {
+                                               *exceptionptr =
+                                                       new_classformaterror(c,
+                                                                                                "Repetitive method name/signature");
+
+                                               return NULL;
+                                       }
+                               } while ((old = next[old]));
+                       }
+                       hashtab[index] = i + 1;
+               }
+               
+               MFREE(hashtab, u2, (hashlen + len));
+       }
+
+#if defined(STATISTICS)
+       if (opt_stat) {
+               count_class_infos += sizeof(classinfo*) * c->interfacescount;
+               count_class_infos += sizeof(fieldinfo) * c->fieldscount;
+               count_class_infos += sizeof(methodinfo) * c->methodscount;
+       }
 #endif
 
 #endif
 
-       /* load variable-length attribute structures */ 
-       attribute_load(suck_u2(), c);
+       /* load attribute structures */
+       if (!check_classbuffer_size(cb, 2))
+               return NULL;
 
 
-       /* free memory */
-       suck_stop();
+       if (!attribute_load(cb, c, suck_u2(cb)))
+               return NULL;
 
 
-       /* remove class from list of unloaded classes and 
-          add to list of unlinked classes                */
-       list_remove(&unloadedclasses, c);
-       list_addlast(&unlinkedclasses, c);
+#if 0
+       /* 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 */
+               s4 classdata_left = ((cb->data + cb->size) - cb->pos - 1);
+
+               if (classdata_left > 0) {
+                       *exceptionptr =
+                               new_classformaterror(c, "Extra bytes at the end of class file");
+                       return NULL;
+               }
+       }
+#endif
 
 
-       c->loaded = true;
+       if (loadverbose)
+               log_message_class("Loading done class: ", c);
 
 
-       return true;
+       return c;
 }
 
 
 
 }
 
 
 
-/************** internal Function: class_highestinterface ***********************
+/************** internal Function: class_highestinterface **********************
 
        Used by the function class_link to determine the amount of memory needed
        for the interface table.
 
        Used by the function class_link to determine the amount of memory needed
        for the interface table.
@@ -1576,13 +2503,8 @@ static s4 class_highestinterface(classinfo *c)
        s4 h;
        s4 i;
        
        s4 h;
        s4 i;
        
-       if (!(c->flags & ACC_INTERFACE)) {
-               char logtext[MAXLOGTEXT];
-               sprintf(logtext, "Interface-methods count requested for non-interface:  ");
-       utf_sprint(logtext + strlen(logtext), c->name);
-       error("%s",logtext);
-       }
-    
+    /* check for ACC_INTERFACE bit already done in class_link_intern */
+
     h = c->index;
        for (i = 0; i < c->interfacescount; i++) {
                s4 h2 = class_highestinterface(c->interfaces[i]);
     h = c->index;
        for (i = 0; i < c->interfacescount; i++) {
                s4 h2 = class_highestinterface(c->interfaces[i]);
@@ -1595,52 +2517,54 @@ static s4 class_highestinterface(classinfo *c)
 
 /* class_addinterface **********************************************************
 
 
 /* class_addinterface **********************************************************
 
-       Is needed by class_link for adding a VTBL to a class. All interfaces
-       implemented by ic are added as well.
+   Is needed by class_link for adding a VTBL to a class. All interfaces
+   implemented by ic are added as well.
 
 
-*******************************************************************************/       
+*******************************************************************************/
 
 
-static void class_addinterface (classinfo *c, classinfo *ic)
+static void class_addinterface(classinfo *c, classinfo *ic)
 {
        s4     j, m;
 {
        s4     j, m;
-       s4     i     = ic->index;
-       vftbl *vftbl = c->vftbl;
-       
-       if (i >= vftbl->interfacetablelength)
+       s4     i   = ic->index;
+       vftbl_t *v = c->vftbl;
+
+       if (i >= v->interfacetablelength)
                panic ("Inernal error: interfacetable overflow");
                panic ("Inernal error: interfacetable overflow");
-       if (vftbl->interfacetable[-i])
+
+       if (v->interfacetable[-i])
                return;
 
        if (ic->methodscount == 0) {  /* fake entry needed for subtype test */
                return;
 
        if (ic->methodscount == 0) {  /* fake entry needed for subtype test */
-               vftbl->interfacevftbllength[i] = 1;
-               vftbl->interfacetable[-i] = MNEW(methodptr, 1);
-               vftbl->interfacetable[-i][0] = NULL;
-               }
-       else {
-               vftbl->interfacevftbllength[i] = ic->methodscount;
-               vftbl->interfacetable[-i] = MNEW(methodptr, ic->methodscount); 
+               v->interfacevftbllength[i] = 1;
+               v->interfacetable[-i] = MNEW(methodptr, 1);
+               v->interfacetable[-i][0] = NULL;
 
 
-#ifdef STATISTICS
-       count_vftbl_len += sizeof(methodptr) *
-                                (ic->methodscount + (ic->methodscount == 0));
+       } else {
+               v->interfacevftbllength[i] = ic->methodscount;
+               v->interfacetable[-i] = MNEW(methodptr, ic->methodscount);
+
+#if defined(STATISTICS)
+               if (opt_stat)
+                       count_vftbl_len += sizeof(methodptr) *
+                               (ic->methodscount + (ic->methodscount == 0));
 #endif
 
 #endif
 
-               for (j=0; j<ic->methodscount; j++) {
+               for (j = 0; j < ic->methodscount; j++) {
                        classinfo *sc = c;
                        while (sc) {
                                for (m = 0; m < sc->methodscount; m++) {
                                        methodinfo *mi = &(sc->methods[m]);
                                        if (method_canoverwrite(mi, &(ic->methods[j]))) {
                        classinfo *sc = c;
                        while (sc) {
                                for (m = 0; m < sc->methodscount; m++) {
                                        methodinfo *mi = &(sc->methods[m]);
                                        if (method_canoverwrite(mi, &(ic->methods[j]))) {
-                                               vftbl->interfacetable[-i][j] = 
-                                                                         vftbl->table[mi->vftblindex];
+                                               v->interfacetable[-i][j] = v->table[mi->vftblindex];
                                                goto foundmethod;
                                                goto foundmethod;
-                                               }
                                        }
                                        }
-                               sc = sc->super;
                                }
                                }
-                        foundmethod: ;
+                               sc = sc->super;
                        }
                        }
+               foundmethod:
+                       ;
                }
                }
+       }
 
        for (j = 0; j < ic->interfacescount; j++) 
                class_addinterface(c, ic->interfaces[j]);
 
        for (j = 0; j < ic->interfacescount; j++) 
                class_addinterface(c, ic->interfaces[j]);
@@ -1659,11 +2583,6 @@ void class_new_array(classinfo *c)
        methodinfo *clone;
        int namelen;
 
        methodinfo *clone;
        int namelen;
 
-       /* XXX remove */ /* dolog("class_new_array: %s",c->name->text); */
-
-       /* Array classes are not loaded from classfiles. */
-       list_remove (&unloadedclasses, c);
-
        /* Check array class name */
        namelen = c->name->blength;
        if (namelen < 2 || c->name->text[0] != '[')
        /* Check array class name */
        namelen = c->name->blength;
        if (namelen < 2 || c->name->text[0] != '[')
@@ -1671,17 +2590,34 @@ void class_new_array(classinfo *c)
 
        /* Check the component type */
        switch (c->name->text[1]) {
 
        /* Check the component type */
        switch (c->name->text[1]) {
-         case '[':
-                 /* c is an array of arrays. We have to create the component class. */
-                 comp = class_new(utf_new(c->name->text + 1,namelen - 1));
-                 break;
+       case '[':
+               /* c is an array of arrays. We have to create the component class. */
+               if (opt_eager) {
+                       comp = class_new_intern(utf_new_intern(c->name->text + 1,
+                                                                                                  namelen - 1));
+                       class_load(comp);
+                       list_addfirst(&unlinkedclasses, comp);
 
 
-         case 'L':
-                 /* c is an array of objects. */
-                 if (namelen < 4 || c->name->text[namelen-1] != ';')
-                         panic("Invalid array class name");
-                 comp = class_new(utf_new(c->name->text + 2,namelen - 3));
-                 break;
+               } else {
+                       comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1));
+               }
+               break;
+
+       case 'L':
+               /* c is an array of objects. */
+               if (namelen < 4 || c->name->text[namelen - 1] != ';')
+                       panic("Invalid array class name");
+
+               if (opt_eager) {
+                       comp = class_new_intern(utf_new_intern(c->name->text + 2,
+                                                                                                  namelen - 3));
+                       class_load(comp);
+                       list_addfirst(&unlinkedclasses, comp);
+
+               } else {
+                       comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3));
+               }
+               break;
        }
 
        /* Setup the array class */
        }
 
        /* Setup the array class */
@@ -1689,35 +2625,42 @@ void class_new_array(classinfo *c)
        c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
 
     c->interfacescount = 2;
        c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
 
     c->interfacescount = 2;
-    c->interfaces = MNEW(classinfo*,2); /* XXX use GC? */
-    c->interfaces[0] = class_java_lang_Cloneable;
-    c->interfaces[1] = class_java_io_Serializable;
+    c->interfaces = MNEW(classinfo*, 2);
+
+       if (opt_eager) {
+               classinfo *tc;
+
+               tc = class_new_intern(utf_new_char("java/lang/Cloneable"));
+               class_load(tc);
+               list_addfirst(&unlinkedclasses, tc);
+               c->interfaces[0] = tc;
+
+               tc = class_new_intern(utf_new_char("java/io/Serializable"));
+               class_load(tc);
+               list_addfirst(&unlinkedclasses, tc);
+               c->interfaces[1] = tc;
+
+       } else {
+               c->interfaces[0] = class_new(utf_new_char("java/lang/Cloneable"));
+               c->interfaces[1] = class_new(utf_new_char("java/io/Serializable"));
+       }
 
        c->methodscount = 1;
 
        c->methodscount = 1;
-       c->methods = MNEW (methodinfo, c->methodscount); /* XXX use GC? */
+       c->methods = MNEW(methodinfo, c->methodscount);
 
        clone = c->methods;
        memset(clone, 0, sizeof(methodinfo));
 
        clone = c->methods;
        memset(clone, 0, sizeof(methodinfo));
-       clone->flags = ACC_PUBLIC; /* XXX protected? */
+       clone->flags = ACC_PUBLIC;
        clone->name = utf_new_char("clone");
        clone->descriptor = utf_new_char("()Ljava/lang/Object;");
        clone->class = c;
        clone->stubroutine = createnativestub((functionptr) &builtin_clone_array, clone);
        clone->name = utf_new_char("clone");
        clone->descriptor = utf_new_char("()Ljava/lang/Object;");
        clone->class = c;
        clone->stubroutine = createnativestub((functionptr) &builtin_clone_array, clone);
-       clone->monoPoly = MONO; /* XXX should be poly? */
+       clone->monoPoly = MONO;
 
        /* XXX: field: length? */
 
 
        /* XXX: field: length? */
 
-       /* The array class has to be linked */
-       list_addlast(&unlinkedclasses,c);
-       
-       /*
-     * Array classes which are created after the other classes have been
-     * loaded and linked are linked explicitely.
-     */
-        c->loaded=true;
-     
-       if (loader_inited)
-               loader_load(c->name); /* XXX handle errors */
+       /* array classes are not loaded from class files */
+       c->loaded = true;
 }
 
 
 }
 
 
@@ -1734,28 +2677,36 @@ void class_new_array(classinfo *c)
 static arraydescriptor *class_link_array(classinfo *c)
 {
        classinfo *comp = NULL;
 static arraydescriptor *class_link_array(classinfo *c)
 {
        classinfo *comp = NULL;
-       int namelen = c->name->blength;
+       s4 namelen = c->name->blength;
        arraydescriptor *desc;
        arraydescriptor *desc;
-       vftbl *compvftbl;
+       vftbl_t *compvftbl;
 
        /* Check the component type */
        switch (c->name->text[1]) {
 
        /* Check the component type */
        switch (c->name->text[1]) {
-         case '[':
-                 /* c is an array of arrays. */
-                 comp = class_get(utf_new(c->name->text + 1,namelen - 1));
-                 if (!comp) panic("Could not find component array class.");
-                 break;
-
-         case 'L':
-                 /* c is an array of objects. */
-                 comp = class_get(utf_new(c->name->text + 2,namelen - 3));
-                 if (!comp) panic("Could not find component class.");
-                 break;
+       case '[':
+               /* c is an array of arrays. */
+               comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1));
+               if (!comp)
+                       panic("Could not find component array class.");
+               break;
+
+       case 'L':
+               /* c is an array of objects. */
+               comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3));
+               if (!comp)
+                       panic("Could not find component class.");
+               break;
        }
 
        }
 
-       /* If the component type has not been linked return NULL */
-       if (comp && !comp->linked)
-               return NULL;
+       /* If the component type has not been linked, link it now */
+       if (comp && !comp->linked) {
+               if (!comp->loaded)
+                       if (!class_load(comp))
+                               return NULL;
+
+               if (!class_link(comp))
+                       return NULL;
+       }
 
        /* Allocate the arraydescriptor */
        desc = NEW(arraydescriptor);
 
        /* Allocate the arraydescriptor */
        desc = NEW(arraydescriptor);
@@ -1764,53 +2715,79 @@ static arraydescriptor *class_link_array(classinfo *c)
                /* c is an array of references */
                desc->arraytype = ARRAYTYPE_OBJECT;
                desc->componentsize = sizeof(void*);
                /* c is an array of references */
                desc->arraytype = ARRAYTYPE_OBJECT;
                desc->componentsize = sizeof(void*);
-               desc->dataoffset = OFFSET(java_objectarray,data);
+               desc->dataoffset = OFFSET(java_objectarray, data);
                
                compvftbl = comp->vftbl;
                if (!compvftbl)
                
                compvftbl = comp->vftbl;
                if (!compvftbl)
-                       panic("Component class has no vftbl.");
+                       panic("Component class has no vftbl");
                desc->componentvftbl = compvftbl;
                
                if (compvftbl->arraydesc) {
                        desc->elementvftbl = compvftbl->arraydesc->elementvftbl;
                desc->componentvftbl = compvftbl;
                
                if (compvftbl->arraydesc) {
                        desc->elementvftbl = compvftbl->arraydesc->elementvftbl;
+                       if (compvftbl->arraydesc->dimension >= 255)
+                               panic("Creating array of dimension >255");
                        desc->dimension = compvftbl->arraydesc->dimension + 1;
                        desc->elementtype = compvftbl->arraydesc->elementtype;
                        desc->dimension = compvftbl->arraydesc->dimension + 1;
                        desc->elementtype = compvftbl->arraydesc->elementtype;
-               }
-               else {
+
+               else {
                        desc->elementvftbl = compvftbl;
                        desc->dimension = 1;
                        desc->elementtype = ARRAYTYPE_OBJECT;
                }
                        desc->elementvftbl = compvftbl;
                        desc->dimension = 1;
                        desc->elementtype = ARRAYTYPE_OBJECT;
                }
-       }
-       else {
+
+       else {
                /* c is an array of a primitive type */
                switch (c->name->text[1]) {
                /* c is an array of a primitive type */
                switch (c->name->text[1]) {
-                 case 'Z': desc->arraytype = ARRAYTYPE_BOOLEAN;
-                           desc->dataoffset = OFFSET(java_booleanarray,data);
-                               desc->componentsize = sizeof(u1); break;
-                 case 'B': desc->arraytype = ARRAYTYPE_BYTE;
-                           desc->dataoffset = OFFSET(java_bytearray,data);
-                               desc->componentsize = sizeof(u1); break;
-                 case 'C': desc->arraytype = ARRAYTYPE_CHAR;
-                           desc->dataoffset = OFFSET(java_chararray,data);
-                               desc->componentsize = sizeof(u2); break;
-                 case 'D': desc->arraytype = ARRAYTYPE_DOUBLE;
-                           desc->dataoffset = OFFSET(java_doublearray,data);
-                               desc->componentsize = sizeof(double); break;
-                 case 'F': desc->arraytype = ARRAYTYPE_FLOAT;
-                           desc->dataoffset = OFFSET(java_floatarray,data);
-                               desc->componentsize = sizeof(float); break;
-                 case 'I': desc->arraytype = ARRAYTYPE_INT;
-                           desc->dataoffset = OFFSET(java_intarray,data);
-                               desc->componentsize = sizeof(s4); break;
-                 case 'J': desc->arraytype = ARRAYTYPE_LONG;
-                           desc->dataoffset = OFFSET(java_longarray,data);
-                               desc->componentsize = sizeof(s8); break;
-                 case 'S': desc->arraytype = ARRAYTYPE_SHORT;
-                           desc->dataoffset = OFFSET(java_shortarray,data);
-                               desc->componentsize = sizeof(s2); break;
-                 default:
-                         panic("Invalid array class name");
+               case 'Z':
+                       desc->arraytype = ARRAYTYPE_BOOLEAN;
+                       desc->dataoffset = OFFSET(java_booleanarray,data);
+                       desc->componentsize = sizeof(u1);
+                       break;
+
+               case 'B':
+                       desc->arraytype = ARRAYTYPE_BYTE;
+                       desc->dataoffset = OFFSET(java_bytearray,data);
+                       desc->componentsize = sizeof(u1);
+                       break;
+
+               case 'C':
+                       desc->arraytype = ARRAYTYPE_CHAR;
+                       desc->dataoffset = OFFSET(java_chararray,data);
+                       desc->componentsize = sizeof(u2);
+                       break;
+
+               case 'D':
+                       desc->arraytype = ARRAYTYPE_DOUBLE;
+                       desc->dataoffset = OFFSET(java_doublearray,data);
+                       desc->componentsize = sizeof(double);
+                       break;
+
+               case 'F':
+                       desc->arraytype = ARRAYTYPE_FLOAT;
+                       desc->dataoffset = OFFSET(java_floatarray,data);
+                       desc->componentsize = sizeof(float);
+                       break;
+
+               case 'I':
+                       desc->arraytype = ARRAYTYPE_INT;
+                       desc->dataoffset = OFFSET(java_intarray,data);
+                       desc->componentsize = sizeof(s4);
+                       break;
+
+               case 'J':
+                       desc->arraytype = ARRAYTYPE_LONG;
+                       desc->dataoffset = OFFSET(java_longarray,data);
+                       desc->componentsize = sizeof(s8);
+                       break;
+
+               case 'S':
+                       desc->arraytype = ARRAYTYPE_SHORT;
+                       desc->dataoffset = OFFSET(java_shortarray,data);
+                       desc->componentsize = sizeof(s2);
+                       break;
+
+               default:
+                       panic("Invalid array class name");
                }
                
                desc->componentvftbl = NULL;
                }
                
                desc->componentvftbl = NULL;
@@ -1825,52 +2802,131 @@ static arraydescriptor *class_link_array(classinfo *c)
 
 /********************** Function: class_link ***********************************
 
 
 /********************** Function: class_link ***********************************
 
-       Tries to link a class. The super class and every implemented interface must
-       already have been linked. The function calculates the length in bytes that
+       Tries to link a class. The function calculates the length in bytes that
        an instance of this class requires as well as the VTBL for methods and
        interface methods.
        
        an instance of this class requires as well as the VTBL for methods and
        interface methods.
        
-       If the class can be linked, it is removed from the list 'unlinkedclasses'
-       and added to 'linkedclasses'. Otherwise, it is moved to the end of
-       'unlinkedclasses'.
+*******************************************************************************/
 
 
-       Attention: If cyclical class definitions are encountered, the program gets
-       into an infinite loop (we'll have to work that out)
+static classinfo *class_link_intern(classinfo *c);
 
 
-*******************************************************************************/
+classinfo *class_link(classinfo *c)
+{
+       classinfo *r;
+
+#if defined(USE_THREADS)
+       /* enter a monitor on the class */
+
+       builtin_monitorenter((java_objectheader *) c);
+#endif
+
+       /* maybe the class is already linked */
+       if (c->linked) {
+#if defined(USE_THREADS)
+               builtin_monitorexit((java_objectheader *) c);
+#endif
+
+               return c;
+       }
+
+       /* measure time */
+
+       if (getcompilingtime)
+               compilingtime_stop();
 
 
-void class_link(classinfo *c)
+       if (getloadingtime)
+               loadingtime_start();
+
+       /* call the internal function */
+       r = class_link_intern(c);
+
+       /* if return value is NULL, we had a problem and the class is not linked */
+       if (!r)
+               c->linked = false;
+
+       /* measure time */
+
+       if (getloadingtime)
+               loadingtime_stop();
+
+       if (getcompilingtime)
+               compilingtime_start();
+
+#if defined(USE_THREADS)
+       /* leave the monitor */
+
+       builtin_monitorexit((java_objectheader *) c);
+#endif
+
+       return r;
+}
+
+
+static classinfo *class_link_intern(classinfo *c)
 {
        s4 supervftbllength;          /* vftbllegnth of super class               */
        s4 vftbllength;               /* vftbllength of current class             */
        s4 interfacetablelength;      /* interface table length                   */
 {
        s4 supervftbllength;          /* vftbllegnth of super class               */
        s4 vftbllength;               /* vftbllength of current class             */
        s4 interfacetablelength;      /* interface table length                   */
-       classinfo *super = c->super;  /* super class                              */
-       classinfo *ic, *c2;           /* intermediate class variables             */
-       vftbl *v;                     /* vftbl of current class                   */
+       classinfo *super;             /* super class                              */
+       classinfo *tc;                /* temporary class variable                 */
+       vftbl_t *v;                   /* vftbl of current class                   */
        s4 i;                         /* interface/method/field counter           */
        s4 i;                         /* interface/method/field counter           */
-       arraydescriptor *arraydesc = NULL;  /* descriptor for array classes       */
+       arraydescriptor *arraydesc;   /* descriptor for array classes             */
+
+       /* maybe the class is already linked */
+       if (c->linked)
+               return c;
 
 
+       /* maybe the class is not loaded */
+       if (!c->loaded)
+               if (!class_load(c))
+                       return NULL;
 
 
-       /*  check if all superclasses are already linked, if not put c at end of
-           unlinked list and return. Additionally initialize class fields.       */
+       if (linkverbose)
+               log_message_class("Linking class: ", c);
+
+       /* ok, this class is somewhat linked */
+       c->linked = true;
 
 
-       /*  check interfaces */
+       arraydesc = NULL;
+
+       /* check interfaces */
 
        for (i = 0; i < c->interfacescount; i++) {
 
        for (i = 0; i < c->interfacescount; i++) {
-               ic = c->interfaces[i];
-               if (!ic->linked) {
-                       list_remove(&unlinkedclasses, c);
-                       list_addlast(&unlinkedclasses, c);
-                       return; 
+               tc = c->interfaces[i];
+
+               /* detect circularity */
+               if (tc == c) {
+                       *exceptionptr =
+                               new_exception_utfmessage(string_java_lang_ClassCircularityError,
+                                                                                c->name);
+                       return NULL;
+               }
+
+               if (!tc->loaded)
+                       if (!class_load(tc))
+                               return NULL;
+
+               if (!(tc->flags & ACC_INTERFACE)) {
+                       *exceptionptr =
+                               new_exception_message(string_java_lang_IncompatibleClassChangeError,
+                                                                         "Implementing class");
+                       return NULL;
                }
                }
+
+               if (!tc->linked)
+                       if (!class_link(tc))
+                               return NULL;
        }
        
        }
        
-       /*  check super class */
+       /* check super class */
+
+       super = c->super;
 
 
-       if (super == NULL) {          /* class java.long.Object */
+       if (super == NULL) {          /* class java.lang.Object */
                c->index = 0;
         c->classUsed = USED;     /* Object class is always used CO-RT*/
                c->index = 0;
         c->classUsed = USED;     /* Object class is always used CO-RT*/
-               c -> impldBy = NULL;
+               c->impldBy = NULL;
                c->instancesize = sizeof(java_objectheader);
                
                vftbllength = supervftbllength = 0;
                c->instancesize = sizeof(java_objectheader);
                
                vftbllength = supervftbllength = 0;
@@ -1878,20 +2934,40 @@ void class_link(classinfo *c)
                c->finalizer = NULL;
 
        } else {
                c->finalizer = NULL;
 
        } else {
-               if (!super->linked) {
-                       list_remove(&unlinkedclasses, c);
-                       list_addlast(&unlinkedclasses, c);
-                       return; 
+               /* detect circularity */
+               if (super == c) {
+                       *exceptionptr =
+                               new_exception_utfmessage(string_java_lang_ClassCircularityError,
+                                                                                c->name);
+                       return NULL;
                }
 
                }
 
+               if (!super->loaded)
+                       if (!class_load(super))
+                               return NULL;
+
+               if (super->flags & ACC_INTERFACE) {
+                       /* java.lang.IncompatibleClassChangeError: class a has interface java.lang.Cloneable as super class */
+                       panic("Interface specified as super class");
+               }
+
+               /* Don't allow extending final classes */
+               if (super->flags & ACC_FINAL) {
+                       *exceptionptr =
+                               new_exception_message(string_java_lang_VerifyError,
+                                                                         "Cannot inherit from final class");
+                       return NULL;
+               }
+               
+               if (!super->linked)
+                       if (!class_link(super))
+                               return NULL;
+
                /* handle array classes */
                if (c->name->text[0] == '[')
                /* handle array classes */
                if (c->name->text[0] == '[')
-                       if ((arraydesc = class_link_array(c)) == NULL) {
-                               list_remove(&unlinkedclasses, c);
-                               list_addlast(&unlinkedclasses, c);
-                               return; 
-                       }
-               
+                       if (!(arraydesc = class_link_array(c)))
+                               return NULL;
+
                if (c->flags & ACC_INTERFACE)
                        c->index = interfaceindex++;
                else
                if (c->flags & ACC_INTERFACE)
                        c->index = interfaceindex++;
                else
@@ -1904,59 +2980,65 @@ void class_link(classinfo *c)
                c->finalizer = super->finalizer;
        }
 
                c->finalizer = super->finalizer;
        }
 
-
-       if (linkverbose) {
-               char logtext[MAXLOGTEXT];
-               sprintf(logtext, "Linking Class: ");
-               utf_sprint(logtext + strlen(logtext), c->name );
-               log_text(logtext);
-       }
-
        /* compute vftbl length */
 
        for (i = 0; i < c->methodscount; i++) {
                methodinfo *m = &(c->methods[i]);
                        
                if (!(m->flags & ACC_STATIC)) { /* is instance method */
        /* compute vftbl length */
 
        for (i = 0; i < c->methodscount; i++) {
                methodinfo *m = &(c->methods[i]);
                        
                if (!(m->flags & ACC_STATIC)) { /* is instance method */
-                       classinfo *sc = super;
-                       while (sc) {
-                               int j;
-                               for (j = 0; j < sc->methodscount; j++) {
-                                       if (method_canoverwrite(m, &(sc->methods[j]))) {
-                                               m->vftblindex = sc->methods[j].vftblindex;
+                       tc = super;
+
+                       while (tc) {
+                               s4 j;
+                               for (j = 0; j < tc->methodscount; j++) {
+                                       if (method_canoverwrite(m, &(tc->methods[j]))) {
+                                               if (tc->methods[j].flags & ACC_PRIVATE)
+                                                       goto notfoundvftblindex;
+
+                                               if (tc->methods[j].flags & ACC_FINAL) {
+                                                       /* class a overrides final method . */
+                                                       *exceptionptr =
+                                                               new_exception(string_java_lang_VerifyError);
+                                                       return NULL;
+                                               }
+                                               m->vftblindex = tc->methods[j].vftblindex;
                                                goto foundvftblindex;
                                        }
                                }
                                                goto foundvftblindex;
                                        }
                                }
-                               sc = sc->super;
+                               tc = tc->super;
                        }
                        }
+               notfoundvftblindex:
                        m->vftblindex = (vftbllength++);
                        m->vftblindex = (vftbllength++);
-               foundvftblindex: ;
+               foundvftblindex:
+                       ;
                }
        }       
        
                }
        }       
        
-#ifdef STATISTICS
-       count_vftbl_len += sizeof(vftbl) + (sizeof(methodptr) * (vftbllength - 1));
+#if defined(STATISTICS)
+       if (opt_stat)
+               count_vftbl_len +=
+                       sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1));
 #endif
 
        /* compute interfacetable length */
 
        interfacetablelength = 0;
 #endif
 
        /* compute interfacetable length */
 
        interfacetablelength = 0;
-       c2 = c;
-       while (c2) {
-               for (i = 0; i < c2->interfacescount; i++) {
-                       s4 h = class_highestinterface (c2->interfaces[i]) + 1;
+       tc = c;
+       while (tc) {
+               for (i = 0; i < tc->interfacescount; i++) {
+                       s4 h = class_highestinterface(tc->interfaces[i]) + 1;
                        if (h > interfacetablelength)
                                interfacetablelength = h;
                }
                        if (h > interfacetablelength)
                                interfacetablelength = h;
                }
-               c2 = c2->super;
+               tc = tc->super;
        }
 
        /* allocate virtual function table */
 
        }
 
        /* allocate virtual function table */
 
-       v = (vftbl*) mem_alloc(sizeof(vftbl) + sizeof(methodptr) *
+       v = (vftbl_t*) mem_alloc(sizeof(vftbl_t) + sizeof(methodptr) *
                                                   (vftbllength - 1) + sizeof(methodptr*) *
                                                   (interfacetablelength - (interfacetablelength > 0)));
                                                   (vftbllength - 1) + sizeof(methodptr*) *
                                                   (interfacetablelength - (interfacetablelength > 0)));
-       v = (vftbl*) (((methodptr*) v) + (interfacetablelength - 1) *
+       v = (vftbl_t*) (((methodptr*) v) + (interfacetablelength - 1) *
                                  (interfacetablelength > 1));
        c->header.vftbl = c->vftbl = v;
        v->class = c;
                                  (interfacetablelength > 1));
        c->header.vftbl = c->vftbl = v;
        v->class = c;
@@ -1988,7 +3070,7 @@ void class_link(classinfo *c)
                s4 dsize;
                fieldinfo *f = &(c->fields[i]);
                
                s4 dsize;
                fieldinfo *f = &(c->fields[i]);
                
-               if (!(f->flags & ACC_STATIC) ) {
+               if (!(f->flags & ACC_STATIC)) {
                        dsize = desc_typesize(f->descriptor);
                        c->instancesize = ALIGN(c->instancesize, dsize);
                        f->offset = c->instancesize;
                        dsize = desc_typesize(f->descriptor);
                        c->instancesize = ALIGN(c->instancesize, dsize);
                        f->offset = c->instancesize;
@@ -2000,8 +3082,9 @@ void class_link(classinfo *c)
        
        v->interfacevftbllength = MNEW(s4, interfacetablelength);
 
        
        v->interfacevftbllength = MNEW(s4, interfacetablelength);
 
-#ifdef STATISTICS
-       count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength;
+#if defined(STATISTICS)
+       if (opt_stat)
+               count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength;
 #endif
 
        for (i = 0; i < interfacetablelength; i++) {
 #endif
 
        for (i = 0; i < interfacetablelength; i++) {
@@ -2011,37 +3094,32 @@ void class_link(classinfo *c)
        
        /* add interfaces */
        
        
        /* add interfaces */
        
-       for (c2 = c; c2 != NULL; c2 = c2->super)
-               for (i = 0; i < c2->interfacescount; i++) {
-                       class_addinterface(c, c2->interfaces[i]);
-               }
+       for (tc = c; tc != NULL; tc = tc->super)
+               for (i = 0; i < tc->interfacescount; i++)
+                       class_addinterface(c, tc->interfaces[i]);
 
        /* add finalizer method (not for java.lang.Object) */
 
 
        /* add finalizer method (not for java.lang.Object) */
 
-       if (super != NULL) {
+       if (super) {
                methodinfo *fi;
                methodinfo *fi;
-               static utf *finame = NULL;
-               static utf *fidesc = NULL;
 
 
-               if (finame == NULL)
-                       finame = utf_finalize;
-               if (fidesc == NULL)
-                       fidesc = utf_fidesc;
+               fi = class_findmethod(c, utf_finalize, utf_void__void);
 
 
-               fi = class_findmethod(c, finame, fidesc);
-               if (fi != NULL) {
-                       if (!(fi->flags & ACC_STATIC)) {
+               if (fi)
+                       if (!(fi->flags & ACC_STATIC))
                                c->finalizer = fi;
                                c->finalizer = fi;
-                       }
-               }
        }
 
        /* final tasks */
 
        }
 
        /* final tasks */
 
-       c->linked = true;       
+       loader_compute_subclasses(c);
 
 
-       list_remove(&unlinkedclasses, c);
-       list_addlast(&linkedclasses, c);
+       if (linkverbose)
+               log_message_class("Linking done class: ", c);
+
+       /* just return c to show that we didn't had a problem */
+
+       return c;
 }
 
 
 }
 
 
@@ -2051,44 +3129,49 @@ void class_link(classinfo *c)
 
 *******************************************************************************/
 
 
 *******************************************************************************/
 
-static void class_freecpool (classinfo *c)
+static void class_freecpool(classinfo *c)
 {
        u4 idx;
        u4 tag;
        voidptr info;
        
 {
        u4 idx;
        u4 tag;
        voidptr info;
        
-       for (idx=0; idx < c->cpcount; idx++) {
-               tag = c->cptags[idx];
-               info = c->cpinfos[idx];
+       if (c->cptags && c->cpinfos) {
+               for (idx = 0; idx < c->cpcount; idx++) {
+                       tag = c->cptags[idx];
+                       info = c->cpinfos[idx];
                
                
-               if (info != NULL) {
-                       switch (tag) {
-                       case CONSTANT_Fieldref:
-                       case CONSTANT_Methodref:
-                       case CONSTANT_InterfaceMethodref:
-                               FREE (info, constant_FMIref);
-                               break;
-                       case CONSTANT_Integer:
-                               FREE (info, constant_integer);
-                               break;
-                       case CONSTANT_Float:
-                               FREE (info, constant_float);
-                               break;
-                       case CONSTANT_Long:
-                               FREE (info, constant_long);
-                               break;
-                       case CONSTANT_Double:
-                               FREE (info, constant_double);
-                               break;
-                       case CONSTANT_NameAndType:
-                               FREE (info, constant_nameandtype);
-                               break;
-                       }
+                       if (info != NULL) {
+                               switch (tag) {
+                               case CONSTANT_Fieldref:
+                               case CONSTANT_Methodref:
+                               case CONSTANT_InterfaceMethodref:
+                                       FREE(info, constant_FMIref);
+                                       break;
+                               case CONSTANT_Integer:
+                                       FREE(info, constant_integer);
+                                       break;
+                               case CONSTANT_Float:
+                                       FREE(info, constant_float);
+                                       break;
+                               case CONSTANT_Long:
+                                       FREE(info, constant_long);
+                                       break;
+                               case CONSTANT_Double:
+                                       FREE(info, constant_double);
+                                       break;
+                               case CONSTANT_NameAndType:
+                                       FREE(info, constant_nameandtype);
+                                       break;
+                               }
                        }
                }
                        }
                }
+       }
 
 
-       MFREE (c -> cptags,  u1, c -> cpcount);
-       MFREE (c -> cpinfos, voidptr, c -> cpcount);
+       if (c->cptags)
+               MFREE(c->cptags, u1, c->cpcount);
+
+       if (c->cpinfos)
+               MFREE(c->cpinfos, voidptr, c->cpcount);
 }
 
 
 }
 
 
@@ -2098,21 +3181,27 @@ static void class_freecpool (classinfo *c)
 
 *******************************************************************************/
 
 
 *******************************************************************************/
 
-static void class_free(classinfo *c)
+void class_free(classinfo *c)
 {
        s4 i;
 {
        s4 i;
-       vftbl *v;
+       vftbl_t *v;
                
        class_freecpool(c);
 
                
        class_freecpool(c);
 
-       MFREE(c->interfaces, classinfo*, c->interfacescount);
+       if (c->interfaces)
+               MFREE(c->interfaces, classinfo*, c->interfacescount);
 
 
-       for (i = 0; i < c->fieldscount; i++)
-               field_free(&(c->fields[i]));
+       if (c->fields) {
+               for (i = 0; i < c->fieldscount; i++)
+                       field_free(&(c->fields[i]));
+/*     MFREE(c->fields, fieldinfo, c->fieldscount); */
+       }
        
        
-       for (i = 0; i < c->methodscount; i++)
-               method_free(&(c->methods[i]));
-       MFREE(c->methods, methodinfo, c->methodscount);
+       if (c->methods) {
+               for (i = 0; i < c->methodscount; i++)
+                       method_free(&(c->methods[i]));
+/*     MFREE(c->methods, methodinfo, c->methodscount); */
+       }
 
        if ((v = c->vftbl) != NULL) {
                if (v->arraydesc)
 
        if ((v = c->vftbl) != NULL) {
                if (v->arraydesc)
@@ -2123,21 +3212,21 @@ static void class_free(classinfo *c)
                }
                MFREE(v->interfacevftbllength, s4, v->interfacetablelength);
 
                }
                MFREE(v->interfacevftbllength, s4, v->interfacetablelength);
 
-               i = sizeof(vftbl) + sizeof(methodptr) * (v->vftbllength - 1) +
+               i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) +
                    sizeof(methodptr*) * (v->interfacetablelength -
                                         (v->interfacetablelength > 0));
                    sizeof(methodptr*) * (v->interfacetablelength -
                                         (v->interfacetablelength > 0));
-               v = (vftbl*) (((methodptr*) v) - (v->interfacetablelength - 1) *
+               v = (vftbl_t*) (((methodptr*) v) - (v->interfacetablelength - 1) *
                                             (v->interfacetablelength > 1));
                mem_free(v, i);
        }
 
                                             (v->interfacetablelength > 1));
                mem_free(v, i);
        }
 
-       if (c->innerclasscount)
+       if (c->innerclass)
                MFREE(c->innerclass, innerclassinfo, c->innerclasscount);
 
        /*      if (c->classvftbl)
                mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); */
        
                MFREE(c->innerclass, innerclassinfo, c->innerclasscount);
 
        /*      if (c->classvftbl)
                mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); */
        
-       GCFREE(c);
+/*     GCFREE(c); */
 }
 
 
 }
 
 
@@ -2151,7 +3240,7 @@ static void class_free(classinfo *c)
 fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc)
 {
        s4 i;
 fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc)
 {
        s4 i;
-       
+
        for (i = 0; i < c->fieldscount; i++) { 
                if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) 
                        return &(c->fields[i]);                                                         
        for (i = 0; i < c->fieldscount; i++) { 
                if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) 
                        return &(c->fields[i]);                                                         
@@ -2164,138 +3253,120 @@ fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc)
 }
 
 
 }
 
 
-/************************* Function: class_findmethod **************************
-       
-       Searches a 'classinfo' structure for a method having the given name and
-       type and returns the index in the class info structure.
-       If type is NULL, it is ignored.
+/****************** Function: class_resolvefield_int ***************************
+
+    This is an internally used helper function. Do not use this directly.
+
+       Tries to resolve a field having the given name and type.
+    If the field cannot be resolved, NULL is returned.
 
 *******************************************************************************/
 
 
 *******************************************************************************/
 
-s4 class_findmethodIndex(classinfo *c, utf *name, utf *desc)
+static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc)
 {
        s4 i;
 {
        s4 i;
-#if defined(JOWENN_DEBUG1) || defined(JOWENN_DEBUG2)
-       char *buffer;                   
-       int buffer_len, pos;
-#endif
-#ifdef JOWENN_DEBUG1
+       fieldinfo *fi;
 
 
-       buffer_len = 
-               utf_strlen(name) + utf_strlen(desc) + utf_strlen(c->name) + 64;
-       
-       buffer = MNEW(char, buffer_len);
+       /* search for field in class c */
+       for (i = 0; i < c->fieldscount; i++) { 
+               if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) {
+                       return &(c->fields[i]);
+               }
+    }
 
 
-       strcpy(buffer, "class_findmethod: method:");
-       utf_sprint(buffer + strlen(buffer), name);
-       strcpy(buffer + strlen(buffer), ", desc: ");
-       utf_sprint(buffer + strlen(buffer), desc);
-       strcpy(buffer + strlen(buffer), ", classname: ");
-       utf_sprint(buffer + strlen(buffer), c->name);
-       
-       log_text(buffer);       
+       /* try superinterfaces recursively */
+       for (i = 0; i < c->interfacescount; ++i) {
+               fi = class_resolvefield_int(c->interfaces[i], name, desc);
+               if (fi)
+                       return fi;
+       }
 
 
-       MFREE(buffer, char, buffer_len);
-#endif 
-       for (i = 0; i < c->methodscount; i++) {
-#ifdef JOWENN_DEBUG2
-               buffer_len = 
-                       utf_strlen(c->methods[i].name) + utf_strlen(c->methods[i].descriptor)+ 64;
+       /* try superclass */
+       if (c->super)
+               return class_resolvefield_int(c->super, name, desc);
+
+       /* not found */
+       return NULL;
+}
+
+
+/********************* Function: class_resolvefield ***************************
        
        
-               buffer = MNEW(char, buffer_len);
+       Resolves a reference from REFERER to a field with NAME and DESC in class C.
+
+    If the field cannot be resolved the return value is NULL. If EXCEPT is
+    true *exceptionptr is set, too.
+
+*******************************************************************************/
 
 
-               strcpy(buffer, "class_findmethod: comparing to method:");
-               utf_sprint(buffer + strlen(buffer), c->methods[i].name);
-               strcpy(buffer + strlen(buffer), ", desc: ");
-               utf_sprint(buffer + strlen(buffer), c->methods[i].descriptor);
+fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc,
+                                                         classinfo *referer, bool except)
+{
+       fieldinfo *fi;
+
+       /* XXX resolve class c */
+       /* XXX check access from REFERER to C */
        
        
-               log_text(buffer);       
+       fi = class_resolvefield_int(c, name, desc);
 
 
-               MFREE(buffer, char, buffer_len);
-#endif 
-               
-               
-               if ((c->methods[i].name == name) && ((desc == NULL) ||
-                                                                                        (c->methods[i].descriptor == desc))) {
-                       return i;
-               }
+       if (!fi) {
+               if (except)
+                       *exceptionptr =
+                               new_exception_utfmessage(string_java_lang_NoSuchFieldError,
+                                                                                name);
+
+               return NULL;
        }
 
        }
 
-#ifdef JOWENN_DEBUG2   
-       class_showconstantpool(c);
-       log_text("class_findmethod: returning NULL");
-#endif
+       /* XXX check access rights */
 
 
-       return -1;
+       return fi;
 }
 
 
 /************************* Function: class_findmethod **************************
        
        Searches a 'classinfo' structure for a method having the given name and
 }
 
 
 /************************* Function: class_findmethod **************************
        
        Searches a 'classinfo' structure for a method having the given name and
-       type.
+       type and returns the index in the class info structure.
        If type is NULL, it is ignored.
 
 *******************************************************************************/
 
        If type is NULL, it is ignored.
 
 *******************************************************************************/
 
-methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc)
+s4 class_findmethodIndex(classinfo *c, utf *name, utf *desc)
 {
 {
-#if 0
        s4 i;
        s4 i;
-#if defined(JOWENN_DEBUG1) || defined(JOWENN_DEBUG2)
-       char *buffer;                   
-       int buffer_len, pos;
-#endif
-#ifdef JOWENN_DEBUG1
-
-       buffer_len = 
-               utf_strlen(name) + utf_strlen(desc) + utf_strlen(c->name) + 64;
-       
-       buffer = MNEW(char, buffer_len);
 
 
-       strcpy(buffer, "class_findmethod: method:");
-       utf_sprint(buffer + strlen(buffer), name);
-       strcpy(buffer + strlen(buffer), ", desc: ");
-       utf_sprint(buffer + strlen(buffer), desc);
-       strcpy(buffer + strlen(buffer), ", classname: ");
-       utf_sprint(buffer + strlen(buffer), c->name);
-       
-       log_text(buffer);       
-
-       MFREE(buffer, char, buffer_len);
-#endif 
        for (i = 0; i < c->methodscount; i++) {
        for (i = 0; i < c->methodscount; i++) {
-#ifdef JOWENN_DEBUG2
-               buffer_len = 
-                       utf_strlen(c->methods[i].name) + utf_strlen(c->methods[i].descriptor)+ 64;
-       
-               buffer = MNEW(char, buffer_len);
 
 
-               strcpy(buffer, "class_findmethod: comparing to method:");
-               utf_sprint(buffer + strlen(buffer), c->methods[i].name);
-               strcpy(buffer + strlen(buffer), ", desc: ");
-               utf_sprint(buffer + strlen(buffer), c->methods[i].descriptor);
-       
-               log_text(buffer);       
+/*             utf_display_classname(c->name);printf("."); */
+/*             utf_display(c->methods[i].name);printf("."); */
+/*             utf_display(c->methods[i].descriptor); */
+/*             printf("\n"); */
 
 
-               MFREE(buffer, char, buffer_len);
-#endif 
-               
                if ((c->methods[i].name == name) && ((desc == NULL) ||
                                                                                         (c->methods[i].descriptor == desc))) {
                if ((c->methods[i].name == name) && ((desc == NULL) ||
                                                                                         (c->methods[i].descriptor == desc))) {
-                       return &(c->methods[i]);
+                       return i;
                }
        }
                }
        }
-#ifdef JOWENN_DEBUG2   
-       class_showconstantpool(c);
-       log_text("class_findmethod: returning NULL");
-#endif
-       return NULL;
-#endif
 
 
-       s4 idx=class_findmethodIndex(c, name, desc);
-/*     if (idx==-1) log_text("class_findmethod: method not found");*/
-       if (idx == -1) return NULL;
+       return -1;
+}
+
+
+/************************* Function: class_findmethod **************************
+       
+       Searches a 'classinfo' structure for a method having the given name and
+       type.
+       If type is NULL, it is ignored.
+
+*******************************************************************************/
+
+methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc)
+{
+       s4 idx = class_findmethodIndex(c, name, desc);
+
+       if (idx == -1)
+               return NULL;
 
        return &(c->methods[idx]);
 }
 
        return &(c->methods[idx]);
 }
@@ -2310,6 +3381,7 @@ methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc)
 methodinfo *class_fetchmethod(classinfo *c, utf *name, utf *desc)
 {
        methodinfo *mi;
 methodinfo *class_fetchmethod(classinfo *c, utf *name, utf *desc)
 {
        methodinfo *mi;
+
        mi = class_findmethod(c, name, desc);
 
        if (!mi) {
        mi = class_findmethod(c, name, desc);
 
        if (!mi) {
@@ -2323,6 +3395,42 @@ methodinfo *class_fetchmethod(classinfo *c, utf *name, utf *desc)
 }
 
 
 }
 
 
+/*********************** Function: class_findmethod_w**************************
+
+    like class_findmethod, but logs a warning if the method is not found
+
+*******************************************************************************/
+
+methodinfo *class_findmethod_w(classinfo *c, utf *name, utf *desc, char *from)
+{
+        methodinfo *mi;
+        mi = class_findmethod(c, name, desc);
+
+        if (!mi) {
+                log_plain("Class: "); if (c) log_plain_utf(c->name); log_nl();
+                log_plain("Method: "); if (name) log_plain_utf(name); log_nl();
+                log_plain("Descriptor: "); if (desc) log_plain_utf(desc); log_nl();
+
+                       if ( c->flags & ACC_PUBLIC )       log_plain(" PUBLIC ");
+               if ( c->flags & ACC_PRIVATE )      log_plain(" PRIVATE ");
+               if ( c->flags & ACC_PROTECTED )    log_plain(" PROTECTED ");
+               if ( c->flags & ACC_STATIC )       log_plain(" STATIC ");
+               if ( c->flags & ACC_FINAL )        log_plain(" FINAL ");
+               if ( c->flags & ACC_SYNCHRONIZED ) log_plain(" SYNCHRONIZED ");
+               if ( c->flags & ACC_VOLATILE )     log_plain(" VOLATILE ");
+               if ( c->flags & ACC_TRANSIENT )    log_plain(" TRANSIENT ");
+               if ( c->flags & ACC_NATIVE )       log_plain(" NATIVE ");
+               if ( c->flags & ACC_INTERFACE )    log_plain(" INTERFACE ");
+               if ( c->flags & ACC_ABSTRACT )     log_plain(" ABSTRACT ");
+
+               log_plain(from); 
+                log_plain(" : WARNING: Method not found");log_nl( );
+        }
+
+        return mi;
+}
+
+
 /************************* Function: class_findmethod_approx ******************
        
        like class_findmethod but ignores the return value when comparing the
 /************************* Function: class_findmethod_approx ******************
        
        like class_findmethod but ignores the return value when comparing the
@@ -2390,22 +3498,170 @@ methodinfo *class_resolvemethod_approx(classinfo *c, utf *name, utf *desc)
 }
 
 
 }
 
 
-/************************* Function: class_resolvemethod ***********************
+/************************* Function: class_resolvemethod ***********************
+       
+       Searches a class and every super class for a method.
+
+*******************************************************************************/
+
+methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc)
+{
+       /*log_text("Trying to resolve a method");
+       utf_display(c->name);
+       utf_display(name);
+       utf_display(desc);*/
+
+       while (c) {
+               /*log_text("Looking in:");
+               utf_display(c->name);*/
+               methodinfo *m = class_findmethod(c, name, desc);
+               if (m) return m;
+               /* search superclass */
+               c = c->super;
+       }
+       /*log_text("method not found:");*/
+
+       return NULL;
+}
+
+
+/****************** Function: class_resolveinterfacemethod_int ****************
+
+    Internally used helper function. Do not use this directly.
+
+*******************************************************************************/
+
+static
+methodinfo *class_resolveinterfacemethod_int(classinfo *c, utf *name, utf *desc)
+{
+       methodinfo *mi;
+       int i;
+       
+       mi = class_findmethod(c,name,desc);
+       if (mi)
+               return mi;
+
+       /* try the superinterfaces */
+       for (i=0; i<c->interfacescount; ++i) {
+               mi = class_resolveinterfacemethod_int(c->interfaces[i],name,desc);
+               if (mi)
+                       return mi;
+       }
+       
+       return NULL;
+}
+
+/******************** Function: class_resolveinterfacemethod ******************
+
+    Resolves a reference from REFERER to a method with NAME and DESC in
+    interface C.
+
+    If the method cannot be resolved the return value is NULL. If EXCEPT is
+    true *exceptionptr is set, too.
+
+*******************************************************************************/
+
+methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc,
+                                                                                classinfo *referer, bool except)
+{
+       methodinfo *mi;
+
+       /* XXX resolve class c */
+       /* XXX check access from REFERER to C */
+       
+       if (!(c->flags & ACC_INTERFACE)) {
+               if (except)
+                       *exceptionptr =
+                               new_exception(string_java_lang_IncompatibleClassChangeError);
+
+               return NULL;
+       }
+
+       mi = class_resolveinterfacemethod_int(c, name, desc);
+
+       if (mi)
+               return mi;
+
+       /* try class java.lang.Object */
+       mi = class_findmethod(class_java_lang_Object, name, desc);
+
+       if (mi)
+               return mi;
+
+       if (except)
+               *exceptionptr =
+                       new_exception_utfmessage(string_java_lang_NoSuchMethodError, name);
+
+       return NULL;
+}
+
+
+/********************* Function: class_resolveclassmethod *********************
        
        
-       Searches a class and every super class for a method.
+    Resolves a reference from REFERER to a method with NAME and DESC in
+    class C.
+
+    If the method cannot be resolved the return value is NULL. If EXCEPT is
+    true *exceptionptr is set, too.
 
 *******************************************************************************/
 
 
 *******************************************************************************/
 
-methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc)
+methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc,
+                                                                        classinfo *referer, bool except)
 {
 {
-       while (c) {
-               methodinfo *m = class_findmethod(c, name, desc);
-               if (m) return m;
-               /* search superclass */
-               c = c->super;
+       classinfo *cls;
+       methodinfo *mi;
+       s4 i;
+       char msg[MAXLOGTEXT];
+
+       /* XXX resolve class c */
+       /* XXX check access from REFERER to C */
+       
+/*     if (c->flags & ACC_INTERFACE) { */
+/*             if (except) */
+/*                     *exceptionptr = */
+/*                             new_exception(string_java_lang_IncompatibleClassChangeError); */
+/*             return NULL; */
+/*     } */
+
+       /* try class c and its superclasses */
+       cls = c;
+       do {
+               mi = class_findmethod(cls, name, desc);
+               if (mi)
+                       goto found;
+       } while ((cls = cls->super) != NULL); /* try the superclass */
+
+       /* try the superinterfaces */
+       for (i = 0; i < c->interfacescount; ++i) {
+               mi = class_resolveinterfacemethod_int(c->interfaces[i], name, desc);
+               if (mi)
+                       goto found;
+       }
+       
+       if (except) {
+               utf_sprint(msg, c->name);
+               sprintf(msg + strlen(msg), ".");
+               utf_sprint(msg + strlen(msg), name);
+               utf_sprint(msg + strlen(msg), desc);
+
+               *exceptionptr =
+                       new_exception_message(string_java_lang_NoSuchMethodError, msg);
        }
 
        return NULL;
        }
 
        return NULL;
+
+ found:
+       if ((mi->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) {
+               if (except)
+                       *exceptionptr = new_exception(string_java_lang_AbstractMethodError);
+
+               return NULL;
+       }
+
+       /* XXX check access rights */
+
+       return mi;
 }
 
 
 }
 
 
@@ -2433,116 +3689,193 @@ bool class_issubclass(classinfo *sub, classinfo *super)
 
 *******************************************************************************/
 
 
 *******************************************************************************/
 
-void class_init(classinfo *c)
+static classinfo *class_init_intern(classinfo *c);
+
+classinfo *class_init(classinfo *c)
+{
+       classinfo *r;
+
+       if (!makeinitializations)
+               return c;
+
+#if defined(USE_THREADS)
+       /* enter a monitor on the class */
+
+       builtin_monitorenter((java_objectheader *) c);
+#endif
+
+       /* maybe the class is already initalized or the current thread, which can
+          pass the monitor, is currently initalizing this class */
+
+       /* JOWENN: In future we need an additinal flag: initializationfailed,
+               since further access to the class should cause a NoClassDefFound,
+               if the static initializer failed once
+        */
+
+       if (c->initialized || c->initializing) {
+#if defined(USE_THREADS)
+               builtin_monitorexit((java_objectheader *) c);
+#endif
+
+               return c;
+       }
+
+       /* this initalizing run begins NOW */
+       c->initializing = true;
+
+       /* call the internal function */
+       r = class_init_intern(c);
+
+       /* if return value is not NULL everything was ok and the class is
+          initialized */
+       if (r)
+               c->initialized = true;
+
+       /* this initalizing run is done */
+       c->initializing = false;
+
+#if defined(USE_THREADS)
+       /* leave the monitor */
+
+       builtin_monitorexit((java_objectheader *) c);
+#endif
+
+       return r;
+}
+
+
+/* this function MUST NOT be called directly, because of thread <clinit>
+   race conditions */
+
+static classinfo *class_init_intern(classinfo *c)
 {
        methodinfo *m;
        s4 i;
 {
        methodinfo *m;
        s4 i;
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        int b;
 #endif
 
        int b;
 #endif
 
-       if (!makeinitializations)
-               return;
-       if (c->initialized)
-               return;
+       /* maybe the class is not already loaded */
+       if (!c->loaded)
+               if (!class_load(c))
+                       return NULL;
 
 
-       c->initialized = true;
+       /* maybe the class is not already linked */
+       if (!c->linked)
+               if (!class_link(c))
+                       return NULL;
 
 
-#ifdef STATISTICS
-       count_class_inits++;
+#if defined(STATISTICS)
+       if (opt_stat)
+               count_class_inits++;
 #endif
 
 #endif
 
-       if (c->super)
-               class_init (c->super);
-       for (i = 0; i < c->interfacescount; i++)
-               class_init(c->interfaces[i]);  /* real */
+       /* initialize super class */
+
+       if (c->super) {
+               if (!c->super->initialized) {
+                       if (initverbose) {
+                               char logtext[MAXLOGTEXT];
+                               sprintf(logtext, "Initialize super class ");
+                               utf_sprint_classname(logtext + strlen(logtext), c->super->name);
+                               sprintf(logtext + strlen(logtext), " from ");
+                               utf_sprint_classname(logtext + strlen(logtext), c->name);
+                               log_text(logtext);
+                       }
+
+                       if (!class_init(c->super))
+                               return NULL;
+               }
+       }
+
+       /* initialize interface classes */
+
+       for (i = 0; i < c->interfacescount; i++) {
+               if (!c->interfaces[i]->initialized) {
+                       if (initverbose) {
+                               char logtext[MAXLOGTEXT];
+                               sprintf(logtext, "Initialize interface class ");
+                               utf_sprint_classname(logtext + strlen(logtext), c->interfaces[i]->name);
+                               sprintf(logtext + strlen(logtext), " from ");
+                               utf_sprint_classname(logtext + strlen(logtext), c->name);
+                               log_text(logtext);
+                       }
+                       
+                       if (!class_init(c->interfaces[i]))
+                               return NULL;
+               }
+       }
+
+       m = class_findmethod(c, utf_clinit, utf_void__void);
 
 
-       m = class_findmethod(c, utf_clinit, utf_fidesc);
        if (!m) {
                if (initverbose) {
                        char logtext[MAXLOGTEXT];
                        sprintf(logtext, "Class ");
        if (!m) {
                if (initverbose) {
                        char logtext[MAXLOGTEXT];
                        sprintf(logtext, "Class ");
-                       utf_sprint(logtext + strlen(logtext), c->name);
-                       sprintf(logtext + strlen(logtext), " has no initializer");
+                       utf_sprint_classname(logtext + strlen(logtext), c->name);
+                       sprintf(logtext + strlen(logtext), " has no static class initializer");
                        log_text(logtext);
                }
                        log_text(logtext);
                }
-               /*              goto callinitialize;*/
-               return;
+
+               return c;
        }
 
        }
 
-       if (!(m->flags & ACC_STATIC))
-               panic("Class initializer is not static!");
+       /* Sun's and IBM's JVM don't care about the static flag */
+/*     if (!(m->flags & ACC_STATIC)) { */
+/*             panic("Class initializer is not static!"); */
 
 
-       if (initverbose) {
-               char logtext[MAXLOGTEXT];
-               sprintf(logtext, "Starting initializer for class: ");
-               utf_sprint(logtext + strlen(logtext), c->name);
-               log_text(logtext);
-       }
+       if (initverbose)
+               log_message_class("Starting static class initializer for class: ", c);
 
 
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        b = blockInts;
        blockInts = 0;
 #endif
 
        b = blockInts;
        blockInts = 0;
 #endif
 
+       /* now call the initializer */
        asm_calljavafunction(m, NULL, NULL, NULL, NULL);
 
        asm_calljavafunction(m, NULL, NULL, NULL, NULL);
 
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        assert(blockInts == 0);
        blockInts = b;
 #endif
 
        assert(blockInts == 0);
        blockInts = b;
 #endif
 
-       if (exceptionptr) {
-               printf("#### Initializer of ");
-               utf_display(c->name);
-               printf(" has thrown: ");
-               utf_display(exceptionptr->vftbl->class->name);
-               printf("\n");
-               fflush(stdout);
-       }
-
-       if (initverbose) {
-               char logtext[MAXLOGTEXT];
-               sprintf(logtext, "Finished initializer for class: ");
-               utf_sprint(logtext + strlen(logtext), c->name);
-               log_text(logtext);
-       }
-       if (c->name == utf_systemclass) {
-               /* class java.lang.System requires explicit initialization */
-
-               if (initverbose)
-                       printf("#### Initializing class System");
+       /* we have an exception or error */
+       if (*exceptionptr) {
+               /* class is NOT initialized */
+               c->initialized = false;
 
 
-                /* find initializing method */
-               m = class_findmethod(c,
-                                                        utf_initsystemclass,
-                                                        utf_fidesc);
+               /* is this an exception, than wrap it */
+               if (builtin_instanceof(*exceptionptr, class_java_lang_Exception)) {
+                       java_objectheader *xptr;
+                       java_objectheader *cause;
 
 
-               if (!m) {
-                       /* no method found */
-                       /* printf("initializeSystemClass failed"); */
-                       return;
-               }
+                       /* get the cause */
+                       cause = *exceptionptr;
 
 
-#ifdef USE_THREADS
-               b = blockInts;
-               blockInts = 0;
-#endif
+                       /* clear exception, because we are calling jit code again */
+                       *exceptionptr = NULL;
 
 
-               asm_calljavafunction(m, NULL, NULL, NULL, NULL);
+                       /* wrap the exception */
+                       xptr =
+                               new_exception_throwable(string_java_lang_ExceptionInInitializerError,
+                                                                               (java_lang_Throwable *) cause);
 
 
-#ifdef USE_THREADS
-               assert(blockInts == 0);
-               blockInts = b;
-#endif
+                       /* XXX should we exit here? */
+                       if (*exceptionptr)
+                               throw_exception();
 
 
-               if (exceptionptr) {
-                       printf("#### initializeSystemClass has thrown: ");
-                       utf_display(exceptionptr->vftbl->class->name);
-                       printf("\n");
-                       fflush(stdout);
+                       /* set new exception */
+                       *exceptionptr = xptr;
                }
                }
+
+               return NULL;
        }
        }
+
+       if (initverbose)
+               log_message_class("Finished static class initializer for class: ", c);
+
+       return c;
 }
 
 
 }
 
 
@@ -2795,199 +4128,56 @@ void class_showmethods (classinfo *c)
 }
 
 
 }
 
 
-
 /******************************************************************************/
 /******************* General functions for the class loader *******************/
 /******************************************************************************/
 
 /******************************************************************************/
 /******************* General functions for the class loader *******************/
 /******************************************************************************/
 
-/********************* Function: loader_load ***********************************
-
-       Loads and links the class desired class and each class and interface
-       referenced by it.
-       Returns: a pointer to this class
-
-*******************************************************************************/
-
-static int loader_load_running = 0;
-
-classinfo *loader_load(utf *topname)
-{
-       classinfo *top;
-       classinfo *c;
-       s8 starttime = 0;
-       s8 stoptime = 0;
-       classinfo *notlinkable;
-       
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       pthread_mutex_lock(&compiler_mutex);
-#endif
-
-       /* avoid recursive calls */
-       if (loader_load_running)
-               return class_new(topname);
-
-       loader_load_running++;
-       
-       intsDisable();
-
-       if (getloadingtime)
-               starttime = getcputime();
-
-       top = class_new(topname);
-
-       /* load classes */
-       while ((c = list_first(&unloadedclasses))) {
-               if (!class_load(c)) {
-                       if (linkverbose)
-                               dolog("Failed to load class");
-                       list_remove(&unloadedclasses, c);
-                       top = NULL;
-               }
-       }
-
-       /* link classes */
-       if (linkverbose)
-               dolog("Linking...");
-
-       /* XXX added a hack to break infinite linking loops. A better
-        * linking algorithm would be nice. -Edwin */
-       notlinkable = NULL;
-       while ((c = list_first(&unlinkedclasses))) {
-               class_link(c);
-               if (!c->linked) {
-                       if (!notlinkable)
-                               notlinkable = c;
-                       else if (notlinkable == c) {
-                               /* We tried to link this class for the second time and
-                                * no other classes were linked in between, so we are
-                                * caught in a loop.
-                                */
-                               if (linkverbose)
-                                       dolog("Cannot resolve linking dependencies");
-                               top = NULL;
-                               if (!exceptionptr)
-                                       throw_linkageerror_message(c->name);
-                               break;
-                       }
-
-               } else
-                       notlinkable = NULL;
-       }
-       if (linkverbose)
-               dolog("Linking done.");
-
-       if (loader_inited)
-               loader_compute_subclasses();
-
-       /* measure time */
-       if (getloadingtime) {
-               stoptime = getcputime();
-               loadingtime += (stoptime - starttime);
-       }
-
-
-       loader_load_running--;
-       
-       /* check if a former loader_load call tried to load/link the class and 
-          failed. This is needed because the class didn't appear in the 
-          undloadclasses or unlinkedclasses list during this class. */
-       if (top) {
-               if (!top->loaded) {
-                       if (linkverbose) dolog("Failed to load class (former call)");
-                       throw_noclassdeffounderror_message(top->name);
-                       top = NULL;
-                       
-               } else if (!top->linked) {
-                       if (linkverbose)
-                               dolog("Failed to link class (former call)");
-                       throw_linkageerror_message(top->name);
-                       top = NULL;
-               }
-       }
-
-       intsRestore();
-       
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       pthread_mutex_unlock(&compiler_mutex);
-#endif
-
-       /* XXX DEBUG */ if (linkverbose && !top) dolog("returning NULL from loader_load");
-       
-       return top; 
-}
-
-/****************** Function: loader_load_sysclass ****************************
-
-       Loads and links the class desired class and each class and interface
-       referenced by it.
-
-    The pointer to the classinfo is stored in *top if top != NULL.
-    The pointer is also returned.
-
-    If the class could not be loaded the function aborts with an error.
-
-*******************************************************************************/
-
-classinfo *loader_load_sysclass(classinfo **top,utf *topname)
-{
-       classinfo *cls;
-
-       if ((cls = loader_load(topname)) == NULL) {
-               log_plain("Could not important system class: ");
-               log_plain_utf(topname);
-               log_nl();
-               panic("Could not load important system class");
-       }
-
-       if (top) *top = cls;
-
-       return cls;
-}
-
 /**************** function: create_primitive_classes ***************************
 
 /**************** function: create_primitive_classes ***************************
 
-       create classes representing primitive types 
-
-********************************************************************************/
+       create classes representing primitive types
 
 
+*******************************************************************************/
 
 
-void create_primitive_classes()
+static bool create_primitive_classes()
 {  
 {  
-       int i;
+       s4 i;
 
 
-       for (i=0;i<PRIMITIVETYPE_COUNT;i++) {
+       for (i = 0; i < PRIMITIVETYPE_COUNT; i++) {
                /* create primitive class */
                /* create primitive class */
-               classinfo *c = class_new ( utf_new_char(primitivetype_table[i].name) );
-                c -> classUsed = NOTUSED; /* not used initially CO-RT */               
-               c -> impldBy = NULL;
+               classinfo *c =
+                       class_new_intern(utf_new_char(primitivetype_table[i].name));
+               c->classUsed = NOTUSED; /* not used initially CO-RT */
+               c->impldBy = NULL;
                
                /* prevent loader from loading primitive class */
                
                /* prevent loader from loading primitive class */
-               list_remove (&unloadedclasses, c);
-               c->loaded=true;
-               /* add to unlinked classes */
-               list_addlast (&unlinkedclasses, c);             
-/*JOWENN primitive types don't have objects as super class             c -> super = class_java_lang_Object; */
-               class_link (c);
+               c->loaded = true;
+               if (!class_link(c))
+                       return false;
 
                primitivetype_table[i].class_primitive = c;
 
                /* create class for wrapping the primitive type */
 
                primitivetype_table[i].class_primitive = c;
 
                /* create class for wrapping the primitive type */
-               primitivetype_table[i].class_wrap =
-                       class_new( utf_new_char(primitivetype_table[i].wrapname) );
-                primitivetype_table[i].class_wrap -> classUsed = NOTUSED; /* not used initially CO-RT */
-               primitivetype_table[i].class_wrap  -> impldBy = NULL;
+               c = class_new_intern(utf_new_char(primitivetype_table[i].wrapname));
+               primitivetype_table[i].class_wrap = c;
+               primitivetype_table[i].class_wrap->classUsed = NOTUSED; /* not used initially CO-RT */
+               primitivetype_table[i].class_wrap->impldBy = NULL;
 
                /* create the primitive array class */
                if (primitivetype_table[i].arrayname) {
 
                /* create the primitive array class */
                if (primitivetype_table[i].arrayname) {
-                       c = class_new( utf_new_char(primitivetype_table[i].arrayname) );
+                       c = class_new_intern(utf_new_char(primitivetype_table[i].arrayname));
                        primitivetype_table[i].arrayclass = c;
                        primitivetype_table[i].arrayclass = c;
-                       c->loaded=true;
-                       if (!c->linked) class_link(c);
+                       c->loaded = true;
+                       if (!c->linked)
+                               if (!class_link(c))
+                                       return false;
                        primitivetype_table[i].arrayvftbl = c->vftbl;
                }
        }
                        primitivetype_table[i].arrayvftbl = c->vftbl;
                }
        }
+
+       return true;
 }
 
 }
 
+
 /**************** function: class_primitive_from_sig ***************************
 
        return the primitive class indicated by the given signature character
 /**************** function: class_primitive_from_sig ***************************
 
        return the primitive class indicated by the given signature character
@@ -3053,7 +4243,7 @@ classinfo *class_primitive_from_sig(char sig)
                             * CLASSLOAD_PANIC....abort execution with an error message
                    CLASSLOAD_NOPANIC..return NULL on error
 
                             * CLASSLOAD_PANIC....abort execution with an error message
                    CLASSLOAD_NOPANIC..return NULL on error
 
-********************************************************************************/
+*******************************************************************************/
 
 classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr,
                                                                 char **next, int mode)
 
 classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr,
                                                                 char **next, int mode)
@@ -3062,7 +4252,7 @@ classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr,
        bool error = false;
        utf *name;
 
        bool error = false;
        utf *name;
 
-       SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,error);
+       SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error);
 
        if (mode & CLASSLOAD_CHECKEND)
                error |= (utf_ptr != end_ptr);
 
        if (mode & CLASSLOAD_CHECKEND)
                error |= (utf_ptr != end_ptr);
@@ -3093,9 +4283,20 @@ classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr,
                          /* FALLTHROUGH! */
                  case '[':
                          if (mode & CLASSLOAD_SKIP) return class_java_lang_Object;
                          /* FALLTHROUGH! */
                  case '[':
                          if (mode & CLASSLOAD_SKIP) return class_java_lang_Object;
-                         name = utf_new(start,utf_ptr-start);
-                         return (mode & CLASSLOAD_LOAD)
-                                 ? loader_load(name) : class_new(name); /* XXX */
+                         name = utf_new(start, utf_ptr - start);
+                         if (opt_eager) {
+                                 classinfo *tc;
+
+                                 tc = class_new_intern(name);
+                                 class_load(tc);
+                                 list_addfirst(&unlinkedclasses, tc);
+
+                                 return tc;
+
+                         } else {
+                                 return (mode & CLASSLOAD_LOAD)
+                                         ? class_load(class_new(name)) : class_new(name); /* XXX handle errors */
+                         }
                }
        }
 
                }
        }
 
@@ -3104,7 +4305,7 @@ classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr,
                return NULL;
 
        log_plain("Invalid descriptor at beginning of '");
                return NULL;
 
        log_plain("Invalid descriptor at beginning of '");
-       log_plain_utf(utf_new(start, end_ptr-start));
+       log_plain_utf(utf_new(start, end_ptr - start));
        log_plain("'");
        log_nl();
                                                  
        log_plain("'");
        log_nl();
                                                  
@@ -3167,39 +4368,28 @@ static void create_pseudo_classes()
 {
     /* pseudo class for Arraystubs (extends java.lang.Object) */
     
 {
     /* pseudo class for Arraystubs (extends java.lang.Object) */
     
-    pseudo_class_Arraystub = class_new(utf_new_char("$ARRAYSTUB$"));
-    list_remove(&unloadedclasses, pseudo_class_Arraystub);
-
+       pseudo_class_Arraystub->loaded = true;
     pseudo_class_Arraystub->super = class_java_lang_Object;
     pseudo_class_Arraystub->interfacescount = 2;
     pseudo_class_Arraystub->interfaces = MNEW(classinfo*, 2);
     pseudo_class_Arraystub->interfaces[0] = class_java_lang_Cloneable;
     pseudo_class_Arraystub->interfaces[1] = class_java_io_Serializable;
 
     pseudo_class_Arraystub->super = class_java_lang_Object;
     pseudo_class_Arraystub->interfacescount = 2;
     pseudo_class_Arraystub->interfaces = MNEW(classinfo*, 2);
     pseudo_class_Arraystub->interfaces[0] = class_java_lang_Cloneable;
     pseudo_class_Arraystub->interfaces[1] = class_java_io_Serializable;
 
-    list_addlast(&unlinkedclasses, pseudo_class_Arraystub);
     class_link(pseudo_class_Arraystub);
 
        pseudo_class_Arraystub_vftbl = pseudo_class_Arraystub->vftbl;
 
     /* pseudo class representing the null type */
     
     class_link(pseudo_class_Arraystub);
 
        pseudo_class_Arraystub_vftbl = pseudo_class_Arraystub->vftbl;
 
     /* pseudo class representing the null type */
     
-    pseudo_class_Null = class_new(utf_new_char("$NULL$"));
-    list_remove(&unloadedclasses, pseudo_class_Null);
-
+       pseudo_class_Null->loaded = true;
     pseudo_class_Null->super = class_java_lang_Object;
     pseudo_class_Null->super = class_java_lang_Object;
-
-    list_addlast(&unlinkedclasses, pseudo_class_Null);
-    class_link(pseudo_class_Null);     
+       class_link(pseudo_class_Null);  
 
     /* pseudo class representing new uninitialized objects */
     
 
     /* pseudo class representing new uninitialized objects */
     
-    pseudo_class_New = class_new( utf_new_char("$NEW$") );
-    list_remove(&unloadedclasses,pseudo_class_New);
-
-    pseudo_class_New->super = class_java_lang_Object;
-
-    list_addlast(&unlinkedclasses,pseudo_class_New);
-    class_link(pseudo_class_New);      
+       pseudo_class_New->loaded = true;
+       pseudo_class_New->linked = true;
+       pseudo_class_New->super = class_java_lang_Object;
 }
 
 
 }
 
 
@@ -3210,67 +4400,42 @@ static void create_pseudo_classes()
 
 *******************************************************************************/
  
 
 *******************************************************************************/
  
-void loader_init(u1 * stackbottom)
+bool loader_init(u1 *stackbottom)
 {
 {
+       classpath_info *cpi;
+
+       /* reset interface index */
+
        interfaceindex = 0;
        
        interfaceindex = 0;
        
-       log_text("Entering loader_init");
-       
-       list_init (&unloadedclasses, OFFSET(classinfo, listnode) );
-       list_init (&unlinkedclasses, OFFSET(classinfo, listnode) );
-       list_init (&linkedclasses, OFFSET(classinfo, listnode) );
-
-       /* create utf-symbols for pointer comparison of frequently used strings */
-       utf_innerclasses    = utf_new_char("InnerClasses");
-       utf_constantvalue   = utf_new_char("ConstantValue");
-       utf_code                = utf_new_char("Code");
-       utf_finalize        = utf_new_char("finalize");
-       utf_fidesc              = utf_new_char("()V");
-       utf_clinit              = utf_new_char("<clinit>");
-       utf_initsystemclass = utf_new_char("initializeSystemClass");
-       utf_systemclass     = utf_new_char("java/lang/System");
-       utf_vmclassloader   = utf_new_char("java/lang/VMClassLoader");
-       utf_initialize      = utf_new_char("initialize");
-       utf_initializedesc  = utf_new_char("(I)V");
-
-       utf_vmclass         = utf_new_char("java/lang/VMClass");
-
-       /* create some important classes */
-       /* These classes have to be created now because the classinfo
-        * pointers are used in the loading code.
-        */
-       class_java_lang_Object = class_new(utf_new_char("java/lang/Object"));
-       class_java_lang_String = class_new(utf_new_char("java/lang/String"));
-       class_java_lang_Cloneable = class_new(utf_new_char("java/lang/Cloneable"));
-       class_java_io_Serializable = class_new(utf_new_char("java/io/Serializable"));
-
-       log_text("loader_init: java/lang/Object");
-       /* load the classes which were created above */
-       loader_load_sysclass(NULL, class_java_lang_Object->name);
-
-       loader_inited = 1; /*JOWENN*/
-
-       loader_load_sysclass(&class_java_lang_Throwable,
-                                                utf_new_char("java/lang/Throwable"));
-
-       log_text("loader_init:  loader_load: java/lang/ClassCastException");
-       loader_load_sysclass(&class_java_lang_ClassCastException,
-                                                utf_new_char ("java/lang/ClassCastException"));
-       loader_load_sysclass(&class_java_lang_NullPointerException,
-                                                utf_new_char ("java/lang/NullPointerException"));
-       loader_load_sysclass(&class_java_lang_ArrayIndexOutOfBoundsException,
-                                                utf_new_char ("java/lang/ArrayIndexOutOfBoundsException"));
-       loader_load_sysclass(&class_java_lang_NegativeArraySizeException,
-                                                utf_new_char ("java/lang/NegativeArraySizeException"));
-       loader_load_sysclass(&class_java_lang_OutOfMemoryError,
-                                                utf_new_char ("java/lang/OutOfMemoryError"));
-       loader_load_sysclass(&class_java_lang_ArrayStoreException,
-                                                utf_new_char ("java/lang/ArrayStoreException"));
-       loader_load_sysclass(&class_java_lang_ArithmeticException,
-                                                utf_new_char ("java/lang/ArithmeticException"));
-       loader_load_sysclass(&class_java_lang_ThreadDeath,
-                                                utf_new_char ("java/lang/ThreadDeath"));
-               
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+       /* Initialize the monitor pointer for zip/jar file locking.               */
+
+       for (cpi = classpath_entries; cpi != NULL; cpi = cpi->next) {
+               if (cpi->type == CLASSPATH_ARCHIVE) 
+                       initObjectLock(&cpi->header);
+       }
+#endif
+
+       /* Create some important classes. These classes have to be created now    */
+       /* because the classinfo pointers are used in the loading code.           */
+
+       if (!class_load(class_java_lang_Object) ||
+               !class_link(class_java_lang_Object))
+               return false;
+
+       if (!class_load(class_java_lang_String) ||
+               !class_link(class_java_lang_String))
+               return false;
+
+       if (!class_load(class_java_lang_Cloneable) ||
+               !class_link(class_java_lang_Cloneable))
+               return false;
+
+       if (!class_load(class_java_io_Serializable) ||
+               !class_link(class_java_io_Serializable))
+               return false;
+
        /* create classes representing primitive types */
        create_primitive_classes();
 
        /* create classes representing primitive types */
        create_primitive_classes();
 
@@ -3280,83 +4445,69 @@ void loader_init(u1 * stackbottom)
        /* correct vftbl-entries (retarded loading of class java/lang/String) */
        stringtable_update();
 
        /* correct vftbl-entries (retarded loading of class java/lang/String) */
        stringtable_update();
 
-#ifdef USE_THREADS
-       if (stackbottom!=0)
+#if defined(USE_THREADS)
+       if (stackbottom != 0)
                initLocks();
 #endif
 
                initLocks();
 #endif
 
-       log_text("loader_init: creating global proto_java_lang_ClassCastException");
-       proto_java_lang_ClassCastException =
-               builtin_new(class_java_lang_ClassCastException);
-/*     heap_addreference((void**) &proto_java_lang_ClassCastException); */
-
-       log_text("loader_init: proto_java_lang_ClassCastException has been initialized");
+       return true;
+}
 
 
-       proto_java_lang_NullPointerException =
-               builtin_new(class_java_lang_NullPointerException);
-/*     heap_addreference((void**) &proto_java_lang_NullPointerException); */
-       log_text("loader_init: proto_java_lang_NullPointerException has been initialized");
 
 
-       proto_java_lang_ArrayIndexOutOfBoundsException =
-               builtin_new(class_java_lang_ArrayIndexOutOfBoundsException);
-/*     heap_addreference((void**) &proto_java_lang_ArrayIndexOutOfBoundsException); */
+/* loader_compute_subclasses ***************************************************
 
 
-       proto_java_lang_NegativeArraySizeException =
-               builtin_new(class_java_lang_NegativeArraySizeException);
-/*     heap_addreference((void**) &proto_java_lang_NegativeArraySizeException); */
+   XXX
 
 
-       proto_java_lang_OutOfMemoryError =
-               builtin_new(class_java_lang_OutOfMemoryError);
-/*     heap_addreference((void**) &proto_java_lang_OutOfMemoryError); */
+*******************************************************************************/
 
 
-       proto_java_lang_ArithmeticException =
-               builtin_new(class_java_lang_ArithmeticException);
-/*     heap_addreference((void**) &proto_java_lang_ArithmeticException); */
+static void loader_compute_class_values(classinfo *c);
 
 
-       proto_java_lang_ArrayStoreException =
-               builtin_new(class_java_lang_ArrayStoreException);
-/*     heap_addreference((void**) &proto_java_lang_ArrayStoreException); */
+void loader_compute_subclasses(classinfo *c)
+{
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+       compiler_lock();
+#else
+       intsDisable();
+#endif
+#endif
 
 
-       proto_java_lang_ThreadDeath =                             /* schani */
-               builtin_new(class_java_lang_ThreadDeath);
-/*     heap_addreference((void**) &proto_java_lang_ThreadDeath); */
+       if (!(c->flags & ACC_INTERFACE)) {
+               c->nextsub = 0;
+               c->sub = 0;
+       }
 
 
-       loader_inited = 1;
-}
+       if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) {
+               c->nextsub = c->super->sub;
+               c->super->sub = c;
+       }
 
 
+       classvalue = 0;
 
 
-/********************* Function: loader_initclasses ****************************
+       /* this is the java.lang.Object special case */
 
 
-       Initializes all loaded but uninitialized classes
+       if (!class_java_lang_Object) {
+               loader_compute_class_values(c);
 
 
-*******************************************************************************/
+       } else {
+               loader_compute_class_values(class_java_lang_Object);
+       }
 
 
-void loader_initclasses ()
-{
-       classinfo *c;
-       
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       pthread_mutex_lock(&compiler_mutex);
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+       compiler_unlock();
+#else
+       intsRestore();
+#endif
 #endif
 #endif
+}
 
 
-       intsDisable();                     /* schani */
 
 
-       if (makeinitializations) {
-               c = list_first (&linkedclasses);
-               while (c) {
-                       class_init (c);
-                       c = list_next (&linkedclasses, c);
-                       }
-               }
+/* loader_compute_class_values *************************************************
 
 
-       intsRestore();                      /* schani */
-       
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       pthread_mutex_unlock(&compiler_mutex);
-#endif
-}
+   XXX
 
 
-static s4 classvalue;
+*******************************************************************************/
 
 static void loader_compute_class_values(classinfo *c)
 {
 
 static void loader_compute_class_values(classinfo *c)
 {
@@ -3365,73 +4516,12 @@ static void loader_compute_class_values(classinfo *c)
        c->vftbl->baseval = ++classvalue;
 
        subs = c->sub;
        c->vftbl->baseval = ++classvalue;
 
        subs = c->sub;
-       while (subs != NULL) {
+       while (subs) {
                loader_compute_class_values(subs);
                subs = subs->nextsub;
        }
                loader_compute_class_values(subs);
                subs = subs->nextsub;
        }
-       c->vftbl->diffval = classvalue - c->vftbl->baseval;
-       
-       /*
-       {
-       int i;
-       for (i = 0; i < c->index; i++)
-               printf(" ");
-       printf("%3d  %3d  ", (int) c->vftbl->baseval, c->vftbl->diffval);
-       utf_display(c->name);
-       printf("\n");
-       }
-       */
-}
-
-
-void loader_compute_subclasses()
-{
-       classinfo *c;
-       
-       intsDisable();                     /* schani */
-
-       c = list_first(&linkedclasses);
-       while (c) {
-               if (!(c->flags & ACC_INTERFACE)) {
-                       c->nextsub = 0;
-                       c->sub = 0;
-               }
-               c = list_next (&linkedclasses, c);
-       }
-
-       c = list_first (&linkedclasses);
-       while (c) {
-               if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) {
-                       c->nextsub = c->super->sub;
-                       c->super->sub = c;
-               }
-               c = list_next (&linkedclasses, c);
-       }
-
-       classvalue = 0;
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       cast_lock();
-#endif
-       loader_compute_class_values(class_java_lang_Object);
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       cast_unlock();
-#endif
-
-       intsRestore();                      /* schani */
-}
-
-
-/******************** function classloader_buffer ******************************
-    sets buffer for reading classdata
-
-*******************************************************************************/
 
 
-void classload_buffer(u1 *buf, int len)
-{
-       classbuffer      = buf;
-       classbuffer_size = len;
-       classbuf_pos     = buf - 1;
+       c->vftbl->diffval = classvalue - c->vftbl->baseval;
 }
 
 
 }
 
 
@@ -3444,18 +4534,15 @@ void classload_buffer(u1 *buf, int len)
 void loader_close()
 {
        classinfo *c;
 void loader_close()
 {
        classinfo *c;
+       s4 slot;
 
 
-       while ((c = list_first(&unloadedclasses))) {
-               list_remove(&unloadedclasses, c);
-               class_free(c);
-       }
-       while ((c = list_first(&unlinkedclasses))) {
-               list_remove(&unlinkedclasses, c);
-               class_free(c);
-       }
-       while ((c = list_first(&linkedclasses))) {
-               list_remove(&linkedclasses, c);
-               class_free(c);
+       for (slot = 0; slot < class_hash.size; slot++) {
+               c = class_hash.ptr[slot];
+
+               while (c) {
+                       class_free(c);
+                       c = c->hashlink;
+               }
        }
 }
 
        }
 }