* src/vm/jit/replace.c (replace_create_replacement_points): Don't use
[cacao.git] / src / vm / linker.c
index e080a679e051b2757c2f09b7f58631713c85b067..bb2a8e13963383db1c0fd9ca036474a019f79c5c 100644 (file)
@@ -1,9 +1,9 @@
 /* src/vm/linker.c - class linker 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
 
             Edwin Steiner
             Christian Thalinger
 
-   $Id: linker.c 3292 2005-09-28 10:36:34Z twisti $
+   $Id: linker.c 4551 2006-03-03 00:00:39Z twisti $
 
 */
 
 
+#include "config.h"
+
 #include <assert.h>
 
+#include "vm/types.h"
+
 #include "mm/memory.h"
 #include "native/native.h"
 #include "vm/builtin.h"
@@ -50,7 +54,7 @@
 #include "vm/resolve.h"
 #include "vm/statistics.h"
 #include "vm/stringlocal.h"
-#include "vm/jit/codegen.inc.h"
+#include "vm/access.h"
 
 
 /* global variables ***********************************************************/
@@ -109,6 +113,19 @@ bool linker_init(void)
 
        interfaceindex = 0;
 
+       /* link java.lang.Class as first class of the system, because we
+       need it's vftbl for all other classes so we can use a class as
+       object */
+
+       if (!link_class(class_java_lang_Class))
+               return false;
+
+       /* now set the header.vftbl of all classes which were created
+       before java.lang.Class was linked */
+
+       class_postset_header_vftbl();
+
+
        /* link important system classes */
 
        if (!link_class(class_java_lang_Object))
@@ -156,9 +173,6 @@ bool linker_init(void)
 
        /* load some other important classes */
 
-       if (!link_class(class_java_lang_Class))
-               return false;
-
        if (!link_class(class_java_lang_ClassLoader))
                return false;
 
@@ -206,14 +220,14 @@ bool linker_init(void)
 
     /* pseudo class for Arraystubs (extends java.lang.Object) */
     
-    pseudo_class_Arraystub =
+       pseudo_class_Arraystub =
                class_create_classinfo(utf_new_char("$ARRAYSTUB$"));
