- removed unused exception class_ declarations
[cacao.git] / loader.c
index a427ad559810b4524a63d85cfd229fd1289d408d..98d0fc92b48c4a42b33380f26d2334418b7abcfc 100644 (file)
--- a/loader.c
+++ b/loader.c
@@ -30,7 +30,7 @@
             Mark Probst
                        Edwin Steiner
 
-   $Id: loader.c 867 2004-01-07 22:05:04Z edwin $
+   $Id: loader.c 991 2004-03-29 11:22:34Z stefan $
 
 */
 
@@ -51,7 +51,7 @@
 #include "toolbox/loging.h"
 #include "threads/thread.h"
 #include "threads/locks.h"
-#include <sys/stat.h>
+#include "nat/java_lang_Throwable.h"
 
 #ifdef USE_ZLIB
 #include "unzip.h"
@@ -85,6 +85,9 @@ list linkedclasses;         /* list of all completely linked classes          */
 static utf *utf_innerclasses;          /* InnerClasses            */
 static utf *utf_constantvalue;                 /* ConstantValue           */
 static utf *utf_code;                      /* Code                    */
+static utf *utf_exceptions;            /* Exceptions                    */
+static utf *utf_linenumbertable;               /* LineNumberTable                    */
+static utf *utf_sourcefile;            /*SourceFile*/
 static utf *utf_finalize;                  /* finalize                */
 static utf *utf_fidesc;                    /* ()V changed             */
 static utf *utf_init;                          /* <init>                  */
@@ -135,6 +138,8 @@ static classinfo *class_java_lang_ArithmeticException;
 static classinfo *class_java_lang_ArrayStoreException;
 static classinfo *class_java_lang_ThreadDeath;
 
+utf *array_packagename = NULL;
+
 static int loader_inited = 0;
 
 
@@ -212,21 +217,31 @@ static int classbuffer_size;        /* size of classfile-data                 */
        do {ASSERT_LEFT(len);                                           \
                classbuf_pos+=len;} while(0)
 
+
 inline u1 suck_u1()
 {
        ASSERT_LEFT(1);
        return *++classbuf_pos;
 }
+
+
 inline u2 suck_u2()
 {
-       u1 a=suck_u1(), b=suck_u1();
-       return ((u2)a<<8)+(u2)b;
+       u1 a = suck_u1();
+       u1 b = suck_u1();
+       return ((u2) a << 8) + (u2) b;
 }
+
+
 inline u4 suck_u4()
 {
-       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();
+       u1 b = suck_u1();
+       u1 c = suck_u1();
+       u1 d = suck_u1();
+       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()
@@ -682,7 +697,10 @@ static void attribute_load(u4 num, classinfo *c)
                                info->name  = innerclass_getconstant(c, suck_u2(), CONSTANT_Utf8);        /* CONSTANT_Utf8_info index  */
                                info->flags = suck_u2();                                                  /* access_flags bitmask      */
                        }
-
+               } else if (aname==utf_sourcefile) {
+                       suck_u4();
+                       /*log_text("source file attribute found");*/
+                       c->sourcefile = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
                } else {
                        /* unknown attribute */
                        skipattributebody();
@@ -744,10 +762,13 @@ 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.
+
+    The number of arguments is returned. A long or double argument is counted
+    as two arguments.
        
 *******************************************************************************/
 
-static void checkmethoddescriptor (utf *d)
+static int checkmethoddescriptor (utf *d)
 {
        char *utf_ptr = d->text;     /* current position in utf text   */
        char *end_pos = utf_end(d);  /* points behind utf string       */
@@ -758,12 +779,12 @@ static void checkmethoddescriptor (utf *d)
 
     /* check arguments */
     while (utf_ptr != end_pos && *utf_ptr != ')') {
-               /* XXX we cannot count the this argument here because
+               /* 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++;
-               if (++argcount > 255)
-                       panic("Invalid method descriptor: too many arguments");
                class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
                                                          CLASSLOAD_NEW
                                                          | CLASSLOAD_NULLPRIMITIVE
@@ -778,9 +799,13 @@ static void checkmethoddescriptor (utf *d)
                                                  | CLASSLOAD_NULLPRIMITIVE
                                                  | CLASSLOAD_CHECKEND);
 
+       if (argcount > 255)
+               panic("Invalid method descriptor: too many arguments");
+
+       return argcount;
+
        /* XXX use the following if -noverify */
 #if 0
-       /* XXX check length */
        /* check arguments */
        while ((c = *utf_ptr++) != ')') {
                start = utf_ptr-1;
@@ -881,13 +906,13 @@ static void field_load(fieldinfo *f, classinfo *c)
        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;
-       f->xta = NULL;
        
-       /* check flag consistency */
        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)
                        panic("Field has invalid access flags");
@@ -897,9 +922,19 @@ static void field_load(fieldinfo *f, classinfo *c)
                        if ((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
                                != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
                                panic("Interface field is not declared static final public");
+                       if ((f->flags & ACC_TRANSIENT) != 0)
+                               panic("Interface field declared transient");
                }
+
+               /* 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) {
        case TYPE_INT:        f->value.i = 0; break;
        case TYPE_FLOAT:      f->value.f = 0.0; break;
@@ -1021,21 +1056,37 @@ void field_display(fieldinfo *f)
 static void method_load(methodinfo *m, classinfo *c)
 {
        u4 attrnum, i, e;
+       int argcount;
        
 #ifdef STATISTICS
        count_all_methods++;
 #endif
-
+       m->thrownexceptionscount=0;
+       m->linenumbercount=0;
+       m->linenumbers=0;
        m->class = c;
        
        m->flags = suck_u2();
        m->name = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
+
+       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");
+       }
+       
        m->descriptor = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
-       checkmethoddescriptor(m->descriptor);   
+       argcount = checkmethoddescriptor(m->descriptor);
+       if ((m->flags & ACC_STATIC) == 0)
+               argcount++; /* count the 'this' argument */
 
-       /* check flag consistency */
        if (opt_verify) {
-               /* XXX could check if <clinit> is STATIC */
+               if (argcount > 255)
+                       panic("Method has more than 255 arguments");
+
+               /* 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)
@@ -1089,6 +1140,18 @@ static void method_load(methodinfo *m, classinfo *c)
                aname = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
 
                if (aname != utf_code) {
+                       if (aname == utf_exceptions) {
+                               u2 exceptionCount;
+                               u2 exceptionID;
+                               suck_u4(); /*length*/
+                               exceptionCount=suck_u2();
+                               m->thrownexceptionscount=exceptionCount;
+                               m->thrownexceptions=MNEW(classinfo*,exceptionCount);
+                               for (exceptionID=0;exceptionID<exceptionCount;exceptionID++) {
+                                       (m->thrownexceptions)[exceptionID]=class_getconstant(c,suck_u2(),CONSTANT_Class);
+                               }
+                       }
+                       else
                        skipattributebody();
 
                } else {
@@ -1102,6 +1165,9 @@ static void method_load(methodinfo *m, classinfo *c)
                        suck_u4();
                        m->maxstack = suck_u2();
                        m->maxlocals = suck_u2();
+                       if (m->maxlocals < argcount)
+                               panic("max_locals is smaller than the number of arguments");
+                       
                        codelen = suck_u4();
                        if (codelen == 0)
                                panic("bytecode has zero length");
@@ -1134,8 +1200,28 @@ static void method_load(methodinfo *m, classinfo *c)
                                      class_getconstant(c, idx, CONSTANT_Class);
                                }
                        }                       
-
-                       skipattributes(suck_u2());
+                       {
+                               u2 codeattrnum;
+                               for (codeattrnum=suck_u2();codeattrnum>0;codeattrnum--) {
+                                       utf * caname = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
+                                       if (caname==utf_linenumbertable) {
+                                               u2 lncid;
+                                               /*log_text("LineNumberTable found");*/
+                                               suck_u4();
+                                               m->linenumbercount=suck_u2();
+                                               /*printf("length:%d\n",m->linenumbercount);*/
+                                               m->linenumbers=MNEW(lineinfo,m->linenumbercount);
+                                               for (lncid=0;lncid<m->linenumbercount;lncid++) {
+                                                       m->linenumbers[lncid].start_pc=suck_u2();
+                                                       m->linenumbers[lncid].line_number=suck_u2();
+                                               }
+                                               codeattrnum--;
+                                               skipattributes(codeattrnum);
+                                               break;
+                                       } else skipattributebody();
+                                       
+                               }                               
+                       }
                }
        }
 
@@ -1185,6 +1271,19 @@ void method_display(methodinfo *m)
        printf("\n");
 }
 
+/************** Function: method_display_flags_last  (debugging only) **************/
+
+void method_display_flags_last(methodinfo *m)
+{
+        printf(" ");
+        utf_display(m->name);
+        printf(" ");
+        utf_display(m->descriptor);
+        printf("   ");
+        printflags(m->flags);
+        printf("\n");
+}
+
 
 /******************** Function: method_canoverwrite ****************************
 
@@ -1193,7 +1292,7 @@ void method_display(methodinfo *m)
        
 *******************************************************************************/  
 
-static bool method_canoverwrite (methodinfo *m, methodinfo *old)
+static bool method_canoverwrite(methodinfo *m, methodinfo *old)
 {
        if (m->name != old->name) return false;
        if (m->descriptor != old->descriptor) return false;
@@ -1308,10 +1407,11 @@ static void class_loadcpool(classinfo *c)
        forward_fieldmethint *forward_fieldmethints = NULL;
 
        /* number of entries in the constant_pool table plus one */
-       u4 cpcount       = c -> cpcount = suck_u2();
+       u4 cpcount       = c->cpcount = suck_u2();
+
        /* allocate memory */
-       u1 *cptags       = c -> cptags  = MNEW (u1, cpcount);
-       voidptr *cpinfos = c -> cpinfos = MNEW (voidptr, cpcount);
+       u1 *cptags       = c->cptags  = MNEW(u1, cpcount);
+       voidptr *cpinfos = c->cpinfos = MNEW(voidptr, cpcount);
 
        if (!cpcount)
                panic("Invalid constant_pool_count (0)");
@@ -1321,22 +1421,22 @@ static void class_loadcpool(classinfo *c)
 #endif
        
        /* initialize constantpool */
-       for (idx=0; idx<cpcount; idx++) {
+       for (idx = 0; idx < cpcount; idx++) {
                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) {
                /* get constant type */
-               u4 t = suck_u1 (); 
-               switch ( t ) {
+               u4 t = suck_u1();
 
+               switch (t) {
                        case CONSTANT_Class: { 
                                forward_class *nfc = DNEW(forward_class);
 
@@ -1372,14 +1472,14 @@ static void class_loadcpool(classinfo *c)
                                }
                                
                        case CONSTANT_String: {
-                               forward_string *nfs = DNEW (forward_string);
+                               forward_string *nfs = DNEW(forward_string);
                                
-                               nfs -> next = forward_strings;
+                               nfs->next = forward_strings;
                                forward_strings = nfs;
                                
-                               nfs -> thisindex = idx;
+                               nfs->thisindex = idx;
                                /* reference to CONSTANT_Utf8_info with string characters */
-                               nfs -> string_index = suck_u2 ();
+                               nfs->string_index = suck_u2();
                                
                                idx ++;
                                break;
@@ -1471,7 +1571,10 @@ static void class_loadcpool(classinfo *c)
                                ASSERT_LEFT(length);
                                if (opt_verify &&
                                        !is_valid_utf(classbuf_pos+1, classbuf_pos+1+length))
-                                       panic("Invalid UTF-8 string"); 
+                               {
+                                       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(classbuf_pos+1, length);
                                /* skip bytes of the string */
@@ -1495,6 +1598,9 @@ static void class_loadcpool(classinfo *c)
                utf *name =
                  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;
                /* retrieve class from class-table */
                cpinfos [forward_classes -> thisindex] = class_new (name);
@@ -1530,7 +1636,16 @@ static void class_loadcpool(classinfo *c)
                   (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))
+                               panic("NameAndType with invalid name");
+                       /* disallow referencing <clinit> among others */
+                       if (cn->name->text[0] == '<' && cn->name != utf_init)
+                               panic("NameAndType with invalid special name");
+               }
+
                cptags   [forward_nameandtypes -> thisindex] = CONSTANT_NameAndType;
                cpinfos  [forward_nameandtypes -> thisindex] = cn;
                
@@ -1578,7 +1693,6 @@ static void class_loadcpool(classinfo *c)
                                         break;
                case CONSTANT_InterfaceMethodref: 
                case CONSTANT_Methodref: /* check validity of descriptor */
-                       /* XXX check special names (<init>) */
                                         checkmethoddescriptor (fmi->descriptor);
                                         break;
                }               
@@ -1587,9 +1701,9 @@ static void class_loadcpool(classinfo *c)
 
                }
 
-/*     class_showconstantpool(c); */
+/*     class_showconstantpool(c); */
 
-       dump_release (dumpsize);
+       dump_release(dumpsize);
 }
 
 
@@ -1630,14 +1744,18 @@ static int class_load(classinfo *c)
                return false;
        }
        
-       /* check signature */           
-       if (suck_u4() != MAGIC) panic("Can not find class-file signature");     
+       /* check signature */
+       if (suck_u4() != MAGIC)
+               panic("Can not find class-file signature");
+
        /* check version */
-       mi = suck_u2(); 
+       mi = suck_u2();
        ma = suck_u2();
+#if 0
        if (ma != MAJOR_VERSION && (ma != MAJOR_VERSION+1 || mi != 0)) {
                error("File version %d.%d is not supported", (int) ma, (int) mi);
        }
+#endif
 
        class_loadcpool(c);
        /*JOWENN*/
@@ -1653,16 +1771,35 @@ static int class_load(classinfo *c)
 
        /* check ACC flags consistency */
        if ((c->flags & ACC_INTERFACE) != 0) {
-               if ((c->flags & ACC_ABSTRACT) == 0)
-                       panic("Interface class not declared abstract");
-               if ((c->flags & (ACC_FINAL | ACC_SUPER)) != 0)
+               if ((c->flags & ACC_ABSTRACT) == 0) {
+                       /* 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)) != 0)
                        panic("Interface class has invalid flags");
+               if ((c->flags & (ACC_SUPER)) != 0)
+                       c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */
        }
+       if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL))
+               panic("Class is declared both abstract and final");
 
        /* this class */
        i = suck_u2();
