X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Floader.c;h=92d8c0fa395bda9fd3d6888de431d3c57d7e7038;hb=4f021ace4cbb48cb8d75e5445929a01f61ca756a;hp=b9f09209c79f8570f20dad8f1aa30835686beb18;hpb=30692a0b2c828eeb7ee4ad26bcbdab8af110c056;p=cacao.git diff --git a/src/vm/loader.c b/src/vm/loader.c index b9f09209c..92d8c0fa3 100644 --- a/src/vm/loader.c +++ b/src/vm/loader.c @@ -32,11 +32,10 @@ Edwin Steiner Christian Thalinger - $Id: loader.c 2137 2005-03-30 10:18:38Z twisti $ + $Id: loader.c 3684 2005-11-16 13:28:33Z twisti $ */ - #include #include #include @@ -61,11 +60,13 @@ #include "vm/exceptions.h" #include "vm/builtin.h" #include "vm/global.h" +#include "vm/linker.h" #include "vm/loader.h" #include "vm/options.h" #include "vm/statistics.h" #include "vm/stringlocal.h" #include "vm/tables.h" +#include "vm/classcache.h" #if defined(USE_ZLIB) # include "vm/unzip.h" @@ -74,11 +75,36 @@ #include "vm/jit/asmpart.h" #include "vm/jit/codegen.inc.h" +/******************************************************************************/ +/* DEBUG HELPERS */ +/******************************************************************************/ + +/*#define LOADER_VERBOSE*/ + +#ifndef NDEBUG +#define LOADER_DEBUG +#endif + +#ifdef LOADER_DEBUG +#define LOADER_ASSERT(cond) assert(cond) +#else +#define LOADER_ASSERT(cond) +#endif #undef JOWENN_DEBUG #undef JOWENN_DEBUG1 #undef JOWENN_DEBUG2 +#ifdef LOADER_VERBOSE +static int loader_recursion = 0; +#define LOADER_INDENT(str) do { int i; for(i=0;inext) { + if (cpi->type == CLASSPATH_ARCHIVE) + initObjectLock(&cpi->header); + } #endif -} + /* load some important classes */ -/******************* function checkmethoddescriptor **************************** + if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object))) + return false; - checks whether a method-descriptor is valid and aborts otherwise. - All referenced classes are inserted into the list of unloaded classes. + if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String))) + return false; - The number of arguments is returned. A long or double argument is counted - as two arguments. - -*******************************************************************************/ + if (!(class_java_lang_Cloneable = + load_class_bootstrap(utf_java_lang_Cloneable))) + return false; -static int checkmethoddescriptor(classinfo *c, utf *descriptor) -{ - char *utf_ptr; /* current position in utf text */ - char *end_pos; /* points behind utf string */ - s4 argcount = 0; /* number of arguments */ - - utf_ptr = descriptor->text; - end_pos = utf_end(descriptor); - - /* method descriptor must start with parenthesis */ - if (utf_ptr == end_pos || *utf_ptr++ != '(') - panic ("Missing '(' in method descriptor"); - - /* check arguments */ - while (utf_ptr != end_pos && *utf_ptr != ')') { - /* We cannot count the this argument here because - * we don't know if the method is static. */ - if (*utf_ptr == 'J' || *utf_ptr == 'D') - argcount+=2; - else - argcount++; - class_from_descriptor(utf_ptr,end_pos,&utf_ptr, - CLASSLOAD_NEW - | CLASSLOAD_NULLPRIMITIVE - | CLASSLOAD_NOVOID); - } + if (!(class_java_io_Serializable = + load_class_bootstrap(utf_java_io_Serializable))) + return false; - if (utf_ptr == end_pos) - panic("Missing ')' in method descriptor"); - utf_ptr++; /* skip ')' */ + /* load classes for wrapping primitive types */ - class_from_descriptor(utf_ptr, - end_pos, - NULL, - CLASSLOAD_NEW | - CLASSLOAD_NULLPRIMITIVE | - CLASSLOAD_CHECKEND); + if (!(class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void))) + return false; - if (argcount > 255) { - *exceptionptr = - new_classformaterror(c, "Too many arguments in signature"); + if (!(class_java_lang_Boolean = + load_class_bootstrap(utf_java_lang_Boolean))) + return false; - return 0; - } + if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte))) + return false; - return argcount; + if (!(class_java_lang_Character = + load_class_bootstrap(utf_java_lang_Character))) + return false; - /* XXX use the following if -noverify */ -#if 0 - /* check arguments */ - while ((c = *utf_ptr++) != ')') { - start = utf_ptr-1; - - switch (c) { - case 'B': - case 'C': - case 'I': - case 'S': - case 'Z': - case 'J': - case 'F': - case 'D': - /* primitive type */ - break; + if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short))) + return false; - case '[': - case 'L': - if (!class_from_descriptor(start,end_pos,&utf_ptr,CLASSLOAD_NEW)) - panic ("Ill formed method descriptor"); - break; - - default: - panic ("Ill formed methodtype-descriptor"); - } - } + if (!(class_java_lang_Integer = + load_class_bootstrap(utf_java_lang_Integer))) + return false; - /* check returntype */ - if (*utf_ptr=='V') { - /* returntype void */ - if ((utf_ptr+1) != end_pos) panic ("Method-descriptor has exceeding chars"); - } - else - /* treat as field-descriptor */ - checkfielddescriptor (utf_ptr,end_pos); -#endif -} + if (!(class_java_lang_Long = load_class_bootstrap(utf_java_lang_Long))) + return false; + if (!(class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float))) + return false; -/* loader_init ***************************************************************** + if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double))) + return false; - Initializes all lists and loads all classes required for the system - or the compiler. -*******************************************************************************/ - -bool loader_init(u1 *stackbottom) -{ - classpath_info *cpi; + /* load some other important classes */ -#if defined(USE_THREADS) && defined(NATIVE_THREADS) - /* Initialize the monitor pointer for zip/jar file locking. */ + if (!(class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class))) + return false; - for (cpi = classpath_entries; cpi != NULL; cpi = cpi->next) { - if (cpi->type == CLASSPATH_ARCHIVE) - initObjectLock(&cpi->header); - } -#endif + if (!(class_java_lang_ClassLoader = + load_class_bootstrap(utf_java_lang_ClassLoader))) + return false; - /* load some important classes */ + if (!(class_java_lang_SecurityManager = + load_class_bootstrap(utf_java_lang_SecurityManager))) + return false; + + if (!(class_java_lang_System = load_class_bootstrap(utf_java_lang_System))) + return false; + + if (!(class_java_lang_Thread = + load_class_bootstrap(utf_new_char("java/lang/Thread")))) + return false; + + if (!(class_java_lang_ThreadGroup = + load_class_bootstrap(utf_java_lang_ThreadGroup))) + return false; + + if (!(class_java_lang_VMThread = + load_class_bootstrap(utf_new_char("java/lang/VMThread")))) + return false; + + + /* 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 (!(class_java_lang_reflect_Field = + load_class_bootstrap(utf_java_lang_reflect_Field))) + return false; - if (!class_load(class_java_lang_Object)) + if (!(class_java_lang_reflect_Method = + load_class_bootstrap(utf_java_lang_reflect_Method))) return false; - if (!class_load(class_java_lang_String)) + if (!(class_java_security_PrivilegedAction = + load_class_bootstrap(utf_new_char("java/security/PrivilegedAction")))) return false; - if (!class_load(class_java_lang_Cloneable)) + if (!(class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector))) return false; - if (!class_load(class_java_io_Serializable)) + if (!(arrayclass_java_lang_Object = + load_class_bootstrap(utf_new_char("[Ljava/lang/Object;")))) return false; #if defined(USE_THREADS) @@ -390,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(); @@ -410,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 @@ -419,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(); @@ -512,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 @@ -558,9 +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; for (cpi = classpath_entries; cpi != 0; cpi = cpi->next) { #if defined(USE_ZLIB) @@ -572,7 +567,13 @@ void create_all_classes() ce = s->cacao_dir_list; while (ce) { - (void) class_new(ce->name); + /* 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; } @@ -637,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); @@ -680,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); @@ -705,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; @@ -755,17 +766,7 @@ void fprintflags (FILE *fp, u2 f) void printflags(u2 f) { - if ( f & ACC_PUBLIC ) printf (" PUBLIC"); - if ( f & ACC_PRIVATE ) printf (" PRIVATE"); - if ( f & ACC_PROTECTED ) printf (" PROTECTED"); - if ( f & ACC_STATIC ) printf (" STATIC"); - if ( f & ACC_FINAL ) printf (" FINAL"); - if ( f & ACC_SYNCHRONIZED ) printf (" SYNCHRONIZED"); - if ( f & ACC_VOLATILE ) printf (" VOLATILE"); - if ( f & ACC_TRANSIENT ) printf (" TRANSIENT"); - if ( f & ACC_NATIVE ) printf (" NATIVE"); - if ( f & ACC_INTERFACE ) printf (" INTERFACE"); - if ( f & ACC_ABSTRACT ) printf (" ABSTRACT"); + fprintflags(stdout,f); } @@ -822,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 @@ -895,7 +831,7 @@ u4 class_constanttype(classinfo *c, u4 pos) *******************************************************************************/ -static bool load_constantpool(classbuffer *cb) +static bool load_constantpool(classbuffer *cb, descriptor_pool *descpool) { /* The following structures are used to save information which cannot be @@ -997,7 +933,7 @@ static bool load_constantpool(classbuffer *cb) switch (t) { case CONSTANT_Class: - nfc = NEW(forward_class); + nfc = DNEW(forward_class); nfc->next = forward_classes; forward_classes = nfc; @@ -1013,7 +949,7 @@ static bool load_constantpool(classbuffer *cb) break; case CONSTANT_String: - nfs = NEW(forward_string); + nfs = DNEW(forward_string); nfs->next = forward_strings; forward_strings = nfs; @@ -1030,7 +966,7 @@ static bool load_constantpool(classbuffer *cb) break; case CONSTANT_NameAndType: - nfn = NEW(forward_nameandtype); + nfn = DNEW(forward_nameandtype); nfn->next = forward_nameandtypes; forward_nameandtypes = nfn; @@ -1053,7 +989,7 @@ static bool load_constantpool(classbuffer *cb) case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: - nff = NEW(forward_fieldmethint); + nff = DNEW(forward_fieldmethint); nff->next = forward_fieldmethints; forward_fieldmethints = nff; @@ -1176,11 +1112,11 @@ static bool load_constantpool(classbuffer *cb) 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); @@ -1201,37 +1137,45 @@ static bool load_constantpool(classbuffer *cb) 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)) - panic("Class reference with invalid name"); + if (opt_verify && !is_valid_name_utf(name)) { + *exceptionptr = + new_classformaterror(c, "Class reference with invalid name"); + 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; - /* retrieve class from class-table */ + if (opt_eager) { classinfo *tc; - tc = class_new_intern(name); - if (!class_load(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); - - cpinfos[forward_classes->thisindex] = tc; - - } else { - cpinfos[forward_classes->thisindex] = class_new(name); } + /* the classref is created later */ + cpinfos[forward_classes->thisindex] = name; + nfc = forward_classes; forward_classes = forward_classes->next; - FREE(nfc, forward_class); } 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; @@ -1239,7 +1183,6 @@ static bool load_constantpool(classbuffer *cb) nfs = forward_strings; forward_strings = forward_strings->next; - FREE(nfs, forward_string); } while (forward_nameandtypes) { @@ -1254,10 +1197,14 @@ static bool load_constantpool(classbuffer *cb) 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 */ @@ -1273,8 +1220,7 @@ static bool load_constantpool(classbuffer *cb) /* 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; } } @@ -1284,7 +1230,6 @@ static bool load_constantpool(classbuffer *cb) nfn = forward_nameandtypes; forward_nameandtypes = forward_nameandtypes->next; - FREE(nfn, forward_nameandtype); } while (forward_fieldmethints) { @@ -1296,33 +1241,29 @@ static bool load_constantpool(classbuffer *cb) 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 */ - fmi->class = class_getconstant(c, - forward_fieldmethints->class_index, - CONSTANT_Class); + 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->name = nat->name; fmi->descriptor = nat->descriptor; cptags[forward_fieldmethints->thisindex] = forward_fieldmethints->tag; cpinfos[forward_fieldmethints->thisindex] = fmi; - switch (forward_fieldmethints->tag) { - case CONSTANT_Fieldref: /* check validity of descriptor */ - checkfielddescriptor(fmi->descriptor->text, - utf_end(fmi->descriptor)); - break; - case CONSTANT_InterfaceMethodref: - case CONSTANT_Methodref: /* check validity of descriptor */ - checkmethoddescriptor(c, fmi->descriptor); - break; - } - nff = forward_fieldmethints; forward_fieldmethints = forward_fieldmethints->next; - FREE(nff, forward_fieldmethint); } /* everything was ok */ @@ -1341,7 +1282,7 @@ static bool load_constantpool(classbuffer *cb) #define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */ -static bool load_field(classbuffer *cb, fieldinfo *f) +static bool load_field(classbuffer *cb, fieldinfo *f, descriptor_pool *descpool) { classinfo *c; u4 attrnum, i; @@ -1358,11 +1299,24 @@ static bool load_field(classbuffer *cb, fieldinfo *f) 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)) + 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 */ @@ -1396,9 +1350,6 @@ static bool load_field(classbuffer *cb, fieldinfo *f) return false; } } - - /* check descriptor */ - checkfielddescriptor(f->descriptor->text, utf_end(f->descriptor)); } f->type = jtype = desc_to_type(f->descriptor); /* data type */ @@ -1529,10 +1480,10 @@ static bool load_field(classbuffer *cb, fieldinfo *f) *******************************************************************************/ -static bool load_method(classbuffer *cb, methodinfo *m) +static bool load_method(classbuffer *cb, methodinfo *m, descriptor_pool *descpool) { classinfo *c; - s4 argcount; + int argcount; s4 i, j; u4 attrnum; u4 codeattrnum; @@ -1562,23 +1513,31 @@ static bool load_method(classbuffer *cb, methodinfo *m) 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)) + 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; + } } - argcount = checkmethoddescriptor(c, m->descriptor); - if (!(m->flags & ACC_STATIC)) argcount++; /* count the 'this' argument */ @@ -1624,8 +1583,11 @@ static bool load_method(classbuffer *cb, methodinfo *m) 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; + } } } } @@ -1649,21 +1611,6 @@ static bool load_method(classbuffer *cb, methodinfo *m) m->xta = NULL; -#if 0 - if (!(m->flags & ACC_NATIVE)) { - m->stubroutine = createcompilerstub(m); - - } else { - functionptr f = native_findfunction(c->name, - m->name, m->descriptor, - (m->flags & ACC_STATIC)); -#if defined(STATIC_CLASSPATH) - if (f) -#endif - m->stubroutine = createnativestub(f, m); - } -#endif - if (!check_classbuffer_size(cb, 2)) return false; @@ -1745,7 +1692,8 @@ static bool load_method(classbuffer *cb, methodinfo *m) #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 @@ -1757,11 +1705,12 @@ static bool load_method(classbuffer *cb, methodinfo *m) idx = suck_u2(cb); if (!idx) { - m->exceptiontable[j].catchtype = NULL; + m->exceptiontable[j].catchtype.any = NULL; } else { - if (!(m->exceptiontable[j].catchtype = - class_getconstant(c, idx, CONSTANT_Class))) + /* the classref is created later */ + if (!(m->exceptiontable[j].catchtype.any = + (utf*)class_getconstant(c, idx, CONSTANT_Class))) return false; } } @@ -1830,11 +1779,12 @@ static bool load_method(classbuffer *cb, methodinfo *m) if (!check_classbuffer_size(cb, 2 * m->thrownexceptionscount)) return false; - m->thrownexceptions = MNEW(classinfo*, m->thrownexceptionscount); + m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount); for (j = 0; j < m->thrownexceptionscount; j++) { - if (!((m->thrownexceptions)[j] = - class_getconstant(c, suck_u2(cb), CONSTANT_Class))) + /* the classref is created later */ + if (!((m->thrownexceptions)[j].any = + (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class))) return false; } @@ -1910,9 +1860,9 @@ static bool load_attributes(classbuffer *cb, u4 num) innerclassinfo *info = c->innerclass + j; - info->inner_class = + info->inner_class.ref = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); - info->outer_class = + info->outer_class.ref = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); info->name = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8); @@ -1949,122 +1899,276 @@ static bool load_attributes(classbuffer *cb, u4 num) } -/***************** Function: print_arraydescriptor **************************** +/* load_class_from_sysloader *************************************************** + + Load the class with the given name using the system class loader + + IN: + name.............the classname + + RETURN VALUE: + the loaded class, or + NULL if an exception has been thrown - Debugging helper for displaying an arraydescriptor - *******************************************************************************/ -void print_arraydescriptor(FILE *file, arraydescriptor *desc) +classinfo *load_class_from_sysloader(utf *name) { - if (!desc) { - fprintf(file, ""); - return; - } + methodinfo *m; + java_objectheader *cl; + classinfo *r; + +#ifdef LOADER_VERBOSE + 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 - fprintf(file, "{"); - if (desc->componentvftbl) { - if (desc->componentvftbl->class) - utf_fprint(file, desc->componentvftbl->class->name); - else - fprintf(file, ""); - } - else - fprintf(file, "0"); - - fprintf(file, ","); - if (desc->elementvftbl) { - if (desc->elementvftbl->class) - utf_fprint(file, desc->elementvftbl->class->name); - else - fprintf(file, ""); - } - else - fprintf(file, "0"); - fprintf(file, ",%d,%d,%d,%d}", desc->arraytype, desc->dimension, - desc->dataoffset, desc->componentsize); + LOADER_ASSERT(class_java_lang_Object); + LOADER_ASSERT(class_java_lang_ClassLoader); + LOADER_ASSERT(class_java_lang_ClassLoader->linked); + + m = class_resolveclassmethod(class_java_lang_ClassLoader, + utf_getSystemClassLoader, + utf_void__java_lang_ClassLoader, + class_java_lang_Object, + false); + + if (!m) + return false; + + cl = (java_objectheader *) asm_calljavafunction(m, NULL, NULL, NULL, NULL); + if (!cl) + return false; + + LOADER_INC(); + r = load_class_from_classloader(name, cl); + LOADER_DEC(); + + return r; } +/* load_class_from_classloader ************************************************* -/********************** Function: class_load *********************************** - - Loads everything interesting about a class from the class file. The - 'classinfo' structure must have been allocated previously. + Load the class with the given name using the given user-defined class loader. - The super class and the interfaces implemented by this class need not be - loaded. The link is set later by the function 'class_link'. + IN: + name.............the classname + cl...............user-defined class loader + + RETURN VALUE: + the loaded class, or + NULL if an exception has been thrown - The loaded class is removed from the list 'unloadedclasses' and added to - the list 'unlinkedclasses'. - *******************************************************************************/ -classinfo *class_load_intern(classbuffer *cb); - -/* classinfo *load_class_from_classloader(java_objectheader *cl, classinfo *c) */ -classinfo *class_load_extern(classinfo *rc, classinfo *c) +classinfo *load_class_from_classloader(utf *name, java_objectheader *cl) { classinfo *r; - /* if other class loader than bootstrap, call it */ - - if (rc->classloader) { - methodinfo *lc; +#ifdef LOADER_VERBOSE + 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 -/* printf("DefineClass: name="); */ -/* utf_display(c->name); */ -/* printf(" loader="); */ -/* utf_display(rc->classloader->vftbl->class->name); */ -/* printf("\n"); */ + LOADER_ASSERT(name); - lc = class_resolveclassmethod(rc->classloader->vftbl->class, - utf_loadClass, - utf_java_lang_String__java_lang_Class, - class_java_lang_Object, - true); + /* lookup if this class has already been loaded */ - if (!lc) - return NULL; + r = classcache_lookup(cl, name); - r = (classinfo *) asm_calljavafunction(lc, - rc->classloader, - javastring_new(c->name), - NULL, NULL); +#ifdef LOADER_VERBOSE + if (r) + dolog(" cached -> %p",(void*)r); +#endif + if (r) return r; - } else { - return class_load(c); - } -} + /* 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 (text[0] == '[') { + classinfo *comp; + 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; + } -classinfo *class_load(classinfo *c) -{ - classbuffer *cb; - classinfo *r; + u = utf_new(text + 2, namelen - 3); -#if defined(USE_THREADS) - /* enter a monitor on the class */ + if (!(comp = load_class_from_classloader(u, cl))) + return false; - builtin_monitorenter((java_objectheader *) c); -#endif + /* create the array class */ + return class_array_of(comp, false); - /* maybe the class is already loaded */ + case '[': + /* load the component class */ - if (c->loaded) { -#if defined(USE_THREADS) - builtin_monitorexit((java_objectheader *) c); -#endif + u = utf_new(text + 1, namelen - 1); - return c; - } + if (!(comp = load_class_from_classloader(u, cl))) + return false; -#if defined(STATISTICS) - /* measure time */ + /* create the array class */ + return class_array_of(comp, false); - if (getcompilingtime) - compilingtime_stop(); + default: + /* primitive array classes are loaded by the bootstrap loader */ + return load_class_bootstrap(name); + } + } + + LOADER_ASSERT(class_java_lang_Object); + + lc = class_resolveclassmethod(cl->vftbl->class, + utf_loadClass, + utf_java_lang_String__java_lang_Class, + class_java_lang_Object, + true); + + if (!lc) + return false; /* exception */ + + LOADER_INC(); + r = (classinfo *) asm_calljavafunction(lc, + cl, + javastring_new_slash_to_dot(name), + NULL, NULL); + LOADER_DEC(); + + 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"); + } + + return r; + } + + LOADER_INC(); + r = load_class_bootstrap(name); + LOADER_DEC(); + + return r; +} + + +/* load_class_bootstrap ******************************************************** + + Load the class with the given name using the bootstrap class loader. + + IN: + name.............the classname + + RETURN VALUE: + loaded classinfo, or + NULL if an exception has been thrown + + SYNCHRONIZATION: + load_class_bootstrap is synchronized. It can be treated as an + atomic operation. + +*******************************************************************************/ + +classinfo *load_class_bootstrap(utf *name) +{ + classbuffer *cb; + classinfo *c; + classinfo *r; +#ifdef LOADER_VERBOSE + char logtext[MAXLOGTEXT]; +#endif + + /* for debugging */ + + LOADER_ASSERT(name); + LOADER_INC(); + + /* lookup if this class has already been loaded */ + + if ((r = classcache_lookup(NULL, name))) + goto success; + +#ifdef LOADER_VERBOSE + 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] == '[') { + c = load_newly_created_array(c, NULL); + if (c == NULL) + goto return_exception; + LOADER_ASSERT(c->loaded); + r = c; + goto success; + } + +#if defined(STATISTICS) + /* measure time */ + + if (getcompilingtime) + compilingtime_stop(); if (getloadingtime) loadingtime_start(); @@ -2073,34 +2177,52 @@ classinfo *class_load(classinfo *c) /* load classdata, throw exception on error */ if ((cb = suck_start(c)) == NULL) { - /* this means, the classpath was not set properly */ - if (c->name == utf_java_lang_Object) + /* 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"); *exceptionptr = new_exception_utfmessage(string_java_lang_NoClassDefFoundError, - c->name); - -#if defined(USE_THREADS) - builtin_monitorexit((java_objectheader *) c); -#endif - - return NULL; + name); + goto return_exception; } - /* call the internal function */ - r = class_load_intern(cb); + /* load the class from the buffer */ + + r = load_class_from_classbuffer(cb); - /* if return value is NULL, we had a problem and the class is not loaded */ if (!r) { - c->loaded = false; + /* 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 */ - /* now free the allocated memory, otherwise we could ran into a DOS */ - class_remove(c); + if (opt_verboseclass && r) { + printf("[Loaded "); + utf_display_classname(name); + printf(" from %s]\n", cb->path); } /* free memory */ + suck_stop(cb); #if defined(STATISTICS) @@ -2113,54 +2235,102 @@ classinfo *class_load(classinfo *c) compilingtime_start(); #endif -#if defined(USE_THREADS) - /* leave the monitor */ + if (!r) + goto return_exception; - builtin_monitorexit((java_objectheader *) c); -#endif +success: + LOADER_DEC(); return r; + +return_exception: + LOADER_DEC(); + + return NULL; } -classinfo *class_load_intern(classbuffer *cb) +/* load_class_from_classbuffer ************************************************* + + Loads everything interesting about a class from the class file. The + 'classinfo' structure must have been allocated previously. + + The super class and the interfaces implemented by this class need + not be loaded. The link is set later by the function 'class_link'. + + 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) { classinfo *c; - classinfo *tc; - u4 i; + utf *name; + utf *supername; + u4 i,j; u4 ma, mi; - char msg[MAXLOGTEXT]; /* maybe we get an exception */ + s4 dumpsize; + descriptor_pool *descpool; +#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(logtext); + strcat(logtext,"load_class_from_classbuffer("); + utf_sprint(logtext+strlen(logtext),c->name);strcat(logtext,")"); + log_text(logtext); + LOADER_INC(); +#endif + #if defined(STATISTICS) if (opt_stat) count_class_loads++; #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)) - return NULL; + goto return_exception; /* check signature */ + if (suck_u4(cb) != MAGIC) { *exceptionptr = new_classformaterror(c, "Bad magic number"); - return NULL; + goto return_exception; } /* check version */ + mi = suck_u2(cb); ma = suck_u2(cb); @@ -2170,12 +2340,17 @@ classinfo *class_load_intern(classbuffer *cb) "Unsupported major.minor version %d.%d", ma, mi); - return NULL; + goto return_exception; } + /* create a new descriptor pool */ + + descpool = descriptor_pool_new(c); + /* load the constant pool */ - if (!load_constantpool(cb)) - return NULL; + + if (!load_constantpool(cb, descpool)) + goto return_exception; /*JOWENN*/ c->erroneous_state = 0; @@ -2185,20 +2360,20 @@ classinfo *class_load_intern(classbuffer *cb) c->impldBy = NULL; /* ACC flags */ + if (!check_classbuffer_size(cb, 2)) - return NULL; + goto return_exception; c->flags = suck_u2(cb); - /*if (!(c->flags & ACC_PUBLIC)) { log_text("CLASS NOT PUBLIC"); } JOWENN*/ /* 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 * not declared abstract. */ c->flags |= ACC_ABSTRACT; - /* panic("Interface class not declared abstract"); */ } if (c->flags & ACC_FINAL) { @@ -2206,7 +2381,7 @@ classinfo *class_load_intern(classbuffer *cb) new_classformaterror(c, "Illegal class modifiers: 0x%X", c->flags); - return NULL; + goto return_exception; } if (c->flags & ACC_SUPER) { @@ -2218,105 +2393,253 @@ classinfo *class_load_intern(classbuffer *cb) *exceptionptr = new_classformaterror(c, "Illegal class modifiers: 0x%X", c->flags); - return NULL; + goto return_exception; } if (!check_classbuffer_size(cb, 2 + 2)) - return NULL; + goto return_exception; /* this class */ + i = suck_u2(cb); - if (!(tc = class_getconstant(c, i, CONSTANT_Class))) - return NULL; + if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class))) + goto return_exception; + + 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); - if (tc != c) { utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), " (wrong name: "); - utf_sprint(msg + strlen(msg), tc->name); - sprintf(msg + strlen(msg), ")"); + strcat(msg, " (wrong name: "); + utf_strcat(msg, name); + strcat(msg, ")"); *exceptionptr = new_exception_message(string_java_lang_NoClassDefFoundError, msg); - return NULL; + MFREE(msg, char, msglen); + + goto return_exception; } /* retrieve superclass */ + + c->super.any = NULL; if ((i = suck_u2(cb))) { - if (!(c->super = class_getconstant(c, i, CONSTANT_Class))) - return NULL; + 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, "java.lang.Object with superclass"); - return NULL; + goto return_exception; } /* Interfaces must have java.lang.Object as super class. */ + if ((c->flags & ACC_INTERFACE) && - c->super->name != utf_java_lang_Object) { + supername != utf_java_lang_Object) { *exceptionptr = new_exception_message(string_java_lang_ClassFormatError, "Interfaces must have java.lang.Object as superclass"); - return NULL; + goto return_exception; } } else { - c->super = NULL; + supername = NULL; /* This is only allowed for java.lang.Object. */ + if (c->name != utf_java_lang_Object) { *exceptionptr = new_classformaterror(c, "Bad superclass index"); - return NULL; + goto return_exception; } } /* retrieve interfaces */ + if (!check_classbuffer_size(cb, 2)) - return NULL; + goto return_exception; c->interfacescount = suck_u2(cb); if (!check_classbuffer_size(cb, 2 * c->interfacescount)) - return NULL; + goto return_exception; - c->interfaces = MNEW(classinfo*, c->interfacescount); + c->interfaces = MNEW(classref_or_classinfo, c->interfacescount); for (i = 0; i < c->interfacescount; i++) { - if (!(c->interfaces[i] = class_getconstant(c, suck_u2(cb), CONSTANT_Class))) - return NULL; + /* the classrefs are created later */ + if (!(c->interfaces[i].any = (utf *) class_getconstant(c, suck_u2(cb), CONSTANT_Class))) + goto return_exception; } /* load fields */ if (!check_classbuffer_size(cb, 2)) - return NULL; + 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]))) - return NULL; + if (!load_field(cb, &(c->fields[i]),descpool)) + goto return_exception; } /* load methods */ if (!check_classbuffer_size(cb, 2)) - return NULL; + goto return_exception; c->methodscount = suck_u2(cb); /* c->methods = GCNEW(methodinfo, c->methodscount); */ c->methods = MNEW(methodinfo, c->methodscount); for (i = 0; i < c->methodscount; i++) { - if (!load_method(cb, &(c->methods[i]))) - return NULL; + if (!load_method(cb, &(c->methods[i]),descpool)) + goto return_exception; + } + + /* create the class reference table */ + + 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)); + +#if defined(STATISTICS) + if (opt_stat) { + descriptor_pool_get_sizes(descpool, &classrefsize, &descsize); + count_classref_len += classrefsize; + count_parsed_desc_len += descsize; + } +#endif + + /* put the classrefs in the constant pool */ + for (i = 0; i < c->cpcount; i++) { + if (c->cptags[i] == CONSTANT_Class) { + utf *name = (utf *) c->cpinfos[i]; + c->cpinfos[i] = descriptor_pool_lookup_classref(descpool, name); + } + } + + /* set the super class reference */ + + if (supername) { + c->super.ref = descriptor_pool_lookup_classref(descpool, supername); + if (!c->super.ref) + goto return_exception; + } + + /* 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); + if (!c->interfaces[i].ref) + goto return_exception; + } + + /* parse field descriptors */ + + for (i = 0; i < c->fieldscount; i++) { + 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, + m->flags, class_get_self_classref(m->class)); + if (!m->parseddesc) + goto return_exception; + + for (j = 0; j < m->exceptiontablelength; j++) { + if (!m->exceptiontable[j].catchtype.any) + continue; + if ((m->exceptiontable[j].catchtype.ref = + descriptor_pool_lookup_classref(descpool, + (utf *) m->exceptiontable[j].catchtype.any)) == NULL) + goto return_exception; + } + + for (j = 0; j < m->thrownexceptionscount; j++) { + if (!m->thrownexceptions[j].any) + continue; + if ((m->thrownexceptions[j].ref = descriptor_pool_lookup_classref(descpool, + (utf *) m->thrownexceptions[j].any)) == NULL) + goto return_exception; + } + } + + /* 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. @@ -2365,7 +2688,7 @@ classinfo *class_load_intern(classbuffer *cb) new_classformaterror(c, "Repetitive field name/signature"); - return NULL; + goto return_exception; } } while ((old = next[old])); } @@ -2399,7 +2722,7 @@ classinfo *class_load_intern(classbuffer *cb) new_classformaterror(c, "Repetitive method name/signature"); - return NULL; + goto return_exception; } } while ((old = next[old])); } @@ -2418,11 +2741,12 @@ classinfo *class_load_intern(classbuffer *cb) #endif /* load attribute structures */ + if (!check_classbuffer_size(cb, 2)) - return NULL; + goto return_exception; if (!load_attributes(cb, suck_u2(cb))) - return NULL; + goto return_exception; #if 0 /* Pre java 1.5 version don't check this. This implementation is like @@ -2436,1126 +2760,243 @@ classinfo *class_load_intern(classbuffer *cb) if (classdata_left > 0) { *exceptionptr = new_classformaterror(c, "Extra bytes at the end of class file"); - return NULL; + goto return_exception; } } #endif + /* release dump area */ + + dump_release(dumpsize); + if (loadverbose) log_message_class("Loading done class: ", c); + LOADER_DEC(); return c; + +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. + + 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 -/******************* Function: class_new_array ********************************* + Note: + This is an internal function. Do not use it unless you know exactly + what you are doing! - This function is called by class_new to setup an array class. + Use one of the load_class_... functions for general array class loading. *******************************************************************************/ -void class_new_array(classinfo *c) +classinfo *load_newly_created_array(classinfo *c, java_objectheader *loader) { - classinfo *comp = NULL; - methodinfo *clone; - int namelen; + classinfo *comp = NULL; + methodinfo *clone; + methoddesc *clonedesc; + constant_classref *classrefs; + char *text; + s4 namelen; + utf *u; + +#ifdef LOADER_VERBOSE + 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] != '[') - panic("Invalid array class name"); - /* Check the component type */ - switch (c->name->text[1]) { + /* Check array class name */ + + if (namelen < 2 || text[0] != '[') { + *exceptionptr = new_noclassdeffounderror(c->name); + return NULL; + } + + /* Check the element type */ + + switch (text[1]) { case '[': /* c is an array of arrays. We have to create the component class. */ - if (opt_eager) { - comp = class_new_intern(utf_new_intern(c->name->text + 1, - namelen - 1)); - class_load(comp); - list_addfirst(&unlinkedclasses, comp); - } else { - comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1)); + u = utf_new(text + 1, namelen - 1); + LOADER_INC(); + if (!(comp = load_class_from_classloader(u, loader))) { + LOADER_DEC(); + return NULL; } + LOADER_DEC(); + LOADER_ASSERT(comp->loaded); + if (opt_eager) + if (!link_class(c)) + 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] != ';') - panic("Invalid array class name"); - if (opt_eager) { - comp = class_new_intern(utf_new_intern(c->name->text + 2, - namelen - 3)); - class_load(comp); - list_addfirst(&unlinkedclasses, comp); + /* 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; + } - } else { - comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3)); + u = utf_new(text + 2, namelen - 3); + + LOADER_INC(); + if (!(comp = load_class_from_classloader(u, loader))) { + LOADER_DEC(); + return NULL; } + LOADER_DEC(); + LOADER_ASSERT(comp->loaded); + if (opt_eager) + if (!link_class(c)) + 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; } - /* Setup the array class */ - c->super = class_java_lang_Object; - c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; + LOADER_ASSERT(class_java_lang_Object); + LOADER_ASSERT(class_java_lang_Cloneable); + LOADER_ASSERT(class_java_io_Serializable); + + /* setup the array class */ + + c->super.cls = class_java_lang_Object; c->interfacescount = 2; - c->interfaces = MNEW(classinfo*, 2); + c->interfaces = MNEW(classref_or_classinfo, 2); if (opt_eager) { classinfo *tc; - tc = class_new_intern(utf_new_char("java/lang/Cloneable")); - class_load(tc); + tc = class_java_lang_Cloneable; + LOADER_ASSERT(tc->loaded); list_addfirst(&unlinkedclasses, tc); - c->interfaces[0] = tc; + c->interfaces[0].cls = tc; - tc = class_new_intern(utf_new_char("java/io/Serializable")); - class_load(tc); + tc = class_java_io_Serializable; + LOADER_ASSERT(tc->loaded); list_addfirst(&unlinkedclasses, tc); - c->interfaces[1] = tc; + c->interfaces[1].cls = tc; } else { - c->interfaces[0] = class_new(utf_new_char("java/lang/Cloneable")); - c->interfaces[1] = class_new(utf_new_char("java/io/Serializable")); + c->interfaces[0].cls = class_java_lang_Cloneable; + c->interfaces[1].cls = class_java_io_Serializable; } c->methodscount = 1; c->methods = MNEW(methodinfo, c->methodscount); - clone = c->methods; - memset(clone, 0, sizeof(methodinfo)); - clone->flags = ACC_PUBLIC; - clone->name = utf_new_char("clone"); - clone->descriptor = utf_new_char("()Ljava/lang/Object;"); - clone->class = c; - clone->stubroutine = createnativestub((functionptr) &builtin_clone_array, clone); - clone->monoPoly = MONO; - - /* XXX: field: length? */ - - /* array classes are not loaded from class files */ - c->loaded = 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; -} - + classrefs = MNEW(constant_classref, 2); + CLASSREF_INIT(classrefs[0], c, c->name); + CLASSREF_INIT(classrefs[1], c, utf_java_lang_Object); -/****************** Function: class_resolvefield_int *************************** + /* 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 + 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; - This is an internally used helper function. Do not use this directly. + /* create methodinfo */ - Tries to resolve a field having the given name and type. - If the field cannot be resolved, NULL is returned. + clone = c->methods; + MSET(clone, 0, methodinfo, 1); -*******************************************************************************/ +#if defined(USE_THREADS) && defined(NATIVE_THREADS) + initObjectLock(&clone->header); +#endif -static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc) -{ - fieldinfo *fi; - s4 i; + /* 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->monoPoly = MONO; - /* search for field in class c */ + /* parse the descriptor to get the register allocation */ - for (i = 0; i < c->fieldscount; i++) { - if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) { - return &(c->fields[i]); - } - } + if (!descriptor_params_from_paramtypes(clonedesc, clone->flags)) + return false; - /* try superinterfaces recursively */ + clone->entrypoint = + codegen_createnativestub((functionptr) &builtin_clone_array, clone); - for (i = 0; i < c->interfacescount; i++) { - fi = class_resolvefield_int(c->interfaces[i], name, desc); - if (fi) - return fi; - } + /* XXX: field: length? */ - /* try superclass */ + /* array classes are not loaded from class files */ - if (c->super) - return class_resolvefield_int(c->super, name, desc); + c->loaded = true; + c->parseddescs = (u1 *) clonedesc; + c->parseddescsize = sizeof(methodinfo); + c->classrefs = classrefs; + c->classrefcount = 1; - /* not found */ + /* insert class into the loaded class cache */ + /* XXX free classinfo if NULL returned? */ - return NULL; + return classcache_store(loader,c,true); } -/********************* 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. +/* loader_close **************************************************************** + Frees all resources. + *******************************************************************************/ -fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool except) +void loader_close(void) { - 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; - } - - 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; - } - - 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], 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 */ - 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; - } - - /* try the superinterfaces */ - - for (i = 0; i < c->interfacescount; i++) { - mi = class_resolveinterfacemethod_intern(c->interfaces[i], 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; - } -} - - -/****************** Initialization function for classes ****************** - - In Java, every class can have a static initialization function. This - function has to be called BEFORE calling other methods or accessing static - variables. - -*******************************************************************************/ - -static classinfo *class_init_intern(classinfo *c); - -classinfo *class_init(classinfo *c) -{ - classinfo *r; - - if (!makeinitializations) - return c; - -#if defined(USE_THREADS) - /* enter a monitor on the class */ - - builtin_monitorenter((java_objectheader *) c); -#endif - - /* maybe the class is already initalized or the current thread, which can - pass the monitor, is currently initalizing this class */ - - /* JOWENN: In future we need an additinal flag: initializationfailed, - since further access to the class should cause a NoClassDefFound, - if the static initializer failed once - */ - - if (c->initialized || c->initializing) { -#if defined(USE_THREADS) - builtin_monitorexit((java_objectheader *) c); -#endif - - return c; - } - - /* this initalizing run begins NOW */ - c->initializing = true; - - /* call the internal function */ - r = class_init_intern(c); - - /* if return value is not NULL everything was ok and the class is - initialized */ - if (r) - c->initialized = true; - - /* this initalizing run is done */ - c->initializing = false; - -#if defined(USE_THREADS) - /* leave the monitor */ - - builtin_monitorexit((java_objectheader *) c); -#endif - - return r; -} - - -/* this function MUST NOT be called directly, because of thread - race conditions */ - -static classinfo *class_init_intern(classinfo *c) -{ - methodinfo *m; - s4 i; -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - int b; -#endif - - /* maybe the class is not already loaded */ - if (!c->loaded) - if (!class_load(c)) - return NULL; - - /* maybe the class is not already linked */ - if (!c->linked) - if (!class_link(c)) - return NULL; - -#if defined(STATISTICS) - if (opt_stat) - count_class_inits++; -#endif - - /* initialize super class */ - - if (c->super) { - if (!c->super->initialized) { - if (initverbose) { - char logtext[MAXLOGTEXT]; - sprintf(logtext, "Initialize super class "); - utf_sprint_classname(logtext + strlen(logtext), c->super->name); - sprintf(logtext + strlen(logtext), " from "); - utf_sprint_classname(logtext + strlen(logtext), c->name); - log_text(logtext); - } - - if (!class_init(c->super)) - return NULL; - } - } - - /* initialize interface classes */ - - for (i = 0; i < c->interfacescount; i++) { - if (!c->interfaces[i]->initialized) { - if (initverbose) { - char logtext[MAXLOGTEXT]; - sprintf(logtext, "Initialize interface class "); - utf_sprint_classname(logtext + strlen(logtext), c->interfaces[i]->name); - sprintf(logtext + strlen(logtext), " from "); - utf_sprint_classname(logtext + strlen(logtext), c->name); - log_text(logtext); - } - - if (!class_init(c->interfaces[i])) - return NULL; - } - } - - m = class_findmethod(c, utf_clinit, utf_void__void); - - if (!m) { - if (initverbose) { - char logtext[MAXLOGTEXT]; - sprintf(logtext, "Class "); - utf_sprint_classname(logtext + strlen(logtext), c->name); - sprintf(logtext + strlen(logtext), " has no static class initializer"); - log_text(logtext); - } - - return c; - } - - /* Sun's and IBM's JVM don't care about the static flag */ -/* if (!(m->flags & ACC_STATIC)) { */ -/* panic("Class initializer is not static!"); */ - - if (initverbose) - log_message_class("Starting static class initializer for class: ", c); - -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - b = blockInts; - blockInts = 0; -#endif - - /* now call the initializer */ - asm_calljavafunction(m, NULL, NULL, NULL, NULL); - -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - assert(blockInts == 0); - blockInts = b; -#endif - - /* we have an exception or error */ - if (*exceptionptr) { - /* class is NOT initialized */ - c->initialized = false; - - /* is this an exception, than wrap it */ - if (builtin_instanceof(*exceptionptr, class_java_lang_Exception)) { - java_objectheader *xptr; - java_objectheader *cause; - - /* get the cause */ - cause = *exceptionptr; - - /* clear exception, because we are calling jit code again */ - *exceptionptr = NULL; - - /* wrap the exception */ - xptr = - new_exception_throwable(string_java_lang_ExceptionInInitializerError, - (java_lang_Throwable *) cause); - - /* XXX should we exit here? */ - if (*exceptionptr) - throw_exception(); - - /* set new exception */ - *exceptionptr = xptr; - } - - return NULL; - } - - if (initverbose) - log_message_class("Finished static class initializer for class: ", c); - - return c; -} - - -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(((classinfo*)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->class->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 ( ((classinfo*)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->class->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) { - printf ("Super: "); utf_display (c->super->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] -> name); - printf (" (%d)\n", c->interfaces[i] -> 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]) ); - } - -} - - -/******************************************************************************/ -/******************* General functions for the class loader *******************/ -/******************************************************************************/ - -/**************** function: class_primitive_from_sig *************************** - - return the primitive class indicated by the given signature character - - If the descriptor does not indicate a valid primitive type the - return value is NULL. - -********************************************************************************/ - -classinfo *class_primitive_from_sig(char sig) -{ - switch (sig) { - case 'I': return primitivetype_table[PRIMITIVETYPE_INT].class_primitive; - case 'J': return primitivetype_table[PRIMITIVETYPE_LONG].class_primitive; - case 'F': return primitivetype_table[PRIMITIVETYPE_FLOAT].class_primitive; - case 'D': return primitivetype_table[PRIMITIVETYPE_DOUBLE].class_primitive; - case 'B': return primitivetype_table[PRIMITIVETYPE_BYTE].class_primitive; - case 'C': return primitivetype_table[PRIMITIVETYPE_CHAR].class_primitive; - case 'S': return primitivetype_table[PRIMITIVETYPE_SHORT].class_primitive; - case 'Z': return primitivetype_table[PRIMITIVETYPE_BOOLEAN].class_primitive; - case 'V': return primitivetype_table[PRIMITIVETYPE_VOID].class_primitive; - } - return NULL; -} - -/****************** function: class_from_descriptor **************************** - - return the class indicated by the given descriptor - - utf_ptr....first character of descriptor - end_ptr....first character after the end of the string - next.......if non-NULL, *next is set to the first character after - the descriptor. (Undefined if an error occurs.) - - mode.......a combination (binary or) of the following flags: - - (Flags marked with * are the default settings.) - - What to do if a reference type descriptor is parsed successfully: - - CLASSLOAD_SKIP...skip it and return something != NULL - * CLASSLOAD_NEW....get classinfo * via class_new - CLASSLOAD_LOAD...get classinfo * via loader_load - - How to handle primitive types: - - * CLASSLOAD_PRIMITIVE.......return primitive class (eg. "int") - CLASSLOAD_NULLPRIMITIVE...return NULL for primitive types - - How to handle "V" descriptors: - - * CLASSLOAD_VOID.....handle it like other primitive types - CLASSLOAD_NOVOID...treat it as an error - - How to deal with extra characters after the end of the - descriptor: - - * CLASSLOAD_NOCHECKEND...ignore (useful for parameter lists) - CLASSLOAD_CHECKEND.....treat them as an error - - How to deal with errors: - - * CLASSLOAD_PANIC....abort execution with an error message - CLASSLOAD_NOPANIC..return NULL on error - -*******************************************************************************/ - -classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr, - char **next, int mode) -{ - char *start = utf_ptr; - bool error = false; - utf *name; - - SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error); - - if (mode & CLASSLOAD_CHECKEND) - error |= (utf_ptr != end_ptr); - - if (!error) { - if (next) *next = utf_ptr; - - switch (*start) { - case 'V': - if (mode & CLASSLOAD_NOVOID) - break; - /* FALLTHROUGH! */ - case 'I': - case 'J': - case 'F': - case 'D': - case 'B': - case 'C': - case 'S': - case 'Z': - return (mode & CLASSLOAD_NULLPRIMITIVE) - ? NULL - : class_primitive_from_sig(*start); - - case 'L': - start++; - utf_ptr--; - /* FALLTHROUGH! */ - case '[': - if (mode & CLASSLOAD_SKIP) return class_java_lang_Object; - name = utf_new(start, utf_ptr - start); - if (opt_eager) { - classinfo *tc; - - tc = class_new_intern(name); - class_load(tc); - list_addfirst(&unlinkedclasses, tc); - - return tc; - - } else { - return (mode & CLASSLOAD_LOAD) - ? class_load(class_new(name)) : class_new(name); /* XXX handle errors */ - } - } - } - - /* An error occurred */ - if (mode & CLASSLOAD_NOPANIC) - return NULL; - - log_plain("Invalid descriptor at beginning of '"); - log_plain_utf(utf_new(start, end_ptr - start)); - log_plain("'"); - log_nl(); - - panic("Invalid descriptor"); - - /* keep compiler happy */ - return NULL; -} - - -/******************* function: type_from_descriptor **************************** - - return the basic type indicated by the given descriptor - - This function parses a descriptor and returns its basic type as - TYPE_INT, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, TYPE_ADDRESS or TYPE_VOID. - - cls...if non-NULL the referenced variable is set to the classinfo * - returned by class_from_descriptor. - - For documentation of the arguments utf_ptr, end_ptr, next and mode - see class_from_descriptor. The only difference is that - type_from_descriptor always uses CLASSLOAD_PANIC. - -********************************************************************************/ - -int type_from_descriptor(classinfo **cls, char *utf_ptr, char *end_ptr, - char **next, int mode) -{ - classinfo *mycls; - if (!cls) cls = &mycls; - *cls = class_from_descriptor(utf_ptr, end_ptr, next, mode & (~CLASSLOAD_NOPANIC)); - switch (*utf_ptr) { - case 'B': - case 'C': - case 'I': - case 'S': - case 'Z': - return TYPE_INT; - case 'D': - return TYPE_DOUBLE; - case 'F': - return TYPE_FLOAT; - case 'J': - return TYPE_LONG; - case 'V': - return TYPE_VOID; - } - return TYPE_ADDRESS; -} - - -/******************** Function: loader_close *********************************** - - Frees all resources - -*******************************************************************************/ - -void loader_close() -{ - classinfo *c; - s4 slot; - - for (slot = 0; slot < class_hash.size; slot++) { - c = class_hash.ptr[slot]; - - while (c) { - class_free(c); - c = c->hashlink; - } - } + /* empty */ }