* ICMD_CHECKASIZE, ICMD_CHECKEXCEPTION: Removed.
[cacao.git] / src / vm / class.c
index d191532ae9fa2553ec030d5f8e6964e9ffdf949f..394da80f6b44157e0046e3590feb2fd8d8ba7029 100644 (file)
@@ -30,7 +30,7 @@
             Andreas Krall
             Christian Thalinger
 
-   $Id: class.c 2193 2005-04-02 19:33:43Z edwin $
+   $Id: class.c 3292 2005-09-28 10:36:34Z twisti $
 
 */
 
 
 #include "toolbox/logging.h"
 #include "vm/class.h"
+#include "vm/classcache.h"
+#include "vm/exceptions.h"
+#include "vm/loader.h"
 #include "vm/options.h"
 #include "vm/resolve.h"
 #include "vm/statistics.h"
 #include "vm/tables.h"
 #include "vm/utf8.h"
-#include "vm/loader.h"
 
 
 /******************************************************************************/
@@ -76,8 +78,6 @@
 
 /* global variables ***********************************************************/
 
-hashtable class_hash;                   /* hashtable for classes              */
-
 list unlinkedclasses;                   /* this is only used for eager class  */
                                         /* loading                            */
 
@@ -93,6 +93,9 @@ classinfo *class_java_lang_Cloneable = NULL;
 classinfo *class_java_lang_SecurityManager = NULL;
 classinfo *class_java_lang_String = NULL;
 classinfo *class_java_lang_System = NULL;
+classinfo *class_java_lang_Thread = NULL;
+classinfo *class_java_lang_ThreadGroup = NULL;
+classinfo *class_java_lang_VMThread = NULL;
 classinfo *class_java_io_Serializable = NULL;
 
 
@@ -100,10 +103,12 @@ classinfo *class_java_io_Serializable = NULL;
 
 classinfo *class_java_lang_Throwable = NULL;
 classinfo *class_java_lang_VMThrowable = NULL;
-classinfo *class_java_lang_Exception = NULL;
 classinfo *class_java_lang_Error = NULL;
-classinfo *class_java_lang_OutOfMemoryError = NULL;
 classinfo *class_java_lang_NoClassDefFoundError = NULL;
+classinfo *class_java_lang_OutOfMemoryError = NULL;
+
+classinfo *class_java_lang_Exception = NULL;
+classinfo *class_java_lang_ClassNotFoundException = NULL;
 
 classinfo *class_java_lang_Void = NULL;
 classinfo *class_java_lang_Boolean = NULL;
@@ -115,10 +120,18 @@ classinfo *class_java_lang_Long = NULL;
 classinfo *class_java_lang_Float = NULL;
 classinfo *class_java_lang_Double = NULL;
 
+
 /* some classes which may be used more often */
 
+classinfo *class_java_lang_StackTraceElement = NULL;
+classinfo *class_java_lang_reflect_Constructor = NULL;
+classinfo *class_java_lang_reflect_Field = NULL;
+classinfo *class_java_lang_reflect_Method = NULL;
+classinfo *class_java_security_PrivilegedAction = NULL;
 classinfo *class_java_util_Vector = NULL;
 
+classinfo *arrayclass_java_lang_Object = NULL;
+
 
 /* pseudo classes for the typechecker */
 
@@ -126,118 +139,68 @@ classinfo *pseudo_class_Arraystub = NULL;
 classinfo *pseudo_class_Null = NULL;
 classinfo *pseudo_class_New = NULL;
 
-/* class_new *******************************************************************
 
-   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.
+/* class_set_packagename *******************************************************
+
+   Derive the package name from the class name and store it in the struct.
 
 *******************************************************************************/
 