-       pseudo_class_Arraystub->loaded = true;
-    pseudo_class_Arraystub->super.cls = class_java_lang_Object;
-    pseudo_class_Arraystub->interfacescount = 2;
-    pseudo_class_Arraystub->interfaces = MNEW(classref_or_classinfo, 2);
-    pseudo_class_Arraystub->interfaces[0].cls = class_java_lang_Cloneable;
-    pseudo_class_Arraystub->interfaces[1].cls = class_java_io_Serializable;
+       pseudo_class_Arraystub->state |= CLASS_LOADED;
+       pseudo_class_Arraystub->super.cls = class_java_lang_Object;
+       pseudo_class_Arraystub->interfacescount = 2;
+       pseudo_class_Arraystub->interfaces = MNEW(classref_or_classinfo, 2);
+       pseudo_class_Arraystub->interfaces[0].cls = class_java_lang_Cloneable;
+       pseudo_class_Arraystub->interfaces[1].cls = class_java_io_Serializable;
 
        if (!classcache_store_unique(pseudo_class_Arraystub)) {
                log_text("could not cache pseudo_class_Arraystub");
@@ -224,9 +238,9 @@ bool linker_init(void)
                return false;
 
        /* pseudo class representing the null type */
-    
+
        pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$"));
-       pseudo_class_Null->loaded = true;
+       pseudo_class_Null->state |= CLASS_LOADED;
        pseudo_class_Null->super.cls = class_java_lang_Object;
 
        if (!classcache_store_unique(pseudo_class_Null)) {
@@ -240,8 +254,8 @@ bool linker_init(void)
        /* pseudo class representing new uninitialized objects */
     
        pseudo_class_New = class_create_classinfo(utf_new_char("$NEW$"));
-       pseudo_class_New->loaded = true;
-       pseudo_class_New->linked = true; /* XXX is this allright? */
+       pseudo_class_New->state |= CLASS_LOADED;
+       pseudo_class_New->state |= CLASS_LINKED; /* XXX is this allright? */
        pseudo_class_New->super.cls = class_java_lang_Object;
 
        if (!classcache_store_unique(pseudo_class_New)) {
@@ -287,12 +301,10 @@ static bool link_primitivetype_table(void)
                c = class_create_classinfo(utf_new_char(primitivetype_table[i].name));
 
                c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
-               c->classUsed = NOTUSED; /* not used initially CO-RT */
-               c->impldBy = NULL;
                
                /* prevent loader from loading primitive class */
 
-               c->loaded = true;
+               c->state |= CLASS_LOADED;
 
                /* INFO: don't put primitive classes into the classcache */
 
@@ -309,8 +321,6 @@ static bool link_primitivetype_table(void)
                        return false;
 
                primitivetype_table[i].class_wrap = c;
-               primitivetype_table[i].class_wrap->classUsed = NOTUSED; /* not used initially CO-RT */
-               primitivetype_table[i].class_wrap->impldBy = NULL;
 
                /* create the primitive array class */
 
@@ -323,8 +333,9 @@ static bool link_primitivetype_table(void)
 
                        primitivetype_table[i].arrayclass = c;
 
-                       assert(c->loaded);
-                       if (!c->linked)
+                       assert(c->state & CLASS_LOADED);
+
+                       if (!(c->state & CLASS_LINKED))
                                if (!link_class(c))
                                        return false;
 
@@ -348,7 +359,7 @@ classinfo *link_class(classinfo *c)
        classinfo *r;
 
        if (!c) {
-               *exceptionptr = new_nullpointerexception();
+               exceptions_throw_nullpointerexception();
                return NULL;
        }
 
@@ -359,7 +370,8 @@ classinfo *link_class(classinfo *c)
 #endif
 
        /* maybe the class is already linked */
-       if (c->linked) {
+
+       if (c->state & CLASS_LINKED) {
 #if defined(USE_THREADS)
                builtin_monitorexit((java_objectheader *) c);
 #endif
@@ -367,7 +379,7 @@ classinfo *link_class(classinfo *c)
                return c;
        }
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        /* measure time */
 
        if (getcompilingtime)
@@ -384,9 +396,9 @@ classinfo *link_class(classinfo *c)
        /* if return value is NULL, we had a problem and the class is not linked */
 
        if (!r)
-               c->linked = false;
+               c->state &= ~CLASS_LINKING;
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        /* measure time */
 
        if (getloadingtime)
@@ -425,9 +437,9 @@ static classinfo *link_class_intern(classinfo *c)
        s4 i,j;                       /* interface/method/field counter           */
        arraydescriptor *arraydesc;   /* descriptor for array classes             */
 
-       /* maybe the class is already linked */
+       /* the class is already linked */
 
-       if (c->linked)
+       if (c->state & CLASS_LINKED)
                return c;
 
        if (linkverbose)
@@ -435,13 +447,22 @@ static classinfo *link_class_intern(classinfo *c)
 
        /* the class must be loaded */
 
-       if (!c->loaded)
-               throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                  "Trying to link unloaded class");
+       /* XXX should this be a specific exception? */
+       assert(c->state & CLASS_LOADED);
 
-       /* ok, this class is somewhat linked */
+       /* cache the self-reference of this class                          */
+       /* we do this for cases where the defining loader of the class     */
+       /* has not yet been recorded as an initiating loader for the class */
+       /* this is needed so subsequent code can assume that self-refs     */
+       /* will always resolve lazily                                      */
+       /* No need to do it for the bootloader - it is always registered   */
+       /* as initiating loader for the classes it loads.                  */
+       if (c->classloader)
+               classcache_store(c->classloader,c,false);
 
-       c->linked = true;
+       /* this class is currently linking */
+
+       c->state |= CLASS_LINKING;
 
        arraydesc = NULL;
 
@@ -465,7 +486,7 @@ static classinfo *link_class_intern(classinfo *c)
                        return NULL;
                }
 
-               assert(tc->loaded);
+               assert(tc->state & CLASS_LOADED);
 
                if (!(tc->flags & ACC_INTERFACE)) {
                        *exceptionptr =
@@ -474,7 +495,7 @@ static classinfo *link_class_intern(classinfo *c)
                        return NULL;
                }
 
-               if (!tc->linked)
+               if (!(tc->state & CLASS_LINKED))
                        if (!link_class(tc))
                                return NULL;
        }
@@ -485,8 +506,6 @@ static classinfo *link_class_intern(classinfo *c)
 
        if (c->super.any == NULL) {                     /* class java.lang.Object */
                c->index = 0;
-        c->classUsed = USED;              /* Object class is always used CO-RT*/
-               c->impldBy = NULL;
                c->instancesize = sizeof(java_objectheader);
                
                vftbllength = supervftbllength = 0;
@@ -510,7 +529,7 @@ static classinfo *link_class_intern(classinfo *c)
                        return NULL;
                }
 
-               assert(super->loaded);
+               assert(super->state & CLASS_LOADED);
 
                if (super->flags & ACC_INTERFACE) {
                        /* java.lang.IncompatibleClassChangeError: class a has interface java.lang.Cloneable as super class */
@@ -527,7 +546,7 @@ static classinfo *link_class_intern(classinfo *c)
                        return NULL;
                }
                
-               if (!super->linked)
+               if (!(super->state & CLASS_LINKED))
                        if (!link_class(super))
                                return NULL;
 
@@ -566,6 +585,15 @@ static classinfo *link_class_intern(classinfo *c)
                                                if (tc->methods[j].flags & ACC_PRIVATE)
                                                        goto notfoundvftblindex;
 
+                                               /* package-private methods in other packages */
+                                               /* must not be overridden                    */
+                                               /* (see Java Language Specification 8.4.8.1) */
+                                               if ( !(tc->methods[j].flags & (ACC_PUBLIC | ACC_PROTECTED)) 
+                                                        && !SAME_PACKAGE(c,tc) ) 
+                                               {
+                                                   goto notfoundvftblindex;
+                                               }
+
                                                if (tc->methods[j].flags & ACC_FINAL) {
                                                        /* class a overrides final method . */
                                                        *exceptionptr =
@@ -589,7 +617,10 @@ static classinfo *link_class_intern(classinfo *c)
        }       
 
 
-       /* check interfaces of ABSTRACT class for unimplemented methods */
+       /* Check all interfaces of an abtract class (maybe be an interface
+          too) for unimplemented methods.  Such methods are called
+          miranda-methods and are marked with the ACC_MIRANDA flag.
+          VMClass.getDeclaredMethods does not return such methods. */
 
        if (c->flags & ACC_ABSTRACT) {
                classinfo  *ic;
@@ -600,6 +631,8 @@ static classinfo *link_class_intern(classinfo *c)
 
                abstractmethodscount = 0;
 
+               /* check all interfaces of the abtract class */
+
                for (i = 0; i < c->interfacescount; i++) {
                        ic = c->interfaces[i].cls;
 
@@ -608,18 +641,14 @@ static classinfo *link_class_intern(classinfo *c)
 
                                /* skip `<clinit>' and `<init>' */
 
-                               if (im->name == utf_clinit || im->name == utf_init)
+                               if ((im->name == utf_clinit) || (im->name == utf_init))
                                        continue;
 
-                               tc = c;
-
-                               while (tc) {
+                               for (tc = c; tc != NULL; tc = tc->super.cls) {
                                        for (k = 0; k < tc->methodscount; k++) {
                                                if (method_canoverwrite(im, &(tc->methods[k])))
                                                        goto noabstractmethod;
                                        }
-
-                                       tc = tc->super.cls;
                                }
 
                                abstractmethodscount++;
@@ -645,27 +674,27 @@ static classinfo *link_class_intern(classinfo *c)
 
                                        /* skip `<clinit>' and `<init>' */
 
-                                       if (im->name == utf_clinit || im->name == utf_init)
+                                       if ((im->name == utf_clinit) || (im->name == utf_init))
                                                continue;
 
-                                       tc = c;
-
-                                       while (tc) {
+                                       for (tc = c; tc != NULL; tc = tc->super.cls) {
                                                for (k = 0; k < tc->methodscount; k++) {
                                                        if (method_canoverwrite(im, &(tc->methods[k])))
                                                                goto noabstractmethod2;
                                                }
-
-                                               tc = tc->super.cls;
                                        }
 
+                                       /* Copy the method found into the new c->methods
+                                          array and tag it as miranda-method. */
+
                                        am = &(c->methods[c->methodscount]);
                                        c->methodscount++;
 
                                        MCOPY(am, im, methodinfo, 1);
 
-                                       am->vftblindex = (vftbllength++);
-                                       am->class = c;
+                                       am->vftblindex  = (vftbllength++);
+                                       am->class       = c;
+                                       am->flags      |= ACC_MIRANDA;
 
                                noabstractmethod2:
                                        ;
@@ -675,7 +704,7 @@ static classinfo *link_class_intern(classinfo *c)
        }
 
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        if (opt_stat)
                count_vftbl_len +=
                        sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1));
@@ -701,7 +730,7 @@ static classinfo *link_class_intern(classinfo *c)
                                                          sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0)));
        v = (vftbl_t *) (((methodptr *) v) +
                                         (interfacetablelength - 1) * (interfacetablelength > 1));
-       c->header.vftbl = c->vftbl = v;
+       c->vftbl = v;
        v->class = c;
        v->vftbllength = vftbllength;
        v->interfacetablelength = interfacetablelength;
@@ -722,11 +751,21 @@ static classinfo *link_class_intern(classinfo *c)
        for (i = 0; i < c->methodscount; i++) {
                methodinfo *m = &(c->methods[i]);
 
-               /* Methods in ABSTRACT classes from interfaces maybe already have a   */
-               /* stubroutine.                                                       */
+               /* Methods in ABSTRACT classes from interfaces maybe already
+                  have a stubroutine. */
 
-               if (!m->stubroutine)
-                       m->stubroutine = createcompilerstub(m);
+               if (!m->stubroutine) {
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+                       if (opt_intrp)
+                               m->stubroutine = intrp_createcompilerstub(m);
+                       else
+#endif
+                               m->stubroutine = createcompilerstub(m);
+#else
+                       m->stubroutine = intrp_createcompilerstub(m);
+#endif
+               }
 
                if (!(m->flags & ACC_STATIC))
                        v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine;
@@ -739,7 +778,7 @@ static classinfo *link_class_intern(classinfo *c)
                fieldinfo *f = &(c->fields[i]);
                
                if (!(f->flags & ACC_STATIC)) {
-                       dsize = desc_typesize(f->descriptor);
+                       dsize = descriptor_typesize(f->parseddesc);
                        c->instancesize = ALIGN(c->instancesize, dsize);
                        f->offset = c->instancesize;
                        c->instancesize += dsize;
@@ -750,7 +789,7 @@ static classinfo *link_class_intern(classinfo *c)
        
        v->interfacevftbllength = MNEW(s4, interfacetablelength);
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        if (opt_stat)
                count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength;
 #endif
@@ -792,18 +831,16 @@ static classinfo *link_class_intern(classinfo *c)
                                                                                           &(m->exceptiontable[j].catchtype.cls)))
                                return NULL;
                }
