X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Flinker.c;h=c1b00e40b199f8a605f4a6249c62db6b88851c9f;hb=0ce178c56bb73f85555e1693ed2019387838b362;hp=2dd620df370e0fd564d01bb8df07aea25ddab3c1;hpb=646f880e80964668d44d755e7179d529a1185d1a;p=cacao.git diff --git a/src/vm/linker.c b/src/vm/linker.c index 2dd620df3..c1b00e40b 100644 --- a/src/vm/linker.c +++ b/src/vm/linker.c @@ -1,9 +1,7 @@ /* src/vm/linker.c - class linker functions - 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 + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -22,329 +20,328 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Andreas Krall - Roman Obermaiser - Mark Probst - Edwin Steiner - Christian Thalinger - - $Id: linker.c 4799 2006-04-20 20:38:07Z edwin $ - */ #include "config.h" #include +#include #include "vm/types.h" #include "mm/memory.h" + #include "native/native.h" -#include "vm/builtin.h" + +#include "threads/lock-common.h" +#include "threads/mutex.hpp" + +#include "toolbox/logging.h" + +#include "vm/access.h" +#include "vm/array.h" #include "vm/class.h" #include "vm/classcache.h" -#include "vm/exceptions.h" -#include "vm/loader.h" +#include "vm/exceptions.hpp" +#include "vm/globals.hpp" +#include "vm/loader.hpp" #include "vm/options.h" -#include "vm/resolve.h" -#include "vm/statistics.h" -#include "vm/stringlocal.h" -#include "vm/access.h" +#include "vm/primitive.hpp" #include "vm/rt-timing.h" +#include "vm/string.hpp" +#include "vm/vm.hpp" +#include "vm/jit/asmpart.h" +#include "vm/jit/stubs.hpp" -/* global variables ***********************************************************/ -static s4 interfaceindex; /* sequential numbering of interfaces */ -static s4 classvalue; +/* debugging macros ***********************************************************/ +#if !defined(NDEBUG) +# define TRACELINKCLASS(c) \ + do { \ + if (opt_TraceLinkClass) { \ + log_start(); \ + log_print("[Linking "); \ + class_print((c)); \ + log_print("]"); \ + log_finish(); \ + } \ + } while (0) +#else +# define TRACELINKCLASS(c) +#endif -/* primitivetype_table ********************************************************* - Structure for primitive classes: contains the class for wrapping - the primitive type, the primitive class, the name of the class for - wrapping, the one character type signature and the name of the - primitive class. - - CAUTION: Don't change the order of the types. This table is indexed - by the ARRAYTYPE_ constants (except ARRAYTYPE_OBJECT). +/* #include "vm/resolve.h" */ +/* copied prototype to avoid bootstrapping problem: */ +classinfo *resolve_classref_or_classinfo_eager(classref_or_classinfo cls, bool checkaccess); -*******************************************************************************/ +#if defined(ENABLE_STATISTICS) +# include "vm/statistics.h" +#endif -primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT] = { - { NULL, NULL, "java/lang/Integer", 'I', "int" , "[I", NULL, NULL }, - { NULL, NULL, "java/lang/Long", 'J', "long" , "[J", NULL, NULL }, - { NULL, NULL, "java/lang/Float", 'F', "float" , "[F", NULL, NULL }, - { NULL, NULL, "java/lang/Double", 'D', "double" , "[D", NULL, NULL }, - { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL }, - { NULL, NULL, "java/lang/Byte", 'B', "byte" , "[B", NULL, NULL }, - { NULL, NULL, "java/lang/Character", 'C', "char" , "[C", NULL, NULL }, - { NULL, NULL, "java/lang/Short", 'S', "short" , "[S", NULL, NULL }, - { NULL, NULL, "java/lang/Boolean", 'Z', "boolean" , "[Z", NULL, NULL }, - { NULL, NULL, NULL, 0 , NULL , NULL, NULL, NULL }, - { NULL, NULL, "java/lang/Void", 'V', "void" , NULL, NULL, NULL } -}; +#if !defined(NDEBUG) && defined(ENABLE_INLINING) +#define INLINELOG(code) do { if (opt_TraceInlining) { code } } while (0) +#else +#define INLINELOG(code) +#endif + + +/* global variables ***********************************************************/ + +static s4 interfaceindex; /* sequential numbering of interfaces */ +static s4 classvalue; /* private functions **********************************************************/ -static bool link_primitivetype_table(void); 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); /* linker_init ***************************************************************** - Initializes the linker subsystem. + Initializes the linker subsystem and links classes required for the + primitive table. *******************************************************************************/ -bool linker_init(void) +void linker_preinit(void) { - /* reset interface index */ + TRACESUBSYSTEMINITIALIZATION("linker_preinit"); + + /* Reset interface index. */ 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 */ + /* Link the most basic classes. */ - if (!link_class(class_java_lang_Class)) - return false; + if (!link_class(class_java_lang_Object)) + vm_abort("linker_preinit: linking java/lang/Object failed"); - /* now set the header.vftbl of all classes which were created - before java.lang.Class was linked */ +#if defined(ENABLE_JAVASE) + if (!link_class(class_java_lang_Cloneable)) + vm_abort("linker_preinit: linking java/lang/Cloneable failed"); - class_postset_header_vftbl(); + if (!link_class(class_java_io_Serializable)) + vm_abort("linker_preinit: linking java/io/Serializable failed"); +#endif +} - /* link important system classes */ +/* linker_init ***************************************************************** - if (!link_class(class_java_lang_Object)) - return false; + Links all classes required in the VM. - if (!link_class(class_java_lang_String)) - return false; +*******************************************************************************/ - if (!link_class(class_java_lang_Cloneable)) - return false; +void linker_init(void) +{ + TRACESUBSYSTEMINITIALIZATION("linker_init"); - if (!link_class(class_java_io_Serializable)) - return false; + /* 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)) + vm_abort("linker_init: linking java/lang/Class failed"); + + /* Now set the header.vftbl of all classes which were created + before java.lang.Class was linked. */ - /* link classes for wrapping primitive types */ + class_postset_header_vftbl(); + /* Link primitive-type wrapping classes. */ + +#if defined(ENABLE_JAVASE) if (!link_class(class_java_lang_Void)) - return false; + vm_abort("linker_init: linking failed"); +#endif if (!link_class(class_java_lang_Boolean)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_Byte)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_Character)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_Short)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_Integer)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_Long)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_Float)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_Double)) - return false; + vm_abort("linker_init: linking failed"); + /* Link important system classes. */ - /* load some other important classes */ + if (!link_class(class_java_lang_String)) + vm_abort("linker_init: linking java/lang/String failed"); +#if defined(ENABLE_JAVASE) if (!link_class(class_java_lang_ClassLoader)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_SecurityManager)) - return false; + vm_abort("linker_init: linking failed"); +#endif if (!link_class(class_java_lang_System)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_Thread)) - return false; + vm_abort("linker_init: linking failed"); +#if defined(ENABLE_JAVASE) if (!link_class(class_java_lang_ThreadGroup)) - return false; + vm_abort("linker_init: linking failed"); +#endif + + if (!link_class(class_java_lang_Throwable)) + vm_abort("linker_init: linking failed"); + +#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) + if (!link_class(class_java_lang_VMSystem)) + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_VMThread)) - return false; + vm_abort("linker_init: linking failed"); + if (!link_class(class_java_lang_VMThrowable)) + vm_abort("linker_init: linking failed"); +#endif + + /* Important system exceptions. */ + + if (!link_class(class_java_lang_Exception)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_ClassNotFoundException)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_RuntimeException)) + vm_abort("linker_init: linking failed"); /* some classes which may be used more often */ +#if defined(ENABLE_JAVASE) if (!link_class(class_java_lang_StackTraceElement)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_reflect_Constructor)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_reflect_Field)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_lang_reflect_Method)) - return false; + vm_abort("linker_init: linking failed"); + +# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH) + if (!link_class(class_java_lang_reflect_VMConstructor)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_reflect_VMField)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_lang_reflect_VMMethod)) + vm_abort("linker_init: linking failed"); +# endif if (!link_class(class_java_security_PrivilegedAction)) - return false; + vm_abort("linker_init: linking failed"); if (!link_class(class_java_util_Vector)) - return false; + vm_abort("linker_init: linking failed"); + + if (!link_class(class_java_util_HashMap)) + vm_abort("linker_init: linking failed"); + +# if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) + if (!link_class(class_sun_misc_Signal)) + vm_abort("linker_init: linking failed"); + + if (!link_class(class_sun_reflect_MagicAccessorImpl)) + vm_abort("linker_init: linking failed"); +# endif if (!link_class(arrayclass_java_lang_Object)) - return false; + vm_abort("linker_init: linking failed"); +#endif /* create pseudo classes used by the typechecker */ /* pseudo class for Arraystubs (extends java.lang.Object) */ - - pseudo_class_Arraystub = + + pseudo_class_Arraystub = class_create_classinfo(utf_new_char("$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); - } + pseudo_class_Arraystub->state |= CLASS_LOADED; + pseudo_class_Arraystub->super = class_java_lang_Object; + +#if defined(ENABLE_JAVASE) + + pseudo_class_Arraystub->interfacescount = 2; + pseudo_class_Arraystub->interfaces = MNEW(classinfo*, 2); + pseudo_class_Arraystub->interfaces[0] = class_java_lang_Cloneable; + pseudo_class_Arraystub->interfaces[1] = class_java_io_Serializable; + +#elif defined(ENABLE_JAVAME_CLDC1_1) + + pseudo_class_Arraystub->interfacescount = 0; + pseudo_class_Arraystub->interfaces = NULL; + +#else +# error unknown Java configuration +#endif + + if (!classcache_store_unique(pseudo_class_Arraystub)) + vm_abort("linker_init: could not cache pseudo_class_Arraystub"); if (!link_class(pseudo_class_Arraystub)) - return false; + vm_abort("linker_init: linking pseudo_class_Arraystub failed"); /* pseudo class representing the null type */ - pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$")); + pseudo_class_Null = class_create_classinfo(utf_new_char("$NULL$")); pseudo_class_Null->state |= CLASS_LOADED; - pseudo_class_Null->super.cls = class_java_lang_Object; + pseudo_class_Null->super = class_java_lang_Object; - if (!classcache_store_unique(pseudo_class_Null)) { - log_text("could not cache pseudo_class_Null"); - assert(0); - } + if (!classcache_store_unique(pseudo_class_Null)) + vm_abort("linker_init: could not cache pseudo_class_Null"); if (!link_class(pseudo_class_Null)) - return false; + vm_abort("linker_init: linking failed"); /* pseudo class representing new uninitialized objects */ - pseudo_class_New = class_create_classinfo(utf_new_char("$NEW$")); + pseudo_class_New = class_create_classinfo(utf_new_char("$NEW$")); 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)) { - log_text("could not cache pseudo_class_New"); - assert(0); - } - - /* create classes representing primitive types */ - - if (!link_primitivetype_table()) - return false; + pseudo_class_New->super = class_java_lang_Object; + if (!classcache_store_unique(pseudo_class_New)) + vm_abort("linker_init: could not cache pseudo_class_New"); - /* Correct vftbl-entries (retarded loading and linking of class */ - /* java/lang/String). */ + /* Correct vftbl-entries (retarded loading and linking of class + java/lang/String). */ stringtable_update(); - - return true; -} - - -/* link_primitivetype_table **************************************************** - - Create classes representing primitive types. - -*******************************************************************************/ - -static bool link_primitivetype_table(void) -{ - classinfo *c; - utf *u; - s4 i; - - for (i = 0; i < PRIMITIVETYPE_COUNT; i++) { - /* skip dummies */ - - if (!primitivetype_table[i].name) - continue; - - /* create primitive class */ - - c = class_create_classinfo(utf_new_char(primitivetype_table[i].name)); - - c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; - - /* prevent loader from loading primitive class */ - - c->state |= CLASS_LOADED; - - /* INFO: don't put primitive classes into the classcache */ - - if (!link_class(c)) - return false; - - primitivetype_table[i].class_primitive = c; - - /* create class for wrapping the primitive type */ - - u = utf_new_char(primitivetype_table[i].wrapname); - - if (!(c = load_class_bootstrap(u))) - return false; - - primitivetype_table[i].class_wrap = c; - - /* create the primitive array class */ - - if (primitivetype_table[i].arrayname) { - u = utf_new_char(primitivetype_table[i].arrayname); - c = class_create_classinfo(u); - c = load_newly_created_array(c, NULL); - if (c == NULL) - return false; - - primitivetype_table[i].arrayclass = c; - - assert(c->state & CLASS_LOADED); - - if (!(c->state & CLASS_LINKED)) - if (!link_class(c)) - return false; - - primitivetype_table[i].arrayvftbl = c->vftbl; - } - } - - return true; } @@ -364,23 +361,17 @@ classinfo *link_class(classinfo *c) RT_TIMING_GET_TIME(time_start); - if (!c) { + if (c == NULL) { exceptions_throw_nullpointerexception(); return NULL; } -#if defined(USE_THREADS) - /* enter a monitor on the class */ - - builtin_monitorenter((java_objectheader *) c); -#endif + LOCK_MONITOR_ENTER(c); - /* maybe the class is already linked */ + /* Maybe the class is currently linking or is already linked.*/ - if (c->state & CLASS_LINKED) { -#if defined(USE_THREADS) - builtin_monitorexit((java_objectheader *) c); -#endif + if ((c->state & CLASS_LINKING) || (c->state & CLASS_LINKED)) { + LOCK_MONITOR_EXIT(c); return c; } @@ -388,10 +379,10 @@ classinfo *link_class(classinfo *c) #if defined(ENABLE_STATISTICS) /* measure time */ - if (getcompilingtime) + if (opt_getcompilingtime) compilingtime_stop(); - if (getloadingtime) + if (opt_getloadingtime) loadingtime_start(); #endif @@ -399,26 +390,23 @@ classinfo *link_class(classinfo *c) r = link_class_intern(c); - /* if return value is NULL, we had a problem and the class is not linked */ + /* If return value is NULL, we had a problem and the class is not + linked. */ - if (!r) + if (r == NULL) c->state &= ~CLASS_LINKING; #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) - /* leave the monitor */ - - builtin_monitorexit((java_objectheader *) c); -#endif + LOCK_MONITOR_EXIT(c); RT_TIMING_GET_TIME(time_end); @@ -428,6 +416,98 @@ classinfo *link_class(classinfo *c) } +/* linker_overwrite_method ***************************************************** + + Overwrite a method with another one, update method flags and check + assumptions. + + IN: + mg................the general method being overwritten + ms................the overwriting (more specialized) method + wl................worklist where to add invalidated methods + + RETURN VALUE: + true..............everything ok + false.............an exception has been thrown + +*******************************************************************************/ + +static bool linker_overwrite_method(methodinfo *mg, + methodinfo *ms, + method_worklist **wl) +{ + classinfo *cg; + classinfo *cs; + + cg = mg->clazz; + cs = ms->clazz; + + /* overriding a final method is illegal */ + + if (mg->flags & ACC_FINAL) { + exceptions_throw_verifyerror(mg, "Overriding final method"); + return false; + } + + /* method ms overwrites method mg */ + +#if defined(ENABLE_VERIFIER) + /* Add loading constraints (for the more general types of method mg). */ + /* Not for , as it is not invoked virtually. */ + + if ((ms->name != utf_init) + && !classcache_add_constraints_for_params( + cs->classloader, cg->classloader, mg)) + { + return false; + } +#endif + + /* inherit the vftbl index, and record the overwriting */ + + ms->vftblindex = mg->vftblindex; + ms->overwrites = mg; + + /* update flags and check assumptions */ + /* methods are a special case, as they are never dispatched dynamically */ + + if ((ms->flags & ACC_METHOD_IMPLEMENTED) && ms->name != utf_init) { + do { + +#if defined(ENABLE_TLH) + if (mg->flags & ACC_METHOD_MONOMORPHY_USED) { + printf("%s/%s is evil! the siner is %s/%s\n", mg->clazz->name->text, mg->name->text, + ms->clazz->name->text, ms->name->text); + ms->flags |= ACC_METHOD_PARENT_MONOMORPHY_USED; + } +#endif + + if (mg->flags & ACC_METHOD_IMPLEMENTED) { + /* this adds another implementation */ + + mg->flags &= ~ACC_METHOD_MONOMORPHIC; + + INLINELOG( printf("becomes polymorphic: "); method_println(mg); ); + + method_break_assumption_monomorphic(mg, wl); + } + else { + /* this is the first implementation */ + + mg->flags |= ACC_METHOD_IMPLEMENTED; + + INLINELOG( printf("becomes implemented: "); method_println(mg); ); + } + + ms = mg; + mg = mg->overwrites; + } while (mg != NULL); + } + + return true; +} + + /* link_class_intern *********************************************************** Tries to link a class. The function calculates the length in bytes @@ -436,6 +516,70 @@ classinfo *link_class(classinfo *c) *******************************************************************************/ +static int build_display_inner(classinfo *topc, classinfo *c, int i) +{ + int depth; + if (!c) + return 0; + do { + if (c->vftbl->arraydesc) + { + arraydescriptor *a = c->vftbl->arraydesc; + if (a->elementvftbl && a->elementvftbl->clazz->super) + { + classinfo *cls = a->elementvftbl->clazz->super; + int n; + for (n=0; ndimension; n++) + cls = class_array_of(cls, true); + depth = build_display_inner(topc, cls, i+1); + break; + } + if (a->componentvftbl && a->elementvftbl) + { + depth = build_display_inner(topc, a->componentvftbl->clazz, i+1); + break; + } + } + depth = build_display_inner(topc, c->super, i+1); + } while (false); + if (depth >= DISPLAY_SIZE) + { + if (depth == DISPLAY_SIZE) + { + topc->vftbl->subtype_overflow_length = i+1; + topc->vftbl->subtype_overflow = malloc(sizeof(void*) * (i+1)); +#if defined(ENABLE_STATISTICS) + if (opt_stat) + count_vftbl_len += sizeof(void*) * (i+1); +#endif + } + topc->vftbl->subtype_overflow[depth - DISPLAY_SIZE] = c->vftbl; + return depth + 1; + } + topc->vftbl->subtype_display[depth] = c->vftbl; + return depth + 1; +} + +static void build_display(classinfo *c) +{ + int depth; + int i; + + depth = build_display_inner(c, c, 0) - 1; + c->vftbl->subtype_depth = depth; + if (depth >= DISPLAY_SIZE) + { + c->vftbl->subtype_offset = OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]); + } + else + { + c->vftbl->subtype_offset = OFFSET(vftbl_t, subtype_display[0]) + sizeof(void*) * depth; + for (i=depth+1; i<=DISPLAY_SIZE; i++) + c->vftbl->subtype_display[i] = NULL; + c->vftbl->subtype_overflow_length = 0; + } +} + static classinfo *link_class_intern(classinfo *c) { classinfo *super; /* super class */ @@ -444,32 +588,29 @@ static classinfo *link_class_intern(classinfo *c) s4 vftbllength; /* vftbllength of current class */ s4 interfacetablelength; /* interface table length */ vftbl_t *v; /* vftbl of current class */ - s4 i,j; /* interface/method/field counter */ + s4 i; /* interface/method/field counter */ arraydescriptor *arraydesc; /* descriptor for array classes */ + method_worklist *worklist; /* worklist for recompilation */ #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; + time_subclasses; #endif RT_TIMING_GET_TIME(time_start); - /* the class is already linked */ - - if (c->state & CLASS_LINKED) - return c; - -#if !defined(NDEBUG) - if (linkverbose) - log_message_class("Linking class: ", c); -#endif + TRACELINKCLASS(c); /* the class must be loaded */ /* XXX should this be a specific exception? */ assert(c->state & CLASS_LOADED); + /* This is check in link_class. */ + + assert(!(c->state & CLASS_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 */ @@ -485,35 +626,12 @@ static classinfo *link_class_intern(classinfo *c) c->state |= CLASS_LINKING; arraydesc = NULL; + worklist = NULL; - /* check interfaces */ + /* Link the super interfaces. */ for (i = 0; i < c->interfacescount; i++) { - /* resolve this super interface */ - - if (!resolve_classref_or_classinfo(NULL, c->interfaces[i], resolveEager, - true, false, &tc)) - return NULL; - - c->interfaces[i].cls = tc; - - /* detect circularity */ - - if (tc == c) { - *exceptionptr = - new_exception_utfmessage(string_java_lang_ClassCircularityError, - c->name); - return NULL; - } - - assert(tc->state & CLASS_LOADED); - - if (!(tc->flags & ACC_INTERFACE)) { - *exceptionptr = - new_exception_message(string_java_lang_IncompatibleClassChangeError, - "Implementing class"); - return NULL; - } + tc = c->interfaces[i]; if (!(tc->state & CLASS_LINKED)) if (!link_class(tc)) @@ -524,52 +642,33 @@ static classinfo *link_class_intern(classinfo *c) super = NULL; - if (c->super.any == NULL) { /* class java.lang.Object */ + /* Check for java/lang/Object. */ + + if (c->super == NULL) { c->index = 0; - c->instancesize = sizeof(java_objectheader); + c->instancesize = sizeof(java_object_t); vftbllength = supervftbllength = 0; c->finalizer = NULL; + } + else { + /* Get super class. */ - } else { - /* resolve super class */ - - if (!resolve_classref_or_classinfo(NULL, c->super, resolveEager, true, false, - &super)) - return NULL; - c->super.cls = super; - - /* detect circularity */ - - if (super == c) { - *exceptionptr = - new_exception_utfmessage(string_java_lang_ClassCircularityError, - c->name); - return NULL; - } - - assert(super->state & CLASS_LOADED); - - if (super->flags & ACC_INTERFACE) { - /* java.lang.IncompatibleClassChangeError: class a has interface java.lang.Cloneable as super class */ - log_text("Interface specified as super class"); - assert(0); - } - - /* Don't allow extending final classes */ + super = c->super; - if (super->flags & ACC_FINAL) { - *exceptionptr = - new_exception_message(string_java_lang_VerifyError, - "Cannot inherit from final class"); - return NULL; - } + /* Link the super class if necessary. */ if (!(super->state & CLASS_LINKED)) if (!link_class(super)) return NULL; + /* OR the ACC_CLASS_HAS_POINTERS and the ACC_CLASS_REFERENCE_* + flags. */ + + c->flags |= (super->flags & + (ACC_CLASS_HAS_POINTERS | ACC_CLASS_REFERENCE_MASK)); + /* handle array classes */ if (c->name->text[0] == '[') @@ -582,7 +681,7 @@ 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; @@ -615,25 +714,14 @@ static classinfo *link_class_intern(classinfo *c) goto notfoundvftblindex; } - if (tc->methods[j].flags & ACC_FINAL) { - /* class a overrides final method . */ - *exceptionptr = - new_exception(string_java_lang_VerifyError); - return NULL; - } - - /* method m overwrites method j of class tc */ - - if (!classcache_add_constraints_for_params( - c->classloader, tc->classloader, m)) + if (!linker_overwrite_method(&(tc->methods[j]), m, &worklist)) return NULL; - m->vftblindex = tc->methods[j].vftblindex; goto foundvftblindex; } } - tc = tc->super.cls; + tc = tc->super; } notfoundvftblindex: @@ -645,10 +733,11 @@ static classinfo *link_class_intern(classinfo *c) RT_TIMING_GET_TIME(time_compute_vftbl); - /* 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. */ + /* 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; @@ -659,10 +748,10 @@ static classinfo *link_class_intern(classinfo *c) abstractmethodscount = 0; - /* check all interfaces of the abtract class */ + /* check all interfaces of the abstract class */ for (i = 0; i < c->interfacescount; i++) { - ic = c->interfaces[i].cls; + ic = c->interfaces[i]; for (j = 0; j < ic->methodscount; j++) { im = &(ic->methods[j]); @@ -672,7 +761,7 @@ static classinfo *link_class_intern(classinfo *c) if ((im->name == utf_clinit) || (im->name == utf_init)) continue; - for (tc = c; tc != NULL; tc = tc->super.cls) { + for (tc = c; tc != NULL; tc = tc->super) { for (k = 0; k < tc->methodscount; k++) { if (method_canoverwrite(im, &(tc->methods[k]))) goto noabstractmethod; @@ -695,7 +784,7 @@ static classinfo *link_class_intern(classinfo *c) c->methodscount + abstractmethodscount); for (i = 0; i < c->interfacescount; i++) { - ic = c->interfaces[i].cls; + ic = c->interfaces[i]; for (j = 0; j < ic->methodscount; j++) { im = &(ic->methods[j]); @@ -705,7 +794,7 @@ static classinfo *link_class_intern(classinfo *c) if ((im->name == utf_clinit) || (im->name == utf_init)) continue; - for (tc = c; tc != NULL; tc = tc->super.cls) { + for (tc = c; tc != NULL; tc = tc->super) { for (k = 0; k < tc->methodscount; k++) { if (method_canoverwrite(im, &(tc->methods[k]))) goto noabstractmethod2; @@ -721,7 +810,7 @@ static classinfo *link_class_intern(classinfo *c) MCOPY(am, im, methodinfo, 1); am->vftblindex = (vftbllength++); - am->class = c; + am->clazz = c; am->flags |= ACC_MIRANDA; noabstractmethod2: @@ -742,14 +831,14 @@ static classinfo *link_class_intern(classinfo *c) /* compute interfacetable length */ interfacetablelength = 0; - tc = c; - while (tc) { + + for (tc = c; tc != NULL; tc = tc->super) { for (i = 0; i < tc->interfacescount; i++) { - s4 h = class_highestinterface(tc->interfaces[i].cls) + 1; + s4 h = class_highestinterface(tc->interfaces[i]) + 1; + if (h > interfacetablelength) interfacetablelength = h; } - tc = tc->super.cls; } RT_TIMING_GET_TIME(time_compute_iftbl); @@ -760,11 +849,12 @@ static classinfo *link_class_intern(classinfo *c) sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0))); v = (vftbl_t *) (((methodptr *) v) + (interfacetablelength - 1) * (interfacetablelength > 1)); - c->vftbl = v; - v->class = c; - v->vftbllength = vftbllength; + + c->vftbl = v; + v->clazz = c; + v->vftbllength = vftbllength; v->interfacetablelength = interfacetablelength; - v->arraydesc = arraydesc; + v->arraydesc = arraydesc; /* store interface index in vftbl */ @@ -775,30 +865,57 @@ 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++) { +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror; + else +# endif + v->table[i] = (methodptr) (ptrint) &asm_abstractmethoderror; +#else + v->table[i] = (methodptr) (ptrint) &intrp_asm_abstractmethoderror; +#endif + } + /* 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); + + /* 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. */ + + if (m->flags & ACC_ABSTRACT) + continue; - if (!m->stubroutine) { #if defined(ENABLE_JIT) # if defined(ENABLE_INTRP) - if (opt_intrp) - m->stubroutine = intrp_createcompilerstub(m); - else + if (opt_intrp) + m->stubroutine = intrp_createcompilerstub(m); + else #endif - m->stubroutine = createcompilerstub(m); + m->stubroutine = CompilerStub_generate(m); #else - m->stubroutine = intrp_createcompilerstub(m); + m->stubroutine = intrp_createcompilerstub(m); #endif - } - if (!(m->flags & ACC_STATIC)) - v->table[m->vftblindex] = (methodptr) (ptrint) m->stubroutine; + /* static methods are not in the vftbl */ + + 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); @@ -810,7 +927,7 @@ static classinfo *link_class_intern(classinfo *c) if (!(f->flags & ACC_STATIC)) { dsize = descriptor_typesize(f->parseddesc); - c->instancesize = ALIGN(c->instancesize, dsize); + c->instancesize = MEMORY_ALIGN(c->instancesize, dsize); f->offset = c->instancesize; c->instancesize += dsize; } @@ -818,7 +935,7 @@ static classinfo *link_class_intern(classinfo *c) RT_TIMING_GET_TIME(time_offsets); /* initialize interfacetable and interfacevftbllength */ - + v->interfacevftbllength = MNEW(s4, interfacetablelength); #if defined(ENABLE_STATISTICS) @@ -830,13 +947,14 @@ 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 (tc = c; tc != NULL; tc = tc->super) for (i = 0; i < tc->interfacescount; i++) - linker_addinterface(c, tc->interfaces[i].cls); - + if (!linker_addinterface(c, tc->interfaces[i])) + return NULL; + RT_TIMING_GET_TIME(time_fill_iftbl); /* add finalizer method (not for java.lang.Object) */ @@ -852,37 +970,34 @@ static classinfo *link_class_intern(classinfo *c) } RT_TIMING_GET_TIME(time_finalizer); - /* resolve exception class references */ - - for (i = 0; i < c->methodscount; i++) { - methodinfo *m = &(c->methods[i]); - - for (j = 0; j < m->exceptiontablelength; j++) { - if (!m->exceptiontable[j].catchtype.any) - continue; - if (!resolve_classref_or_classinfo(NULL, - m->exceptiontable[j].catchtype, - resolveEager, true, false, - &(m->exceptiontable[j].catchtype.cls))) - return NULL; - } - } - RT_TIMING_GET_TIME(time_exceptions); - /* final tasks */ linker_compute_subclasses(c); + /* FIXME: this is completely useless now */ RT_TIMING_GET_TIME(time_subclasses); + build_display(c); + /* 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 + /* check worklist */ + + /* XXX must this also be done in case of exception? */ + + while (worklist != NULL) { + method_worklist *wi = worklist; + + worklist = worklist->next; + + INLINELOG( printf("MUST BE RECOMPILED: "); method_println(wi->m); ); + jit_invalidate_code(wi->m); + + /* XXX put worklist into dump memory? */ + FREE(wi, method_worklist); + } 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); @@ -892,8 +1007,7 @@ static classinfo *link_class_intern(classinfo *c) 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); + RT_TIMING_TIME_DIFF(time_finalizer ,time_subclasses ,RT_TIMING_LINK_SUBCLASS); /* just return c to show that we didn't had a problem */ @@ -956,7 +1070,7 @@ static arraydescriptor *link_array(classinfo *c) /* c is an array of references */ desc->arraytype = ARRAYTYPE_OBJECT; desc->componentsize = sizeof(void*); - desc->dataoffset = OFFSET(java_objectarray, data); + desc->dataoffset = OFFSET(java_objectarray_t, data); compvftbl = comp->vftbl; @@ -989,54 +1103,54 @@ static arraydescriptor *link_array(classinfo *c) switch (c->name->text[1]) { case 'Z': desc->arraytype = ARRAYTYPE_BOOLEAN; - desc->dataoffset = OFFSET(java_booleanarray,data); + desc->dataoffset = OFFSET(java_booleanarray_t,data); desc->componentsize = sizeof(u1); break; case 'B': desc->arraytype = ARRAYTYPE_BYTE; - desc->dataoffset = OFFSET(java_bytearray,data); + desc->dataoffset = OFFSET(java_bytearray_t,data); desc->componentsize = sizeof(u1); break; case 'C': desc->arraytype = ARRAYTYPE_CHAR; - desc->dataoffset = OFFSET(java_chararray,data); + desc->dataoffset = OFFSET(java_chararray_t,data); desc->componentsize = sizeof(u2); break; case 'D': desc->arraytype = ARRAYTYPE_DOUBLE; - desc->dataoffset = OFFSET(java_doublearray,data); + desc->dataoffset = OFFSET(java_doublearray_t,data); desc->componentsize = sizeof(double); break; case 'F': desc->arraytype = ARRAYTYPE_FLOAT; - desc->dataoffset = OFFSET(java_floatarray,data); + desc->dataoffset = OFFSET(java_floatarray_t,data); desc->componentsize = sizeof(float); break; case 'I': desc->arraytype = ARRAYTYPE_INT; - desc->dataoffset = OFFSET(java_intarray,data); + desc->dataoffset = OFFSET(java_intarray_t,data); desc->componentsize = sizeof(s4); break; case 'J': desc->arraytype = ARRAYTYPE_LONG; - desc->dataoffset = OFFSET(java_longarray,data); + desc->dataoffset = OFFSET(java_longarray_t,data); desc->componentsize = sizeof(s8); break; case 'S': desc->arraytype = ARRAYTYPE_SHORT; - desc->dataoffset = OFFSET(java_shortarray,data); + desc->dataoffset = OFFSET(java_shortarray_t,data); desc->componentsize = sizeof(s2); break; default: - *exceptionptr = new_noclassdeffounderror(c->name); + exceptions_throw_noclassdeffounderror(c->name); return NULL; } @@ -1054,41 +1168,30 @@ static arraydescriptor *link_array(classinfo *c) XXX + ATTENTION: DO NOT REMOVE ANY OF THE LOCKING MECHANISMS BELOW: + This function needs to take the class renumber lock and stop the + world during class renumbering. The lock is used in C code which + is not that performance critical. Whereas JIT code uses critical + sections to atomically access the class values. + *******************************************************************************/ static void linker_compute_subclasses(classinfo *c) { -#if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - compiler_lock(); -#else - intsDisable(); -#endif -#endif if (!(c->flags & ACC_INTERFACE)) { - c->nextsub = 0; - c->sub = 0; + c->nextsub = NULL; + c->sub = NULL; + c->vftbl->baseval = 1; /* so it does not look like an interface */ } - if (!(c->flags & ACC_INTERFACE) && (c->super.any != NULL)) { - c->nextsub = c->super.cls->sub; - c->super.cls->sub = c; + if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) { + c->nextsub = c->super->sub; + c->super->sub = c; } classvalue = 0; - /* compute class values */ - - linker_compute_class_values(class_java_lang_Object); - -#if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - compiler_unlock(); -#else - intsRestore(); -#endif -#endif } @@ -1121,30 +1224,39 @@ 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(ENABLE_STATISTICS) if (opt_stat) @@ -1153,26 +1265,69 @@ static void linker_addinterface(classinfo *c, classinfo *ic) #endif for (j = 0; j < ic->methodscount; j++) { - classinfo *sc = c; + for (sc = c; sc != NULL; sc = sc->super) { + 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. */ + +#if defined(ENABLE_JIT) +# if defined(ENABLE_INTRP) + if (opt_intrp) + v->interfacetable[-i][j] = + (methodptr) (ptrint) &intrp_asm_abstractmethoderror; + else +# endif + v->interfacetable[-i][j] = + (methodptr) (ptrint) &asm_abstractmethoderror; +#else + v->interfacetable[-i][j] = + (methodptr) (ptrint) &intrp_asm_abstractmethoderror; +#endif + 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])) + return false; + + /* everything ok */ + + return true; } @@ -1194,7 +1349,7 @@ static s4 class_highestinterface(classinfo *c) h = c->index; for (i = 0; i < c->interfacescount; i++) { - h2 = class_highestinterface(c->interfaces[i].cls); + h2 = class_highestinterface(c->interfaces[i]); if (h2 > h) h = h2;