-classinfo *class_new(utf *classname)
+void class_set_packagename(classinfo *c)
 {
-    classinfo *c;
+       char *p = UTF_END(c->name) - 1;
+       char *start = c->name->text;
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-    tables_lock();
-#endif
+       /* set the package name */
+       /* classes in the unnamed package keep packagename == NULL */
 
-       /* we support eager class loading and linking on demand */
-       if (opt_eager) {
-               classinfo *tc;
-               classinfo *tmp;
+       if (c->name->text[0] == '[') {
+               /* set packagename of arrays to the element's package */
 
-               list_init(&unlinkedclasses, OFFSET(classinfo, listnode));
+               for (; *start == '['; start++);
 
-               if (!load_class_bootstrap(classname,&c)) {
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-                       tables_unlock();
-#endif
-                       return NULL;
-               }
+               /* skip the 'L' in arrays of references */
+               if (*start == 'L')
+                       start++;
 
-               /* link all referenced classes */
+               for (; (p > start) && (*p != '/'); --p);
 
-               tc = list_first(&unlinkedclasses);
+               c->packagename = utf_new(start, p - start);
 
-               while (tc) {
-                       /* skip the current loaded/linked class */
-                       if (tc != c) {
-                               if (!link_class(tc)) {
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-                                       tables_unlock();
-#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;
-               }
+       } else {
+               for (; (p > start) && (*p != '/'); --p);
 
-               if (!c->linked) {
-                       if (!link_class(c)) {
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-                               tables_unlock();
-#endif
-                               return c;
-                       }
-               }
-       }
-       else {
-               c = class_new_intern(classname);
+               c->packagename = utf_new(start, p - start);
        }
+}
 
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-    tables_unlock();
-#endif
+/* class_create_classinfo ******************************************************
 
-    return c;
-}
+   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_intern(utf *classname)
-{
-       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];
-
-       /* 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;
-               }
-                       
-       nomatch:
-               c = c->hashlink; /* next element in external chain */
-       }
+*******************************************************************************/
 
-       /* location in hashtable found, create new classinfo structure */
+classinfo *class_create_classinfo(utf *classname)
+{
+       classinfo *c;
 
 #if defined(STATISTICS)
        if (opt_stat)
                count_class_infos += sizeof(classinfo);
 #endif
 
-       if (initverbose) {
-               char logtext[MAXLOGTEXT];
-               sprintf(logtext, "Creating class: ");
-               utf_sprint_classname(logtext + strlen(logtext), classname);
-               log_text(logtext);
-       }
+       /* we use a safe name for temporarily unnamed classes */
+       if (!classname)
+               classname = utf_not_named_yet;
+
+       if (initverbose)
+               log_message_utf("Creating class: ", classname);
 
        c = GCNEW(classinfo, 1); /*JOWENN: NEW*/
        /*c=NEW(classinfo);*/
@@ -278,63 +241,8 @@ classinfo *class_new_intern(utf *classname)
        c->classloader = NULL;
        c->sourcefile = NULL;
        
-       /* insert class into the hashtable */
-       c->hashlink = class_hash.ptr[slot];
-       class_hash.ptr[slot] = c;
-
-       /* update number of hashtable-entries */
-       class_hash.entries++;
-
-       if (class_hash.entries > (class_hash.size * 2)) {
-
-               /* reorganization of hashtable, average length of 
-                  the external chains is approx. 2                */  
-
-               u4 i;
-               classinfo *c;
-               hashtable newhash;  /* the new hashtable */
-
-               /* create new hashtable, double the size */
-               init_hashtable(&newhash, class_hash.size * 2);
-               newhash.entries = class_hash.entries;
-
-               /* 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;
-       }
-
-       /* 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;
-
-       } 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;
-                       }
-               }
+       if (classname != utf_not_named_yet) {
+               class_set_packagename(c);
        }
 
 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
@@ -344,97 +252,6 @@ classinfo *class_new_intern(utf *classname)
        return c;
 }
 
-
-/* class_get *******************************************************************
-
-   Searches for the class with the specified name in the classes
-   hashtable if there is no such class NULL is returned.
-
-*******************************************************************************/
-
-classinfo *class_get(utf *classname)
-{
-       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];
-
-       /* 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;
-               }
-                       
-       nomatch:
-               c = c->hashlink;
-       }
-
-       /* class not found */
-       return NULL;
-}
-
-
-/* class_remove ****************************************************************
-
-   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.
-
-*******************************************************************************/
-
-bool class_remove(classinfo *c)
-{
-       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;
-
-                       /* class found in hashtable */
-                       if (!pc)
-                               class_hash.ptr[slot] = tc->hashlink;
-                       else
-                               pc->hashlink = tc->hashlink;
-
-                       class_free(tc);
-
-                       return true;
-               }
-                       
-       nomatch:
-               pc = tc;
-               tc = tc->hashlink;
-       }
-
-       /* class not found */
-       return false;
-}
-
-
 /* class_freepool **************************************************************
 
        Frees all resources used by this classes Constant Pool.
@@ -487,6 +304,56 @@ static void class_freecpool(classinfo *c)
 }
 
 
+/* class_getconstant ***********************************************************
+
+   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.
+
+*******************************************************************************/
+
+voidptr class_getconstant(classinfo *c, u4 pos, u4 ctype)
+{
+       /* check index and type of constantpool entry */
+       /* (pos == 0 is caught by type comparison) */
+
+       if (pos >= c->cpcount || c->cptags[pos] != ctype) {
+               *exceptionptr = new_classformaterror(c, "Illegal constant pool index");
+               return NULL;
+       }
+
+       return c->cpinfos[pos];
+}
+
+
+/* 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;
+       }
+
+       /* constantpool entry of type 0 */      
+       if (!c->cptags[pos])
+               return NULL;
+
+       /* 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_free ******************************************************************
 
    Frees all resources used by the class.
@@ -542,6 +409,47 @@ void class_free(classinfo *c)
 }
 
 
+/* get_array_class *************************************************************
+
+   Returns the array class with the given name for the given
+   classloader, or NULL if an exception occurred.
+
+   Note: This function does eager loading. 
+
+*******************************************************************************/
+
+static classinfo *get_array_class(utf *name,java_objectheader *initloader,
+                                                                                       java_objectheader *defloader,bool link)
+{
+       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_ASSERT(c);
+       CLASS_ASSERT(c->loaded);
+       CLASS_ASSERT(c->classloader == defloader);
+
+       if (link && !c->linked)
+               if (!link_class(c))
+                       return NULL;
+
+       CLASS_ASSERT(!link || c->linked);
+
+       return c;
+}
+
+
 /* class_array_of **************************************************************
 
    Returns an array class with the given component class. The array
@@ -549,11 +457,10 @@ void class_free(classinfo *c)
 
 *******************************************************************************/
 
-classinfo *class_array_of(classinfo *component)
+classinfo *class_array_of(classinfo *component, bool link)
 {
     s4 namelen;
     char *namebuf;
-       classinfo *c;
 
     /* Assemble the array class name */
     namelen = component->name->blength;
@@ -575,17 +482,10 @@ classinfo *class_array_of(classinfo *component)
         namelen += 3;
     }
 
-       c = class_new(utf_new(namebuf, namelen));
-
-       /* load this class and link it */
-
-       c->loaded = true;
-
-       if (!c->linked)
-               if (!link_class(c))
-                       return NULL;
-
-    return c;
+       return get_array_class(utf_new(namebuf, namelen),
+                                                  component->classloader,
+                                                  component->classloader,
+                                                  link);
 }
 
 