-
-               for (j = 0; j < m->thrownexceptionscount; j++)
-                       if (!resolve_classref_or_classinfo(NULL, m->thrownexceptions[j],
-                                                                                          resolveEager, true, false,
-                                                                                          &(m->thrownexceptions[j].cls)))
-                               return NULL;
        }
        
        /* final tasks */
 
        linker_compute_subclasses(c);
 
+       /* revert the linking state and class is linked */
+
+       c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED;
+
        if (linkverbose)
                log_message_class("Linking done class: ", c);
 
@@ -839,28 +876,29 @@ static arraydescriptor *link_array(classinfo *c)
        switch (c->name->text[1]) {
        case '[':
                /* c is an array of arrays. */
-               u = utf_new_intern(c->name->text + 1, namelen - 1);
+               u = utf_new(c->name->text + 1, namelen - 1);
                if (!(comp = load_class_from_classloader(u, c->classloader)))
                        return NULL;
                break;
 
        case 'L':
                /* c is an array of objects. */
-               u = utf_new_intern(c->name->text + 2, namelen - 3);
+               u = utf_new(c->name->text + 2, namelen - 3);
                if (!(comp = load_class_from_classloader(u, c->classloader)))
                        return NULL;
                break;
        }
 
        /* If the component type has not been linked, link it now */
-       assert(!comp || comp->loaded);
-       if (comp && !comp->linked) {
 
+       assert(!comp || (comp->state & CLASS_LOADED));
+
+       if (comp && !(comp->state & CLASS_LINKED))
                if (!link_class(comp))
                        return NULL;
-       }
 
        /* Allocate the arraydescriptor */
+
        desc = NEW(arraydescriptor);
 
        if (comp) {
@@ -947,7 +985,7 @@ static arraydescriptor *link_array(classinfo *c)
                        break;
 
                default:
-                       *exceptionptr = new_classnotfoundexception(c->name);
+                       *exceptionptr = new_noclassdeffounderror(c->name);
                        return NULL;
                }
                
@@ -1057,7 +1095,7 @@ static void linker_addinterface(classinfo *c, classinfo *ic)
                v->interfacevftbllength[i] = ic->methodscount;
                v->interfacetable[-i] = MNEW(methodptr, ic->methodscount);
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
                if (opt_stat)
                        count_vftbl_len += sizeof(methodptr) *
                                (ic->methodscount + (ic->methodscount == 0));
@@ -1126,4 +1164,5 @@ static s4 class_highestinterface(classinfo *c)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */