X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Flinker.c;h=7e35e9545eacf163b52132d5223b2d42f13b4240;hb=460625b9f5efe2c48bbda24d59fe1f283a0cbf67;hp=040ab5700a2acfb03a33eb43a081dea7d54d8fc4;hpb=d5926e27b5d611a93122e06ca119ad4b1490b200;p=cacao.git diff --git a/src/vm/linker.c b/src/vm/linker.c index 040ab5700..7e35e9545 100644 --- a/src/vm/linker.c +++ b/src/vm/linker.c @@ -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. @@ -19,10 +19,10 @@ 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 @@ -32,13 +32,17 @@ Edwin Steiner Christian Thalinger - $Id: linker.c 2667 2005-06-13 14:26:04Z twisti $ + $Id: linker.c 5058 2006-06-28 21:46:41Z twisti $ */ +#include "config.h" + #include +#include "vm/types.h" + #include "mm/memory.h" #include "native/native.h" #include "vm/builtin.h" @@ -50,7 +54,10 @@ #include "vm/resolve.h" #include "vm/statistics.h" #include "vm/stringlocal.h" -#include "vm/jit/codegen.inc.h" +#include "vm/access.h" +#include "vm/rt-timing.h" +#include "vm/vm.h" +#include "vm/jit/asmpart.h" /* global variables ***********************************************************/ @@ -67,7 +74,7 @@ static s4 classvalue; primitive class. CAUTION: Don't change the order of the types. This table is indexed - by the ARRAYTYPE_ constants (expcept ARRAYTYPE_OBJECT). + by the ARRAYTYPE_ constants (except ARRAYTYPE_OBJECT). *******************************************************************************/ @@ -93,7 +100,7 @@ static classinfo *link_class_intern(classinfo *c); static arraydescriptor *link_array(classinfo *c); static void linker_compute_class_values(classinfo *c); static void linker_compute_subclasses(classinfo *c); -static void linker_addinterface(classinfo *c, classinfo *ic); +static bool linker_addinterface(classinfo *c, classinfo *ic); static s4 class_highestinterface(classinfo *c); @@ -109,6 +116,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 +176,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; @@ -168,9 +185,15 @@ bool linker_init(void) if (!link_class(class_java_lang_System)) return false; + if (!link_class(class_java_lang_Thread)) + return false; + if (!link_class(class_java_lang_ThreadGroup)) return false; + if (!link_class(class_java_lang_VMThread)) + return false; + /* some classes which may be used more often */ @@ -200,30 +223,30 @@ 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; - - if (!classcache_store(NULL, pseudo_class_Arraystub)) { + 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"); assert(0); } - if (!link_class(pseudo_class_Arraystub)) + if (!link_class(pseudo_class_Arraystub)) return false; - /* pseudo class representing the null type */ - + /* pseudo class representing the null type */ + pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$")); - pseudo_class_Null->loaded = true; - pseudo_class_Null->super.cls = class_java_lang_Object; + pseudo_class_Null->state |= CLASS_LOADED; + pseudo_class_Null->super.cls = class_java_lang_Object; - if (!classcache_store(NULL, pseudo_class_Null)) { + if (!classcache_store_unique(pseudo_class_Null)) { log_text("could not cache pseudo_class_Null"); assert(0); } @@ -231,14 +254,14 @@ bool linker_init(void) if (!link_class(pseudo_class_Null)) return false; - /* pseudo class representing new uninitialized objects */ + /* 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(NULL, pseudo_class_New)) { + if (!classcache_store_unique(pseudo_class_New)) { log_text("could not cache pseudo_class_New"); assert(0); } @@ -279,16 +302,15 @@ static bool link_primitivetype_table(void) /* create primitive class */ c = class_create_classinfo(utf_new_char(primitivetype_table[i].name)); - c->classUsed = NOTUSED; /* not used initially CO-RT */ - c->impldBy = NULL; + + c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; /* prevent loader from loading primitive class */ - c->loaded = true; - if (!classcache_store(NULL,c)) { - log_text("Could not cache primitive class"); - return false; - } + c->state |= CLASS_LOADED; + + /* INFO: don't put primitive classes into the classcache */ + if (!link_class(c)) return false; @@ -302,22 +324,21 @@ 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 */ if (primitivetype_table[i].arrayname) { u = utf_new_char(primitivetype_table[i].arrayname); c = class_create_classinfo(u); - - if (!load_newly_created_array(c, NULL)) + c = load_newly_created_array(c, NULL); + if (c == NULL) return false; 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; @@ -339,34 +360,40 @@ static bool link_primitivetype_table(void) classinfo *link_class(classinfo *c) { classinfo *r; +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_end; +#endif + + RT_TIMING_GET_TIME(time_start); if (!c) { - *exceptionptr = new_nullpointerexception(); + exceptions_throw_nullpointerexception(); return NULL; } -#if defined(USE_THREADS) +#if defined(ENABLE_THREADS) /* enter a monitor on the class */ builtin_monitorenter((java_objectheader *) c); #endif /* maybe the class is already linked */ - if (c->linked) { -#if defined(USE_THREADS) + + if (c->state & CLASS_LINKED) { +#if defined(ENABLE_THREADS) builtin_monitorexit((java_objectheader *) c); #endif return c; } -#if defined(STATISTICS) +#if defined(ENABLE_STATISTICS) /* measure time */ - if (getcompilingtime) + if (opt_getcompilingtime) compilingtime_stop(); - if (getloadingtime) + if (opt_getloadingtime) loadingtime_start(); #endif @@ -377,24 +404,28 @@ 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) + if (opt_getloadingtime) loadingtime_stop(); - if (getcompilingtime) + if (opt_getcompilingtime) compilingtime_start(); #endif -#if defined(USE_THREADS) +#if defined(ENABLE_THREADS) /* leave the monitor */ builtin_monitorexit((java_objectheader *) c); #endif + RT_TIMING_GET_TIME(time_end); + + RT_TIMING_TIME_DIFF(time_start,time_end,RT_TIMING_LINK_TOTAL); + return r; } @@ -417,24 +448,43 @@ static classinfo *link_class_intern(classinfo *c) vftbl_t *v; /* vftbl of current class */ s4 i,j; /* interface/method/field counter */ arraydescriptor *arraydesc; /* descriptor for array classes */ +#if defined(ENABLE_RT_TIMING) + struct timespec time_start, time_resolving, time_compute_vftbl, + time_abstract, time_compute_iftbl, time_fill_vftbl, + time_offsets, time_fill_iftbl, time_finalizer, + time_exceptions, time_subclasses; +#endif - /* maybe the class is already linked */ + RT_TIMING_GET_TIME(time_start); - if (c->linked) + /* the class is already linked */ + + if (c->state & CLASS_LINKED) return c; +#if !defined(NDEBUG) if (linkverbose) log_message_class("Linking class: ", c); +#endif /* 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; @@ -444,7 +494,7 @@ static classinfo *link_class_intern(classinfo *c) /* resolve this super interface */ if (!resolve_classref_or_classinfo(NULL, c->interfaces[i], resolveEager, - false, &tc)) + true, false, &tc)) return NULL; c->interfaces[i].cls = tc; @@ -458,7 +508,7 @@ static classinfo *link_class_intern(classinfo *c) return NULL; } - assert(tc->loaded); + assert(tc->state & CLASS_LOADED); if (!(tc->flags & ACC_INTERFACE)) { *exceptionptr = @@ -467,7 +517,7 @@ static classinfo *link_class_intern(classinfo *c) return NULL; } - if (!tc->linked) + if (!(tc->state & CLASS_LINKED)) if (!link_class(tc)) return NULL; } @@ -478,8 +528,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; @@ -489,7 +537,7 @@ static classinfo *link_class_intern(classinfo *c) } else { /* resolve super class */ - if (!resolve_classref_or_classinfo(NULL, c->super, resolveEager, false, + if (!resolve_classref_or_classinfo(NULL, c->super, resolveEager, true, false, &super)) return NULL; c->super.cls = super; @@ -503,7 +551,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 */ @@ -519,11 +567,17 @@ static classinfo *link_class_intern(classinfo *c) "Cannot inherit from final class"); return NULL; } + + /* link the superclass if necessary */ - if (!super->linked) + if (!(super->state & CLASS_LINKED)) if (!link_class(super)) return NULL; + /* OR the ACC_CLASS_HAS_POINTERS flag */ + + c->flags |= (super->flags & ACC_CLASS_HAS_POINTERS); + /* handle array classes */ if (c->name->text[0] == '[') @@ -536,11 +590,12 @@ static classinfo *link_class_intern(classinfo *c) c->index = super->index + 1; c->instancesize = super->instancesize; - + vftbllength = supervftbllength = super->vftbl->vftbllength; c->finalizer = super->finalizer; } + RT_TIMING_GET_TIME(time_resolving); /* compute vftbl length */ @@ -559,6 +614,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 = @@ -566,6 +630,21 @@ static classinfo *link_class_intern(classinfo *c) return NULL; } + /* method m overwrites method j of class tc */ + +#if defined(ENABLE_VERIFIER) + /* Add loading constraints (for the more general */ + /* types of method tc->methods[j]). -- */ + /* Not for , as it is not invoked virtually. */ + if ((m->name != utf_init) + && !classcache_add_constraints_for_params( + c->classloader, tc->classloader, + &(tc->methods[j]))) + { + return NULL; + } +#endif + m->vftblindex = tc->methods[j].vftblindex; goto foundvftblindex; } @@ -579,10 +658,15 @@ static classinfo *link_class_intern(classinfo *c) foundvftblindex: ; } - } + } + RT_TIMING_GET_TIME(time_compute_vftbl); - /* check interfaces of ABSTRACT class for unimplemented methods */ + /* Check all interfaces of an abstract 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; @@ -593,6 +677,8 @@ static classinfo *link_class_intern(classinfo *c) abstractmethodscount = 0; + /* check all interfaces of the abstract class */ + for (i = 0; i < c->interfacescount; i++) { ic = c->interfaces[i].cls; @@ -601,18 +687,14 @@ static classinfo *link_class_intern(classinfo *c) /* skip `' and `' */ - 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++; @@ -638,27 +720,27 @@ static classinfo *link_class_intern(classinfo *c) /* skip `' and `' */ - 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: ; @@ -666,9 +748,10 @@ static classinfo *link_class_intern(classinfo *c) } } } + RT_TIMING_GET_TIME(time_abstract); -#if defined(STATISTICS) +#if defined(ENABLE_STATISTICS) if (opt_stat) count_vftbl_len += sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1)); @@ -677,15 +760,16 @@ static classinfo *link_class_intern(classinfo *c) /* compute interfacetable length */ interfacetablelength = 0; - tc = c; - while (tc) { + + for (tc = c; tc != NULL; tc = tc->super.cls) { for (i = 0; i < tc->interfacescount; i++) { s4 h = class_highestinterface(tc->interfaces[i].cls) + 1; + if (h > interfacetablelength) interfacetablelength = h; } - tc = tc->super.cls; } + RT_TIMING_GET_TIME(time_compute_iftbl); /* allocate virtual function table */ @@ -694,11 +778,12 @@ 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; - v->class = c; - v->vftbllength = vftbllength; + + c->vftbl = v; + v->class = c; + v->vftbllength = vftbllength; v->interfacetablelength = interfacetablelength; - v->arraydesc = arraydesc; + v->arraydesc = arraydesc; /* store interface index in vftbl */ @@ -709,33 +794,49 @@ static classinfo *link_class_intern(classinfo *c) for (i = 0; i < supervftbllength; i++) v->table[i] = super->vftbl->table[i]; - + + /* Fill the remaining vftbl slots with the AbstractMethodError + stub (all after the super class slots, because they are already + initialized). */ + + for (; i < vftbllength; i++) + v->table[i] = (methodptr) (ptrint) &asm_abstractmethoderror; + /* add method stubs into virtual function table */ for (i = 0; i < c->methodscount; i++) { methodinfo *m = &(c->methods[i]); - /* Methods in ABSTRACT classes from interfaces maybe already have a */ - /* stubroutine. */ + assert(m->stubroutine == NULL); - if (!m->stubroutine) { - if (!(m->flags & ACC_NATIVE)) { - m->stubroutine = createcompilerstub(m); + /* Don't create a compiler stub for abstract methods as they + throw an AbstractMethodError with the default stub in the + vftbl. This entry is simply copied by sub-classes. */ - } else { - functionptr f = native_findfunction(c->name, - m->name, m->descriptor, - (m->flags & ACC_STATIC)); -#if defined(STATIC_CLASSPATH) - if (f) + if (m->flags & ACC_ABSTRACT) + continue; + +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + m->stubroutine = intrp_createcompilerstub(m); + else #endif - m->stubroutine = codegen_createnativestub(f, m); - } - } + m->stubroutine = createcompilerstub(m); +#else + m->stubroutine = intrp_createcompilerstub(m); +#endif + + /* static methods are not in the vftbl */ - if (!(m->flags & ACC_STATIC)) - v->table[m->vftblindex] = m->stubroutine; + if (m->flags & ACC_STATIC) + continue; + + /* insert the stubroutine into the vftbl */ + + v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine; } + RT_TIMING_GET_TIME(time_fill_vftbl); /* compute instance size and offset of each field */ @@ -744,18 +845,30 @@ 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); + + /* On i386 we only align to 4 bytes even for double and s8. */ + /* This matches what gcc does for struct members. We must */ + /* do the same as gcc here because the offsets in native */ + /* header structs like java_lang_Double must match the offsets */ + /* of the Java fields (eg. java.lang.Double.value). */ +#if defined(__I386__) + c->instancesize = ALIGN(c->instancesize, 4); +#else c->instancesize = ALIGN(c->instancesize, dsize); +#endif + f->offset = c->instancesize; c->instancesize += dsize; } } + RT_TIMING_GET_TIME(time_offsets); /* initialize interfacetable and interfacevftbllength */ - + v->interfacevftbllength = MNEW(s4, interfacetablelength); -#if defined(STATISTICS) +#if defined(ENABLE_STATISTICS) if (opt_stat) count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength; #endif @@ -764,12 +877,15 @@ static classinfo *link_class_intern(classinfo *c) v->interfacevftbllength[i] = 0; v->interfacetable[-i] = NULL; } - + /* add interfaces */ - + for (tc = c; tc != NULL; tc = tc->super.cls) for (i = 0; i < tc->interfacescount; i++) - linker_addinterface(c, tc->interfaces[i].cls); + if (!linker_addinterface(c, tc->interfaces[i].cls)) + return NULL; + + RT_TIMING_GET_TIME(time_fill_iftbl); /* add finalizer method (not for java.lang.Object) */ @@ -782,6 +898,7 @@ static classinfo *link_class_intern(classinfo *c) if (!(fi->flags & ACC_STATIC)) c->finalizer = fi; } + RT_TIMING_GET_TIME(time_finalizer); /* resolve exception class references */ @@ -793,24 +910,38 @@ static classinfo *link_class_intern(classinfo *c) continue; if (!resolve_classref_or_classinfo(NULL, m->exceptiontable[j].catchtype, - resolveEager, false, + resolveEager, true, false, &(m->exceptiontable[j].catchtype.cls))) return NULL; } - - for (j = 0; j < m->thrownexceptionscount; j++) - if (!resolve_classref_or_classinfo(NULL, m->thrownexceptions[j], - resolveEager, false, - &(m->thrownexceptions[j].cls))) - return NULL; } + RT_TIMING_GET_TIME(time_exceptions); /* final tasks */ linker_compute_subclasses(c); + RT_TIMING_GET_TIME(time_subclasses); + + /* revert the linking state and class is linked */ + + c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED; + +#if !defined(NDEBUG) if (linkverbose) log_message_class("Linking done class: ", c); +#endif + + RT_TIMING_TIME_DIFF(time_start ,time_resolving ,RT_TIMING_LINK_RESOLVE); + RT_TIMING_TIME_DIFF(time_resolving ,time_compute_vftbl,RT_TIMING_LINK_C_VFTBL); + RT_TIMING_TIME_DIFF(time_compute_vftbl,time_abstract ,RT_TIMING_LINK_ABSTRACT); + RT_TIMING_TIME_DIFF(time_abstract ,time_compute_iftbl,RT_TIMING_LINK_C_IFTBL); + RT_TIMING_TIME_DIFF(time_compute_iftbl,time_fill_vftbl ,RT_TIMING_LINK_F_VFTBL); + RT_TIMING_TIME_DIFF(time_fill_vftbl ,time_offsets ,RT_TIMING_LINK_OFFSETS); + RT_TIMING_TIME_DIFF(time_offsets ,time_fill_iftbl ,RT_TIMING_LINK_F_IFTBL); + RT_TIMING_TIME_DIFF(time_fill_iftbl ,time_finalizer ,RT_TIMING_LINK_FINALIZER); + RT_TIMING_TIME_DIFF(time_finalizer ,time_exceptions ,RT_TIMING_LINK_EXCEPTS); + RT_TIMING_TIME_DIFF(time_exceptions ,time_subclasses ,RT_TIMING_LINK_SUBCLASS); /* just return c to show that we didn't had a problem */ @@ -830,37 +961,43 @@ static classinfo *link_class_intern(classinfo *c) static arraydescriptor *link_array(classinfo *c) { - classinfo *comp = NULL; - s4 namelen = c->name->blength; + classinfo *comp; + s4 namelen; arraydescriptor *desc; - vftbl_t *compvftbl; + vftbl_t *compvftbl; + utf *u; + + comp = NULL; + namelen = c->name->blength; /* Check the component type */ + switch (c->name->text[1]) { case '[': /* c is an array of arrays. */ - if (!load_class_from_classloader(utf_new_intern(c->name->text + 1, namelen - 1), - c->classloader,&comp)) + 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. */ - if (!load_class_from_classloader(utf_new_intern(c->name->text + 2, namelen - 3), - c->classloader,&comp)) + 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,8 +1084,8 @@ static arraydescriptor *link_array(classinfo *c) break; default: - log_text("Invalid array class name"); - assert(0); + *exceptionptr = new_noclassdeffounderror(c->name); + return NULL; } desc->componentvftbl = NULL; @@ -969,12 +1106,8 @@ static arraydescriptor *link_array(classinfo *c) static void linker_compute_subclasses(classinfo *c) { -#if defined(USE_THREADS) -#if defined(NATIVE_THREADS) +#if defined(ENABLE_THREADS) compiler_lock(); -#else - intsDisable(); -#endif #endif if (!(c->flags & ACC_INTERFACE)) { @@ -993,12 +1126,8 @@ static void linker_compute_subclasses(classinfo *c) linker_compute_class_values(class_java_lang_Object); -#if defined(USE_THREADS) -#if defined(NATIVE_THREADS) +#if defined(ENABLE_THREADS) compiler_unlock(); -#else - intsRestore(); -#endif #endif } @@ -1032,58 +1161,99 @@ static void linker_compute_class_values(classinfo *c) Is needed by link_class for adding a VTBL to a class. All interfaces implemented by ic are added as well. + RETURN VALUE: + true.........everything ok + false........an exception has been thrown + *******************************************************************************/ -static void linker_addinterface(classinfo *c, classinfo *ic) +static bool linker_addinterface(classinfo *c, classinfo *ic) { - s4 j, m; - s4 i = ic->index; - vftbl_t *v = c->vftbl; + s4 j, k; + vftbl_t *v; + s4 i; + classinfo *sc; + methodinfo *m; - if (i >= v->interfacetablelength) { - log_text("Inernal error: interfacetable overflow"); - assert(0); - } + v = c->vftbl; + i = ic->index; + + if (i >= v->interfacetablelength) + vm_abort("Internal error: interfacetable overflow"); + + /* if this interface has already been added, return immediately */ - if (v->interfacetable[-i]) - return; + if (v->interfacetable[-i] != NULL) + return true; if (ic->methodscount == 0) { /* fake entry needed for subtype test */ v->interfacevftbllength[i] = 1; - v->interfacetable[-i] = MNEW(methodptr, 1); - v->interfacetable[-i][0] = NULL; - - } else { + v->interfacetable[-i] = MNEW(methodptr, 1); + v->interfacetable[-i][0] = NULL; + } + else { v->interfacevftbllength[i] = ic->methodscount; - v->interfacetable[-i] = MNEW(methodptr, 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)); #endif for (j = 0; j < ic->methodscount; j++) { - classinfo *sc = c; + for (sc = c; sc != NULL; sc = sc->super.cls) { + for (k = 0; k < sc->methodscount; k++) { + m = &(sc->methods[k]); + + if (method_canoverwrite(m, &(ic->methods[j]))) { + /* method m overwrites the (abstract) method */ +#if defined(ENABLE_VERIFIER) + /* Add loading constraints (for the more + general types of the method + ic->methods[j]). */ + if (!classcache_add_constraints_for_params( + c->classloader, ic->classloader, + &(ic->methods[j]))) + { + return false; + } +#endif + + /* XXX taken from gcj */ + /* check for ACC_STATIC: IncompatibleClassChangeError */ - while (sc) { - for (m = 0; m < sc->methodscount; m++) { - methodinfo *mi = &(sc->methods[m]); + /* check for !ACC_PUBLIC: IllegalAccessError */ - if (method_canoverwrite(mi, &(ic->methods[j]))) { - v->interfacetable[-i][j] = v->table[mi->vftblindex]; + /* check for ACC_ABSTRACT: AbstracMethodError, + not sure about that one */ + + v->interfacetable[-i][j] = v->table[m->vftblindex]; goto foundmethod; } } - sc = sc->super.cls; } + + /* If no method was found, insert the AbstractMethodError + stub. */ + + v->interfacetable[-i][j] = + (methodptr) (ptrint) &asm_abstractmethoderror; + foundmethod: ; } } - for (j = 0; j < ic->interfacescount; j++) - linker_addinterface(c, ic->interfaces[j].cls); + /* add superinterfaces of this interface */ + + for (j = 0; j < ic->interfacescount; j++) + if (!linker_addinterface(c, ic->interfaces[j].cls)) + return false; + + /* everything ok */ + + return true; } @@ -1126,4 +1296,5 @@ static s4 class_highestinterface(classinfo *c) * c-basic-offset: 4 * tab-width: 4 * End: + * vim:noexpandtab:sw=4:ts=4: */