@@ -596,13 +496,15 @@ 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;
 
-       if (dim < 1)
-               panic("Invalid array dimension requested");
+       if (dim < 1) {
+               log_text("Invalid array dimension requested");
+               assert(0);
+       }
 
     /* Assemble the array class name */
     namelen = element->name->blength;
@@ -623,9 +525,13 @@ classinfo *class_multiarray_of(s4 dim, classinfo *element)
     }
        memset(namebuf, '[', dim);
 
-    return class_new(utf_new(namebuf, namelen));
+       return get_array_class(utf_new(namebuf, namelen),
+                                                  element->classloader,
+                                                  element->classloader,
+                                                  link);
 }
 
+
 /* class_lookup_classref *******************************************************
 
    Looks up the constant_classref for a given classname in the classref
@@ -641,7 +547,7 @@ classinfo *class_multiarray_of(s4 dim, classinfo *element)
    
 *******************************************************************************/
 
-constant_classref *class_lookup_classref(classinfo *cls,utf *name)
+constant_classref *class_lookup_classref(classinfo *cls, utf *name)
 {
        constant_classref *ref;
        extra_classref *xref;
@@ -659,7 +565,7 @@ constant_classref *class_lookup_classref(classinfo *cls,utf *name)
                        return ref;
 
        /* next try the list of extra classrefs */
-       for (xref=cls->extclassrefs; xref; xref=xref->next) {
+       for (xref = cls->extclassrefs; xref; xref = xref->next) {
                if (xref->classref.name == name)
                        return &(xref->classref);
        }
@@ -685,7 +591,7 @@ constant_classref *class_lookup_classref(classinfo *cls,utf *name)
    
 *******************************************************************************/
 
-constant_classref *class_get_classref(classinfo *cls,utf *name)
+constant_classref *class_get_classref(classinfo *cls, utf *name)
 {
        constant_classref *ref;
        extra_classref *xref;
@@ -706,6 +612,26 @@ constant_classref *class_get_classref(classinfo *cls,utf *name)
        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
@@ -724,7 +650,7 @@ constant_classref *class_get_classref(classinfo *cls,utf *name)
 
 *******************************************************************************/
 
-constant_classref *class_get_classref_multiarray_of(s4 dim,constant_classref *ref)
+constant_classref *class_get_classref_multiarray_of(s4 dim, constant_classref *ref)
 {
     s4 namelen;
     char *namebuf;
@@ -790,7 +716,7 @@ constant_classref *class_get_classref_component_of(constant_classref *ref)
                return NULL;
        }
 
-    return class_get_classref(ref->referer,utf_new(name, namelen));
+    return class_get_classref(ref->referer, utf_new(name, namelen));
 }