* src/vm/jit/i386/codegen.cn (codegen): Use the new functions for
[cacao.git] / src / vm / class.c
index 305ad900363d52a48c83e1a1ecf45128ffebb883..50b6fd24fa48fa450de1c7f49fc705b732a53e83 100644 (file)
@@ -1,9 +1,9 @@
-/* vm/class.c - class related functions
+/* src/vm/class.c - class related functions
 
-   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
+   Copyright (C) 1996-2005, 2006 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.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
-   Contact: cacao@complang.tuwien.ac.at
+   Contact: cacao@cacaojvm.org
 
    Authors: Reinhard Grafl
 
    Changes: Mark Probst
             Andreas Krall
             Christian Thalinger
+                       Edwin Steiner
 
-   $Id: class.c 1926 2005-02-10 10:47:29Z twisti $
+   $Id: class.c 6033 2006-11-21 16:56:56Z michi $
 
 */
 
 
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
 #include <string.h>
 
-#include "config.h"
-#include "types.h"
+#include "vm/types.h"
 
 #include "mm/memory.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
+#if defined(ENABLE_THREADS)
+# include "threads/native/threads.h"
 #endif
 
 #include "toolbox/logging.h"
 #include "vm/class.h"
+#include "vm/classcache.h"
+#include "vm/exceptions.h"
+#include "vm/global.h"
 #include "vm/loader.h"
 #include "vm/options.h"
+#include "vm/resolve.h"
 #include "vm/statistics.h"
-#include "vm/tables.h"
+#include "vm/stringlocal.h"
 #include "vm/utf8.h"
 
 
 /* global variables ***********************************************************/
 
-hashtable class_hash;                   /* hashtable for classes              */
-
 list unlinkedclasses;                   /* this is only used for eager class  */
                                         /* loading                            */
 
@@ -79,6 +80,10 @@ classinfo *class_java_lang_Cloneable;
 classinfo *class_java_lang_SecurityManager;
 classinfo *class_java_lang_String;
 classinfo *class_java_lang_System;
+classinfo *class_java_lang_Thread;
+classinfo *class_java_lang_ThreadGroup;
+classinfo *class_java_lang_VMSystem;
+classinfo *class_java_lang_VMThread;
 classinfo *class_java_io_Serializable;
 
 
@@ -86,10 +91,18 @@ classinfo *class_java_io_Serializable;
 
 classinfo *class_java_lang_Throwable;
 classinfo *class_java_lang_VMThrowable;
-classinfo *class_java_lang_Exception;
 classinfo *class_java_lang_Error;
+classinfo *class_java_lang_AbstractMethodError;
+classinfo *class_java_lang_LinkageError;
+classinfo *class_java_lang_NoClassDefFoundError;
+classinfo *class_java_lang_NoSuchMethodError;
 classinfo *class_java_lang_OutOfMemoryError;
 
+classinfo *class_java_lang_Exception;
+classinfo *class_java_lang_ClassCastException;
+classinfo *class_java_lang_ClassNotFoundException;
+classinfo *class_java_lang_IllegalArgumentException;
+classinfo *class_java_lang_IllegalMonitorStateException;
 
 classinfo *class_java_lang_Void;
 classinfo *class_java_lang_Boolean;
@@ -102,6 +115,23 @@ classinfo *class_java_lang_Float;
 classinfo *class_java_lang_Double;
 
 
+/* some runtime exception */
+
+classinfo *class_java_lang_NullPointerException;
+
+
+/* some classes which may be used more often */
+
+classinfo *class_java_lang_StackTraceElement;
+classinfo *class_java_lang_reflect_Constructor;
+classinfo *class_java_lang_reflect_Field;
+classinfo *class_java_lang_reflect_Method;
+classinfo *class_java_security_PrivilegedAction;
+classinfo *class_java_util_Vector;
+
+classinfo *arrayclass_java_lang_Object;
+
+
 /* pseudo classes for the typechecker */
 
 classinfo *pseudo_class_Arraystub;
@@ -109,349 +139,327 @@ classinfo *pseudo_class_Null;
 classinfo *pseudo_class_New;
 
 
-/* class_init ******************************************************************
+/* class_set_packagename *******************************************************
 
-   Initialize the class subsystem.
+   Derive the package name from the class name and store it in the struct.
 
 *******************************************************************************/
 
