X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Floader.c;h=92d8c0fa395bda9fd3d6888de431d3c57d7e7038;hb=4f021ace4cbb48cb8d75e5445929a01f61ca756a;hp=88eb58c33e5f4543a06af2f09901d4c5f4c2022d;hpb=7991559c9753c82a0057845f2767e90105159ff6;p=cacao.git diff --git a/src/vm/loader.c b/src/vm/loader.c index 88eb58c33..92d8c0fa3 100644 --- a/src/vm/loader.c +++ b/src/vm/loader.c @@ -32,11 +32,10 @@ Edwin Steiner Christian Thalinger - $Id: loader.c 2199 2005-04-03 21:42:44Z twisti $ + $Id: loader.c 3684 2005-11-16 13:28:33Z twisti $ */ - #include #include #include @@ -76,7 +75,6 @@ #include "vm/jit/asmpart.h" #include "vm/jit/codegen.inc.h" - /******************************************************************************/ /* DEBUG HELPERS */ /******************************************************************************/ @@ -99,7 +97,7 @@ #ifdef LOADER_VERBOSE static int loader_recursion = 0; -#define LOADER_INDENT() do { int i; for(i=0;inext) { if (cpi->type == CLASSPATH_ARCHIVE) @@ -137,81 +136,110 @@ bool loader_init(u1 *stackbottom) /* load some important classes */ - if (!load_class_bootstrap(utf_java_lang_Object,&class_java_lang_Object)) + if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object))) return false; - if (!load_class_bootstrap(utf_java_lang_String,&class_java_lang_String)) + if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String))) return false; - if (!load_class_bootstrap(utf_java_lang_Cloneable,&class_java_lang_Cloneable)) + if (!(class_java_lang_Cloneable = + load_class_bootstrap(utf_java_lang_Cloneable))) return false; - if (!load_class_bootstrap(utf_java_io_Serializable,&class_java_io_Serializable)) + if (!(class_java_io_Serializable = + load_class_bootstrap(utf_java_io_Serializable))) return false; /* load classes for wrapping primitive types */ - if (!load_class_bootstrap(utf_java_lang_Void,&class_java_lang_Void)) + if (!(class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void))) return false; - if (!load_class_bootstrap(utf_java_lang_Boolean,&class_java_lang_Boolean)) + if (!(class_java_lang_Boolean = + load_class_bootstrap(utf_java_lang_Boolean))) return false; - if (!load_class_bootstrap(utf_java_lang_Byte,&class_java_lang_Byte)) + if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte))) return false; - if (!load_class_bootstrap(utf_java_lang_Character,&class_java_lang_Character)) + if (!(class_java_lang_Character = + load_class_bootstrap(utf_java_lang_Character))) return false; - if (!load_class_bootstrap(utf_java_lang_Short,&class_java_lang_Short)) + if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short))) return false; - if (!load_class_bootstrap(utf_java_lang_Integer,&class_java_lang_Integer)) + if (!(class_java_lang_Integer = + load_class_bootstrap(utf_java_lang_Integer))) return false; - if (!load_class_bootstrap(utf_java_lang_Long,&class_java_lang_Long)) + if (!(class_java_lang_Long = load_class_bootstrap(utf_java_lang_Long))) return false; - if (!load_class_bootstrap(utf_java_lang_Float,&class_java_lang_Float)) + if (!(class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float))) return false; - if (!load_class_bootstrap(utf_java_lang_Double,&class_java_lang_Double)) + if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double))) return false; + /* load some other important classes */ - if (!load_class_bootstrap(utf_java_lang_Class,&class_java_lang_Class)) + if (!(class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class))) + return false; + + if (!(class_java_lang_ClassLoader = + load_class_bootstrap(utf_java_lang_ClassLoader))) return false; - if (!load_class_bootstrap(utf_java_lang_ClassLoader,&class_java_lang_ClassLoader)) + if (!(class_java_lang_SecurityManager = + load_class_bootstrap(utf_java_lang_SecurityManager))) return false; - if (!load_class_bootstrap(utf_java_lang_SecurityManager,&class_java_lang_SecurityManager)) + if (!(class_java_lang_System = load_class_bootstrap(utf_java_lang_System))) return false; - if (!load_class_bootstrap(utf_java_lang_System,&class_java_lang_System)) + if (!(class_java_lang_Thread = + load_class_bootstrap(utf_new_char("java/lang/Thread")))) return false; - if (!load_class_bootstrap(utf_java_lang_Throwable,&class_java_lang_Throwable)) + if (!(class_java_lang_ThreadGroup = + load_class_bootstrap(utf_java_lang_ThreadGroup))) return false; - if (!load_class_bootstrap(utf_java_lang_VMThrowable,&class_java_lang_VMThrowable)) + if (!(class_java_lang_VMThread = + load_class_bootstrap(utf_new_char("java/lang/VMThread")))) return false; - if (!load_class_bootstrap(utf_java_lang_Exception,&class_java_lang_Exception)) + + /* some classes which may be used more often */ + + if (!(class_java_lang_StackTraceElement = + load_class_bootstrap(utf_java_lang_StackTraceElement))) + return false; + + if (!(class_java_lang_reflect_Constructor = + load_class_bootstrap(utf_java_lang_reflect_Constructor))) return false; - if (!load_class_bootstrap(utf_java_lang_Error,&class_java_lang_Error)) + if (!(class_java_lang_reflect_Field = + load_class_bootstrap(utf_java_lang_reflect_Field))) return false; - if (!load_class_bootstrap(utf_java_lang_OutOfMemoryError,&class_java_lang_OutOfMemoryError)) + if (!(class_java_lang_reflect_Method = + load_class_bootstrap(utf_java_lang_reflect_Method))) return false; - if (!load_class_bootstrap(utf_java_lang_NoClassDefFoundError,&class_java_lang_NoClassDefFoundError)) + if (!(class_java_security_PrivilegedAction = + load_class_bootstrap(utf_new_char("java/security/PrivilegedAction")))) return false; - if (!load_class_bootstrap(utf_java_util_Vector,&class_java_util_Vector)) + if (!(class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector))) + return false; + + if (!(arrayclass_java_lang_Object = + load_class_bootstrap(utf_new_char("[Ljava/lang/Object;")))) return false; #if defined(USE_THREADS) @@ -334,8 +362,7 @@ static float suck_float(classbuffer *cb) #endif if (sizeof(float) != 4) { - *exceptionptr = new_exception_message(string_java_lang_InternalError, - "Incompatible float-format"); + *exceptionptr = new_internalerror("Incompatible float-format"); /* XXX should we exit in such a case? */ throw_exception_exit(); @@ -354,8 +381,21 @@ static double suck_double(classbuffer *cb) u1 buffer[8]; u2 i; +#if defined(__ARM__) && defined(__ARMEL__) && !defined(__VFP_FP__) + /* + * On little endian ARM processors when using FPA, word order + * of doubles is still big endian. So take that into account + * here. When using VFP, word order of doubles follows byte + * order. (michi 2005/07/24) + */ + for (i = 0; i < 4; i++) + buffer[3 - i] = suck_u1(cb); + for (i = 0; i < 4; i++) + buffer[7 - i] = suck_u1(cb); +#else for (i = 0; i < 8; i++) buffer[7 - i] = suck_u1(cb); +#endif /* defined(__ARM__) && ... */ memcpy((u1*) (&d), buffer, 8); #else @@ -363,8 +403,7 @@ static double suck_double(classbuffer *cb) #endif if (sizeof(double) != 8) { - *exceptionptr = new_exception_message(string_java_lang_InternalError, - "Incompatible double-format"); + *exceptionptr = new_internalerror("Incompatible double-format"); /* XXX should we exit in such a case? */ throw_exception_exit(); @@ -456,6 +495,11 @@ void suck_init(char *classpath) cpi->next = NULL; cpi->path = filename; cpi->pathlen = filenamelen; + + /* SUN compatible -verbose:class output */ + + if (opt_verboseclass) + printf("[Opened %s]\n", filename); } #else @@ -502,10 +546,16 @@ void suck_init(char *classpath) } -void create_all_classes() +/* loader_load_all_classes ***************************************************** + + Loads all classes specified in the BOOTCLASSPATH. + +*******************************************************************************/ + +void loader_load_all_classes(void) { classpath_info *cpi; - classinfo *c; + classinfo *c; for (cpi = classpath_entries; cpi != 0; cpi = cpi->next) { #if defined(USE_ZLIB) @@ -517,7 +567,13 @@ void create_all_classes() ce = s->cacao_dir_list; while (ce) { - load_class_bootstrap(ce->name,&c); + /* skip all entries in META-INF and .properties, .png files */ + + if (strncmp(ce->name->text, "META-INF", strlen("META-INF")) && + !strstr(ce->name->text, ".properties") && + !strstr(ce->name->text, ".png")) + c = load_class_bootstrap(ce->name); + ce = ce->next; } @@ -582,9 +638,10 @@ classbuffer *suck_start(classinfo *c) if (unzOpenCurrentFile(cpi->uf) == UNZ_OK) { cb = NEW(classbuffer); cb->class = c; - cb->size = file_info.uncompressed_size; - cb->data = MNEW(u1, cb->size); - cb->pos = cb->data - 1; + cb->size = file_info.uncompressed_size; + cb->data = MNEW(u1, cb->size); + cb->pos = cb->data - 1; + cb->path = cpi->path; len = unzReadCurrentFile(cpi->uf, cb->data, cb->size); @@ -625,9 +682,10 @@ classbuffer *suck_start(classinfo *c) if (!stat(path, &buffer)) { /* read classfile data */ cb = NEW(classbuffer); cb->class = c; - cb->size = buffer.st_size; - cb->data = MNEW(u1, cb->size); - cb->pos = cb->data - 1; + cb->size = buffer.st_size; + cb->data = MNEW(u1, cb->size); + cb->pos = cb->data - 1; + cb->path = cpi->path; /* read class data */ len = fread(cb->data, 1, cb->size, classfile); @@ -650,9 +708,17 @@ classbuffer *suck_start(classinfo *c) } if (opt_verbose) - if (!found) + if (!found) { dolog("Warning: Can not open class file '%s'", filename); + if (strcmp(filename, "org/mortbay/util/MultiException.class") == 0) { + static int i = 0; + i++; + if (i == 3) + assert(0); + } + } + MFREE(filename, char, filenamelen); return cb; @@ -757,71 +823,6 @@ static bool skipattributes(classbuffer *cb, u4 num) } -/******************** function:: class_getconstant ***************************** - - retrieves the value at position 'pos' of the constantpool of a class - if the type of the value is other than 'ctype' the system is stopped - -*******************************************************************************/ - -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]; -} - - -/******************** function: 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]; -} - - -/********************* Function: class_constanttype **************************** - - Determines the type of a class entry in the ConstantPool - -*******************************************************************************/ - -u4 class_constanttype(classinfo *c, u4 pos) -{ - if (pos <= 0 || pos >= c->cpcount) { - *exceptionptr = new_classformaterror(c, "Illegal constant pool index"); - return 0; - } - - return c->cptags[pos]; -} - - /* load_constantpool *********************************************************** Loads the constantpool of a class, the entries are transformed into @@ -830,7 +831,7 @@ u4 class_constanttype(classinfo *c, u4 pos) *******************************************************************************/ -static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool) +static bool load_constantpool(classbuffer *cb, descriptor_pool *descpool) { /* The following structures are used to save information which cannot be @@ -1111,11 +1112,11 @@ static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool) if (opt_verify && !is_valid_utf((char *) (cb->pos + 1), (char *) (cb->pos + 1 + length))) { - dolog("Invalid UTF-8 string (constant pool index %d)",idx); - panic("Invalid UTF-8 string"); + *exceptionptr = new_classformaterror(c,"Invalid UTF-8 string"); + return false; } /* insert utf-string into the utf-symboltable */ - cpinfos[idx] = utf_new_intern((char *) (cb->pos + 1), length); + cpinfos[idx] = utf_new((char *) (cb->pos + 1), length); /* skip bytes of the string (buffer size check above) */ skip_nbytes(cb, length); @@ -1130,24 +1131,14 @@ static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool) } /* end switch */ } /* end while */ - /* add all class references to the descriptor_pool */ - for (nfc=forward_classes; nfc; nfc=nfc->next) { - utf *name = class_getconstant(c,nfc->name_index,CONSTANT_Utf8); - if (!descriptor_pool_add_class(descpool,name)) - return false; - } - /* add all descriptors in NameAndTypes to the descriptor_pool */ - for (nfn=forward_nameandtypes; nfn; nfn=nfn->next) { - utf *desc = class_getconstant(c,nfn->sig_index,CONSTANT_Utf8); - if (!descriptor_pool_add(descpool,desc,NULL)) - return false; - } /* resolve entries in temporary structures */ while (forward_classes) { utf *name = class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8); + if (!name) + return false; if (opt_verify && !is_valid_name_utf(name)) { *exceptionptr = @@ -1155,7 +1146,24 @@ static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool) return false; } + /* add all class references to the descriptor_pool */ + + if (!descriptor_pool_add_class(descpool, name)) + return false; + cptags[forward_classes->thisindex] = CONSTANT_Class; + + if (opt_eager) { + classinfo *tc; + + if (!(tc = load_class_bootstrap(name))) + return false; + + /* link the class later, because we cannot link the class currently + loading */ + list_addfirst(&unlinkedclasses, tc); + } + /* the classref is created later */ cpinfos[forward_classes->thisindex] = name; @@ -1166,6 +1174,8 @@ static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool) while (forward_strings) { utf *text = class_getconstant(c, forward_strings->string_index, CONSTANT_Utf8); + if (!text) + return false; /* resolve utf-string */ cptags[forward_strings->thisindex] = CONSTANT_String; @@ -1187,10 +1197,14 @@ static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool) cn->name = class_getconstant(c, forward_nameandtypes->name_index, CONSTANT_Utf8); + if (!cn->name) + return false; cn->descriptor = class_getconstant(c, forward_nameandtypes->sig_index, CONSTANT_Utf8); + if (!cn->descriptor) + return false; if (opt_verify) { /* check name */ @@ -1206,8 +1220,7 @@ static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool) /* disallow referencing among others */ if (cn->name->text[0] == '<' && cn->name != utf_init) { *exceptionptr = - new_exception_utfmessage(string_java_lang_InternalError, - cn->name); + new_classformaterror(c,"Illegal reference to special method"); return false; } } @@ -1228,12 +1241,21 @@ static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool) count_const_pool_len += sizeof(constant_FMIref); #endif /* resolve simple name and descriptor */ + nat = class_getconstant(c, forward_fieldmethints->nameandtype_index, CONSTANT_NameAndType); + if (!nat) + return false; + + /* add all descriptors in {Field,Method}ref to the descriptor_pool */ + + if (!descriptor_pool_add(descpool, nat->descriptor, NULL)) + return false; /* the classref is created later */ - fmi->classref = (constant_classref*) (size_t) forward_fieldmethints->class_index; + + fmi->classref = (constant_classref *) (size_t) forward_fieldmethints->class_index; fmi->name = nat->name; fmi->descriptor = nat->descriptor; @@ -1260,7 +1282,7 @@ static bool load_constantpool(classbuffer *cb,descriptor_pool *descpool) #define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */ -static bool load_field(classbuffer *cb, fieldinfo *f,descriptor_pool *descpool) +static bool load_field(classbuffer *cb, fieldinfo *f, descriptor_pool *descpool) { classinfo *c; u4 attrnum, i; @@ -1277,15 +1299,25 @@ static bool load_field(classbuffer *cb, fieldinfo *f,descriptor_pool *descpool) if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) return false; + f->name = u; if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) return false; + f->descriptor = u; f->parseddesc = NULL; - if (!descriptor_pool_add(descpool,u,NULL)) + + if (!descriptor_pool_add(descpool, u, NULL)) return false; + /* descriptor_pool_add accepts method descriptors, so we have to check */ + /* against them here before the call of desc_to_type below. */ + if (u->text[0] == '(') { + *exceptionptr = new_classformaterror(c,"Method descriptor used for field"); + return false; + } + if (opt_verify) { /* check name */ if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') { @@ -1448,7 +1480,7 @@ static bool load_field(classbuffer *cb, fieldinfo *f,descriptor_pool *descpool) *******************************************************************************/ -static bool load_method(classbuffer *cb, methodinfo *m,descriptor_pool *descpool) +static bool load_method(classbuffer *cb, methodinfo *m, descriptor_pool *descpool) { classinfo *c; int argcount; @@ -1481,22 +1513,29 @@ static bool load_method(classbuffer *cb, methodinfo *m,descriptor_pool *descpool if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) return false; + m->name = u; if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) return false; + m->descriptor = u; m->parseddesc = NULL; - if (!descriptor_pool_add(descpool,u,&argcount)) + + if (!descriptor_pool_add(descpool, u, &argcount)) return false; if (opt_verify) { - if (!is_valid_name_utf(m->name)) - panic("Method with invalid name"); + if (!is_valid_name_utf(m->name)) { + *exceptionptr = new_classformaterror(c,"Method with invalid name"); + return false; + } - if (m->name->text[0] == '<' - && m->name != utf_init && m->name != utf_clinit) - panic("Method with invalid special name"); + if (m->name->text[0] == '<' && + m->name != utf_init && m->name != utf_clinit) { + *exceptionptr = new_classformaterror(c,"Method with invalid special name"); + return false; + } } if (!(m->flags & ACC_STATIC)) @@ -1544,8 +1583,11 @@ static bool load_method(classbuffer *cb, methodinfo *m,descriptor_pool *descpool if (m->name == utf_init) { if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | - ACC_NATIVE | ACC_ABSTRACT)) - panic("Instance initialization method has invalid flags set"); + ACC_NATIVE | ACC_ABSTRACT)) { + *exceptionptr = new_classformaterror(c, + "Instance initialization method has invalid flags set"); + return false; + } } } } @@ -1650,7 +1692,8 @@ static bool load_method(classbuffer *cb, methodinfo *m,descriptor_pool *descpool #if defined(STATISTICS) if (opt_stat) { count_vmcode_len += m->jcodelength + 18; - count_extable_len += 8 * m->exceptiontablelength; + count_extable_len += + m->exceptiontablelength * sizeof(exceptiontable); } #endif @@ -1855,33 +1898,32 @@ static bool load_attributes(classbuffer *cb, u4 num) return true; } + /* load_class_from_sysloader *************************************************** Load the class with the given name using the system class loader IN: name.............the classname - - - OUT: - *result..........set to the loaded class RETURN VALUE: - true.............everything ok - false............an exception has been thrown + the loaded class, or + NULL if an exception has been thrown *******************************************************************************/ -bool load_class_from_sysloader(utf *name,classinfo **result) +classinfo *load_class_from_sysloader(utf *name) { - methodinfo *m; + methodinfo *m; java_objectheader *cl; - bool success; + classinfo *r; #ifdef LOADER_VERBOSE - LOADER_INDENT(); - fprintf(stderr,"load_class_from_sysloader("); - utf_fprint(stderr,name);fprintf(stderr,")\n"); + char logtext[MAXLOGTEXT]; + LOADER_INDENT(logtext); + sprintf(logtext+strlen(logtext),"load_class_from_sysloader("); + utf_sprint(logtext+strlen(logtext),name);strcat(logtext,")"); + log_text(logtext); #endif LOADER_ASSERT(class_java_lang_Object); @@ -1889,22 +1931,23 @@ bool load_class_from_sysloader(utf *name,classinfo **result) LOADER_ASSERT(class_java_lang_ClassLoader->linked); m = class_resolveclassmethod(class_java_lang_ClassLoader, - utf_new_char("getSystemClassLoader"), /* XXX use variable */ - utf_new_char("()Ljava/lang/ClassLoader;"), /* XXX use variable */ + utf_getSystemClassLoader, + utf_void__java_lang_ClassLoader, class_java_lang_Object, false); if (!m) - return false; /* exception */ + return false; cl = (java_objectheader *) asm_calljavafunction(m, NULL, NULL, NULL, NULL); if (!cl) - return false; /* exception */ + return false; LOADER_INC(); - success = load_class_from_classloader(name,cl,result); + r = load_class_from_classloader(name, cl); LOADER_DEC(); - return success; + + return r; } /* load_class_from_classloader ************************************************* @@ -1915,73 +1958,87 @@ bool load_class_from_sysloader(utf *name,classinfo **result) name.............the classname cl...............user-defined class loader - - OUT: - *result..........set to the loaded class - RETURN VALUE: - true.............everything ok - false............an exception has been thrown + the loaded class, or + NULL if an exception has been thrown *******************************************************************************/ -bool load_class_from_classloader(utf *name,java_objectheader *cl,classinfo **result) +classinfo *load_class_from_classloader(utf *name, java_objectheader *cl) { classinfo *r; - bool success; - - LOADER_ASSERT(name); - LOADER_ASSERT(result); #ifdef LOADER_VERBOSE - LOADER_INDENT(); - fprintf(stderr,"load_class_from_classloader("); - utf_fprint(stderr,name);fprintf(stderr,",%p)\n",(void*)cl); + char logtext[MAXLOGTEXT]; + LOADER_INDENT(logtext); + strcat(logtext,"load_class_from_classloader("); + utf_sprint(logtext+strlen(logtext),name);sprintf(logtext+strlen(logtext),",%p,",(void*)cl); + if (!cl) strcat(logtext,""); + else if (cl->vftbl && cl->vftbl->class) utf_sprint(logtext+strlen(logtext),cl->vftbl->class->name); + else strcat(logtext,""); + strcat(logtext,")"); + log_text(logtext); #endif + LOADER_ASSERT(name); + /* lookup if this class has already been loaded */ - *result = classcache_lookup(cl,name); + + r = classcache_lookup(cl, name); + #ifdef LOADER_VERBOSE - if (*result) - fprintf(stderr," cached -> %p\n",(void*)(*result)); + if (r) + dolog(" cached -> %p",(void*)r); #endif - if (*result) - return true; + if (r) + return r; /* if other class loader than bootstrap, call it */ if (cl) { methodinfo *lc; + char *text; + s4 namelen; + + text = name->text; + namelen = name->blength; /* handle array classes */ - if (name->text[0] == '[') { - char *utf_ptr = name->text + 1; - int len = name->blength - 1; + if (text[0] == '[') { classinfo *comp; - switch (*utf_ptr) { - case 'L': - utf_ptr++; - len -= 2; - /* FALLTHROUGH */ - case '[': - /* load the component class */ - LOADER_INC(); - if (!load_class_from_classloader(utf_new(utf_ptr,len),cl,&comp)) { - LOADER_DEC(); - return false; - } - LOADER_DEC(); - /* create the array class */ - *result = class_array_of(comp,false); - return (*result != 0); - break; - default: - /* primitive array classes are loaded by the bootstrap loader */ - LOADER_INC(); - success = load_class_bootstrap(name,result); - LOADER_DEC(); - return success; + utf *u; + + switch (text[1]) { + case 'L': + /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */ + if (namelen < 4 || text[2] == '[' || text[namelen - 1] != ';') { + *exceptionptr = new_noclassdeffounderror(name); + return false; + } + + u = utf_new(text + 2, namelen - 3); + + if (!(comp = load_class_from_classloader(u, cl))) + return false; + + /* create the array class */ + return class_array_of(comp, false); + + case '[': + /* load the component class */ + + u = utf_new(text + 1, namelen - 1); + + if (!(comp = load_class_from_classloader(u, cl))) + return false; + + /* create the array class */ + return class_array_of(comp, false); + + default: + /* primitive array classes are loaded by the bootstrap loader */ + return load_class_bootstrap(name); } } @@ -1999,25 +2056,53 @@ bool load_class_from_classloader(utf *name,java_objectheader *cl,classinfo **res LOADER_INC(); r = (classinfo *) asm_calljavafunction(lc, cl, - javastring_new(name), + javastring_new_slash_to_dot(name), NULL, NULL); LOADER_DEC(); - /* store this class in the loaded class cache */ - if (r && !classcache_store(cl,r)) { - r->loaded = false; - class_free(r); - r = NULL; /* exception */ + if (r) { + /* Store this class in the loaded class cache. If another + class with the same (initloader,name) pair has been + stored earlier it will be returned by classcache_store + In this case classcache_store may not free the class + because it has already been exposed to Java code which + may have kept references to that class. */ + + classinfo *c = classcache_store(cl,r,false); + + if (c == NULL) { + /* exception, free the loaded class */ + r->loaded = false; + class_free(r); + } + + r = c; + } + else { + /* loadClass has thrown an exception */ + /* we must convert ClassNotFoundException into NoClassDefFoundException */ + /* XXX maybe we should have a flag that avoids this conversion */ + /* for calling load_class_from_classloader from Class.forName */ + /* Currently we do a double conversion in these cases */ + classnotfoundexception_to_noclassdeffounderror(); + } + + /* SUN compatible -verbose:class output */ + + if (opt_verboseclass && (r != NULL) && (r->classloader == cl)) { + printf("[Loaded "); + utf_display_classname(name); + printf("]\n"); } - *result = r; - return (r != NULL); + return r; } LOADER_INC(); - success = load_class_bootstrap(name,result); + r = load_class_bootstrap(name); LOADER_DEC(); - return success; + + return r; } @@ -2028,61 +2113,60 @@ bool load_class_from_classloader(utf *name,java_objectheader *cl,classinfo **res IN: name.............the classname - OUT: - *result..........set to the loaded class - RETURN VALUE: - true.............everything ok - false............an exception has been thrown + loaded classinfo, or + NULL if an exception has been thrown + + SYNCHRONIZATION: + load_class_bootstrap is synchronized. It can be treated as an + atomic operation. *******************************************************************************/ -bool load_class_bootstrap(utf *name, classinfo **result) +classinfo *load_class_bootstrap(utf *name) { classbuffer *cb; - classinfo *c; - classinfo *r; + classinfo *c; + classinfo *r; +#ifdef LOADER_VERBOSE + char logtext[MAXLOGTEXT]; +#endif + + /* for debugging */ LOADER_ASSERT(name); - LOADER_ASSERT(result); + LOADER_INC(); /* lookup if this class has already been loaded */ - *result = classcache_lookup(NULL, name); - if (*result) - return true; - /* check if this class has already been defined */ - *result = classcache_lookup_defined(NULL, name); - if (*result) - return true; + if ((r = classcache_lookup(NULL, name))) + goto success; #ifdef LOADER_VERBOSE - LOADER_INDENT(); - fprintf(stderr,"load_class_bootstrap("); - utf_fprint(stderr,name);fprintf(stderr,")\n"); + LOADER_INDENT(logtext); + strcat(logtext,"load_class_bootstrap("); + utf_sprint(logtext+strlen(logtext),name);strcat(logtext,")"); + log_text(logtext); #endif /* create the classinfo */ + c = class_create_classinfo(name); /* handle array classes */ + if (name->text[0] == '[') { - LOADER_INC(); - load_newly_created_array(c, NULL); - LOADER_DEC(); + c = load_newly_created_array(c, NULL); + if (c == NULL) + goto return_exception; LOADER_ASSERT(c->loaded); - *result = c; - return true; + r = c; + goto success; } -#if defined(USE_THREADS) - /* enter a monitor on the class */ - - builtin_monitorenter((java_objectheader *) c); -#endif - #if defined(STATISTICS) /* measure time */ + if (getcompilingtime) compilingtime_stop(); @@ -2093,7 +2177,8 @@ bool load_class_bootstrap(utf *name, classinfo **result) /* load classdata, throw exception on error */ if ((cb = suck_start(c)) == NULL) { - /* this means, the classpath was not set properly */ + /* this normally means, the classpath was not set properly */ + if (name == utf_java_lang_Object) throw_cacao_exception_exit(string_java_lang_NoClassDefFoundError, "java/lang/Object"); @@ -2101,25 +2186,48 @@ bool load_class_bootstrap(utf *name, classinfo **result) *exceptionptr = new_exception_utfmessage(string_java_lang_NoClassDefFoundError, name); - -#if defined(USE_THREADS) - builtin_monitorexit((java_objectheader *) c); -#endif - - return false; + goto return_exception; } /* load the class from the buffer */ - LOADER_INC(); r = load_class_from_classbuffer(cb); - LOADER_DEC(); + + if (!r) { + /* the class could not be loaded, free the classinfo struct */ + + class_free(c); + + } else { + /* Store this class in the loaded class cache this step also + checks the loading constraints. If the class has been loaded + before, the earlier loaded class is returned. */ + + classinfo *res = classcache_store(NULL, c, true); + + if (!res) { + /* exception */ + class_free(c); + } + + r = res; + } + + /* SUN compatible -verbose:class output */ + + if (opt_verboseclass && r) { + printf("[Loaded "); + utf_display_classname(name); + printf(" from %s]\n", cb->path); + } /* free memory */ + suck_stop(cb); #if defined(STATISTICS) /* measure time */ + if (getloadingtime) loadingtime_stop(); @@ -2127,29 +2235,18 @@ bool load_class_bootstrap(utf *name, classinfo **result) compilingtime_start(); #endif - if (!r) { -#if defined(USE_THREADS) - builtin_monitorexit((java_objectheader *) c); -#endif - class_free(c); - } + if (!r) + goto return_exception; - /* store this class in the loaded class cache */ - if (r && !classcache_store(NULL, c)) { -#if defined(USE_THREADS) - builtin_monitorexit((java_objectheader *) c); -#endif - class_free(c); - r = NULL; /* exception */ - } +success: + LOADER_DEC(); -#if defined(USE_THREADS) - /* leave the monitor */ - if (c) builtin_monitorexit((java_objectheader *) c); -#endif + return r; - *result = r; - return (r != NULL); +return_exception: + LOADER_DEC(); + + return NULL; } @@ -2164,6 +2261,9 @@ bool load_class_bootstrap(utf *name, classinfo **result) The loaded class is removed from the list 'unloadedclasses' and added to the list 'unlinkedclasses'. + SYNCHRONIZATION: + This function is NOT synchronized! + *******************************************************************************/ classinfo *load_class_from_classbuffer(classbuffer *cb) @@ -2175,23 +2275,28 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) u4 ma, mi; s4 dumpsize; descriptor_pool *descpool; - char msg[MAXLOGTEXT]; /* maybe we get an exception */ #if defined(STATISTICS) u4 classrefsize; u4 descsize; #endif +#ifdef LOADER_VERBOSE + char logtext[MAXLOGTEXT]; +#endif /* get the classbuffer's class */ + c = cb->class; /* maybe the class is already loaded */ + if (c->loaded) return c; #ifdef LOADER_VERBOSE - LOADER_INDENT(); - fprintf(stderr,"load_class_from_classbuffer("); - utf_fprint(stderr,c->name);fprintf(stderr,")\n"); + LOADER_INDENT(logtext); + strcat(logtext,"load_class_from_classbuffer("); + utf_sprint(logtext+strlen(logtext),c->name);strcat(logtext,")"); + log_text(logtext); LOADER_INC(); #endif @@ -2201,19 +2306,23 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) #endif /* output for debugging purposes */ + if (loadverbose) log_message_class("Loading class: ", c); /* mark start of dump memory area */ + dumpsize = dump_size(); /* class is somewhat loaded */ + c->loaded = true; if (!check_classbuffer_size(cb, 4 + 2 + 2)) goto return_exception; /* check signature */ + if (suck_u4(cb) != MAGIC) { *exceptionptr = new_classformaterror(c, "Bad magic number"); @@ -2221,6 +2330,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) } /* check version */ + mi = suck_u2(cb); ma = suck_u2(cb); @@ -2234,10 +2344,12 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) } /* create a new descriptor pool */ + descpool = descriptor_pool_new(c); - + /* load the constant pool */ - if (!load_constantpool(cb,descpool)) + + if (!load_constantpool(cb, descpool)) goto return_exception; /*JOWENN*/ @@ -2248,12 +2360,14 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) c->impldBy = NULL; /* ACC flags */ + if (!check_classbuffer_size(cb, 2)) goto return_exception; c->flags = suck_u2(cb); /* check ACC flags consistency */ + if (c->flags & ACC_INTERFACE) { if (!(c->flags & ACC_ABSTRACT)) { /* We work around this because interfaces in JDK 1.1 are @@ -2286,11 +2400,25 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) goto return_exception; /* this class */ + i = suck_u2(cb); if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class))) goto return_exception; - if (name != c->name) { + if (c->name == utf_not_named_yet) { + /* we finally have a name for this class */ + c->name = name; + class_set_packagename(c); + + } else if (name != c->name) { + char *msg; + s4 msglen; + + msglen = utf_strlen(c->name) + strlen(" (wrong name: ") + + utf_strlen(name) + strlen(")") + strlen("0"); + + msg = MNEW(char, msglen); + utf_sprint(msg, c->name); strcat(msg, " (wrong name: "); utf_strcat(msg, name); @@ -2299,16 +2427,20 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) *exceptionptr = new_exception_message(string_java_lang_NoClassDefFoundError, msg); + MFREE(msg, char, msglen); + goto return_exception; } /* retrieve superclass */ + c->super.any = NULL; if ((i = suck_u2(cb))) { if (!(supername = (utf *) class_getconstant(c, i, CONSTANT_Class))) goto return_exception; /* java.lang.Object may not have a super class. */ + if (c->name == utf_java_lang_Object) { *exceptionptr = new_exception_message(string_java_lang_ClassFormatError, @@ -2318,6 +2450,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) } /* Interfaces must have java.lang.Object as super class. */ + if ((c->flags & ACC_INTERFACE) && supername != utf_java_lang_Object) { *exceptionptr = @@ -2331,6 +2464,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) supername = NULL; /* This is only allowed for java.lang.Object. */ + if (c->name != utf_java_lang_Object) { *exceptionptr = new_classformaterror(c, "Bad superclass index"); @@ -2339,6 +2473,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) } /* retrieve interfaces */ + if (!check_classbuffer_size(cb, 2)) goto return_exception; @@ -2359,7 +2494,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) goto return_exception; c->fieldscount = suck_u2(cb); - c->fields = GCNEW(fieldinfo, c->fieldscount); + c->fields = GCNEW_UNCOLLECTABLE(fieldinfo, c->fieldscount); /* c->fields = MNEW(fieldinfo, c->fieldscount); */ for (i = 0; i < c->fieldscount; i++) { if (!load_field(cb, &(c->fields[i]),descpool)) @@ -2379,15 +2514,19 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) } /* create the class reference table */ - c->classrefs = descriptor_pool_create_classrefs(descpool,&(c->classrefcount)); + + c->classrefs = + descriptor_pool_create_classrefs(descpool, &(c->classrefcount)); /* allocate space for the parsed descriptors */ + descriptor_pool_alloc_parsed_descriptors(descpool); - c->parseddescs = descriptor_pool_get_parsed_descriptors(descpool,&(c->parseddescsize)); + c->parseddescs = + descriptor_pool_get_parsed_descriptors(descpool, &(c->parseddescsize)); #if defined(STATISTICS) if (opt_stat) { - descriptor_pool_get_sizes(descpool,&classrefsize,&descsize); + descriptor_pool_get_sizes(descpool, &classrefsize, &descsize); count_classref_len += classrefsize; count_parsed_desc_len += descsize; } @@ -2402,6 +2541,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) } /* set the super class reference */ + if (supername) { c->super.ref = descriptor_pool_lookup_classref(descpool, supername); if (!c->super.ref) @@ -2409,53 +2549,32 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) } /* set the super interfaces references */ + for (i = 0; i < c->interfacescount; i++) { - c->interfaces[i].ref = descriptor_pool_lookup_classref(descpool, (utf *) c->interfaces[i].any); + c->interfaces[i].ref = + descriptor_pool_lookup_classref(descpool, + (utf *) c->interfaces[i].any); if (!c->interfaces[i].ref) goto return_exception; } - /* parse the loaded descriptors */ - for (i = 0; i < c->cpcount; i++) { - constant_FMIref *fmi; - int index; - - switch (c->cptags[i]) { - case CONSTANT_Fieldref: - fmi = (constant_FMIref *) c->cpinfos[i]; - fmi->parseddesc.fd = - descriptor_pool_parse_field_descriptor(descpool, fmi->descriptor); - if (!fmi->parseddesc.fd) - goto return_exception; - index = (int) (size_t) fmi->classref; - fmi->classref = (constant_classref *) class_getconstant(c, index, CONSTANT_Class); - if (!fmi->classref) - goto return_exception; - break; - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - fmi = (constant_FMIref *) c->cpinfos[i]; - fmi->parseddesc.md = - descriptor_pool_parse_method_descriptor(descpool, fmi->descriptor); - if (!fmi->parseddesc.md) - goto return_exception; - index = (int) (size_t) fmi->classref; - fmi->classref = (constant_classref *) class_getconstant(c, index, CONSTANT_Class); - if (!fmi->classref) - goto return_exception; - break; - } - } + /* parse field descriptors */ for (i = 0; i < c->fieldscount; i++) { - c->fields[i].parseddesc = descriptor_pool_parse_field_descriptor(descpool, c->fields[i].descriptor); + c->fields[i].parseddesc = + descriptor_pool_parse_field_descriptor(descpool, + c->fields[i].descriptor); if (!c->fields[i].parseddesc) goto return_exception; } + /* parse method descriptors */ + for (i = 0; i < c->methodscount; i++) { - methodinfo *m = c->methods + i; - m->parseddesc = descriptor_pool_parse_method_descriptor(descpool, m->descriptor); + methodinfo *m = &c->methods[i]; + m->parseddesc = + descriptor_pool_parse_method_descriptor(descpool, m->descriptor, + m->flags, class_get_self_classref(m->class)); if (!m->parseddesc) goto return_exception; @@ -2477,12 +2596,54 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) } } - /* Check if all fields and methods can be uniquely - * identified by (name,descriptor). */ - if (opt_verify) { - /* We use a hash table here to avoid making the - * average case quadratic in # of methods, fields. - */ + /* parse the loaded descriptors */ + + for (i = 0; i < c->cpcount; i++) { + constant_FMIref *fmi; + s4 index; + + switch (c->cptags[i]) { + case CONSTANT_Fieldref: + fmi = (constant_FMIref *) c->cpinfos[i]; + fmi->parseddesc.fd = + descriptor_pool_parse_field_descriptor(descpool, + fmi->descriptor); + if (!fmi->parseddesc.fd) + goto return_exception; + index = (int) (size_t) fmi->classref; + fmi->classref = + (constant_classref *) class_getconstant(c, index, + CONSTANT_Class); + if (!fmi->classref) + goto return_exception; + break; + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + fmi = (constant_FMIref *) c->cpinfos[i]; + index = (int) (size_t) fmi->classref; + fmi->classref = + (constant_classref *) class_getconstant(c, index, + CONSTANT_Class); + if (!fmi->classref) + goto return_exception; + fmi->parseddesc.md = + descriptor_pool_parse_method_descriptor(descpool, + fmi->descriptor, + ACC_UNDEF, + fmi->classref); + if (!fmi->parseddesc.md) + goto return_exception; + break; + } + } + + /* Check if all fields and methods can be uniquely + * identified by (name,descriptor). */ + + if (opt_verify) { + /* We use a hash table here to avoid making the + * average case quadratic in # of methods, fields. + */ static int shift = 0; u2 *hashtab; u2 *next; /* for chaining colliding hash entries */ @@ -2580,6 +2741,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) #endif /* load attribute structures */ + if (!check_classbuffer_size(cb, 2)) goto return_exception; @@ -2604,6 +2766,7 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) #endif /* release dump area */ + dump_release(dumpsize); if (loadverbose) @@ -2614,18 +2777,25 @@ classinfo *load_class_from_classbuffer(classbuffer *cb) return_exception: /* release dump area */ + dump_release(dumpsize); /* an exception has been thrown */ + LOADER_DEC(); return NULL; } - /* load_newly_created_array **************************************************** - Load a newly created array class. + Load a newly created array class. + + RETURN VALUE: + c....................the array class C has been loaded + other classinfo......the array class was found in the class cache, + C has been freed + NULL.................an exception has been thrown Note: This is an internal function. Do not use it unless you know exactly @@ -2635,81 +2805,105 @@ return_exception: *******************************************************************************/ -bool load_newly_created_array(classinfo *c,java_objectheader *loader) +classinfo *load_newly_created_array(classinfo *c, java_objectheader *loader) { - classinfo *comp = NULL; - methodinfo *clone; - methoddesc *clonedesc; + classinfo *comp = NULL; + methodinfo *clone; + methoddesc *clonedesc; constant_classref *classrefs; - int namelen; - java_objectheader *definingloader = NULL; + char *text; + s4 namelen; + utf *u; #ifdef LOADER_VERBOSE - LOADER_INDENT(); - fprintf(stderr,"load_newly_created_array(");utf_fprint_classname(stderr,c->name); - fprintf(stderr,") loader=%p\n",loader); + char logtext[MAXLOGTEXT]; + LOADER_INDENT(logtext); + strcat(logtext,"load_newly_created_array(");utf_sprint_classname(logtext+strlen(logtext),c->name); + sprintf(logtext+strlen(logtext),") loader=%p",loader); + log_text(logtext); #endif - /* Check array class name */ + text = c->name->text; namelen = c->name->blength; - if (namelen < 2 || c->name->text[0] != '[') { - *exceptionptr = new_internalerror("Invalid array class name"); - return false; + + /* Check array class name */ + + if (namelen < 2 || text[0] != '[') { + *exceptionptr = new_noclassdeffounderror(c->name); + return NULL; } - /* Check the component type */ - switch (c->name->text[1]) { + /* Check the element type */ + + switch (text[1]) { case '[': /* c is an array of arrays. We have to create the component class. */ + + u = utf_new(text + 1, namelen - 1); LOADER_INC(); - if (!load_class_from_classloader(utf_new_intern(c->name->text + 1, - namelen - 1), - loader, - &comp)) - { + if (!(comp = load_class_from_classloader(u, loader))) { LOADER_DEC(); - return false; + return NULL; } LOADER_DEC(); LOADER_ASSERT(comp->loaded); if (opt_eager) if (!link_class(c)) - return false; - definingloader = comp->classloader; + return NULL; + + /* the array's flags are that of the component class */ + c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT; + c->classloader = comp->classloader; break; case 'L': /* c is an array of objects. */ - if (namelen < 4 || c->name->text[namelen - 1] != ';') { - *exceptionptr = new_internalerror("Invalid array class name"); - return false; + + /* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */ + if (namelen < 4 || text[2] == '[' || text[namelen - 1] != ';') { + *exceptionptr = new_noclassdeffounderror(c->name); + return NULL; } + u = utf_new(text + 2, namelen - 3); + LOADER_INC(); - if (!load_class_from_classloader(utf_new_intern(c->name->text + 2, - namelen - 3), - loader, - &comp)) - { + if (!(comp = load_class_from_classloader(u, loader))) { LOADER_DEC(); - return false; + return NULL; } LOADER_DEC(); LOADER_ASSERT(comp->loaded); if (opt_eager) if (!link_class(c)) - return false; - definingloader = comp->classloader; + return NULL; + + /* the array's flags are that of the component class */ + c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT; + c->classloader = comp->classloader; break; + + default: + /* c is an array of a primitive type */ + + /* check for cases like `[II' */ + if (namelen > 2) { + *exceptionptr = new_noclassdeffounderror(c->name); + return NULL; + } + + /* the accessibility of the array class is public (VM Spec 5.3.3) */ + c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; + c->classloader = NULL; } LOADER_ASSERT(class_java_lang_Object); LOADER_ASSERT(class_java_lang_Cloneable); LOADER_ASSERT(class_java_io_Serializable); - /* Setup the array class */ + /* setup the array class */ + c->super.cls = class_java_lang_Object; - c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; c->interfacescount = 2; c->interfaces = MNEW(classref_or_classinfo, 2); @@ -2735,655 +2929,62 @@ bool load_newly_created_array(classinfo *c,java_objectheader *loader) c->methodscount = 1; c->methods = MNEW(methodinfo, c->methodscount); - classrefs = MNEW(constant_classref,1); - CLASSREF_INIT(classrefs[0],c,utf_java_lang_Object); + classrefs = MNEW(constant_classref, 2); + CLASSREF_INIT(classrefs[0], c, c->name); + CLASSREF_INIT(classrefs[1], c, utf_java_lang_Object); + /* create descriptor for clone method */ + /* we need one paramslot which is reserved for the 'this' parameter */ clonedesc = NEW(methoddesc); clonedesc->returntype.type = TYPE_ADDRESS; - clonedesc->returntype.classref = classrefs; + clonedesc->returntype.classref = classrefs + 1; clonedesc->returntype.arraydim = 0; + /* initialize params to "empty", add real params below in + descriptor_params_from_paramtypes */ clonedesc->paramcount = 0; clonedesc->paramslots = 0; + clonedesc->paramtypes[0].classref = classrefs + 0; + + /* create methodinfo */ clone = c->methods; MSET(clone, 0, methodinfo, 1); - clone->flags = ACC_PUBLIC; - clone->name = utf_new_char("clone"); + +#if defined(USE_THREADS) && defined(NATIVE_THREADS) + initObjectLock(&clone->header); +#endif + + /* if you delete the ACC_NATIVE below, set clone->maxlocals=1 (interpreter + related) */ + clone->flags = ACC_PUBLIC | ACC_NATIVE; + clone->name = utf_clone; clone->descriptor = utf_void__java_lang_Object; clone->parseddesc = clonedesc; clone->class = c; - clone->stubroutine = createnativestub((functionptr) &builtin_clone_array, clone); clone->monoPoly = MONO; + /* parse the descriptor to get the register allocation */ + + if (!descriptor_params_from_paramtypes(clonedesc, clone->flags)) + return false; + + clone->entrypoint = + codegen_createnativestub((functionptr) &builtin_clone_array, clone); + /* XXX: field: length? */ /* array classes are not loaded from class files */ + c->loaded = true; - c->parseddescs = (u1*) clonedesc; + c->parseddescs = (u1 *) clonedesc; c->parseddescsize = sizeof(methodinfo); c->classrefs = classrefs; c->classrefcount = 1; - c->classloader = definingloader; /* insert class into the loaded class cache */ - if (!classcache_store(loader,c)) - return false; - - return true; -} - - -/************************* Function: class_findfield *************************** - - Searches a 'classinfo' structure for a field having the given name and - type. - -*******************************************************************************/ - -fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc) -{ - s4 i; - - for (i = 0; i < c->fieldscount; i++) { - if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) - return &(c->fields[i]); - } - - panic("Can not find field given in CONSTANT_Fieldref"); - - /* keep compiler happy */ - return NULL; -} - - -/****************** Function: class_resolvefield_int *************************** - - This is an internally used helper function. Do not use this directly. - - Tries to resolve a field having the given name and type. - If the field cannot be resolved, NULL is returned. - -*******************************************************************************/ - -static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc) -{ - fieldinfo *fi; - s4 i; - - /* search for field in class c */ - - for (i = 0; i < c->fieldscount; i++) { - if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) { - return &(c->fields[i]); - } - } - - /* try superinterfaces recursively */ - - for (i = 0; i < c->interfacescount; i++) { - fi = class_resolvefield_int(c->interfaces[i].cls, name, desc); - if (fi) - return fi; - } - - /* try superclass */ - - if (c->super.cls) - return class_resolvefield_int(c->super.cls, name, desc); - - /* not found */ - - return NULL; -} - - -/********************* Function: class_resolvefield *************************** - - Resolves a reference from REFERER to a field with NAME and DESC in class C. - - If the field cannot be resolved the return value is NULL. If EXCEPT is - true *exceptionptr is set, too. - -*******************************************************************************/ - -fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool except) -{ - fieldinfo *fi; - - /* XXX resolve class c */ - /* XXX check access from REFERER to C */ - - fi = class_resolvefield_int(c, name, desc); - - if (!fi) { - if (except) - *exceptionptr = - new_exception_utfmessage(string_java_lang_NoSuchFieldError, - name); - - return NULL; - } - - /* XXX check access rights */ - - return fi; -} - - -/* class_findmethod ************************************************************ - - Searches a 'classinfo' structure for a method having the given name - and descriptor. If descriptor is NULL, it is ignored. - -*******************************************************************************/ - -methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc) -{ - methodinfo *m; - s4 i; - - for (i = 0; i < c->methodscount; i++) { - m = &(c->methods[i]); - - if ((m->name == name) && ((desc == NULL) || (m->descriptor == desc))) - return m; - } - - return NULL; -} - - -/*********************** Function: class_fetchmethod ************************** - - like class_findmethod, but aborts with an error if the method is not found - -*******************************************************************************/ - -methodinfo *class_fetchmethod(classinfo *c, utf *name, utf *desc) -{ - methodinfo *mi; - - mi = class_findmethod(c, name, desc); - - if (!mi) { - log_plain("Class: "); if (c) log_plain_utf(c->name); log_nl(); - log_plain("Method: "); if (name) log_plain_utf(name); log_nl(); - log_plain("Descriptor: "); if (desc) log_plain_utf(desc); log_nl(); - panic("Method not found"); - } - - return mi; -} - - -/************************* Function: class_findmethod_approx ****************** - - like class_findmethod but ignores the return value when comparing the - descriptor. - -*******************************************************************************/ - -methodinfo *class_findmethod_approx(classinfo *c, utf *name, utf *desc) -{ - s4 i; - - for (i = 0; i < c->methodscount; i++) { - if (c->methods[i].name == name) { - utf *meth_descr = c->methods[i].descriptor; - - if (desc == NULL) - /* ignore type */ - return &(c->methods[i]); - - if (desc->blength <= meth_descr->blength) { - /* current position in utf text */ - char *desc_utf_ptr = desc->text; - char *meth_utf_ptr = meth_descr->text; - /* points behind utf strings */ - char *desc_end = utf_end(desc); - char *meth_end = utf_end(meth_descr); - char ch; - - /* compare argument types */ - while (desc_utf_ptr < desc_end && meth_utf_ptr < meth_end) { - - if ((ch = *desc_utf_ptr++) != (*meth_utf_ptr++)) - break; /* no match */ - - if (ch == ')') - return &(c->methods[i]); /* all parameter types equal */ - } - } - } - } - - return NULL; -} - - -/***************** Function: class_resolvemethod_approx *********************** - - Searches a class and every super class for a method (without paying - attention to the return value) - -*******************************************************************************/ - -methodinfo *class_resolvemethod_approx(classinfo *c, utf *name, utf *desc) -{ - while (c) { - /* search for method (ignore returntype) */ - methodinfo *m = class_findmethod_approx(c, name, desc); - /* method found */ - if (m) return m; - /* search superclass */ - c = c->super.cls; - } - - return NULL; -} - - -/* class_resolvemethod ********************************************************* - - Searches a class and it's super classes for a method. - -*******************************************************************************/ - -methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc) -{ - methodinfo *m; - - while (c) { - m = class_findmethod(c, name, desc); - - if (m) - return m; - - c = c->super.cls; - } - - return NULL; -} - - -/* class_resolveinterfacemethod_intern ***************************************** - - Internally used helper function. Do not use this directly. - -*******************************************************************************/ - -static methodinfo *class_resolveinterfacemethod_intern(classinfo *c, - utf *name, utf *desc) -{ - methodinfo *m; - s4 i; - - m = class_findmethod(c, name, desc); - - if (m) - return m; - - /* try the superinterfaces */ - - for (i = 0; i < c->interfacescount; i++) { - m = class_resolveinterfacemethod_intern(c->interfaces[i].cls, name, desc); - - if (m) - return m; - } - - return NULL; -} - -/* class_resolveinterfacemethod ************************************************ - - Resolves a reference from REFERER to a method with NAME and DESC in - interface C. - - If the method cannot be resolved the return value is NULL. If - EXCEPT is true *exceptionptr is set, too. - -*******************************************************************************/ - -methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool except) -{ - methodinfo *mi; - - /* XXX resolve class c */ - /* XXX check access from REFERER to C */ - - if (!(c->flags & ACC_INTERFACE)) { - if (except) - *exceptionptr = - new_exception(string_java_lang_IncompatibleClassChangeError); - - return NULL; - } - - mi = class_resolveinterfacemethod_intern(c, name, desc); - - if (mi) - return mi; - - /* try class java.lang.Object */ - LOADER_ASSERT(class_java_lang_Object); - mi = class_findmethod(class_java_lang_Object, name, desc); - - if (mi) - return mi; - - if (except) - *exceptionptr = - new_exception_utfmessage(string_java_lang_NoSuchMethodError, name); - - return NULL; -} - - -/* class_resolveclassmethod **************************************************** - - Resolves a reference from REFERER to a method with NAME and DESC in - class C. - - If the method cannot be resolved the return value is NULL. If EXCEPT is - true *exceptionptr is set, too. - -*******************************************************************************/ - -methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool except) -{ - classinfo *cls; - methodinfo *mi; - s4 i; - char *msg; - s4 msglen; - - /* XXX resolve class c */ - /* XXX check access from REFERER to C */ - -/* if (c->flags & ACC_INTERFACE) { */ -/* if (except) */ -/* *exceptionptr = */ -/* new_exception(string_java_lang_IncompatibleClassChangeError); */ -/* return NULL; */ -/* } */ - - /* try class c and its superclasses */ - - cls = c; - - while (cls) { - mi = class_findmethod(cls, name, desc); - - if (mi) - goto found; - - cls = cls->super.cls; - } - - /* try the superinterfaces */ - - for (i = 0; i < c->interfacescount; i++) { - mi = class_resolveinterfacemethod_intern(c->interfaces[i].cls, name, desc); - - if (mi) - goto found; - } - - if (except) { - msglen = utf_strlen(c->name) + strlen(".") + utf_strlen(name) + - utf_strlen(desc) + strlen("0"); - - msg = MNEW(char, msglen); - - utf_sprint(msg, c->name); - strcat(msg, "."); - utf_sprint(msg + strlen(msg), name); - utf_sprint(msg + strlen(msg), desc); - - *exceptionptr = - new_exception_message(string_java_lang_NoSuchMethodError, msg); - - MFREE(msg, char, msglen); - } - - return NULL; - - found: - if ((mi->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) { - if (except) - *exceptionptr = new_exception(string_java_lang_AbstractMethodError); - - return NULL; - } - - /* XXX check access rights */ - - return mi; -} - - -/************************* Function: class_issubclass ************************** - - Checks if sub is a descendant of super. - -*******************************************************************************/ - -bool class_issubclass(classinfo *sub, classinfo *super) -{ - for (;;) { - if (!sub) return false; - if (sub == super) return true; - sub = sub->super.cls; - } -} - - -void class_showconstanti(classinfo *c, int ii) -{ - u4 i = ii; - voidptr e; - - e = c->cpinfos [i]; - printf ("#%d: ", (int) i); - if (e) { - switch (c->cptags [i]) { - case CONSTANT_Class: - printf("Classreference -> "); - utf_display(((constant_classref*)e)->name); - break; - - case CONSTANT_Fieldref: - printf("Fieldref -> "); goto displayFMIi; - case CONSTANT_Methodref: - printf("Methodref -> "); goto displayFMIi; - case CONSTANT_InterfaceMethodref: - printf("InterfaceMethod -> "); goto displayFMIi; - displayFMIi: - { - constant_FMIref *fmi = e; - utf_display(fmi->classref->name); - printf("."); - utf_display(fmi->name); - printf(" "); - utf_display(fmi->descriptor); - } - break; - - case CONSTANT_String: - printf("String -> "); - utf_display(e); - break; - case CONSTANT_Integer: - printf("Integer -> %d", (int) (((constant_integer*)e)->value)); - break; - case CONSTANT_Float: - printf("Float -> %f", ((constant_float*)e)->value); - break; - case CONSTANT_Double: - printf("Double -> %f", ((constant_double*)e)->value); - break; - case CONSTANT_Long: - { - u8 v = ((constant_long*)e)->value; -#if U8_AVAILABLE - printf("Long -> %ld", (long int) v); -#else - printf("Long -> HI: %ld, LO: %ld\n", - (long int) v.high, (long int) v.low); -#endif - } - break; - case CONSTANT_NameAndType: - { - constant_nameandtype *cnt = e; - printf("NameAndType: "); - utf_display(cnt->name); - printf(" "); - utf_display(cnt->descriptor); - } - break; - case CONSTANT_Utf8: - printf("Utf8 -> "); - utf_display(e); - break; - default: - panic("Invalid type of ConstantPool-Entry"); - } - } - printf("\n"); -} - - -void class_showconstantpool (classinfo *c) -{ - u4 i; - voidptr e; - - printf ("---- dump of constant pool ----\n"); - - for (i=0; icpcount; i++) { - printf ("#%d: ", (int) i); - - e = c -> cpinfos [i]; - if (e) { - - switch (c -> cptags [i]) { - case CONSTANT_Class: - printf ("Classreference -> "); - utf_display ( ((constant_classref*)e) -> name ); - break; - - case CONSTANT_Fieldref: - printf ("Fieldref -> "); goto displayFMI; - case CONSTANT_Methodref: - printf ("Methodref -> "); goto displayFMI; - case CONSTANT_InterfaceMethodref: - printf ("InterfaceMethod -> "); goto displayFMI; - displayFMI: - { - constant_FMIref *fmi = e; - utf_display ( fmi->classref->name ); - printf ("."); - utf_display ( fmi->name); - printf (" "); - utf_display ( fmi->descriptor ); - } - break; - - case CONSTANT_String: - printf ("String -> "); - utf_display (e); - break; - case CONSTANT_Integer: - printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) ); - break; - case CONSTANT_Float: - printf ("Float -> %f", ((constant_float*)e) -> value); - break; - case CONSTANT_Double: - printf ("Double -> %f", ((constant_double*)e) -> value); - break; - case CONSTANT_Long: - { - u8 v = ((constant_long*)e) -> value; -#if U8_AVAILABLE - printf ("Long -> %ld", (long int) v); -#else - printf ("Long -> HI: %ld, LO: %ld\n", - (long int) v.high, (long int) v.low); -#endif - } - break; - case CONSTANT_NameAndType: - { - constant_nameandtype *cnt = e; - printf ("NameAndType: "); - utf_display (cnt->name); - printf (" "); - utf_display (cnt->descriptor); - } - break; - case CONSTANT_Utf8: - printf ("Utf8 -> "); - utf_display (e); - break; - default: - panic ("Invalid type of ConstantPool-Entry"); - } - } - - printf ("\n"); - } -} - - - -/********** Function: class_showmethods (debugging only) *************/ - -void class_showmethods (classinfo *c) -{ - s4 i; - - printf ("--------- Fields and Methods ----------------\n"); - printf ("Flags: "); printflags (c->flags); printf ("\n"); - - printf ("This: "); utf_display (c->name); printf ("\n"); - if (c->super.cls) { - printf ("Super: "); utf_display (c->super.cls->name); printf ("\n"); - } - printf ("Index: %d\n", c->index); - - printf ("interfaces:\n"); - for (i=0; i < c-> interfacescount; i++) { - printf (" "); - utf_display (c -> interfaces[i].cls -> name); - printf (" (%d)\n", c->interfaces[i].cls -> index); - } - - printf ("fields:\n"); - for (i=0; i < c -> fieldscount; i++) { - field_display (&(c -> fields[i])); - } - - printf ("methods:\n"); - for (i=0; i < c -> methodscount; i++) { - methodinfo *m = &(c->methods[i]); - if ( !(m->flags & ACC_STATIC)) - printf ("vftblindex: %d ", m->vftblindex); - - method_display ( m ); - - } - - printf ("Virtual function table:\n"); - for (i=0; ivftbl->vftbllength; i++) { - printf ("entry: %d, %ld\n", i, (long int) (c->vftbl->table[i]) ); - } + /* XXX free classinfo if NULL returned? */ + return classcache_store(loader,c,true); }