-       if (class_getconstant(c, i, CONSTANT_Class) != c)
+       if (class_getconstant(c, i, CONSTANT_Class) != c) {
+/*             char message[MAXLOGTEXT]; */
+/*             utf_sprint(message, c->name); */
+/*             sprintf(message + strlen(message), " (wrong name: "); */
+/*             utf_sprint(message + strlen(message), class_getconstant(c, i, CONSTANT_Class)); */
+/*             sprintf(message + strlen(message), ")"); */
+
+/*             *exceptionptr = new_exception_message("java/lang/NoClassDefFoundError", */
+/*                                                                                       message); */
+/*             return false; */
                panic("Invalid this_class in class file");
+       }
        
        /* retrieve superclass */
        if ((i = suck_u2())) {
@@ -1690,7 +1827,7 @@ static int class_load(classinfo *c)
        c->interfacescount = suck_u2();
        c->interfaces = MNEW(classinfo*, c->interfacescount);
        for (i = 0; i < c->interfacescount; i++) {
-               c->interfaces [i] = 
+               c->interfaces[i] =
                        class_getconstant(c, suck_u2(), CONSTANT_Class);
        }
 
@@ -1711,6 +1848,91 @@ static int class_load(classinfo *c)
                method_load(&(c->methods[i]), c);
        }
 
+       /* 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]) != 0) {
+                               old--;
+                               /* dolog("HASHHIT %d --> %d",index,old); */
+                               next[i] = old;
+                               do {
+                                       /* dolog("HASHCHECK %d",old); */
+                                       if (c->fields[old].name == fi->name
+                                               && c->fields[old].descriptor == fi->descriptor)
+                                       {
+                                               dolog("Duplicate field (%d,%d):",i,old);
+                                               log_utf(fi->name); log_utf(fi->descriptor);
+                                               panic("Fields with same name and descriptor");
+                                       }
+                               } while ((old = next[old]) != 0);
+                       }
+                       /* else dolog("HASHLUCKY"); */
+                       hashtab[index] = i+1;
+               }
+               
+               /* Check methods */
+               memset(hashtab,0,sizeof(u2) * (hashlen + len));
+               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;
+                       if ((old = hashtab[index]) != 0) {
+                               old--;
+                               /* dolog("HASHHIT %d --> %d",index,old); */
+                               next[i] = old;
+                               do {
+                                       /* dolog("HASHCHECK %d",old); */
+                                       if (c->methods[old].name == mi->name
+                                               && c->methods[old].descriptor == mi->descriptor)
+                                       {
+                                               dolog("Duplicate method (%d,%d):",i,old);
+                                               log_utf(mi->name); log_utf(mi->descriptor);
+                                               panic("Methods with same name and descriptor");
+                                       }
+                               } while ((old = next[old]) != 0);
+                       }
+                       /* else dolog("HASHLUCKY"); */
+                       hashtab[index] = i+1;
+               }
+               
+               MFREE(hashtab,u2,(hashlen + len));
+       }
+
 #ifdef STATISTICS
        count_class_infos += sizeof(classinfo*) * c->interfacescount;
        count_class_infos += sizeof(fieldinfo) * c->fieldscount;
@@ -1830,7 +2052,7 @@ void class_new_array(classinfo *c)
        methodinfo *clone;
        int namelen;
 
-       /* XXX remove */ /* dolog("class_new_array: %s",c->name->text); */
+       /* DEBUG */ /* dolog("class_new_array: %s",c->name->text); */
 
        /* Array classes are not loaded from classfiles. */
        list_remove(&unloadedclasses, c);
@@ -1860,21 +2082,21 @@ void class_new_array(classinfo *c)
        c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
 
     c->interfacescount = 2;
-    c->interfaces = MNEW(classinfo*,2); /* XXX use GC? */
+    c->interfaces = MNEW(classinfo*,2);
     c->interfaces[0] = class_java_lang_Cloneable;
     c->interfaces[1] = class_java_io_Serializable;
 
        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->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->monoPoly = MONO; /* XXX should be poly? */
+       clone->monoPoly = MONO;
 
        /* XXX: field: length? */
 
@@ -2052,13 +2274,18 @@ void class_link(classinfo *c)
                        list_addlast(&unlinkedclasses, c);
                        return; 
                }
-               if ((ic->flags & ACC_INTERFACE) == 0)
+               if ((ic->flags & ACC_INTERFACE) == 0) {
+                       dolog("Specified interface is not declared as interface:");
+                       log_utf(ic->name);
+                       dolog("in");
+                       log_utf(c->name);
                        panic("Specified interface is not declared as interface");
+               }
        }
        
        /*  check super class */
 
-       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->impldBy = NULL;
@@ -2075,7 +2302,7 @@ void class_link(classinfo *c)
                        return; 
                }
 
-               if ((super->flags & ACC_INTERFACE) != 0)
+               if (super->flags & ACC_INTERFACE)
                        panic("Interface specified as super class");
 
                /* handle array classes */
@@ -2088,7 +2315,7 @@ void class_link(classinfo *c)
                        }
 
                /* Don't allow extending final classes */
-               if ((super->flags & ACC_FINAL) != 0)
+               if (super->flags & ACC_FINAL)
                        panic("Trying to extend final class");
                
                if (c->flags & ACC_INTERFACE)
@@ -2122,14 +2349,22 @@ void class_link(classinfo *c)
                                int j;
                                for (j = 0; j < sc->methodscount; j++) {
                                        if (method_canoverwrite(m, &(sc->methods[j]))) {
-                                               if ((sc->methods[j].flags & ACC_FINAL) != 0)
+                                               if ((sc->methods[j].flags & ACC_PRIVATE) != 0)
+                                                       goto notfoundvftblindex;
+                                               if ((sc->methods[j].flags & ACC_FINAL) != 0) {
+                                                       log_utf(c->name);
+                                                       log_utf(sc->name);
+                                                       log_utf(sc->methods[j].name);
+                                                       log_utf(sc->methods[j].descriptor);
                                                        panic("Trying to overwrite final method");
+                                               }
                                                m->vftblindex = sc->methods[j].vftblindex;
                                                goto foundvftblindex;
                                        }
                                }
                                sc = sc->super;
                        }
+               notfoundvftblindex:
                        m->vftblindex = (vftbllength++);
                foundvftblindex: ;
                }
@@ -2365,6 +2600,74 @@ fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc)
 }
 
 
+/****************** 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.
+
+*******************************************************************************/
+
+static
+fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc)
+{
+       s4 i;
+       fieldinfo *fi;
+
+       /* 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]);                                                         
+    }
+
+       /* try superinterfaces recursively */
+       for (i=0; i<c->interfacescount; ++i) {
+               fi = class_resolvefield_int(c->interfaces[i],name,desc);
+               if (fi)
+                       return fi;
+       }
+
+       /* try superclass */
+       if (c->super)
+               return class_resolvefield_int(c->super,name,desc);
+
+       /* not found */
+       return NULL;
+}
+
+
+/********************* Function: class_resolvefield ***************************
+       
+       Resolves a reference from REFERER to a field with NAME and DESC in class C.
+    If the field cannot be resolved this function panics.
+
+*******************************************************************************/
+
+fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc,
+                                                         classinfo *referer)
+{
+       fieldinfo *fi;
+
+       /* XXX resolve class c */
+       /* XXX check access from REFERER to C */
+       
+       fi = class_resolvefield_int(c,name,desc);
+
+       if (!fi) {
+               log_utf(c->name);
+               log_utf(name);
+               log_utf(desc);
+               panic("Cannot find field given in CONSTANT_Fieldref");
+               /* XXX should throw NoSuchFieldError */
+       }
+
+       /* XXX check access rights */
+
+       return fi;
+}
+
+
 /************************* Function: class_findmethod **************************
        
        Searches a 'classinfo' structure for a method having the given name and
@@ -2376,10 +2679,13 @@ fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc)
 s4 class_findmethodIndex(classinfo *c, utf *name, utf *desc)
 {
        s4 i;
+       //#define JOWENN_DEBUG1
+       //#define JOWENN_DEBUG2
 #if defined(JOWENN_DEBUG1) || defined(JOWENN_DEBUG2)
        char *buffer;                   
        int buffer_len, pos;
 #endif
+
 #ifdef JOWENN_DEBUG1
 
        buffer_len = 
@@ -2524,6 +2830,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
@@ -2610,6 +2952,113 @@ methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc)
 }
 
 
+/****************** 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.
+
+*******************************************************************************/
+
+methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc,
+                                                                                classinfo *referer)
+{
+       methodinfo *mi;
+
+       /* XXX resolve class c */
+       /* XXX check access from REFERER to C */
+       
+       if ((c->flags & ACC_INTERFACE) == 0)
+               return NULL; /* should throw IncompatibleClassChangeError */
+
+       mi = class_resolveinterfacemethod_int(c,name,desc);
+       if (mi)
+               goto found;
+
+       /* try class java.lang.Object */
+       mi = class_findmethod(class_java_lang_Object,name,desc);
+       if (mi)
+               goto found;
+
+       return NULL; /* should throw NoSuchMethodError */
+
+ found:
+       return mi;
+}
+
+/********************* Function: class_resolveclassmethod *********************
+       
+    Resolves a reference from REFERER to a method with NAME and DESC in
+    class C.
+
+*******************************************************************************/
+
+methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc,
+                                                                        classinfo *referer)
+{
+       methodinfo *mi;
+       int i;
+       classinfo *cls;
+       
+       /* XXX resolve class c */
+       /* XXX check access from REFERER to C */
+       
+       if ((c->flags & ACC_INTERFACE) != 0)
+               return NULL; /* should throw IncompatibleClassChangeError */
+
+       /* 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;
+       }
+       
+       return NULL; /* should throw NoSuchMethodError */
+
+ found:
+       if ((mi->flags & ACC_ABSTRACT) != 0 &&
+               (c->flags & ACC_ABSTRACT) == 0)
+               return NULL; /* should throw AbstractMethodError */
+
+       /* XXX check access rights */
+
+       return mi;
+}
+
+
 /************************* Function: class_issubclass **************************
 
        Checks if sub is a descendant of super.
@@ -2638,7 +3087,7 @@ void class_init(classinfo *c)
 {
        methodinfo *m;
        s4 i;
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        int b;
 #endif
 
@@ -2702,7 +3151,7 @@ void class_init(classinfo *c)
                log_text(logtext);
        }
 
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        b = blockInts;
        blockInts = 0;
 #endif
@@ -2710,7 +3159,7 @@ void class_init(classinfo *c)
        /* now call the initializer */
        asm_calljavafunction(m, NULL, NULL, NULL, NULL);
 
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        assert(blockInts == 0);
        blockInts = b;
 #endif
@@ -2720,6 +3169,13 @@ void class_init(classinfo *c)
                printf("Exception in thread \"main\" java.lang.ExceptionInInitializerError\n");
                printf("Caused by: ");
                utf_display((*exceptionptr)->vftbl->class->name);
+
+               /* do we have a detail message? */
+               if (((java_lang_Throwable *) *exceptionptr)->detailMessage) {
+                       printf(": ");
+                       utf_display(javastring_toutf(((java_lang_Throwable *) *exceptionptr)->detailMessage, false));
+               }
+
                printf("\n");
                fflush(stdout);
                exit(1);
@@ -2749,14 +3205,14 @@ void class_init(classinfo *c)
                        return;
                }
 
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
                b = blockInts;
                blockInts = 0;
 #endif
 
                asm_calljavafunction(m, NULL, NULL, NULL, NULL);
 
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
                assert(blockInts == 0);
                blockInts = b;
 #endif
@@ -3043,17 +3499,19 @@ classinfo *loader_load(utf *topname)
        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);
 
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+       compiler_lock();
+#endif
+
        loader_load_running++;
        
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        intsDisable();
+#endif
 
        if (getloadingtime)
                starttime = getcputime();
@@ -3074,7 +3532,7 @@ classinfo *loader_load(utf *topname)
        if (linkverbose)
                dolog("Linking...");
 
-       /* XXX added a hack to break infinite linking loops. A better
+       /* Added a hack to break infinite linking loops. A better
         * linking algorithm would be nice. -Edwin */
        notlinkable = NULL;
        while ((c = list_first(&unlinkedclasses))) {
@@ -3130,13 +3588,15 @@ classinfo *loader_load(utf *topname)
                }
        }
 
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        intsRestore();
+#endif
        
 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       pthread_mutex_unlock(&compiler_mutex);
+       compiler_unlock();
 #endif
 
-       /* XXX DEBUG */ if (linkverbose && !top) dolog("returning NULL from loader_load");
+       /* DEBUG */ /*if (linkverbose && !top) dolog("returning NULL from loader_load");*/
        
        return top; 
 }
@@ -3177,7 +3637,6 @@ classinfo *loader_load_sysclass(classinfo **top, utf *topname)
 
 ********************************************************************************/
 
-
 void create_primitive_classes()
 {  
        int i;
@@ -3289,7 +3748,7 @@ classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr,
        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);
@@ -3320,9 +3779,9 @@ classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr,
                          /* FALLTHROUGH! */
                  case '[':
                          if (mode & CLASSLOAD_SKIP) return class_java_lang_Object;
-                         name = utf_new(start,utf_ptr-start);
+                         name = utf_new(start, utf_ptr - start);
                          return (mode & CLASSLOAD_LOAD)
-                                 ? loader_load(name) : class_new(name); /* XXX */
+                                 ? loader_load(name) : class_new(name); /* XXX handle errors */
                }
        }
 
@@ -3331,7 +3790,7 @@ classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr,
                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();
                                                  
@@ -3384,6 +3843,79 @@ int type_from_descriptor(classinfo **cls, char *utf_ptr, char *end_ptr,
 }
 
 
+
+/*************** function: create_system_exception_classes *******************************
+
+       create system exception classes needed by default 
+
+********************************************************************************/
+
+static void create_system_exception_classes()
+{
+       if (verbose)
+               log_text("loader_init:  create_system_exception_classs: 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"));
+}
+
+
+/*************** function: create_system_exception_classes *******************************
+
+       create system exception proto classes needed by default 
+
+********************************************************************************/
+
+static void create_system_exception_proto_classes()
+{
+
+       if (verbose) log_text("loader_init: creating global proto_java_lang_ClassCastException");
+       proto_java_lang_ClassCastException =
+               builtin_new(class_java_lang_ClassCastException);
+
+       if (verbose) log_text("loader_init: proto_java_lang_ClassCastException has been initialized");
+
+       proto_java_lang_NullPointerException =
+               builtin_new(class_java_lang_NullPointerException);
+       if (verbose) log_text("loader_init: proto_java_lang_NullPointerException has been initialized");
+
+       proto_java_lang_ArrayIndexOutOfBoundsException =
+               builtin_new(class_java_lang_ArrayIndexOutOfBoundsException);
+
+       proto_java_lang_NegativeArraySizeException =
+               builtin_new(class_java_lang_NegativeArraySizeException);
+
+       proto_java_lang_OutOfMemoryError =
+               builtin_new(class_java_lang_OutOfMemoryError);
+
+       proto_java_lang_ArithmeticException =
+               builtin_new(class_java_lang_ArithmeticException);
+
+       proto_java_lang_ArrayStoreException =
+               builtin_new(class_java_lang_ArrayStoreException);
+
+       proto_java_lang_ThreadDeath =
+               builtin_new(class_java_lang_ThreadDeath);
+
+
+}
+
+
+
 /*************** function: create_pseudo_classes *******************************
 
        create pseudo classes used by the typechecker
@@ -3449,6 +3981,9 @@ void loader_init(u1 *stackbottom)
        utf_innerclasses    = utf_new_char("InnerClasses");
        utf_constantvalue   = utf_new_char("ConstantValue");
        utf_code                = utf_new_char("Code");
+       utf_exceptions          = utf_new_char("Exceptions");
+       utf_linenumbertable     = utf_new_char("LineNumberTable");
+       utf_sourcefile          = utf_new_char("SourceFile");
        utf_finalize        = utf_new_char("finalize");
        utf_fidesc              = utf_new_char("()V");
        utf_init                = utf_new_char("<init>");
@@ -3462,6 +3997,8 @@ void loader_init(u1 *stackbottom)
        utf_vmclass         = utf_new_char("java/lang/VMClass");
        utf_java_lang_Object= utf_new_char("java/lang/Object");
 
+       array_packagename   = utf_new_char("<the array package>");
+
        /* create some important classes */
        /* These classes have to be created now because the classinfo
         * pointers are used in the loading code.
@@ -3480,24 +4017,8 @@ void loader_init(u1 *stackbottom)
        loader_load_sysclass(&class_java_lang_Throwable,
                                                 utf_new_char("java/lang/Throwable"));
 
-       if (verbose) 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"));
-               
+        create_system_exception_classes();
+
        /* create classes representing primitive types */
        create_primitive_classes();
 
@@ -3507,38 +4028,11 @@ void loader_init(u1 *stackbottom)
        /* correct vftbl-entries (retarded loading of class java/lang/String) */
        stringtable_update();
 
-#ifdef USE_THREADS
+#if defined(USE_THREADS)
        if (stackbottom!=0)
                initLocks();
 #endif
-
-       if (verbose) log_text("loader_init: creating global proto_java_lang_ClassCastException");
-       proto_java_lang_ClassCastException =
-               builtin_new(class_java_lang_ClassCastException);
-
-       if (verbose) log_text("loader_init: proto_java_lang_ClassCastException has been initialized");
-
-       proto_java_lang_NullPointerException =
-               builtin_new(class_java_lang_NullPointerException);
-       if (verbose) log_text("loader_init: proto_java_lang_NullPointerException has been initialized");
-
-       proto_java_lang_ArrayIndexOutOfBoundsException =
-               builtin_new(class_java_lang_ArrayIndexOutOfBoundsException);
-
-       proto_java_lang_NegativeArraySizeException =
-               builtin_new(class_java_lang_NegativeArraySizeException);
-
-       proto_java_lang_OutOfMemoryError =
-               builtin_new(class_java_lang_OutOfMemoryError);
-
-       proto_java_lang_ArithmeticException =
-               builtin_new(class_java_lang_ArithmeticException);
-
-       proto_java_lang_ArrayStoreException =
-               builtin_new(class_java_lang_ArrayStoreException);
-
-       proto_java_lang_ThreadDeath =
-               builtin_new(class_java_lang_ThreadDeath);
+        create_system_exception_proto_classes();
 
        loader_inited = 1;
 }
@@ -3592,7 +4086,7 @@ static void loader_compute_class_values(classinfo *c)
        }
        c->vftbl->diffval = classvalue - c->vftbl->baseval;
        
-       /*
+/*     
        {
        int i;
        for (i = 0; i < c->index; i++)
@@ -3601,7 +4095,7 @@ static void loader_compute_class_values(classinfo *c)
        utf_display(c->name);
        printf("\n");
        }
-       */
+*/     
 }
 
 
@@ -3609,7 +4103,9 @@ void loader_compute_subclasses()
 {
        classinfo *c;
        
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        intsDisable();                     /* schani */
+#endif
 
        c = list_first(&linkedclasses);
        while (c) {
@@ -3638,7 +4134,9 @@ void loader_compute_subclasses()
        cast_unlock();
 #endif
 
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
        intsRestore();                      /* schani */
+#endif
 }
 
 
@@ -3668,15 +4166,15 @@ void loader_close()
 
        while ((c = list_first(&unloadedclasses))) {
                list_remove(&unloadedclasses, c);
-               class_free(c);
+/*             class_free(c); */
        }
        while ((c = list_first(&unlinkedclasses))) {
                list_remove(&unlinkedclasses, c);
-               class_free(c);
+/*             class_free(c); */
        }
        while ((c = list_first(&linkedclasses))) {
                list_remove(&linkedclasses, c);
-               class_free(c);
+/*             class_free(c); */
        }
 }