-void class_init_foo(void)
+void class_set_packagename(classinfo *c)
 {
-       class_java_lang_Object          = class_new_intern(utf_java_lang_Object);
+       char *p = UTF_END(c->name) - 1;
+       char *start = c->name->text;
+
+       /* set the package name */
+       /* classes in the unnamed package keep packagename == NULL */
+
+       if (c->name->text[0] == '[') {
+               /* set packagename of arrays to the element's package */
 
-       class_java_lang_Class           = class_new(utf_java_lang_Class);
-       class_java_lang_ClassLoader     = class_new(utf_java_lang_ClassLoader);
-       class_java_lang_Cloneable       = class_new(utf_java_lang_Cloneable);
-       class_java_lang_SecurityManager = class_new(utf_java_lang_SecurityManager);
-       class_java_lang_String          = class_new(utf_java_lang_String);
-       class_java_lang_System          = class_new(utf_java_lang_System);
-       class_java_io_Serializable      = class_new(utf_java_io_Serializable);
+               for (; *start == '['; start++);
 
-       class_java_lang_Throwable       = class_new(utf_java_lang_Throwable);
-       class_java_lang_VMThrowable     = class_new(utf_java_lang_VMThrowable);
-       class_java_lang_Exception       = class_new(utf_java_lang_Exception);
-       class_java_lang_Error           = class_new(utf_java_lang_Error);
-       class_java_lang_OutOfMemoryError =
-               class_new(utf_java_lang_OutOfMemoryError);
+               /* skip the 'L' in arrays of references */
+               if (*start == 'L')
+                       start++;
 
-       class_java_lang_Void            = class_new(utf_java_lang_Void);
-       class_java_lang_Boolean         = class_new(utf_java_lang_Boolean);
-       class_java_lang_Byte            = class_new(utf_java_lang_Byte);
-       class_java_lang_Character       = class_new(utf_java_lang_Character);
-       class_java_lang_Short           = class_new(utf_java_lang_Short);
-       class_java_lang_Integer         = class_new(utf_java_lang_Integer);
-       class_java_lang_Long            = class_new(utf_java_lang_Long);
-       class_java_lang_Float           = class_new(utf_java_lang_Float);
-       class_java_lang_Double          = class_new(utf_java_lang_Double);
+               for (; (p > start) && (*p != '/'); --p);
 
-    pseudo_class_Arraystub = class_new_intern(utf_new_char("$ARRAYSTUB$"));
-       pseudo_class_Null      = class_new_intern(utf_new_char("$NULL$"));
-       pseudo_class_New       = class_new_intern(utf_new_char("$NEW$"));
+               c->packagename = utf_new(start, p - start);
+
+       } else {
+               for (; (p > start) && (*p != '/'); --p);
+
+               c->packagename = utf_new(start, p - start);
+       }
 }
 
 
-/* class_new *******************************************************************
+/* class_create_classinfo ******************************************************
 
-   Searches for the class with the specified name in the classes
-   hashtable, if there is no such class a new classinfo structure is
-   created and inserted into the list of classes to be loaded.
+   Create a new classinfo struct. The class name is set to the given utf *,
+   most other fields are initialized to zero.
+
+   Note: classname may be NULL. In this case a not-yet-named classinfo is
+         created. The name must be filled in later and class_set_packagename
+                must be called after that.
 
 *******************************************************************************/
 
-classinfo *class_new(utf *classname)
+classinfo *class_create_classinfo(utf *classname)
 {
-    classinfo *c;
+       classinfo *c;
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-    tables_lock();
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_classinfo += sizeof(classinfo);
 #endif
 
-    c = class_new_intern(classname);
-
-       /* we support eager class loading and linking on demand */
+       /* we use a safe name for temporarily unnamed classes */
+       if (!classname)
+               classname = utf_not_named_yet;
 
-       if (opt_eager) {
-               classinfo *tc;
-               classinfo *tmp;
+#if !defined(NDEBUG)
+       if (initverbose)
+               log_message_utf("Creating class: ", classname);
+#endif
 
-               list_init(&unlinkedclasses, OFFSET(classinfo, listnode));
+       /* GCNEW_UNCOLLECTABLE clears the allocated memory */
 
-               if (!c->loaded) {
-                       if (!class_load(c)) {
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-                               tables_unlock();
-#endif
-                               return c;
-                       }
-               }
+       c = GCNEW_UNCOLLECTABLE(classinfo, 1);
+       /*c=NEW(classinfo);*/
+       c->name = classname;
 
-               /* link all referenced classes */
+       /* set the header.vftbl of all loaded classes to the one of
+       java.lang.Class, so Java code can use a class as object */
 
-               tc = list_first(&unlinkedclasses);
+       if (class_java_lang_Class)
+               if (class_java_lang_Class->vftbl)
+                       c->object.header.vftbl = class_java_lang_Class->vftbl;
+       
+       if (classname != utf_not_named_yet)
+               class_set_packagename(c);
 
-               while (tc) {
-                       /* skip the current loaded/linked class */
-                       if (tc != c) {
-                               if (!class_link(tc)) {
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-                                       tables_unlock();
+#if defined(ENABLE_THREADS)
+       lock_init_object_lock(&c->object.header);
 #endif
-                                       return c;
-                               }
-                       }
 
-                       /* we need a tmp variable here, because list_remove sets prev and
-                          next to NULL */
-                       tmp = list_next(&unlinkedclasses, tc);
-                       list_remove(&unlinkedclasses, tc);
-                       tc = tmp;
-               }
+       return c;
+}
 
-               if (!c->linked) {
-                       if (!class_link(c)) {
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-                               tables_unlock();
-#endif
-                               return c;
-                       }
-               }
-       }
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-    tables_unlock();
-#endif
+/* class_postset_header_vftbl **************************************************
 
-    return c;
-}
+   Set the header.vftbl of all classes created before java.lang.Class
+   was linked.  This is necessary that Java code can use a class as
+   object.
 
+*******************************************************************************/
 
-classinfo *class_new_intern(utf *classname)
+void class_postset_header_vftbl(void)
 {
-       classinfo *c;     /* hashtable element */
-       u4 key;           /* hashkey computed from classname */
-       u4 slot;          /* slot in hashtable */
-       u2 i;
+       classinfo *c;
+       u4 slot;
+       classcache_name_entry *nmen;
+       classcache_class_entry *clsen;
 
-       key  = utf_hashkey(classname->text, classname->blength);
-       slot = key & (class_hash.size - 1);
-       c    = class_hash.ptr[slot];
+       assert(class_java_lang_Class);
 
-       /* search external hash chain for the class */
-       while (c) {
-               if (c->name->blength == classname->blength) {
-                       for (i = 0; i < classname->blength; i++)
-                               if (classname->text[i] != c->name->text[i]) goto nomatch;
-                                               
-                       /* class found in hashtable */
-                       return c;
+       for (slot = 0; slot < hashtable_classcache.size; slot++) {
+               nmen = (classcache_name_entry *) hashtable_classcache.ptr[slot];
+
+               for (; nmen; nmen = nmen->hashlink) {
+                       /* iterate over all class entries */
+
+                       for (clsen = nmen->classes; clsen; clsen = clsen->next) {
+                               c = clsen->classobj;
+
+                               /* now set the the vftbl */
+
+                               if (c->object.header.vftbl == NULL)
+                                       c->object.header.vftbl = class_java_lang_Class->vftbl;
+                       }
                }
-                       
-       nomatch:
-               c = c->hashlink; /* next element in external chain */
        }
+}
 
-       /* location in hashtable found, create new classinfo structure */
 
-#if defined(STATISTICS)
-       if (opt_stat)
-               count_class_infos += sizeof(classinfo);
-#endif
+/* class_freepool **************************************************************
 
-       if (initverbose) {
-               char logtext[MAXLOGTEXT];
-               sprintf(logtext, "Creating class: ");
-               utf_sprint_classname(logtext + strlen(logtext), classname);
-               log_text(logtext);
-       }
+       Frees all resources used by this classes Constant Pool.
 
-       c = GCNEW(classinfo, 1); /*JOWENN: NEW*/
-       /*c=NEW(classinfo);*/
-       c->vmClass = 0;
-       c->flags = 0;
-       c->name = classname;
-       c->packagename = NULL;
-       c->cpcount = 0;
-       c->cptags = NULL;
-       c->cpinfos = NULL;
-       c->super = NULL;
-       c->sub = NULL;
-       c->nextsub = NULL;
-       c->interfacescount = 0;
-       c->interfaces = NULL;
-       c->fieldscount = 0;
-       c->fields = NULL;
-       c->methodscount = 0;
-       c->methods = NULL;
-       c->linked = false;
-       c->loaded = false;
-       c->index = 0;
-       c->instancesize = 0;
-       c->header.vftbl = NULL;
-       c->innerclasscount = 0;
-       c->innerclass = NULL;
-       c->vftbl = NULL;
-       c->initialized = false;
-       c->initializing = false;
-       c->classvftbl = false;
-    c->classUsed = 0;
-    c->impldBy = NULL;
-       c->classloader = NULL;
-       c->sourcefile = NULL;
+*******************************************************************************/
+
+static void class_freecpool(classinfo *c)
+{
+       u4 idx;
+       u4 tag;
+       voidptr info;
        
-       /* insert class into the hashtable */
-       c->hashlink = class_hash.ptr[slot];
-       class_hash.ptr[slot] = c;
+       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;
+                               }
+                       }
+               }
+       }
 
-       /* update number of hashtable-entries */
-       class_hash.entries++;
+       if (c->cptags)
+               MFREE(c->cptags, u1, c->cpcount);
 
-       if (class_hash.entries > (class_hash.size * 2)) {
+       if (c->cpinfos)
+               MFREE(c->cpinfos, voidptr, c->cpcount);
+}
 
-               /* reorganization of hashtable, average length of 
-                  the external chains is approx. 2                */  
 
-               u4 i;
-               classinfo *c;
-               hashtable newhash;  /* the new hashtable */
+/* class_getconstant ***********************************************************
 
-               /* create new hashtable, double the size */
-               init_hashtable(&newhash, class_hash.size * 2);
-               newhash.entries = class_hash.entries;
+   Retrieves the value at position 'pos' of the constantpool of a
+   class. If the type of the value is other than 'ctype', an error is
+   thrown.
 
-               /* transfer elements to new hashtable */
-               for (i = 0; i < class_hash.size; i++) {
-                       c = (classinfo *) class_hash.ptr[i];
-                       while (c) {
-                               classinfo *nextc = c->hashlink;
-                               u4 slot = (utf_hashkey(c->name->text, c->name->blength)) & (newhash.size - 1);
-                                               
-                               c->hashlink = newhash.ptr[slot];
-                               newhash.ptr[slot] = c;
+*******************************************************************************/
 
-                               c = nextc;
-                       }
-               }
-       
-               /* dispose old table */ 
-               MFREE(class_hash.ptr, void*, class_hash.size);
-               class_hash = newhash;
+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;
        }
 
-       /* Array classes need further initialization. */
-       if (c->name->text[0] == '[') {
-               /* Array classes are not loaded from classfiles. */
-               c->loaded = true;
-               class_new_array(c);
-               c->packagename = array_packagename;
+       return c->cpinfos[pos];
+}
 
-       } else {
-               /* Find the package name */
-               /* Classes in the unnamed package keep packagename == NULL. */
-               char *p = utf_end(c->name) - 1;
-               char *start = c->name->text;
-               for (;p > start; --p) {
-                       if (*p == '/') {
-                               c->packagename = utf_new (start, p - start);
-                               break;
-                       }
-               }
+
+/* innerclass_getconstant ******************************************************
+
+   Like class_getconstant, but if cptags is ZERO, null is returned.
+       
+*******************************************************************************/
+
+voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype)
+{
+       /* invalid position in constantpool */
+       if (pos >= c->cpcount) {
+               *exceptionptr = new_classformaterror(c, "Illegal constant pool index");
+               return NULL;
        }
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       initObjectLock(&c->header);
-#endif
+       /* constantpool entry of type 0 */      
+       if (!c->cptags[pos])
+               return NULL;
 
-       return c;
+       /* check type of constantpool entry */
+       if (c->cptags[pos] != ctype) {
+               *exceptionptr = new_classformaterror(c, "Illegal constant pool index");
+               return NULL;
+       }
+               
+       return c->cpinfos[pos];
 }
 
 
-/* class_get *******************************************************************
+/* class_free ******************************************************************
 
-   Searches for the class with the specified name in the classes
-   hashtable if there is no such class NULL is returned.
+   Frees all resources used by the class.
 
 *******************************************************************************/
 
-classinfo *class_get(utf *classname)
+void class_free(classinfo *c)
 {
-       classinfo *c;  /* hashtable element */ 
-       u4 key;        /* hashkey computed from classname */   
-       u4 slot;       /* slot in hashtable */
-       u2 i;  
-
-       key  = utf_hashkey(classname->text, classname->blength);
-       slot = key & (class_hash.size-1);
-       c    = class_hash.ptr[slot];
+       s4 i;
+       vftbl_t *v;
+               
+       class_freecpool(c);
+
+       if (c->interfaces)
+               MFREE(c->interfaces, classinfo*, c->interfacescount);
+
+       if (c->fields) {
+               for (i = 0; i < c->fieldscount; i++)
+                       field_free(&(c->fields[i]));
+#if defined(ENABLE_CACAO_GC)
+               MFREE(c->fields, fieldinfo, c->fieldscount);
+#endif
+       }
+       
+       if (c->methods) {
+               for (i = 0; i < c->methodscount; i++)
+                       method_free(&(c->methods[i]));
+               MFREE(c->methods, methodinfo, c->methodscount);
+       }
 
-       /* search external hash-chain */
-       while (c) {
-               if (c->name->blength == classname->blength) {
-                       /* compare classnames */
-                       for (i = 0; i < classname->blength; i++) 
-                               if (classname->text[i] != c->name->text[i])
-                                       goto nomatch;
-
-                       /* class found in hashtable */                          
-                       return c;
+       if ((v = c->vftbl) != NULL) {
+               if (v->arraydesc)
+                       mem_free(v->arraydesc,sizeof(arraydescriptor));
+               
+               for (i = 0; i < v->interfacetablelength; i++) {
+                       MFREE(v->interfacetable[-i], methodptr, v->interfacevftbllength[i]);
                }
-                       
-       nomatch:
-               c = c->hashlink;
+               MFREE(v->interfacevftbllength, s4, v->interfacetablelength);
+
+               i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) +
+                   sizeof(methodptr*) * (v->interfacetablelength -
+                                        (v->interfacetablelength > 0));
+               v = (vftbl_t*) (((methodptr*) v) -
+                                               (v->interfacetablelength - 1) * (v->interfacetablelength > 1));
+               mem_free(v, i);
        }
 
-       /* class not found */
-       return NULL;
+       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)); */
+       
+/*     GCFREE(c); */
 }
 
 
-/* class_remove ****************************************************************
+/* get_array_class *************************************************************
 
-   Removes the class entry wth the specified name in the classes
-   hashtable, furthermore the class' resources are freed if there is
-   no such class false is returned.
+   Returns the array class with the given name for the given
+   classloader, or NULL if an exception occurred.
+
+   Note: This function does eager loading. 
 
 *******************************************************************************/
 
-bool class_remove(classinfo *c)
+static classinfo *get_array_class(utf *name,java_objectheader *initloader,
+                                                                                       java_objectheader *defloader,bool link)
 {
-       classinfo *tc;                      /* hashtable element                  */
-       classinfo *pc;
-       u4 key;                             /* hashkey computed from classname    */
-       u4 slot;                            /* slot in hashtable                  */
-       u2 i;  
-
-       key  = utf_hashkey(c->name->text, c->name->blength);
-       slot = key & (class_hash.size - 1);
-       tc   = class_hash.ptr[slot];
-       pc   = NULL;
-
-       /* search external hash-chain */
-       while (tc) {
-               if (tc->name->blength == c->name->blength) {
-                       
-                       /* compare classnames */
-                       for (i = 0; i < c->name->blength; i++)
-                               if (tc->name->text[i] != c->name->text[i])
-                                       goto nomatch;
+       classinfo *c;
+       
+       /* lookup this class in the classcache */
+       c = classcache_lookup(initloader,name);
+       if (!c)
+               c = classcache_lookup_defined(defloader,name);
+
+       if (!c) {
+               /* we have to create it */
+               c = class_create_classinfo(name);
+               c = load_newly_created_array(c,initloader);
+               if (c == NULL)
+                       return NULL;
+       }
 
-                       /* class found in hashtable */
-                       if (!pc)
-                               class_hash.ptr[slot] = tc->hashlink;
-                       else
-                               pc->hashlink = tc->hashlink;
+       assert(c);
+       assert(c->state & CLASS_LOADED);
+       assert(c->classloader == defloader);
 
-                       class_free(tc);
+       if (link && !(c->state & CLASS_LINKED))
+               if (!link_class(c))
+                       return NULL;
 
-                       return true;
-               }
-                       
-       nomatch:
-               pc = tc;
-               tc = tc->hashlink;
-       }
+       assert(!link || (c->state & CLASS_LINKED));
 
-       /* class not found */
-       return false;
+       return c;
 }
 
 
@@ -462,12 +470,15 @@ bool class_remove(classinfo *c)
 
 *******************************************************************************/
 
-classinfo *class_array_of(classinfo *component)
+classinfo *class_array_of(classinfo *component, bool link)
 {
     s4 namelen;
     char *namebuf;
+       s4 dumpsize;
        classinfo *c;
 
+       dumpsize = dump_size();
+
     /* Assemble the array class name */
     namelen = component->name->blength;
     
@@ -488,14 +499,14 @@ classinfo *class_array_of(classinfo *component)
         namelen += 3;
     }
 
-       /* load this class ;-) and link it */
-       c = class_new(utf_new(namebuf, namelen));
-       c->loaded = 1;
+       c = get_array_class(utf_new(namebuf, namelen),
+                                               component->classloader,
+                                               component->classloader,
+                                               link);
 
-       if (!class_link(c))
-               return NULL;
+       dump_release(dumpsize);
 
-    return c;
+       return c;
 }
 
 
@@ -506,13 +517,19 @@ classinfo *class_array_of(classinfo *component)
 
 *******************************************************************************/
 
-classinfo *class_multiarray_of(s4 dim, classinfo *element)
+classinfo *class_multiarray_of(s4 dim, classinfo *element, bool link)
 {
     s4 namelen;
     char *namebuf;
+       s4 dumpsize;
+       classinfo *c;
 
-       if (dim < 1)
-               panic("Invalid array dimension requested");
+       dumpsize = dump_size();
+
+       if (dim < 1) {
+               log_text("Invalid array dimension requested");
+               assert(0);
+       }
 
     /* Assemble the array class name */
     namelen = element->name->blength;
@@ -533,8 +550,849 @@ classinfo *class_multiarray_of(s4 dim, classinfo *element)
     }
        memset(namebuf, '[', dim);
 
-    return class_new(utf_new(namebuf, namelen));
+       c = get_array_class(utf_new(namebuf, namelen),
+                                               element->classloader,
+                                               element->classloader,
+                                               link);
+
+       dump_release(dumpsize);
+
+       return c;
+}
+
+
+/* class_lookup_classref *******************************************************
+
+   Looks up the constant_classref for a given classname in the classref
+   tables of a class.
+
+   IN:
+       cls..............the class containing the reference
+          name.............the name of the class refered to
+
+    RETURN VALUE:
+          a pointer to a constant_classref, or 
+          NULL if the reference was not found
+   
+*******************************************************************************/
+
+constant_classref *class_lookup_classref(classinfo *cls, utf *name)
+{
+       constant_classref *ref;
+       extra_classref *xref;
+       int count;
+
+       assert(cls);
+       assert(name);
+       assert(!cls->classrefcount || cls->classrefs);
+       
+       /* first search the main classref table */
+       count = cls->classrefcount;
+       ref = cls->classrefs;
+       for (; count; --count, ++ref)
+               if (ref->name == name)
+                       return ref;
+
+       /* next try the list of extra classrefs */
+       for (xref = cls->extclassrefs; xref; xref = xref->next) {
+               if (xref->classref.name == name)
+                       return &(xref->classref);
+       }
+
+       /* not found */
+       return NULL;
+}
+
+
+/* class_get_classref **********************************************************
+
+   Returns the constant_classref for a given classname.
+
+   IN:
+       cls..............the class containing the reference
+          name.............the name of the class refered to
+
+   RETURN VALUE:
+       a pointer to a constant_classref (never NULL)
+
+   NOTE:
+       The given name is not checked for validity!
+   
+*******************************************************************************/
+
+constant_classref *class_get_classref(classinfo *cls, utf *name)
+{
+       constant_classref *ref;
+       extra_classref *xref;
+
+       assert(cls);
+       assert(name);
+
+       ref = class_lookup_classref(cls,name);
+       if (ref)
+               return ref;
+
+       xref = NEW(extra_classref);
+       CLASSREF_INIT(xref->classref,cls,name);
+
+       xref->next = cls->extclassrefs;
+       cls->extclassrefs = xref;
+
+       return &(xref->classref);
+}
+
+
+/* class_get_self_classref *****************************************************
+
+   Returns the constant_classref to the class itself.
+
+   IN:
+       cls..............the class containing the reference
+
+   RETURN VALUE:
+       a pointer to a constant_classref (never NULL)
+
+*******************************************************************************/
+
+constant_classref *class_get_self_classref(classinfo *cls)
+{
+       /* XXX this should be done in a faster way. Maybe always make */
+       /* the classref of index 0 a self reference.                  */
+       return class_get_classref(cls,cls->name);
+}
+
+/* class_get_classref_multiarray_of ********************************************
+
+   Returns an array type reference with the given dimension and element class
+   reference.
+
+   IN:
+       dim..............the requested dimension
+                           dim must be in [1;255]. This is NOT checked!
+          ref..............the component class reference
+
+   RETURN VALUE:
+       a pointer to the class reference for the array type
+
+   NOTE:
+       The referer of `ref` is used as the referer for the new classref.
+
+*******************************************************************************/
+
+constant_classref *class_get_classref_multiarray_of(s4 dim, constant_classref *ref)
+{
+    s4 namelen;
+    char *namebuf;
+       s4 dumpsize;
+       constant_classref *cr;
+
+       assert(ref);
+       assert(dim >= 1 && dim <= 255);
+
+       dumpsize = dump_size();
+
+    /* Assemble the array class name */
+    namelen = ref->name->blength;
+    
+    if (ref->name->text[0] == '[') {
+        /* the element is itself an array */
+        namebuf = DMNEW(char, namelen + dim);
+        memcpy(namebuf + dim, ref->name->text, namelen);
+        namelen += dim;
+    }
+    else {
+        /* the element is a non-array class */
+        namebuf = DMNEW(char, namelen + 2 + dim);
+        namebuf[dim] = 'L';
+        memcpy(namebuf + dim + 1, ref->name->text, namelen);
+        namelen += (2 + dim);
+        namebuf[namelen - 1] = ';';
+    }
+       memset(namebuf, '[', dim);
+
+    cr = class_get_classref(ref->referer,utf_new(namebuf, namelen));
+
+       dump_release(dumpsize);
+
+       return cr;
+}
+
+
+/* class_get_classref_component_of *********************************************
+
+   Returns the component classref of a given array type reference
+
+   IN:
+       ref..............the array type reference
+
+   RETURN VALUE:
+       a reference to the component class, or
+          NULL if `ref` is not an object array type reference
+
+   NOTE:
+       The referer of `ref` is used as the referer for the new classref.
+
+*******************************************************************************/
+
+constant_classref *class_get_classref_component_of(constant_classref *ref)
+{
+       s4 namelen;
+       char *name;
+       
+       assert(ref);
+
+       name = ref->name->text;
+       if (*name++ != '[')
+               return NULL;
+       
+       namelen = ref->name->blength - 1;
+       if (*name == 'L') {
+               name++;
+               namelen -= 2;
+       }
+       else if (*name != '[') {
+               return NULL;
+       }
+
+    return class_get_classref(ref->referer, utf_new(name, namelen));
+}
+
+
+/* class_findmethod ************************************************************
+       
+   Searches a 'classinfo' structure for a method having the given name
+   and descriptor. If descriptor is NULL, it is ignored.
+
+*******************************************************************************/
+
+methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc)
+{
+       methodinfo *m;
+       s4          i;
+
+       for (i = 0; i < c->methodscount; i++) {
+               m = &(c->methods[i]);
+
+               if ((m->name == name) && ((desc == NULL) || (m->descriptor == desc)))
+                       return m;
+       }
+
+       return NULL;
+}
+
+
+/* class_resolvemethod *********************************************************
+       
+   Searches a class and it's super classes for a method.
+
+   Superinterfaces are *not* searched.
+
+*******************************************************************************/
+
+methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc)
+{
+       methodinfo *m;
+
+       while (c) {
+               m = class_findmethod(c, name, desc);
+
+               if (m)
+                       return m;
+
+               /* JVM Specification bug: 
+
+                  It is important NOT to resolve special <init> and <clinit>
+                  methods to super classes or interfaces; yet, this is not
+                  explicited in the specification.  Section 5.4.3.3 should be
+                  updated appropriately.  */
+
+               if (name == utf_init || name == utf_clinit)
+                       return NULL;
+
+               c = c->super.cls;
+       }
+
+       return NULL;
+}
+
+
+/* class_resolveinterfacemethod_intern *****************************************
+
+   Internally used helper function. Do not use this directly.
+
+*******************************************************************************/
+
+static methodinfo *class_resolveinterfacemethod_intern(classinfo *c,
+                                                                                                          utf *name, utf *desc)
+{
+       methodinfo *m;
+       s4          i;
+
+       /* try to find the method in the class */
+
+       m = class_findmethod(c, name, desc);
+
+       if (m != NULL)
+               return m;
+
+       /* no method found? try the superinterfaces */
+
+       for (i = 0; i < c->interfacescount; i++) {
+               m = class_resolveinterfacemethod_intern(c->interfaces[i].cls,
+                                                                                                       name, desc);
+
+               if (m != NULL)
+                       return m;
+       }
+
+       /* no method found */
+
+       return NULL;
+}
+
+
+/* class_resolveclassmethod ****************************************************
+       
+   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_resolveclassmethod(classinfo *c, utf *name, utf *desc,
+                                                                        classinfo *referer, bool throwexception)
+{
+       classinfo  *cls;
+       methodinfo *m;
+       s4          i;
+
+/*     if (c->flags & ACC_INTERFACE) { */
+/*             if (throwexception) */
+/*                     *exceptionptr = */
+/*                             new_exception(string_java_lang_IncompatibleClassChangeError); */
+/*             return NULL; */
+/*     } */
+
+       /* try class c and its superclasses */
+
+       cls = c;
+
+       m = class_resolvemethod(cls, name, desc);
+
+       if (m != NULL)
+               goto found;
+
+       /* try the superinterfaces */
+
+       for (i = 0; i < c->interfacescount; i++) {
+               m = class_resolveinterfacemethod_intern(c->interfaces[i].cls,
+                                                                                               name, desc);
+
+               if (m != NULL)
+                       goto found;
+       }
+       
+       if (throwexception)
+               exceptions_throw_nosuchmethoderror(c, name, desc);
+
+       return NULL;
+
+ found:
+       if ((m->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) {
+               if (throwexception)
+                       exceptions_throw_abstractmethoderror();
+
+               return NULL;
+       }
+
+       /* XXX check access rights */
+
+       return m;
+}
+
+
+/* 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 throwexception)
+{
+       methodinfo *mi;
+
+       if (!(c->flags & ACC_INTERFACE)) {
+               if (throwexception)
+                       *exceptionptr =
+                               new_exception(string_java_lang_IncompatibleClassChangeError);
+
+               return NULL;
+       }
+
+       mi = class_resolveinterfacemethod_intern(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 (throwexception)
+               *exceptionptr =
+                       exceptions_new_nosuchmethoderror(c, name, desc);
+
+       return NULL;
+}
+
+
+/* class_findfield *************************************************************
+       
+   Searches for field with specified name and type in a classinfo
+   structure. If no such field is found NULL is returned.
+
+*******************************************************************************/
+
+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]);
+
+       if (c->super.cls)
+               return class_findfield(c->super.cls, name, desc);
+
+       return NULL;
+}
+
+
+/* class_findfield_approx ******************************************************
+       
+   Searches in 'classinfo'-structure for a field with the specified
+   name.
+
+*******************************************************************************/
+fieldinfo *class_findfield_by_name(classinfo *c, utf *name)
+{
+       s4 i;
+
+       /* get field index */
+
+       i = class_findfield_index_by_name(c, name);
+
+       /* field was not found, return */
+
+       if (i == -1)
+               return NULL;
+
+       /* return field address */
+
+       return &(c->fields[i]);
+}
+
+
+s4 class_findfield_index_by_name(classinfo *c, utf *name)
+{
+       s4 i;
+
+       for (i = 0; i < c->fieldscount; i++) {
+               /* compare field names */
+
+               if ((c->fields[i].name == name))
+                       return i;
+       }
+
+       /* field was not found, raise exception */      
+
+       *exceptionptr = new_exception(string_java_lang_NoSuchFieldException);
+
+       return -1;
+}
+
+
+/****************** 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)
+{
+       fieldinfo *fi;
+       s4         i;
+
+       /* 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].cls, name, desc);
+               if (fi)
+                       return fi;
+       }
+
+       /* try superclass */
+
+       if (c->super.cls)
+               return class_resolvefield_int(c->super.cls, 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 the return value is NULL. If EXCEPT is
+    true *exceptionptr is set, too.
+
+*******************************************************************************/
+
+fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc,
+                                                         classinfo *referer, bool throwexception)
+{
+       fieldinfo *fi;
+
+       fi = class_resolvefield_int(c, name, desc);
+
+       if (!fi) {
+               if (throwexception)
+                       *exceptionptr =
+                               new_exception_utfmessage(string_java_lang_NoSuchFieldError,
+                                                                                name);
+
+               return NULL;
+       }
+
+       /* XXX check access rights */
+
+       return fi;
+}
+
+
+/* class_issubclass ************************************************************
+
+   Checks if sub is a descendant of super.
+       
+*******************************************************************************/
+
+bool class_issubclass(classinfo *sub, classinfo *super)
+{
+       for (;;) {
+               if (!sub)
+                       return false;
+
+               if (sub == super)
+                       return true;
+
+               sub = sub->super.cls;
+       }
+}
+
+
+/* class_printflags ************************************************************
+
+   Prints flags of a class.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void class_printflags(classinfo *c)
+{
+       if (c == NULL) {
+               printf("NULL");
+               return;
+       }
+
+       if (c->flags & ACC_PUBLIC)       printf(" PUBLIC");
+       if (c->flags & ACC_PRIVATE)      printf(" PRIVATE");
+       if (c->flags & ACC_PROTECTED)    printf(" PROTECTED");
+       if (c->flags & ACC_STATIC)       printf(" STATIC");
+       if (c->flags & ACC_FINAL)        printf(" FINAL");
+       if (c->flags & ACC_SYNCHRONIZED) printf(" SYNCHRONIZED");
+       if (c->flags & ACC_VOLATILE)     printf(" VOLATILE");
+       if (c->flags & ACC_TRANSIENT)    printf(" TRANSIENT");
+       if (c->flags & ACC_NATIVE)       printf(" NATIVE");
+       if (c->flags & ACC_INTERFACE)    printf(" INTERFACE");
+       if (c->flags & ACC_ABSTRACT)     printf(" ABSTRACT");
+}
+#endif
+
+
+/* class_print *****************************************************************
+
+   Prints classname plus flags.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void class_print(classinfo *c)
+{
+       if (c == NULL) {
+               printf("NULL");
+               return;
+       }
+
+       utf_display_printable_ascii(c->name);
+       class_printflags(c);
+}
+#endif
+
+
+/* class_classref_print ********************************************************
+
+   Prints classname plus referer class.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void class_classref_print(constant_classref *cr)
+{
+       if (cr == NULL) {
+               printf("NULL");
+               return;
+       }
+
+       utf_display_printable_ascii(cr->name);
+       printf("(ref.by ");
+       if (cr->referer)
+               class_print(cr->referer);
+       else
+               printf("NULL");
+       printf(")");
+}
+#endif
+
+
+/* class_println ***************************************************************
+
+   Prints classname plus flags and new line.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void class_println(classinfo *c)
+{
+       class_print(c);
+       printf("\n");
+}
+#endif
+
+
+/* class_classref_println ******************************************************
+
+   Prints classname plus referer class and new line.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void class_classref_println(constant_classref *cr)
+{
+       class_classref_print(cr);
+       printf("\n");
+}
+#endif
+
+
+/* class_classref_or_classinfo_print *******************************************
+
+   Prints classname plus referer class.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void class_classref_or_classinfo_print(classref_or_classinfo c)
+{
+       if (c.any == NULL) {
+               printf("(classref_or_classinfo) NULL");
+               return;
+       }
+       if (IS_CLASSREF(c))
+               class_classref_print(c.ref);
+       else
+               class_print(c.cls);
+}
+#endif
+
+
+/* class_classref_or_classinfo_println *****************************************
+
+   Prints classname plus referer class and a newline.
+
+*******************************************************************************/
+
+void class_classref_or_classinfo_println(classref_or_classinfo c)
+{
+       class_classref_or_classinfo_println(c);
+       printf("\n");
+}
+
+
+/* class_showconstantpool ******************************************************
+
+   Dump the constant pool of the given class to stdout.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void class_showconstantpool (classinfo *c) 
+{
+       u4 i;
+       voidptr e;
+
+       printf ("---- dump of constant pool ----\n");
+
+       for (i=0; i<c->cpcount; i++) {
+               printf ("#%d:  ", (int) i);
+               
+               e = c -> cpinfos [i];
+               if (e) {
+                       
+                       switch (c -> cptags [i]) {
+                       case CONSTANT_Class:
+                               printf ("Classreference -> ");
+                               utf_display_printable_ascii ( ((constant_classref*)e) -> name );
+                               break;
+                       case CONSTANT_Fieldref:
+                               printf ("Fieldref -> ");
+                               field_fieldref_print((constant_FMIref *) e);
+                               break;
+                       case CONSTANT_Methodref:
+                               printf ("Methodref -> ");
+                               method_methodref_print((constant_FMIref *) e);
+                               break;
+                       case CONSTANT_InterfaceMethodref:
+                               printf ("InterfaceMethod -> ");
+                               method_methodref_print((constant_FMIref *) e);
+                               break;
+                       case CONSTANT_String:
+                               printf ("String -> ");
+                               utf_display_printable_ascii (e);
+                               break;
+                       case CONSTANT_Integer:
+                               printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) );
+                               break;
+                       case CONSTANT_Float:
+                               printf ("Float -> %f", ((constant_float*)e) -> value);
+                               break;
+                       case CONSTANT_Double:
+                               printf ("Double -> %f", ((constant_double*)e) -> value);
+                               break;
+                       case CONSTANT_Long:
+                               {
+                                       u8 v = ((constant_long*)e) -> value;
+#if U8_AVAILABLE
+                                       printf ("Long -> %ld", (long int) v);
+#else
+                                       printf ("Long -> HI: %ld, LO: %ld\n", 
+                                                       (long int) v.high, (long int) v.low);
+#endif 
+                               }
+                               break;
+                       case CONSTANT_NameAndType:
+                               {
+                                       constant_nameandtype *cnt = e;
+                                       printf ("NameAndType: ");
+                                       utf_display_printable_ascii (cnt->name);
+                                       printf (" ");
+                                       utf_display_printable_ascii (cnt->descriptor);
+                               }
+                               break;
+                       case CONSTANT_Utf8:
+                               printf ("Utf8 -> ");
+                               utf_display_printable_ascii (e);
+                               break;
+                       default: 
+                               log_text("Invalid type of ConstantPool-Entry");
+                               assert(0);
+                       }
+               }
+
+               printf ("\n");
+       }
+}
+#endif /* !defined(NDEBUG) */
+
+
+/* class_showmethods ***********************************************************
+
+   Dump info about the fields and methods of the given class to stdout.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void class_showmethods (classinfo *c)
+{
+       s4 i;
+       
+       printf("--------- Fields and Methods ----------------\n");
+       printf("Flags: ");
+       class_printflags(c);
+       printf("\n");
+
+       printf("This: ");
+       utf_display_printable_ascii(c->name);
+       printf("\n");
+
+       if (c->super.cls) {
+               printf("Super: ");
+               utf_display_printable_ascii(c->super.cls->name);
+               printf ("\n");
+       }
+
+       printf("Index: %d\n", c->index);
+       
+       printf("Interfaces:\n");        
+       for (i = 0; i < c->interfacescount; i++) {
+               printf("   ");
+               utf_display_printable_ascii(c->interfaces[i].cls->name);
+               printf (" (%d)\n", c->interfaces[i].cls->index);
+       }
+
+       printf("Fields:\n");
+       for (i = 0; i < c->fieldscount; i++)
+               field_println(&(c->fields[i]));
+
+       printf("Methods:\n");
+       for (i = 0; i < c->methodscount; i++) {
+               methodinfo *m = &(c->methods[i]);
+
+               if (!(m->flags & ACC_STATIC))
+                       printf("vftblindex: %d   ", m->vftblindex);
+
+               method_println(m);
+       }
+
+       printf ("Virtual function table:\n");
+       for (i = 0; i < c->vftbl->vftbllength; i++)
+               printf ("entry: %d,  %ld\n", i, (long int) (c->vftbl->table[i]));
 }
+#endif /* !defined(NDEBUG) */
 
 
 /*
@@ -548,4 +1406,5 @@ classinfo *class_multiarray_of(s4 dim, classinfo *element)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */