X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Floader.c;h=92d8c0fa395bda9fd3d6888de431d3c57d7e7038;hb=4f021ace4cbb48cb8d75e5445929a01f61ca756a;hp=afd087707644973710cdb672ed3cd197406b33ba;hpb=5e123bff0a73392421d8aaa8a4ea5a434fa49357;p=cacao.git diff --git a/src/vm/loader.c b/src/vm/loader.c index afd087707..92d8c0fa3 100644 --- a/src/vm/loader.c +++ b/src/vm/loader.c @@ -1,9 +1,9 @@ -/* loader.c - class loader functions +/* src/vm/loader.c - class loader functions - Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 - R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, - M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, - P. Tomsich, J. Wenninger + Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates, + R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner, + C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger, + Institut f. Computersprachen - TU Wien This file is part of CACAO. @@ -32,127 +32,223 @@ Edwin Steiner Christian Thalinger - $Id: loader.c 1372 2004-08-01 21:56:10Z stefan $ + $Id: loader.c 3684 2005-11-16 13:28:33Z twisti $ */ - #include #include #include #include -#include "exceptions.h" -#include "global.h" -#include "loader.h" -#include "options.h" -#include "native.h" -#include "tables.h" -#include "builtin.h" -#include "jit/jit.h" -#include "asmpart.h" -#include "options.h" -#include "statistics.h" -#include "toolbox/memory.h" + +#include "config.h" +#include "mm/memory.h" +#include "native/native.h" +#include "native/include/java_lang_Throwable.h" + +#if defined(USE_THREADS) +# if defined(NATIVE_THREADS) +# include "threads/native/threads.h" +# else +# include "threads/green/threads.h" +# include "threads/green/locks.h" +# endif +#endif + #include "toolbox/logging.h" -#include "threads/thread.h" -#include "threads/locks.h" -#include "nat/java_lang_Throwable.h" +#include "toolbox/util.h" +#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" -#ifdef USE_ZLIB -#include "unzip.h" +#if defined(USE_ZLIB) +# include "vm/unzip.h" #endif -#undef JOWENN_DEBUG -#undef JOWENN_DEBUG1 -#undef JOWENN_DEBUG2 +#include "vm/jit/asmpart.h" +#include "vm/jit/codegen.inc.h" -/* global variables ***********************************************************/ - -static s4 interfaceindex; /* sequential numbering of interfaces */ -static s4 classvalue; - - -/* utf-symbols for pointer comparison of frequently used strings */ - -static utf *utf_innerclasses; /* InnerClasses */ -static utf *utf_constantvalue; /* ConstantValue */ -static utf *utf_code; /* Code */ -static utf *utf_exceptions; /* Exceptions */ -static utf *utf_linenumbertable; /* LineNumberTable */ -static utf *utf_sourcefile; /* SourceFile */ -static utf *utf_finalize; /* finalize */ -static utf *utf_fidesc; /* ()V changed */ -static utf *utf_init; /* */ -static utf *utf_clinit; /* */ -static utf *utf_initsystemclass; /* initializeSystemClass */ -static utf *utf_systemclass; /* java/lang/System */ -static utf *utf_vmclassloader; /* java/lang/VMClassLoader */ -static utf *utf_vmclass; /* java/lang/VMClassLoader */ -static utf *utf_initialize; -static utf *utf_initializedesc; -static utf *utf_java_lang_Object; /* java/lang/Object */ - -utf *utf_fillInStackTrace_name; -utf *utf_fillInStackTrace_desc; - -utf* clinit_desc(){ - return utf_fidesc; -} -utf* clinit_name(){ - return utf_clinit; -} +/******************************************************************************/ +/* DEBUG HELPERS */ +/******************************************************************************/ +/*#define LOADER_VERBOSE*/ -/* important system classes ***************************************************/ +#ifndef NDEBUG +#define LOADER_DEBUG +#endif -classinfo *class_java_lang_Object; -classinfo *class_java_lang_String; -classinfo *class_java_lang_Cloneable; -classinfo *class_java_io_Serializable; +#ifdef LOADER_DEBUG +#define LOADER_ASSERT(cond) assert(cond) +#else +#define LOADER_ASSERT(cond) +#endif -/* Pseudo classes for the typechecker */ -classinfo *pseudo_class_Arraystub = NULL; -classinfo *pseudo_class_Null = NULL; -classinfo *pseudo_class_New = NULL; -vftbl_t *pseudo_class_Arraystub_vftbl = NULL; +#undef JOWENN_DEBUG +#undef JOWENN_DEBUG1 +#undef JOWENN_DEBUG2 -utf *array_packagename = NULL; +#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 */ + + if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object))) + return false; + + if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String))) + return false; + + if (!(class_java_lang_Cloneable = + load_class_bootstrap(utf_java_lang_Cloneable))) + return false; + + if (!(class_java_io_Serializable = + load_class_bootstrap(utf_java_io_Serializable))) + return false; + + + /* load classes for wrapping primitive types */ + + if (!(class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void))) + return false; + + if (!(class_java_lang_Boolean = + load_class_bootstrap(utf_java_lang_Boolean))) + return false; + + if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte))) + return false; + + if (!(class_java_lang_Character = + load_class_bootstrap(utf_java_lang_Character))) + return false; + + if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short))) + return false; + + if (!(class_java_lang_Integer = + load_class_bootstrap(utf_java_lang_Integer))) + return false; + + 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; + + if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double))) + return false; + + + /* load some other important classes */ + + 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 (!(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_java_lang_reflect_Method = + load_class_bootstrap(utf_java_lang_reflect_Method))) + return false; + + if (!(class_java_security_PrivilegedAction = + load_class_bootstrap(utf_new_char("java/security/PrivilegedAction")))) + return false; + + 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; -/* instances of important system classes **************************************/ +#if defined(USE_THREADS) + if (stackbottom != 0) + initLocks(); +#endif -java_objectheader *proto_java_lang_NullPointerException; + return true; +} /************* functions for reading classdata ********************************* @@ -162,9 +258,6 @@ java_objectheader *proto_java_lang_NullPointerException; *******************************************************************************/ -static char *classpath = ""; /* searchpath for classfiles */ - - /* check_classbuffer_size ****************************************************** assert that at least bytes are left to read @@ -172,7 +265,7 @@ static char *classpath = ""; /* searchpath for classfiles */ *******************************************************************************/ -static inline bool check_classbuffer_size(classbuffer *cb, s4 len) +inline bool check_classbuffer_size(classbuffer *cb, s4 len) { if (len < 0 || ((cb->data + cb->size) - cb->pos - 1) < len) { *exceptionptr = @@ -233,11 +326,6 @@ inline u4 suck_u4(classbuffer *cb) return ((u4) a << 24) + ((u4) b << 16) + ((u4) c << 8) + (u4) d; } -#define suck_s8(a) (s8) suck_u8((a)) -#define suck_s2(a) (s2) suck_u2((a)) -#define suck_s4(a) (s4) suck_u4((a)) -#define suck_s1(a) (s1) suck_u1((a)) - /* get u8 from classfile data */ static u8 suck_u8(classbuffer *cb) @@ -274,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(); @@ -294,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 @@ -303,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(); @@ -320,118 +419,161 @@ static double suck_double(classbuffer *cb) *******************************************************************************/ -void suck_init(char *cpath) +void suck_init(char *classpath) { - char *filename=0; - char *start; - char *end; - int isZip; - int filenamelen; - union classpath_info *tmp; - union classpath_info *insertAfter=0; - - if (!cpath) - return; - - classpath = cpath; - - if (classpath_entries) - panic("suck_init should be called only once"); + char *start; + char *end; + char *filename; + s4 filenamelen; + bool is_zip; + classpath_info *cpi; + classpath_info *lastcpi; + char *cwd; + s4 cwdlen; + + /* search for last classpath entry (only if there already some) */ + + if ((lastcpi = classpath_entries)) { + while (lastcpi->next) + lastcpi = lastcpi->next; + } for (start = classpath; (*start) != '\0';) { + + /* search for ':' delimiter to get the end of the current entry */ for (end = start; ((*end) != '\0') && ((*end) != ':'); end++); if (start != end) { - isZip = 0; + is_zip = false; filenamelen = end - start; if (filenamelen > 3) { if (strncasecmp(end - 3, "zip", 3) == 0 || strncasecmp(end - 3, "jar", 3) == 0) { - isZip = 1; + is_zip = true; } } - if (filenamelen >= (CLASSPATH_MAXFILENAME - 1)) - panic("path length >= MAXFILENAME in suck_init"); + /* save classpath entries as absolute pathnames */ + + cwd = NULL; + cwdlen = 0; + + if (*start != '/') { /* XXX fix me for win32 */ + cwd = _Jv_getcwd(); + cwdlen = strlen(cwd) + strlen("/"); + } + + /* allocate memory for filename and fill it */ + + filename = MNEW(char, filenamelen + cwdlen + strlen("/") + + strlen("0")); + + if (cwd) { + strcpy(filename, cwd); + strcat(filename, "/"); + strncat(filename, start, filenamelen); + + /* add cwd length to file length */ + filenamelen += cwdlen; - if (!filename) - filename = MNEW(char, CLASSPATH_MAXFILENAME); + } else { + strncpy(filename, start, filenamelen); + filename[filenamelen] = '\0'; + } - strncpy(filename, start, filenamelen); - filename[filenamelen + 1] = '\0'; - tmp = NULL; + cpi = NULL; - if (isZip) { + if (is_zip) { #if defined(USE_ZLIB) unzFile uf = unzOpen(filename); if (uf) { - tmp = (union classpath_info *) NEW(classpath_info); - tmp->archive.type = CLASSPATH_ARCHIVE; - tmp->archive.uf = uf; - tmp->archive.next = NULL; - filename = NULL; + cpi = NEW(classpath_info); + cpi->type = CLASSPATH_ARCHIVE; + cpi->uf = uf; + cpi->next = NULL; + cpi->path = filename; + cpi->pathlen = filenamelen; + + /* SUN compatible -verbose:class output */ + + if (opt_verboseclass) + printf("[Opened %s]\n", filename); } + #else - throw_cacao_exception_exit(string_java_lang_InternalError, "zip/jar files not supported"); + throw_cacao_exception_exit(string_java_lang_InternalError, + "zip/jar files not supported"); #endif } else { - tmp = (union classpath_info *) NEW(classpath_info); - tmp->filepath.type = CLASSPATH_PATH; - tmp->filepath.next = 0; + cpi = NEW(classpath_info); + cpi->type = CLASSPATH_PATH; + cpi->next = NULL; if (filename[filenamelen - 1] != '/') {/*PERHAPS THIS SHOULD BE READ FROM A GLOBAL CONFIGURATION */ filename[filenamelen] = '/'; filename[filenamelen + 1] = '\0'; filenamelen++; } - - tmp->filepath.filename = filename; - tmp->filepath.pathlen = filenamelen; - filename = NULL; + + cpi->path = filename; + cpi->pathlen = filenamelen; } - if (tmp) { - if (insertAfter) { - insertAfter->filepath.next = tmp; + /* attach current classpath entry */ - } else { - classpath_entries = tmp; - } - insertAfter = tmp; + if (cpi) { + if (!classpath_entries) + classpath_entries = cpi; + else + lastcpi->next = cpi; + + lastcpi = cpi; } } - if ((*end) == ':') + /* goto next classpath entry, skip ':' delimiter */ + + if ((*end) == ':') { start = end + 1; - else + + } else { start = end; - - if (filename) { - MFREE(filename, char, CLASSPATH_MAXFILENAME); - filename = NULL; } } } -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->filepath.next) { + for (cpi = classpath_entries; cpi != 0; cpi = cpi->next) { #if defined(USE_ZLIB) - if (cpi->filepath.type == CLASSPATH_ARCHIVE) { + if (cpi->type == CLASSPATH_ARCHIVE) { cacao_entry_s *ce; unz_s *s; - s = (unz_s *) cpi->archive.uf; + s = (unz_s *) cpi->uf; 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; } @@ -444,111 +586,142 @@ void create_all_classes() } -/************************** function suck_start ******************************** +/* suck_start ****************************************************************** - returns true if classbuffer is already loaded or a file for the - specified class has succussfully been read in. All directories of - the searchpath are used to find the classfile (.class). - Returns false if no classfile is found and writes an error message. + Returns true if classbuffer is already loaded or a file for the + specified class has succussfully been read in. All directories of + the searchpath are used to find the classfile (.class). + Returns false if no classfile is found and writes an error message. *******************************************************************************/ classbuffer *suck_start(classinfo *c) { - classpath_info *currPos; - char *utf_ptr; - char ch; - char filename[CLASSPATH_MAXFILENAME+10]; /* room for '.class' */ - int filenamelen=0; + classpath_info *cpi; + char *filename; + s4 filenamelen; + char *path; FILE *classfile; - int err; + bool found; + s4 len; struct stat buffer; classbuffer *cb; - utf_ptr = c->name->text; + /* initialize return value */ - while (utf_ptr < utf_end(c->name)) { - if (filenamelen >= CLASSPATH_MAXFILENAME) { - *exceptionptr = - new_exception_message(string_java_lang_InternalError, - "Filename too long"); + found = false; + cb = NULL; - /* XXX should we exit in such a case? */ - throw_exception_exit(); - } + filenamelen = utf_strlen(c->name) + strlen(".class") + strlen("0"); + filename = MNEW(char, filenamelen); - ch = *utf_ptr++; - if ((ch <= ' ' || ch > 'z') && (ch != '/')) /* invalid character */ - ch = '?'; - filename[filenamelen++] = ch; - } + utf_sprint(filename, c->name); + strcat(filename, ".class"); - strcpy(filename + filenamelen, ".class"); - filenamelen += 6; + /* walk through all classpath entries */ - for (currPos = classpath_entries; currPos != 0; currPos = currPos->filepath.next) { + for (cpi = classpath_entries; cpi != NULL && cb == NULL; cpi = cpi->next) { #if defined(USE_ZLIB) - if (currPos->filepath.type == CLASSPATH_ARCHIVE) { - if (cacao_locate(currPos->archive.uf, c->name) == UNZ_OK) { + if (cpi->type == CLASSPATH_ARCHIVE) { + +#if defined(USE_THREADS) + /* enter a monitor on zip/jar archives */ + + builtin_monitorenter((java_objectheader *) cpi); +#endif + + if (cacao_locate(cpi->uf, c->name) == UNZ_OK) { unz_file_info file_info; - /*log_text("Class found in zip file");*/ - if (unzGetCurrentFileInfo(currPos->archive.uf, &file_info, filename, - sizeof(filename), NULL, 0, NULL, 0) == UNZ_OK) { - if (unzOpenCurrentFile(currPos->archive.uf) == UNZ_OK) { + + if (unzGetCurrentFileInfo(cpi->uf, &file_info, filename, + sizeof(filename), NULL, 0, NULL, 0) == UNZ_OK) { + 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; - /*printf("classfile size: %d\n",file_info.uncompressed_size);*/ - if (unzReadCurrentFile(currPos->archive.uf, cb->data, cb->size) == cb->size) { - unzCloseCurrentFile(currPos->archive.uf); - return cb; + cb->size = file_info.uncompressed_size; + cb->data = MNEW(u1, cb->size); + cb->pos = cb->data - 1; + cb->path = cpi->path; - } else { - MFREE(cb->data, u1, cb->size); - FREE(cb, classbuffer); + len = unzReadCurrentFile(cpi->uf, cb->data, cb->size); + + if (len != cb->size) { + suck_stop(cb); log_text("Error while unzipping"); + + } else { + found = true; } - } else log_text("Error while opening file in archive"); - } else log_text("Error while retrieving fileinfo"); + + } else { + log_text("Error while opening file in archive"); + } + + } else { + log_text("Error while retrieving fileinfo"); + } } - unzCloseCurrentFile(currPos->archive.uf); + unzCloseCurrentFile(cpi->uf); - } else { +#if defined(USE_THREADS) + /* leave the monitor */ + + builtin_monitorexit((java_objectheader *) cpi); #endif - if ((currPos->filepath.pathlen + filenamelen) >= CLASSPATH_MAXFILENAME) continue; - strcpy(currPos->filepath.filename + currPos->filepath.pathlen, filename); - classfile = fopen(currPos->filepath.filename, "r"); - if (classfile) { /* file exists */ - /* determine size of classfile */ + } else { +#endif /* defined(USE_ZLIB) */ + + path = MNEW(char, cpi->pathlen + filenamelen); + strcpy(path, cpi->path); + strcat(path, filename); - /* dolog("File: %s",filename); */ - err = stat(currPos->filepath.filename, &buffer); + classfile = fopen(path, "r"); - if (!err) { /* read classfile data */ + if (classfile) { /* file exists */ + 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; - fread(cb->data, 1, cb->size, classfile); - fclose(classfile); + cb->size = buffer.st_size; + cb->data = MNEW(u1, cb->size); + cb->pos = cb->data - 1; + cb->path = cpi->path; - return cb; + /* read class data */ + len = fread(cb->data, 1, cb->size, classfile); + + if (len != buffer.st_size) { + suck_stop(cb); +/* if (ferror(classfile)) { */ +/* } */ + + } else { + found = true; + } } } + + MFREE(path, char, cpi->pathlen + filenamelen); #if defined(USE_ZLIB) } #endif } - if (verbose) { - dolog("Warning: Can not open class file '%s'", filename); - } + if (opt_verbose) + if (!found) { + dolog("Warning: Can not open class file '%s'", filename); - return NULL; + 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; } @@ -593,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); } @@ -660,3749 +823,2180 @@ static bool skipattributes(classbuffer *cb, u4 num) } -/******************** function: innerclass_getconstant ************************ +/* load_constantpool *********************************************************** + + Loads the constantpool of a class, the entries are transformed into + a simpler format by resolving references (a detailed overview of + the compact structures can be found in global.h). - like class_getconstant, but if cptags is ZERO null is returned - *******************************************************************************/ -voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype) +static bool load_constantpool(classbuffer *cb, descriptor_pool *descpool) { - /* invalid position in constantpool */ - if (pos >= c->cpcount) - panic("Attempt to access constant outside range"); - /* constantpool entry of type 0 */ - if (!c->cptags[pos]) - return NULL; + /* The following structures are used to save information which cannot be + processed during the first pass. After the complete constantpool has + been traversed the references can be resolved. + (only in specific order) */ + + /* CONSTANT_Class entries */ + typedef struct forward_class { + struct forward_class *next; + u2 thisindex; + u2 name_index; + } forward_class; - /* check type of constantpool entry */ - if (c->cptags[pos] != ctype) { - error("Type mismatch on constant: %d requested, %d here (innerclass_getconstant)", - (int) ctype, (int) c->cptags[pos] ); - } - - return c->cpinfos[pos]; -} + /* CONSTANT_String */ + typedef struct forward_string { + struct forward_string *next; + u2 thisindex; + u2 string_index; + } forward_string; + /* CONSTANT_NameAndType */ + typedef struct forward_nameandtype { + struct forward_nameandtype *next; + u2 thisindex; + u2 name_index; + u2 sig_index; + } forward_nameandtype; -/************************ function: attribute_load **************************** + /* CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref */ + typedef struct forward_fieldmethint { + struct forward_fieldmethint *next; + u2 thisindex; + u1 tag; + u2 class_index; + u2 nameandtype_index; + } forward_fieldmethint; - read attributes from classfile - -*******************************************************************************/ -static bool attribute_load(classbuffer *cb, classinfo *c, u4 num) -{ - u4 i, j; + classinfo *c; + u4 idx; - for (i = 0; i < num; i++) { - utf *aname; + forward_class *forward_classes = NULL; + forward_string *forward_strings = NULL; + forward_nameandtype *forward_nameandtypes = NULL; + forward_fieldmethint *forward_fieldmethints = NULL; - /* retrieve attribute name */ - if (!check_classbuffer_size(cb, 2)) - return false; + forward_class *nfc; + forward_string *nfs; + forward_nameandtype *nfn; + forward_fieldmethint *nff; - aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + u4 cpcount; + u1 *cptags; + voidptr *cpinfos; - if (aname == utf_innerclasses) { - /* innerclasses attribute */ - if (c->innerclass != NULL) - panic("Class has more than one InnerClasses attribute"); - - if (!check_classbuffer_size(cb, 4 + 2)) - return false; + c = cb->class; - /* skip attribute length */ - suck_u4(cb); + /* number of entries in the constant_pool table plus one */ + if (!check_classbuffer_size(cb, 2)) + return false; - /* number of records */ - c->innerclasscount = suck_u2(cb); + cpcount = c->cpcount = suck_u2(cb); - if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount)) - return false; + /* allocate memory */ + cptags = c->cptags = MNEW(u1, cpcount); + cpinfos = c->cpinfos = MNEW(voidptr, cpcount); - /* allocate memory for innerclass structure */ - c->innerclass = MNEW(innerclassinfo, c->innerclasscount); + if (cpcount < 1) { + *exceptionptr = new_classformaterror(c, "Illegal constant pool size"); + return false; + } + +#if defined(STATISTICS) + if (opt_stat) + count_const_pool_len += (sizeof(voidptr) + 1) * cpcount; +#endif + + /* initialize constantpool */ + for (idx = 0; idx < cpcount; idx++) { + cptags[idx] = CONSTANT_UNUSED; + cpinfos[idx] = NULL; + } - for (j = 0; j < c->innerclasscount; j++) { - /* The innerclass structure contains a class with an encoded - name, its defining scope, its simple name and a bitmask of - the access flags. If an inner class is not a member, its - outer_class is NULL, if a class is anonymous, its name is - NULL. */ - - innerclassinfo *info = c->innerclass + j; - - info->inner_class = - innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); - info->outer_class = - innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); - info->name = - innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - info->flags = suck_u2(cb); - } - - } else if (aname == utf_sourcefile) { - if (!check_classbuffer_size(cb, 4 + 2)) - return false; - - suck_u4(cb); - c->sourcefile = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - - } else { - /* unknown attribute */ - if (!skipattributebody(cb)) - return false; - } - } - - return true; -} - - -/******************* function: checkfielddescriptor **************************** - - checks whether a field-descriptor is valid and aborts otherwise - all referenced classes are inserted into the list of unloaded classes - -*******************************************************************************/ - -static void checkfielddescriptor (char *utf_ptr, char *end_pos) -{ - class_from_descriptor(utf_ptr,end_pos,NULL, - CLASSLOAD_NEW - | CLASSLOAD_NULLPRIMITIVE - | CLASSLOAD_NOVOID - | CLASSLOAD_CHECKEND); - - /* XXX use the following if -noverify */ -#if 0 - char *tstart; /* pointer to start of classname */ - char ch; - char *start = utf_ptr; - - switch (*utf_ptr++) { - case 'B': - case 'C': - case 'I': - case 'S': - case 'Z': - case 'J': - case 'F': - case 'D': - /* primitive type */ - break; - - case '[': - case 'L': - if (!class_from_descriptor(start,end_pos,&utf_ptr,CLASSLOAD_NEW)) - panic ("Ill formed descriptor"); - break; - - default: - panic ("Ill formed descriptor"); - } - - /* exceeding characters */ - if (utf_ptr!=end_pos) panic ("descriptor has exceeding chars"); -#endif -} - - -/******************* function checkmethoddescriptor **************************** - - checks whether a method-descriptor is valid and aborts otherwise. - All referenced classes are inserted into the list of unloaded classes. - - The number of arguments is returned. A long or double argument is counted - as two arguments. - -*******************************************************************************/ - -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 (utf_ptr == end_pos) - panic("Missing ')' in method descriptor"); + + /******* first pass *******/ + /* entries which cannot be resolved now are written into + temporary structures and traversed again later */ + + idx = 1; + while (idx < cpcount) { + u4 t; - utf_ptr++; /* skip ')' */ + /* get constant type */ + if (!check_classbuffer_size(cb, 1)) + return false; - class_from_descriptor(utf_ptr, - end_pos, - NULL, - CLASSLOAD_NEW | - CLASSLOAD_NULLPRIMITIVE | - CLASSLOAD_CHECKEND); + t = suck_u1(cb); - if (argcount > 255) { - *exceptionptr = - new_classformaterror(c, "Too many arguments in signature"); + switch (t) { + case CONSTANT_Class: + nfc = DNEW(forward_class); - return 0; - } + nfc->next = forward_classes; + forward_classes = nfc; - return argcount; + nfc->thisindex = idx; + /* reference to CONSTANT_NameAndType */ + if (!check_classbuffer_size(cb, 2)) + 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; + nfc->name_index = suck_u2(cb); - case '[': - case 'L': - if (!class_from_descriptor(start,end_pos,&utf_ptr,CLASSLOAD_NEW)) - panic ("Ill formed method descriptor"); + idx++; break; - default: - panic ("Ill formed methodtype-descriptor"); - } - } - - /* 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 -} - - -/***************** Function: print_arraydescriptor **************************** - - Debugging helper for displaying an arraydescriptor - -*******************************************************************************/ + case CONSTANT_String: + nfs = DNEW(forward_string); + + nfs->next = forward_strings; + forward_strings = nfs; + + nfs->thisindex = idx; -void print_arraydescriptor(FILE *file, arraydescriptor *desc) -{ - if (!desc) { - fprintf(file, ""); - return; - } + /* reference to CONSTANT_Utf8_info with string characters */ + if (!check_classbuffer_size(cb, 2)) + return false; - 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); -} + nfs->string_index = suck_u2(cb); + + idx++; + break; + case CONSTANT_NameAndType: + nfn = DNEW(forward_nameandtype); + + nfn->next = forward_nameandtypes; + forward_nameandtypes = nfn; + + nfn->thisindex = idx; -/******************************************************************************/ -/************************** Functions for fields ****************************/ -/******************************************************************************/ + if (!check_classbuffer_size(cb, 2 + 2)) + return false; + /* reference to CONSTANT_Utf8_info containing simple name */ + nfn->name_index = suck_u2(cb); -/* field_load ****************************************************************** + /* reference to CONSTANT_Utf8_info containing field or method + descriptor */ + nfn->sig_index = suck_u2(cb); + + idx++; + break; - Load everything about a class field from the class file and fill a - 'fieldinfo' structure. For static fields, space in the data segment is - allocated. + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + nff = DNEW(forward_fieldmethint); + + nff->next = forward_fieldmethints; + forward_fieldmethints = nff; -*******************************************************************************/ + nff->thisindex = idx; + /* constant type */ + nff->tag = t; -#define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */ + if (!check_classbuffer_size(cb, 2 + 2)) + return false; -static bool field_load(classbuffer *cb, classinfo *c, fieldinfo *f) -{ - u4 attrnum,i; - u4 jtype; - u4 pindex = field_load_NOVALUE; /* constantvalue_index */ + /* class or interface type that contains the declaration of the + field or method */ + nff->class_index = suck_u2(cb); - if (!check_classbuffer_size(cb, 2 + 2 + 2)) - return false; + /* name and descriptor of the field or method */ + nff->nameandtype_index = suck_u2(cb); - f->flags = suck_u2(cb); - f->name = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - f->descriptor = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - - if (opt_verify) { - /* check name */ - if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') - panic("Field with invalid name"); - - /* check flag consistency */ - i = (f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)); + idx++; + break; + + case CONSTANT_Integer: { + constant_integer *ci = NEW(constant_integer); - if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) - panic("Field has invalid access flags"); +#if defined(STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_integer); +#endif - if ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE)) - panic("Field is declared final and volatile"); + if (!check_classbuffer_size(cb, 4)) + return false; - if ((c->flags & ACC_INTERFACE) != 0) { - if ((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) - != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) - panic("Interface field is not declared static final public"); + ci->value = suck_s4(cb); + cptags[idx] = CONSTANT_Integer; + cpinfos[idx] = ci; - if ((f->flags & ACC_TRANSIENT) != 0) - panic("Interface field declared transient"); + idx++; + break; } + + case CONSTANT_Float: { + constant_float *cf = NEW(constant_float); - /* check descriptor */ - checkfielddescriptor(f->descriptor->text, utf_end(f->descriptor)); - } - - f->type = jtype = desc_to_type(f->descriptor); /* data type */ - f->offset = 0; /* offset from start of object */ - f->class = c; - f->xta = NULL; - - switch (f->type) { - case TYPE_INT: f->value.i = 0; break; - case TYPE_FLOAT: f->value.f = 0.0; break; - case TYPE_DOUBLE: f->value.d = 0.0; break; - case TYPE_ADDRESS: f->value.a = NULL; break; - case TYPE_LONG: -#if U8_AVAILABLE - f->value.l = 0; break; -#else - f->value.l.low = 0; f->value.l.high = 0; break; +#if defined(STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_float); #endif - } - - /* read attributes */ - if (!check_classbuffer_size(cb, 2)) - return false; - - attrnum = suck_u2(cb); - for (i = 0; i < attrnum; i++) { - utf *aname; - - if (!check_classbuffer_size(cb, 2)) - return false; - aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - - if (aname != utf_constantvalue) { - /* unknown attribute */ - if (!skipattributebody(cb)) + if (!check_classbuffer_size(cb, 4)) return false; - } else { - /* constant value attribute */ - if (pindex != field_load_NOVALUE) - panic("Field has more than one ConstantValue attribute"); - - if (!check_classbuffer_size(cb, 4 + 2)) - return false; + cf->value = suck_float(cb); + cptags[idx] = CONSTANT_Float; + cpinfos[idx] = cf; - /* check attribute length */ - if (suck_u4(cb) != 2) - panic("ConstantValue attribute has invalid length"); - - /* index of value in constantpool */ - pindex = suck_u2(cb); - - /* initialize field with value from constantpool */ - switch (jtype) { - case TYPE_INT: { - constant_integer *ci = - class_getconstant(c, pindex, CONSTANT_Integer); - f->value.i = ci->value; - } + idx++; break; + } + + case CONSTANT_Long: { + constant_long *cl = NEW(constant_long); - case TYPE_LONG: { - constant_long *cl = - class_getconstant(c, pindex, CONSTANT_Long); - f->value.l = cl->value; - } - break; +#if defined(STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_long); +#endif - case TYPE_FLOAT: { - constant_float *cf = - class_getconstant(c, pindex, CONSTANT_Float); - f->value.f = cf->value; - } - break; - - case TYPE_DOUBLE: { - constant_double *cd = - class_getconstant(c, pindex, CONSTANT_Double); - f->value.d = cd->value; - } - break; - - case TYPE_ADDRESS: { - utf *u = class_getconstant(c, pindex, CONSTANT_String); - /* create javastring from compressed utf8-string */ - f->value.a = literalstring_new(u); - } - break; - - default: - log_text ("Invalid Constant - Type"); - } - } - } - - /* everything was ok */ - - return true; -} - - -/********************** function: field_free **********************************/ - -static void field_free(fieldinfo *f) -{ - /* empty */ -} - - -/**************** Function: field_display (debugging only) ********************/ - -void field_display(fieldinfo *f) -{ - printf(" "); - printflags(f->flags); - printf(" "); - utf_display(f->name); - printf(" "); - utf_display(f->descriptor); - printf(" offset: %ld\n", (long int) (f->offset)); -} - - -/******************************************************************************/ -/************************* Functions for methods ******************************/ -/******************************************************************************/ - - -/* method_load ***************************************************************** - - Loads a method from the class file and fills an existing 'methodinfo' - structure. For native methods, the function pointer field is set to the - real function pointer, for JavaVM methods a pointer to the compiler is used - preliminarily. - -*******************************************************************************/ - -static bool method_load(classbuffer *cb, classinfo *c, methodinfo *m) -{ - s4 argcount; - s4 i, j; - u4 attrnum; - u4 codeattrnum; - -#if defined(USE_THREADS) && defined(NATIVE_THREADS) - initObjectLock(&m->header); -#endif - -#ifdef STATISTICS - if (opt_stat) - count_all_methods++; -#endif - - m->thrownexceptionscount = 0; - m->linenumbercount = 0; - m->linenumbers = 0; - m->class = c; - m->nativelyoverloaded = false; - - if (!check_classbuffer_size(cb, 2 + 2 + 2)) - return false; - - m->flags = suck_u2(cb); - m->name = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - m->descriptor = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - - if (opt_verify) { - if (!is_valid_name_utf(m->name)) - panic("Method with invalid name"); - - if (m->name->text[0] == '<' - && m->name != utf_init && m->name != utf_clinit) - panic("Method with invalid special name"); - } - - argcount = checkmethoddescriptor(c, m->descriptor); - - if (!(m->flags & ACC_STATIC)) - argcount++; /* count the 'this' argument */ - - if (opt_verify) { - if (argcount > 255) - panic("Too many arguments in signature"); - - /* check flag consistency */ - if (m->name != utf_clinit) { - i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)); - - if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) - panic("Method has invalid access flags"); - - if ((m->flags & ACC_ABSTRACT) != 0) { - if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE | - ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) { - *exceptionptr = - new_classformaterror(c, - "Illegal method modifiers: 0x%x", - m->flags); - - return false; - } - } - - if ((c->flags & ACC_INTERFACE) != 0) { - if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) - != (ACC_ABSTRACT | ACC_PUBLIC)) - panic("Interface method is not declared abstract and public"); - } - - if (m->name == utf_init) { - if ((m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED - | ACC_NATIVE | ACC_ABSTRACT)) != 0) - panic("Instance initialization method has invalid flags set"); - } - } - } - - m->jcode = NULL; - m->basicblockcount = 0; - m->basicblocks = NULL; - m->basicblockindex = NULL; - m->instructioncount = 0; - m->instructions = NULL; - m->stackcount = 0; - m->stack = NULL; - m->exceptiontable = NULL; - m->registerdata = NULL; - m->stubroutine = NULL; - m->mcode = NULL; - m->entrypoint = NULL; - m->methodUsed = NOTUSED; - m->monoPoly = MONO; - m->subRedefs = 0; - m->subRedefsUsed = 0; - - m->xta = NULL; - - if (!(m->flags & ACC_NATIVE)) { - m->stubroutine = createcompilerstub(m); - - } else { - functionptr f = native_findfunction(c->name, m->name, m->descriptor, - (m->flags & ACC_STATIC) != 0); - if (f) { - m->stubroutine = createnativestub(f, m); - } - } - - if (!check_classbuffer_size(cb, 2)) - return false; - - attrnum = suck_u2(cb); - for (i = 0; i < attrnum; i++) { - utf *aname; - - if (!check_classbuffer_size(cb, 2)) - return false; - - aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - - if (aname != utf_code) { - if (aname == utf_exceptions) { - s4 j; - - if (!check_classbuffer_size(cb, 4 + 2)) - return false; - - suck_u4(cb); /*length*/ - m->thrownexceptionscount = suck_u2(cb); - - if (!check_classbuffer_size(cb, 2 * m->thrownexceptionscount)) - return false; - - m->thrownexceptions = MNEW(classinfo*, m->thrownexceptionscount); - - for (j = 0; j < m->thrownexceptionscount; j++) { - (m->thrownexceptions)[j] = - class_getconstant(c, suck_u2(cb), CONSTANT_Class); - } - - } else { - if (!skipattributebody(cb)) - return false; - } - - } else { - if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) { - *exceptionptr = - new_classformaterror(c, - "Code attribute in native or abstract methods"); - - return false; - } - - if (m->jcode) { - *exceptionptr = - new_classformaterror(c, "Multiple Code attributes"); - - return false; - } - - if (!check_classbuffer_size(cb, 4 + 2 + 2)) - return false; - - suck_u4(cb); - m->maxstack = suck_u2(cb); - m->maxlocals = suck_u2(cb); - - if (m->maxlocals < argcount) { - *exceptionptr = - new_classformaterror(c, "Arguments can't fit into locals"); - - return false; - } - - if (!check_classbuffer_size(cb, 4)) - return false; - - m->jcodelength = suck_u4(cb); - - if (m->jcodelength == 0) { - *exceptionptr = - new_classformaterror(c, "Code of a method has length 0"); - - return false; - } - - if (m->jcodelength > 65535) { - *exceptionptr = - new_classformaterror(c, - "Code of a method longer than 65535 bytes"); - - return false; - } - - if (!check_classbuffer_size(cb, m->jcodelength)) - return false; - - m->jcode = MNEW(u1, m->jcodelength); - suck_nbytes(m->jcode, cb, m->jcodelength); - - if (!check_classbuffer_size(cb, 2)) - return false; - - m->exceptiontablelength = suck_u2(cb); - - if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->exceptiontablelength)) - return false; - - m->exceptiontable = MNEW(exceptiontable, m->exceptiontablelength); - -#if defined(STATISTICS) - if (opt_stat) { - count_vmcode_len += m->jcodelength + 18; - count_extable_len += 8 * m->exceptiontablelength; - } -#endif - - for (j = 0; j < m->exceptiontablelength; j++) { - u4 idx; - m->exceptiontable[j].startpc = suck_u2(cb); - m->exceptiontable[j].endpc = suck_u2(cb); - m->exceptiontable[j].handlerpc = suck_u2(cb); - - idx = suck_u2(cb); - if (!idx) { - m->exceptiontable[j].catchtype = NULL; - - } else { - m->exceptiontable[j].catchtype = - class_getconstant(c, idx, CONSTANT_Class); - } - } - - if (!check_classbuffer_size(cb, 2)) + if (!check_classbuffer_size(cb, 8)) return false; - codeattrnum = suck_u2(cb); - - for (; codeattrnum > 0; codeattrnum--) { - utf *caname; - - if (!check_classbuffer_size(cb, 2)) - return false; - - caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - - if (caname == utf_linenumbertable) { - u2 lncid; - - if (!check_classbuffer_size(cb, 4 + 2)) - return false; - - suck_u4(cb); - m->linenumbercount = suck_u2(cb); - - if (!check_classbuffer_size(cb, - (2 + 2) * m->linenumbercount)) - return false; - - m->linenumbers = MNEW(lineinfo, m->linenumbercount); - - for (lncid = 0; lncid < m->linenumbercount; lncid++) { - m->linenumbers[lncid].start_pc = suck_u2(cb); - m->linenumbers[lncid].line_number = suck_u2(cb); - } - codeattrnum--; - - if (!skipattributes(cb, codeattrnum)) - return false; - - break; - } else { - if (!skipattributebody(cb)) - return false; - } - } - } - } - - if (!m->jcode && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) { - *exceptionptr = new_classformaterror(c, "Missing Code attribute"); - - return false; - } - - /* everything was ok */ - - return true; -} - - -/********************* Function: method_free *********************************** - - frees all memory that was allocated for this method - -*******************************************************************************/ - -static void method_free(methodinfo *m) -{ - if (m->jcode) - MFREE(m->jcode, u1, m->jcodelength); - - if (m->exceptiontable) - MFREE(m->exceptiontable, exceptiontable, m->exceptiontablelength); - - if (m->mcode) - CFREE(m->mcode, m->mcodelength); - - if (m->stubroutine) { - if (m->flags & ACC_NATIVE) { - removenativestub(m->stubroutine); - - } else { - removecompilerstub(m->stubroutine); - } - } -} - - -/************** Function: method_display (debugging only) **************/ - -void method_display(methodinfo *m) -{ - printf(" "); - printflags(m->flags); - printf(" "); - utf_display(m->name); - printf(" "); - utf_display(m->descriptor); - printf("\n"); -} - -/************** Function: method_display_flags_last (debugging only) **************/ - -void method_display_flags_last(methodinfo *m) -{ - printf(" "); - utf_display(m->name); - printf(" "); - utf_display(m->descriptor); - printf(" "); - printflags(m->flags); - printf("\n"); -} - - -/******************** Function: method_canoverwrite **************************** - - Check if m and old are identical with respect to type and name. This means - that old can be overwritten with m. - -*******************************************************************************/ - -static bool method_canoverwrite(methodinfo *m, methodinfo *old) -{ - if (m->name != old->name) return false; - if (m->descriptor != old->descriptor) return false; - if (m->flags & ACC_STATIC) return false; - return true; -} - - -/******************************************************************************/ -/************************ Functions for class *********************************/ -/******************************************************************************/ - - -/******************** 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) -{ - /* invalid position in constantpool */ - /* (pos == 0 is caught by type comparison) */ - if (pos >= c->cpcount) - panic("Attempt to access constant outside range"); - - /* check type of constantpool entry */ - - if (c->cptags[pos] != ctype) { - class_showconstantpool(c); - error("Type mismatch on constant: %d requested, %d here (class_getconstant)", - (int) ctype, (int) c->cptags[pos]); - } - - 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 >= c->cpcount) - panic("Attempt to access constant outside range"); - - return c->cptags[pos]; -} - - -/******************** function: class_loadcpool ******************************** - - loads the constantpool of a class, - the entries are transformed into a simpler format - by resolving references - (a detailed overview of the compact structures can be found in global.h) - -*******************************************************************************/ - -static bool class_loadcpool(classbuffer *cb, classinfo *c) -{ - - /* The following structures are used to save information which cannot be - processed during the first pass. After the complete constantpool has - been traversed the references can be resolved. - (only in specific order) */ - - /* CONSTANT_Class_info entries */ - typedef struct forward_class { - struct forward_class *next; - u2 thisindex; - u2 name_index; - } forward_class; - - /* CONSTANT_String */ - typedef struct forward_string { - struct forward_string *next; - u2 thisindex; - u2 string_index; - } forward_string; - - /* CONSTANT_NameAndType */ - typedef struct forward_nameandtype { - struct forward_nameandtype *next; - u2 thisindex; - u2 name_index; - u2 sig_index; - } forward_nameandtype; - - /* CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref */ - typedef struct forward_fieldmethint { - struct forward_fieldmethint *next; - u2 thisindex; - u1 tag; - u2 class_index; - u2 nameandtype_index; - } forward_fieldmethint; - - - u4 idx; - long int dumpsize = dump_size (); - - forward_class *forward_classes = NULL; - forward_string *forward_strings = NULL; - forward_nameandtype *forward_nameandtypes = NULL; - forward_fieldmethint *forward_fieldmethints = NULL; - - u4 cpcount; - u1 *cptags; - voidptr *cpinfos; - - /* number of entries in the constant_pool table plus one */ - if (!check_classbuffer_size(cb, 2)) - return false; - - cpcount = c->cpcount = suck_u2(cb); - - /* allocate memory */ - cptags = c->cptags = MNEW(u1, cpcount); - cpinfos = c->cpinfos = MNEW(voidptr, cpcount); - - if (!cpcount) - panic("Invalid constant_pool_count (0)"); - -#if defined(STATISTICS) - if (opt_stat) - count_const_pool_len += (sizeof(voidptr) + 1) * cpcount; -#endif - - /* initialize constantpool */ - for (idx = 0; idx < cpcount; idx++) { - cptags[idx] = CONSTANT_UNUSED; - cpinfos[idx] = NULL; - } - - - /******* first pass *******/ - /* entries which cannot be resolved now are written into - temporary structures and traversed again later */ - - idx = 1; - while (idx < cpcount) { - u4 t; - - /* get constant type */ - if (!check_classbuffer_size(cb, 1)) - return false; - - t = suck_u1(cb); - - switch (t) { - case CONSTANT_Class: { - forward_class *nfc = DNEW(forward_class); - - nfc->next = forward_classes; - forward_classes = nfc; - - nfc->thisindex = idx; - /* reference to CONSTANT_NameAndType */ - if (!check_classbuffer_size(cb, 2)) - return false; - - nfc->name_index = suck_u2(cb); - - idx++; - break; - } - - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: { - forward_fieldmethint *nff = DNEW(forward_fieldmethint); - - nff->next = forward_fieldmethints; - forward_fieldmethints = nff; - - nff->thisindex = idx; - /* constant type */ - nff->tag = t; - - if (!check_classbuffer_size(cb, 2 + 2)) - return false; - - /* class or interface type that contains the declaration of the - field or method */ - nff->class_index = suck_u2(cb); - - /* name and descriptor of the field or method */ - nff->nameandtype_index = suck_u2(cb); - - idx++; - break; - } - - case CONSTANT_String: { - forward_string *nfs = DNEW(forward_string); - - nfs->next = forward_strings; - forward_strings = nfs; - - nfs->thisindex = idx; - - /* reference to CONSTANT_Utf8_info with string characters */ - if (!check_classbuffer_size(cb, 2)) - return false; - - nfs->string_index = suck_u2(cb); - - idx++; - break; - } - - case CONSTANT_NameAndType: { - forward_nameandtype *nfn = DNEW(forward_nameandtype); - - nfn->next = forward_nameandtypes; - forward_nameandtypes = nfn; - - nfn->thisindex = idx; - - if (!check_classbuffer_size(cb, 2 + 2)) - return false; - - /* reference to CONSTANT_Utf8_info containing simple name */ - nfn->name_index = suck_u2(cb); - - /* reference to CONSTANT_Utf8_info containing field or method - descriptor */ - nfn->sig_index = suck_u2(cb); - - idx++; - break; - } - - case CONSTANT_Integer: { - constant_integer *ci = NEW(constant_integer); - -#if defined(STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_integer); -#endif - - if (!check_classbuffer_size(cb, 4)) - return false; - - ci->value = suck_s4(cb); - cptags[idx] = CONSTANT_Integer; - cpinfos[idx] = ci; - - idx++; - break; - } - - case CONSTANT_Float: { - constant_float *cf = NEW(constant_float); - -#if defined(STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_float); -#endif - - if (!check_classbuffer_size(cb, 4)) - return false; - - cf->value = suck_float(cb); - cptags[idx] = CONSTANT_Float; - cpinfos[idx] = cf; - - idx++; - break; - } - - case CONSTANT_Long: { - constant_long *cl = NEW(constant_long); - -#if defined(STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_long); -#endif - - if (!check_classbuffer_size(cb, 8)) - return false; - - cl->value = suck_s8(cb); - cptags[idx] = CONSTANT_Long; - cpinfos[idx] = cl; - idx += 2; - if (idx > cpcount) - panic("Long constant exceeds constant pool"); - break; - } - - case CONSTANT_Double: { - constant_double *cd = NEW(constant_double); - -#if defined(STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_double); -#endif - - if (!check_classbuffer_size(cb, 8)) - return false; - - cd->value = suck_double(cb); - cptags[idx] = CONSTANT_Double; - cpinfos[idx] = cd; - idx += 2; - if (idx > cpcount) - panic("Double constant exceeds constant pool"); - break; - } - - case CONSTANT_Utf8: { - u4 length; - - /* number of bytes in the bytes array (not string-length) */ - if (!check_classbuffer_size(cb, 2)) - return false; - - length = suck_u2(cb); - cptags[idx] = CONSTANT_Utf8; - - /* validate the string */ - if (!check_classbuffer_size(cb, length)) - return false; - - if (opt_verify && - !is_valid_utf(cb->pos + 1, cb->pos + 1 + length)) { - dolog("Invalid UTF-8 string (constant pool index %d)",idx); - panic("Invalid UTF-8 string"); - } - /* insert utf-string into the utf-symboltable */ - cpinfos[idx] = utf_new_intern(cb->pos + 1, length); - - /* skip bytes of the string (buffer size check above) */ - skip_nbytes(cb, length); - idx++; - break; - } - - default: - error("Unkown constant type: %d",(int) t); - } /* end switch */ - } /* end while */ - - - /* resolve entries in temporary structures */ - - while (forward_classes) { - utf *name = - class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8); - - if (opt_verify && !is_valid_name_utf(name)) - panic("Class reference with invalid name"); - - 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)) - return false; - - /* link the class later, so we cannot link the currently loaded - class */ - list_addfirst(&unlinkedclasses, tc); - - cpinfos[forward_classes->thisindex] = tc; - - } else { - cpinfos[forward_classes->thisindex] = class_new(name); - } - - forward_classes = forward_classes->next; - } - - while (forward_strings) { - utf *text = - class_getconstant(c, forward_strings->string_index, CONSTANT_Utf8); - - /* resolve utf-string */ - cptags[forward_strings->thisindex] = CONSTANT_String; - cpinfos[forward_strings->thisindex] = text; - - forward_strings = forward_strings->next; - } - - while (forward_nameandtypes) { - constant_nameandtype *cn = NEW(constant_nameandtype); - -#if defined(STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_nameandtype); -#endif - - /* resolve simple name and descriptor */ - cn->name = class_getconstant(c, - forward_nameandtypes->name_index, - CONSTANT_Utf8); - - cn->descriptor = class_getconstant(c, - forward_nameandtypes->sig_index, - CONSTANT_Utf8); - - if (opt_verify) { - /* check name */ - if (!is_valid_name_utf(cn->name)) - panic("NameAndType with invalid name"); - /* disallow referencing among others */ - if (cn->name->text[0] == '<' && cn->name != utf_init) - panic("NameAndType with invalid special name"); - } - - cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType; - cpinfos[forward_nameandtypes->thisindex] = cn; - - forward_nameandtypes = forward_nameandtypes->next; - } - - while (forward_fieldmethints) { - constant_nameandtype *nat; - constant_FMIref *fmi = NEW(constant_FMIref); - -#if defined(STATISTICS) - if (opt_stat) - count_const_pool_len += sizeof(constant_FMIref); -#endif - /* resolve simple name and descriptor */ - nat = class_getconstant(c, - forward_fieldmethints->nameandtype_index, - CONSTANT_NameAndType); - - fmi->class = class_getconstant(c, - forward_fieldmethints->class_index, - CONSTANT_Class); - 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; - } - - forward_fieldmethints = forward_fieldmethints->next; - } - - dump_release(dumpsize); - - /* everything was ok */ - - return true; -} - - -/********************** Function: class_load *********************************** - - 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'. - -*******************************************************************************/ - -classinfo *class_load_intern(classbuffer *cb); - -classinfo *class_load(classinfo *c) -{ - classbuffer *cb; - classinfo *r; - s8 starttime; - s8 stoptime; - - /* enter a monitor on the class */ - - builtin_monitorenter((java_objectheader *) c); - - /* maybe the class is already loaded */ - if (c->loaded) { - builtin_monitorexit((java_objectheader *) c); - - return c; - } - - /* measure time */ - if (getloadingtime) - starttime = getcputime(); - - /* 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) - throw_cacao_exception_exit(string_java_lang_NoClassDefFoundError, - "java/lang/Object"); - - *exceptionptr = - new_exception_utfmessage(string_java_lang_NoClassDefFoundError, - c->name); - - builtin_monitorexit((java_objectheader *) c); - - return NULL; - } - - /* call the internal function */ - r = class_load_intern(cb); - - /* if return value is NULL, we had a problem and the class is not loaded */ - if (!r) { - c->loaded = false; - - /* now free the allocated memory, otherwise we could ran into a DOS */ - class_remove(c); - } - - /* free memory */ - suck_stop(cb); - - /* measure time */ - if (getloadingtime) { - stoptime = getcputime(); - loadingtime += (stoptime - starttime); - } - - /* leave the monitor */ - - builtin_monitorexit((java_objectheader *) c); - - return r; -} - - -classinfo *class_load_intern(classbuffer *cb) -{ - classinfo *c; - u4 i; - u4 mi, ma; -/* s4 classdata_left; */ - char msg[MAXLOGTEXT]; /* maybe we get an exception */ - - /* get the classbuffer's class */ - c = cb->class; - - /* maybe the class is already loaded */ - if (c->loaded) - return c; - -#if defined(STATISTICS) - if (opt_stat) - count_class_loads++; -#endif - - /* output for debugging purposes */ - if (loadverbose) - log_message_class("Loading class: ", c); - - /* class is somewhat loaded */ - c->loaded = true; - - if (!check_classbuffer_size(cb, 4 + 2 + 2)) - return NULL; - - /* check signature */ - if (suck_u4(cb) != MAGIC) { - *exceptionptr = new_classformaterror(c, "Bad magic number"); - - return NULL; - } - - /* check version */ - mi = suck_u2(cb); - ma = suck_u2(cb); - - if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) { - *exceptionptr = - new_classformaterror(c, - "Unsupported major.minor version %d.%d", - ma, mi); - - return NULL; - } - - if (!class_loadcpool(cb, c)) - return NULL; - - /*JOWENN*/ - c->erroneous_state = 0; - c->initializing_thread = 0; - /*JOWENN*/ - c->classUsed = NOTUSED; /* not used initially CO-RT */ - c->impldBy = NULL; - - /* ACC flags */ - if (!check_classbuffer_size(cb, 2)) - return NULL; - - 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) { - *exceptionptr = - new_classformaterror(c, - "Illegal class modifiers: 0x%x", c->flags); - - return NULL; - } - - if (c->flags & ACC_SUPER) { - c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */ - } - } - - if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) { - *exceptionptr = - new_classformaterror(c, "Illegal class modifiers: 0x%x", c->flags); - - return NULL; - } - - if (!check_classbuffer_size(cb, 2 + 2)) - return NULL; - - /* this class */ - i = suck_u2(cb); - if (class_getconstant(c, i, CONSTANT_Class) != c) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), " (wrong name: "); - utf_sprint(msg + strlen(msg), - ((classinfo *) class_getconstant(c, i, CONSTANT_Class))->name); - sprintf(msg + strlen(msg), ")"); - - *exceptionptr = - new_exception_message(string_java_lang_NoClassDefFoundError, msg); - - return NULL; - } - - /* retrieve superclass */ - if ((i = suck_u2(cb))) { - c->super = class_getconstant(c, i, CONSTANT_Class); - - /* 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; - } - - /* Interfaces must have java.lang.Object as super class. */ - if ((c->flags & ACC_INTERFACE) && - c->super->name != utf_java_lang_Object) { - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - "Interfaces must have java.lang.Object as superclass"); - - return NULL; - } - - } else { - c->super = 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; - } - - } - - /* retrieve interfaces */ - if (!check_classbuffer_size(cb, 2)) - return NULL; - - c->interfacescount = suck_u2(cb); - - if (!check_classbuffer_size(cb, 2 * c->interfacescount)) - return NULL; - - c->interfaces = MNEW(classinfo*, c->interfacescount); - for (i = 0; i < c->interfacescount; i++) { - c->interfaces[i] = class_getconstant(c, suck_u2(cb), CONSTANT_Class); - } - - /* load fields */ - if (!check_classbuffer_size(cb, 2)) - return NULL; - - c->fieldscount = suck_u2(cb); - c->fields = GCNEW(fieldinfo, c->fieldscount); -/* c->fields = MNEW(fieldinfo, c->fieldscount); */ - for (i = 0; i < c->fieldscount; i++) { - if (!field_load(cb, c, &(c->fields[i]))) - return NULL; - } - - /* load methods */ - if (!check_classbuffer_size(cb, 2)) - return NULL; - - 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 (!method_load(cb, c, &(c->methods[i]))) - return NULL; - } - - /* 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 */ - size_t len; - size_t hashlen; - u2 index; - u2 old; - - /* Allocate hashtable */ - len = c->methodscount; - if (len < c->fieldscount) len = c->fieldscount; - hashlen = 5 * len; - hashtab = MNEW(u2,(hashlen + len)); - next = hashtab + hashlen; - - /* Determine bitshift (to get good hash values) */ - if (!shift) { - len = sizeof(utf); - while (len) { - len >>= 1; - shift++; + cl->value = suck_s8(cb); + cptags[idx] = CONSTANT_Long; + cpinfos[idx] = cl; + idx += 2; + if (idx > cpcount) { + *exceptionptr = + new_classformaterror(c, "Invalid constant pool entry"); + return false; } + break; } + + case CONSTANT_Double: { + constant_double *cd = NEW(constant_double); + +#if defined(STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_double); +#endif - /* Check fields */ - memset(hashtab, 0, sizeof(u2) * (hashlen + len)); - - for (i = 0; i < c->fieldscount; ++i) { - fieldinfo *fi = c->fields + i; - - /* It's ok if we lose bits here */ - index = ((((size_t) fi->name) + - ((size_t) fi->descriptor)) >> shift) % hashlen; - - if ((old = hashtab[index])) { - old--; - next[i] = old; - do { - if (c->fields[old].name == fi->name && - c->fields[old].descriptor == fi->descriptor) { - *exceptionptr = - new_classformaterror(c, - "Repetitive field name/signature"); + if (!check_classbuffer_size(cb, 8)) + return false; - return NULL; - } - } while ((old = next[old])); + cd->value = suck_double(cb); + cptags[idx] = CONSTANT_Double; + cpinfos[idx] = cd; + idx += 2; + if (idx > cpcount) { + *exceptionptr = + new_classformaterror(c, "Invalid constant pool entry"); + return false; } - hashtab[index] = i + 1; + break; } - - /* Check methods */ - memset(hashtab, 0, sizeof(u2) * (hashlen + len)); + + case CONSTANT_Utf8: { + u4 length; - for (i = 0; i < c->methodscount; ++i) { - methodinfo *mi = c->methods + i; + /* number of bytes in the bytes array (not string-length) */ + if (!check_classbuffer_size(cb, 2)) + return false; - /* It's ok if we lose bits here */ - index = ((((size_t) mi->name) + - ((size_t) mi->descriptor)) >> shift) % hashlen; + length = suck_u2(cb); + cptags[idx] = CONSTANT_Utf8; - if ((old = hashtab[index])) { - old--; - next[i] = old; - do { - if (c->methods[old].name == mi->name && - c->methods[old].descriptor == mi->descriptor) { - *exceptionptr = - new_classformaterror(c, - "Repetitive method name/signature"); + /* validate the string */ + if (!check_classbuffer_size(cb, length)) + return false; - return NULL; - } - } while ((old = next[old])); + if (opt_verify && + !is_valid_utf((char *) (cb->pos + 1), + (char *) (cb->pos + 1 + length))) { + *exceptionptr = new_classformaterror(c,"Invalid UTF-8 string"); + return false; } - hashtab[index] = i + 1; + /* insert utf-string into the utf-symboltable */ + cpinfos[idx] = utf_new((char *) (cb->pos + 1), length); + + /* skip bytes of the string (buffer size check above) */ + skip_nbytes(cb, length); + idx++; + break; } - - MFREE(hashtab, u2, (hashlen + len)); - } + + default: + *exceptionptr = + new_classformaterror(c, "Illegal constant pool type"); + return false; + } /* end switch */ + } /* end while */ -#if defined(STATISTICS) - if (opt_stat) { - count_class_infos += sizeof(classinfo*) * c->interfacescount; - count_class_infos += sizeof(fieldinfo) * c->fieldscount; - count_class_infos += sizeof(methodinfo) * c->methodscount; - } -#endif - /* load variable-length attribute structures */ - if (!check_classbuffer_size(cb, 2)) - return NULL; + /* resolve entries in temporary structures */ - if (!attribute_load(cb, c, suck_u2(cb))) - return NULL; + while (forward_classes) { + utf *name = + class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8); + if (!name) + return false; -#if 0 - /* XXX TWISTI is this still in the JVM spec? SUN and IBM don't complain about it */ - - /* check if all data has been read */ - classdata_left = ((cb->data + cb->size) - cb->pos - 1); - - if (classdata_left > 0) { - /* surplus */ - dolog("There are %d extra bytes at end of classfile", classdata_left); - /* The JVM spec disallows extra bytes. */ - panic("Extra bytes at end of classfile"); - } -#endif + if (opt_verify && !is_valid_name_utf(name)) { + *exceptionptr = + new_classformaterror(c, "Class reference with invalid name"); + return false; + } - if (loadverbose) - log_message_class("Loading done class: ", c); + /* add all class references to the descriptor_pool */ - return c; -} + if (!descriptor_pool_add_class(descpool, name)) + return false; + cptags[forward_classes->thisindex] = CONSTANT_Class; + if (opt_eager) { + classinfo *tc; -/************** internal Function: class_highestinterface ********************** + if (!(tc = load_class_bootstrap(name))) + return false; - Used by the function class_link to determine the amount of memory needed - for the interface table. + /* 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; -static s4 class_highestinterface(classinfo *c) -{ - s4 h; - s4 i; - - if (!(c->flags & ACC_INTERFACE)) { - char logtext[MAXLOGTEXT]; - sprintf(logtext, "Interface-methods count requested for non-interface: "); - utf_sprint(logtext + strlen(logtext), c->name); - error("%s",logtext); - } - - h = c->index; - for (i = 0; i < c->interfacescount; i++) { - s4 h2 = class_highestinterface(c->interfaces[i]); - if (h2 > h) h = h2; + nfc = forward_classes; + forward_classes = forward_classes->next; } - return h; -} - - -/* class_addinterface ********************************************************** - - Is needed by class_link for adding a VTBL to a class. All interfaces - implemented by ic are added as well. + 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; + cpinfos[forward_strings->thisindex] = text; + + nfs = forward_strings; + forward_strings = forward_strings->next; + } -static void class_addinterface(classinfo *c, classinfo *ic) -{ - s4 j, m; - s4 i = ic->index; - vftbl_t *vftbl = c->vftbl; + while (forward_nameandtypes) { + constant_nameandtype *cn = NEW(constant_nameandtype); - if (i >= vftbl->interfacetablelength) - panic ("Inernal error: interfacetable overflow"); +#if defined(STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_nameandtype); +#endif - if (vftbl->interfacetable[-i]) - return; + /* resolve simple name and descriptor */ + cn->name = class_getconstant(c, + forward_nameandtypes->name_index, + CONSTANT_Utf8); + if (!cn->name) + return false; - if (ic->methodscount == 0) { /* fake entry needed for subtype test */ - vftbl->interfacevftbllength[i] = 1; - vftbl->interfacetable[-i] = MNEW(methodptr, 1); - vftbl->interfacetable[-i][0] = NULL; + cn->descriptor = class_getconstant(c, + forward_nameandtypes->sig_index, + CONSTANT_Utf8); + if (!cn->descriptor) + return false; - } else { - vftbl->interfacevftbllength[i] = ic->methodscount; - vftbl->interfacetable[-i] = MNEW(methodptr, ic->methodscount); + if (opt_verify) { + /* check name */ + if (!is_valid_name_utf(cn->name)) { + *exceptionptr = + new_classformaterror(c, + "Illegal Field name \"%s\"", + cn->name->text); -#ifdef STATISTICS - if (opt_stat) - count_vftbl_len += sizeof(methodptr) * - (ic->methodscount + (ic->methodscount == 0)); -#endif + return false; + } - for (j = 0; j < ic->methodscount; j++) { - classinfo *sc = c; - while (sc) { - for (m = 0; m < sc->methodscount; m++) { - methodinfo *mi = &(sc->methods[m]); - if (method_canoverwrite(mi, &(ic->methods[j]))) { - vftbl->interfacetable[-i][j] = - vftbl->table[mi->vftblindex]; - goto foundmethod; - } - } - sc = sc->super; + /* disallow referencing among others */ + if (cn->name->text[0] == '<' && cn->name != utf_init) { + *exceptionptr = + new_classformaterror(c,"Illegal reference to special method"); + return false; } - foundmethod: - ; } - } - for (j = 0; j < ic->interfacescount; j++) - class_addinterface(c, ic->interfaces[j]); -} + cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType; + cpinfos[forward_nameandtypes->thisindex] = cn; + nfn = forward_nameandtypes; + forward_nameandtypes = forward_nameandtypes->next; + } -/******************* Function: class_new_array ********************************* + while (forward_fieldmethints) { + constant_nameandtype *nat; + constant_FMIref *fmi = NEW(constant_FMIref); - This function is called by class_new to setup an array class. +#if defined(STATISTICS) + if (opt_stat) + 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; -void class_new_array(classinfo *c) -{ - classinfo *comp = NULL; - methodinfo *clone; - int namelen; + /* add all descriptors in {Field,Method}ref to the descriptor_pool */ - /* Check array class name */ - namelen = c->name->blength; - if (namelen < 2 || c->name->text[0] != '[') - panic("Invalid array class name"); + if (!descriptor_pool_add(descpool, nat->descriptor, NULL)) + return false; - /* Check the component type */ - switch (c->name->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); + /* the classref is created later */ - } else { - comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1)); - } - break; + fmi->classref = (constant_classref *) (size_t) forward_fieldmethints->class_index; + fmi->name = nat->name; + fmi->descriptor = nat->descriptor; - case 'L': - /* c is an array of objects. */ - if (namelen < 4 || c->name->text[namelen - 1] != ';') - panic("Invalid array class name"); + cptags[forward_fieldmethints->thisindex] = forward_fieldmethints->tag; + cpinfos[forward_fieldmethints->thisindex] = fmi; + + nff = forward_fieldmethints; + forward_fieldmethints = forward_fieldmethints->next; + } - if (opt_eager) { - comp = class_new_intern(utf_new_intern(c->name->text + 2, - namelen - 3)); - class_load(comp); - list_addfirst(&unlinkedclasses, comp); + /* everything was ok */ - } else { - comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3)); - } - break; - } + return true; +} - /* Setup the array class */ - c->super = class_java_lang_Object; - c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; - c->interfacescount = 2; - c->interfaces = MNEW(classinfo*, 2); +/* load_field ****************************************************************** - if (opt_eager) { - classinfo *tc; + Load everything about a class field from the class file and fill a + 'fieldinfo' structure. For static fields, space in the data segment + is allocated. - tc = class_new_intern(utf_new_char("java/lang/Cloneable")); - class_load(tc); - list_addfirst(&unlinkedclasses, tc); - c->interfaces[0] = tc; +*******************************************************************************/ - tc = class_new_intern(utf_new_char("java/io/Serializable")); - class_load(tc); - list_addfirst(&unlinkedclasses, tc); - c->interfaces[1] = tc; +#define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */ - } else { - c->interfaces[0] = class_new(utf_new_char("java/lang/Cloneable")); - c->interfaces[1] = class_new(utf_new_char("java/io/Serializable")); - } +static bool load_field(classbuffer *cb, fieldinfo *f, descriptor_pool *descpool) +{ + classinfo *c; + u4 attrnum, i; + u4 jtype; + u4 pindex = field_load_NOVALUE; /* constantvalue_index */ + utf *u; - c->methodscount = 1; - c->methods = MNEW(methodinfo, c->methodscount); + c = cb->class; - 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; + if (!check_classbuffer_size(cb, 2 + 2 + 2)) + return false; - /* XXX: field: length? */ + f->flags = suck_u2(cb); - /* array classes are not loaded from class files */ - c->loaded = true; -} + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + f->name = u; -/****************** Function: class_link_array ********************************* + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; - This function is called by class_link to create the - arraydescriptor for an array class. + f->descriptor = u; + f->parseddesc = NULL; - This function returns NULL if the array cannot be linked because - the component type has not been linked yet. + 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; + } -static arraydescriptor *class_link_array(classinfo *c) -{ - classinfo *comp = NULL; - s4 namelen = c->name->blength; - arraydescriptor *desc; - vftbl_t *compvftbl; + if (opt_verify) { + /* check name */ + if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') { + *exceptionptr = new_classformaterror(c, + "Illegal Field name \"%s\"", + f->name->text); + return false; + } - /* Check the component type */ - switch (c->name->text[1]) { - case '[': - /* c is an array of arrays. */ -/* comp = class_get(utf_new_intern(c->name->text + 1, namelen - 1)); */ - comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1)); - if (!comp) - panic("Could not find component array class."); - break; + /* check flag consistency */ + i = f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED); - case 'L': - /* c is an array of objects. */ -/* comp = class_get(utf_new_intern(c->name->text + 2, namelen - 3)); */ - comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3)); - if (!comp) - panic("Could not find component class."); - break; - } + if ((i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) || + ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE))) { + *exceptionptr = + new_classformaterror(c, + "Illegal field modifiers: 0x%X", + f->flags); + return false; + } - /* If the component type has not been linked, link it now */ - if (comp && !comp->linked) { - if (!comp->loaded) - class_load(comp); - class_link(comp); + if (c->flags & ACC_INTERFACE) { + if (((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) + != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) || + f->flags & ACC_TRANSIENT) { + *exceptionptr = + new_classformaterror(c, + "Illegal field modifiers: 0x%X", + f->flags); + return false; + } + } + } + + f->type = jtype = desc_to_type(f->descriptor); /* data type */ + f->offset = 0; /* offset from start of object */ + f->class = c; + f->xta = NULL; + + switch (f->type) { + case TYPE_INT: f->value.i = 0; break; + case TYPE_FLOAT: f->value.f = 0.0; break; + case TYPE_DOUBLE: f->value.d = 0.0; break; + case TYPE_ADDRESS: f->value.a = NULL; break; + case TYPE_LONG: +#if U8_AVAILABLE + f->value.l = 0; break; +#else + f->value.l.low = 0; f->value.l.high = 0; break; +#endif } - /* Allocate the arraydescriptor */ - desc = NEW(arraydescriptor); + /* read attributes */ + if (!check_classbuffer_size(cb, 2)) + return false; + + attrnum = suck_u2(cb); + for (i = 0; i < attrnum; i++) { + if (!check_classbuffer_size(cb, 2)) + return false; + + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; - if (comp) { - /* c is an array of references */ - desc->arraytype = ARRAYTYPE_OBJECT; - desc->componentsize = sizeof(void*); - desc->dataoffset = OFFSET(java_objectarray, data); - - compvftbl = comp->vftbl; - if (!compvftbl) - panic("Component class has no vftbl"); - desc->componentvftbl = compvftbl; + if (u == utf_ConstantValue) { + if (!check_classbuffer_size(cb, 4 + 2)) + return false; + + /* check attribute length */ + if (suck_u4(cb) != 2) { + *exceptionptr = + new_classformaterror(c, "Wrong size for VALUE attribute"); + return false; + } + + /* constant value attribute */ + if (pindex != field_load_NOVALUE) { + *exceptionptr = + new_classformaterror(c, + "Multiple ConstantValue attributes"); + return false; + } + + /* index of value in constantpool */ + pindex = suck_u2(cb); - if (compvftbl->arraydesc) { - desc->elementvftbl = compvftbl->arraydesc->elementvftbl; - if (compvftbl->arraydesc->dimension >= 255) - panic("Creating array of dimension >255"); - desc->dimension = compvftbl->arraydesc->dimension + 1; - desc->elementtype = compvftbl->arraydesc->elementtype; + /* initialize field with value from constantpool */ + switch (jtype) { + case TYPE_INT: { + constant_integer *ci; - } else { - desc->elementvftbl = compvftbl; - desc->dimension = 1; - desc->elementtype = ARRAYTYPE_OBJECT; - } + if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer))) + return false; - } else { - /* c is an array of a primitive type */ - switch (c->name->text[1]) { - case 'Z': - desc->arraytype = ARRAYTYPE_BOOLEAN; - desc->dataoffset = OFFSET(java_booleanarray,data); - desc->componentsize = sizeof(u1); + f->value.i = ci->value; + } break; + + case TYPE_LONG: { + constant_long *cl; - case 'B': - desc->arraytype = ARRAYTYPE_BYTE; - desc->dataoffset = OFFSET(java_bytearray,data); - desc->componentsize = sizeof(u1); - break; + if (!(cl = class_getconstant(c, pindex, CONSTANT_Long))) + return false; - case 'C': - desc->arraytype = ARRAYTYPE_CHAR; - desc->dataoffset = OFFSET(java_chararray,data); - desc->componentsize = sizeof(u2); + f->value.l = cl->value; + } break; - case 'D': - desc->arraytype = ARRAYTYPE_DOUBLE; - desc->dataoffset = OFFSET(java_doublearray,data); - desc->componentsize = sizeof(double); - break; + case TYPE_FLOAT: { + constant_float *cf; - case 'F': - desc->arraytype = ARRAYTYPE_FLOAT; - desc->dataoffset = OFFSET(java_floatarray,data); - desc->componentsize = sizeof(float); - break; + if (!(cf = class_getconstant(c, pindex, CONSTANT_Float))) + return false; - case 'I': - desc->arraytype = ARRAYTYPE_INT; - desc->dataoffset = OFFSET(java_intarray,data); - desc->componentsize = sizeof(s4); + f->value.f = cf->value; + } break; + + case TYPE_DOUBLE: { + constant_double *cd; - case 'J': - desc->arraytype = ARRAYTYPE_LONG; - desc->dataoffset = OFFSET(java_longarray,data); - desc->componentsize = sizeof(s8); - break; + if (!(cd = class_getconstant(c, pindex, CONSTANT_Double))) + return false; - case 'S': - desc->arraytype = ARRAYTYPE_SHORT; - desc->dataoffset = OFFSET(java_shortarray,data); - desc->componentsize = sizeof(s2); + f->value.d = cd->value; + } break; + + case TYPE_ADDRESS: + if (!(u = class_getconstant(c, pindex, CONSTANT_String))) + return false; - default: - panic("Invalid array class name"); + /* create javastring from compressed utf8-string */ + f->value.a = literalstring_new(u); + break; + + default: + log_text("Invalid Constant - Type"); + } + + } else { + /* unknown attribute */ + if (!skipattributebody(cb)) + return false; } - - desc->componentvftbl = NULL; - desc->elementvftbl = NULL; - desc->dimension = 1; - desc->elementtype = desc->arraytype; } - return desc; + /* everything was ok */ + + return true; } -/********************** Function: class_link *********************************** +/* load_method ***************************************************************** - Tries to link a class. The function calculates the length in bytes that - an instance of this class requires as well as the VTBL for methods and - interface methods. + Loads a method from the class file and fills an existing + 'methodinfo' structure. For native methods, the function pointer + field is set to the real function pointer, for JavaVM methods a + pointer to the compiler is used preliminarily. *******************************************************************************/ -static classinfo *class_link_intern(classinfo *c); - -classinfo *class_link(classinfo *c) +static bool load_method(classbuffer *cb, methodinfo *m, descriptor_pool *descpool) { - classinfo *r; - s8 starttime; - s8 stoptime; - - /* enter a monitor on the class */ - - builtin_monitorenter((java_objectheader *) c); - - /* maybe the class is already linked */ - if (c->linked) { - builtin_monitorexit((java_objectheader *) c); - - return c; - } - - /* measure time */ - if (getloadingtime) - starttime = getcputime(); + classinfo *c; + int argcount; + s4 i, j; + u4 attrnum; + u4 codeattrnum; + utf *u; - /* call the internal function */ - r = class_link_intern(c); + c = cb->class; - /* if return value is NULL, we had a problem and the class is not linked */ - if (!r) - c->linked = false; +#if defined(USE_THREADS) && defined(NATIVE_THREADS) + initObjectLock(&m->header); +#endif - /* measure time */ - if (getloadingtime) { - stoptime = getcputime(); - loadingtime += (stoptime - starttime); - } +#ifdef STATISTICS + if (opt_stat) + count_all_methods++; +#endif - /* leave the monitor */ + m->thrownexceptionscount = 0; + m->linenumbercount = 0; + m->linenumbers = 0; + m->class = c; + m->nativelyoverloaded = false; + + if (!check_classbuffer_size(cb, 2 + 2 + 2)) + return false; - builtin_monitorexit((java_objectheader *) c); + m->flags = suck_u2(cb); - return r; -} + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + m->name = u; -static classinfo *class_link_intern(classinfo *c) -{ - s4 supervftbllength; /* vftbllegnth of super class */ - s4 vftbllength; /* vftbllength of current class */ - s4 interfacetablelength; /* interface table length */ - classinfo *super = c->super; /* super class */ - classinfo *ic, *c2; /* intermediate class variables */ - vftbl_t *v; /* vftbl of current class */ - s4 i; /* interface/method/field counter */ - arraydescriptor *arraydesc = NULL; /* descriptor for array classes */ - - /* maybe the class is already linked */ - if (c->linked) - return c; + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; - if (linkverbose) - log_message_class("Linking class: ", c); + m->descriptor = u; + m->parseddesc = NULL; - /* ok, this class is somewhat linked */ - c->linked = true; + if (!descriptor_pool_add(descpool, u, &argcount)) + return false; - /* check interfaces */ + if (opt_verify) { + if (!is_valid_name_utf(m->name)) { + *exceptionptr = new_classformaterror(c,"Method with invalid name"); + return false; + } - for (i = 0; i < c->interfacescount; i++) { - ic = c->interfaces[i]; + 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)) + argcount++; /* count the 'this' argument */ - /* detect circularity */ - if (ic == c) { + if (opt_verify) { + if (argcount > 255) { *exceptionptr = - new_exception_utfmessage(string_java_lang_ClassCircularityError, - c->name); - - return NULL; + new_classformaterror(c, "Too many arguments in signature"); + return false; } - if (!ic->loaded) - if (!class_load(ic)) - return NULL; + /* check flag consistency */ + if (m->name != utf_clinit) { + i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)); - if (!ic->linked) - if (!class_link(ic)) - return NULL; + if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) { + *exceptionptr = + new_classformaterror(c, + "Illegal method modifiers: 0x%X", + m->flags); + return false; + } + + if (m->flags & ACC_ABSTRACT) { + if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE | + ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) { + *exceptionptr = + new_classformaterror(c, + "Illegal method modifiers: 0x%X", + m->flags); + return false; + } + } + + if (c->flags & ACC_INTERFACE) { + if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) != (ACC_ABSTRACT | ACC_PUBLIC)) { + *exceptionptr = + new_classformaterror(c, + "Illegal method modifiers: 0x%X", + m->flags); + return false; + } + } - if (!(ic->flags & ACC_INTERFACE)) { - dolog("Specified interface is not declared as interface:"); - log_utf(ic->name); - dolog("in"); - log_utf(c->name); - panic("Specified interface is not declared as interface"); + if (m->name == utf_init) { + if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | + ACC_NATIVE | ACC_ABSTRACT)) { + *exceptionptr = new_classformaterror(c, + "Instance initialization method has invalid flags set"); + return false; + } + } } } - - /* check super class */ - - if (super == NULL) { /* class java.lang.Object */ - c->index = 0; - c->classUsed = USED; /* Object class is always used CO-RT*/ - c->impldBy = NULL; - c->instancesize = sizeof(java_objectheader); - vftbllength = supervftbllength = 0; + m->jcode = NULL; + m->basicblockcount = 0; + m->basicblocks = NULL; + m->basicblockindex = NULL; + m->instructioncount = 0; + m->instructions = NULL; + m->stackcount = 0; + m->stack = NULL; + m->exceptiontable = NULL; + m->stubroutine = NULL; + m->mcode = NULL; + m->entrypoint = NULL; + m->methodUsed = NOTUSED; + m->monoPoly = MONO; + m->subRedefs = 0; + m->subRedefsUsed = 0; - c->finalizer = NULL; + m->xta = NULL; - } else { - /* detect circularity */ - if (super == c) { - *exceptionptr = - new_exception_utfmessage(string_java_lang_ClassCircularityError, - c->name); + if (!check_classbuffer_size(cb, 2)) + return false; + + attrnum = suck_u2(cb); + for (i = 0; i < attrnum; i++) { + utf *aname; - return NULL; - } + if (!check_classbuffer_size(cb, 2)) + return false; - if (!super->loaded) - if (!class_load(super)) - return NULL; + if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; - if (!super->linked) - if (!class_link(super)) - return NULL; + if (aname == utf_Code) { + if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) { + *exceptionptr = + new_classformaterror(c, + "Code attribute in native or abstract methods"); - if (super->flags & ACC_INTERFACE) - panic("Interface specified as super class"); + return false; + } + + if (m->jcode) { + *exceptionptr = + new_classformaterror(c, "Multiple Code attributes"); - /* handle array classes */ - /* The component class must have been linked already. */ - if (c->name->text[0] == '[') { - if ((arraydesc = class_link_array(c)) == NULL) { - panic("class_link: class_link_array"); + return false; } - } - /* Don't allow extending final classes */ - if (super->flags & ACC_FINAL) - panic("Trying to extend final class"); - - if (c->flags & ACC_INTERFACE) - c->index = interfaceindex++; - else - c->index = super->index + 1; - - c->instancesize = super->instancesize; - - vftbllength = supervftbllength = super->vftbl->vftbllength; - - c->finalizer = super->finalizer; - } + if (!check_classbuffer_size(cb, 4 + 2 + 2)) + return false; - /* compute vftbl length */ + suck_u4(cb); + m->maxstack = suck_u2(cb); + m->maxlocals = suck_u2(cb); - for (i = 0; i < c->methodscount; i++) { - methodinfo *m = &(c->methods[i]); - - if (!(m->flags & ACC_STATIC)) { /* is instance method */ - classinfo *sc = super; - while (sc) { - s4 j; - for (j = 0; j < sc->methodscount; j++) { - if (method_canoverwrite(m, &(sc->methods[j]))) { - if ((sc->methods[j].flags & ACC_PRIVATE) != 0) - goto notfoundvftblindex; - - if ((sc->methods[j].flags & ACC_FINAL) != 0) { - log_utf(c->name); - log_utf(sc->name); - log_utf(sc->methods[j].name); - log_utf(sc->methods[j].descriptor); - panic("Trying to overwrite final method"); - } - m->vftblindex = sc->methods[j].vftblindex; - goto foundvftblindex; - } - } - sc = sc->super; - } - notfoundvftblindex: - m->vftblindex = (vftbllength++); - foundvftblindex: - ; - } - } - -#if defined(STATISTICS) - if (opt_stat) - count_vftbl_len += - sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1)); -#endif + if (m->maxlocals < argcount) { + *exceptionptr = + new_classformaterror(c, "Arguments can't fit into locals"); - /* compute interfacetable length */ + return false; + } + + if (!check_classbuffer_size(cb, 4)) + return false; - interfacetablelength = 0; - c2 = c; - while (c2) { - for (i = 0; i < c2->interfacescount; i++) { - s4 h = class_highestinterface(c2->interfaces[i]) + 1; - if (h > interfacetablelength) - interfacetablelength = h; - } - c2 = c2->super; - } + m->jcodelength = suck_u4(cb); - /* allocate virtual function table */ + if (m->jcodelength == 0) { + *exceptionptr = + new_classformaterror(c, "Code of a method has length 0"); - v = (vftbl_t*) mem_alloc(sizeof(vftbl_t) + sizeof(methodptr) * - (vftbllength - 1) + sizeof(methodptr*) * - (interfacetablelength - (interfacetablelength > 0))); - v = (vftbl_t*) (((methodptr*) v) + (interfacetablelength - 1) * - (interfacetablelength > 1)); - c->header.vftbl = c->vftbl = v; -/* utf_display_classname(c->name);printf(", c->header.vftbl=%p\n", c->header.vftbl); */ - v->class = c; - v->vftbllength = vftbllength; - v->interfacetablelength = interfacetablelength; - v->arraydesc = arraydesc; + return false; + } + + if (m->jcodelength > 65535) { + *exceptionptr = + new_classformaterror(c, + "Code of a method longer than 65535 bytes"); - /* store interface index in vftbl */ - if (c->flags & ACC_INTERFACE) - v->baseval = -(c->index); + return false; + } - /* copy virtual function table of super class */ + if (!check_classbuffer_size(cb, m->jcodelength)) + return false; - for (i = 0; i < supervftbllength; i++) - v->table[i] = super->vftbl->table[i]; - - /* add method stubs into virtual function table */ + m->jcode = MNEW(u1, m->jcodelength); + suck_nbytes(m->jcode, cb, m->jcodelength); - for (i = 0; i < c->methodscount; i++) { - methodinfo *m = &(c->methods[i]); - if (!(m->flags & ACC_STATIC)) { - v->table[m->vftblindex] = m->stubroutine; - } - } + if (!check_classbuffer_size(cb, 2)) + return false; - /* compute instance size and offset of each field */ - - for (i = 0; i < c->fieldscount; i++) { - s4 dsize; - fieldinfo *f = &(c->fields[i]); - - if (!(f->flags & ACC_STATIC)) { - dsize = desc_typesize(f->descriptor); - c->instancesize = ALIGN(c->instancesize, dsize); - f->offset = c->instancesize; - c->instancesize += dsize; - } - } + m->exceptiontablelength = suck_u2(cb); + if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->exceptiontablelength)) + return false; - /* initialize interfacetable and interfacevftbllength */ - - v->interfacevftbllength = MNEW(s4, interfacetablelength); + m->exceptiontable = MNEW(exceptiontable, m->exceptiontablelength); #if defined(STATISTICS) - if (opt_stat) - count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength; + if (opt_stat) { + count_vmcode_len += m->jcodelength + 18; + count_extable_len += + m->exceptiontablelength * sizeof(exceptiontable); + } #endif - for (i = 0; i < interfacetablelength; i++) { - v->interfacevftbllength[i] = 0; - v->interfacetable[-i] = NULL; - } - - /* add interfaces */ - - for (c2 = c; c2 != NULL; c2 = c2->super) - for (i = 0; i < c2->interfacescount; i++) { - class_addinterface(c, c2->interfaces[i]); - } - - /* add finalizer method (not for java.lang.Object) */ - - if (super != NULL) { - methodinfo *fi; - static utf *finame = NULL; - static utf *fidesc = NULL; + for (j = 0; j < m->exceptiontablelength; j++) { + u4 idx; + m->exceptiontable[j].startpc = suck_u2(cb); + m->exceptiontable[j].endpc = suck_u2(cb); + m->exceptiontable[j].handlerpc = suck_u2(cb); - if (finame == NULL) - finame = utf_finalize; - if (fidesc == NULL) - fidesc = utf_fidesc; + idx = suck_u2(cb); + if (!idx) { + m->exceptiontable[j].catchtype.any = NULL; - fi = class_findmethod(c, finame, fidesc); - if (fi != NULL) { - if (!(fi->flags & ACC_STATIC)) { - c->finalizer = fi; + } else { + /* the classref is created later */ + if (!(m->exceptiontable[j].catchtype.any = + (utf*)class_getconstant(c, idx, CONSTANT_Class))) + return false; + } } - } - } - /* final tasks */ + if (!check_classbuffer_size(cb, 2)) + return false; - loader_compute_subclasses(c); + codeattrnum = suck_u2(cb); - if (linkverbose) - log_message_class("Linking done class: ", c); + for (; codeattrnum > 0; codeattrnum--) { + utf *caname; - /* just return c to show that we didn't had a problem */ + if (!check_classbuffer_size(cb, 2)) + return false; - return c; -} + if (!(caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + if (caname == utf_LineNumberTable) { + u2 lncid; -/******************* Function: class_freepool ********************************** + if (!check_classbuffer_size(cb, 4 + 2)) + return false; - Frees all resources used by this classes Constant Pool. + suck_u4(cb); + m->linenumbercount = suck_u2(cb); -*******************************************************************************/ + if (!check_classbuffer_size(cb, + (2 + 2) * m->linenumbercount)) + return false; -static void class_freecpool(classinfo *c) -{ - u4 idx; - u4 tag; - voidptr info; - - if (c->cptags && c->cpinfos) { - for (idx = 0; idx < c->cpcount; idx++) { - tag = c->cptags[idx]; - info = c->cpinfos[idx]; - - if (info != NULL) { - switch (tag) { - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - FREE(info, constant_FMIref); - break; - case CONSTANT_Integer: - FREE(info, constant_integer); - break; - case CONSTANT_Float: - FREE(info, constant_float); - break; - case CONSTANT_Long: - FREE(info, constant_long); - break; - case CONSTANT_Double: - FREE(info, constant_double); - break; - case CONSTANT_NameAndType: - FREE(info, constant_nameandtype); + m->linenumbers = MNEW(lineinfo, m->linenumbercount); + + for (lncid = 0; lncid < m->linenumbercount; lncid++) { + m->linenumbers[lncid].start_pc = suck_u2(cb); + m->linenumbers[lncid].line_number = suck_u2(cb); + } + codeattrnum--; + + if (!skipattributes(cb, codeattrnum)) + return false; + break; + + } else { + if (!skipattributebody(cb)) + return false; } } - } - } - if (c->cptags) - MFREE(c->cptags, u1, c->cpcount); + } else if (aname == utf_Exceptions) { + s4 j; - if (c->cpinfos) - MFREE(c->cpinfos, voidptr, c->cpcount); -} - - -/*********************** Function: class_free ********************************** + if (m->thrownexceptions) { + *exceptionptr = + new_classformaterror(c, "Multiple Exceptions attributes"); + return false; + } - Frees all resources used by the class. + if (!check_classbuffer_size(cb, 4 + 2)) + return false; -*******************************************************************************/ + suck_u4(cb); /* length */ + m->thrownexceptionscount = suck_u2(cb); -void class_free(classinfo *c) -{ - s4 i; - vftbl_t *v; - - class_freecpool(c); + if (!check_classbuffer_size(cb, 2 * m->thrownexceptionscount)) + return false; - if (c->interfaces) - MFREE(c->interfaces, classinfo*, c->interfacescount); + m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount); - if (c->fields) { - for (i = 0; i < c->fieldscount; i++) - field_free(&(c->fields[i])); -/* MFREE(c->fields, fieldinfo, c->fieldscount); */ - } - - if (c->methods) { - for (i = 0; i < c->methodscount; i++) - method_free(&(c->methods[i])); -/* MFREE(c->methods, methodinfo, c->methodscount); */ + for (j = 0; j < m->thrownexceptionscount; j++) { + /* the classref is created later */ + if (!((m->thrownexceptions)[j].any = + (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class))) + return false; + } + + } else { + if (!skipattributebody(cb)) + return false; + } } - if ((v = c->vftbl) != NULL) { - if (v->arraydesc) - mem_free(v->arraydesc,sizeof(arraydescriptor)); - - for (i = 0; i < v->interfacetablelength; i++) { - MFREE(v->interfacetable[-i], methodptr, v->interfacevftbllength[i]); - } - MFREE(v->interfacevftbllength, s4, v->interfacetablelength); - - i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) + - sizeof(methodptr*) * (v->interfacetablelength - - (v->interfacetablelength > 0)); - v = (vftbl_t*) (((methodptr*) v) - (v->interfacetablelength - 1) * - (v->interfacetablelength > 1)); - mem_free(v, i); + if (!m->jcode && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) { + *exceptionptr = new_classformaterror(c, "Missing Code attribute"); + + return false; } - if (c->innerclass) - MFREE(c->innerclass, innerclassinfo, c->innerclasscount); + /* everything was ok */ - /* if (c->classvftbl) - mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); */ - -/* GCFREE(c); */ + return true; } -/************************* Function: class_findfield *************************** - - Searches a 'classinfo' structure for a field having the given name and - type. +/* load_attribute ************************************************************** + Read attributes from classfile. + *******************************************************************************/ -fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc) +static bool load_attributes(classbuffer *cb, u4 num) { - s4 i; + classinfo *c; + utf *aname; + u4 i, j; - for (i = 0; i < c->fieldscount; i++) { - if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) - return &(c->fields[i]); - } + c = cb->class; - panic("Can not find field given in CONSTANT_Fieldref"); + for (i = 0; i < num; i++) { + /* retrieve attribute name */ + if (!check_classbuffer_size(cb, 2)) + return false; - /* keep compiler happy */ - return NULL; -} + if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + if (aname == utf_InnerClasses) { + /* innerclasses attribute */ + if (c->innerclass) { + *exceptionptr = + new_classformaterror(c, "Multiple InnerClasses attributes"); + return false; + } + + if (!check_classbuffer_size(cb, 4 + 2)) + return false; -/****************** Function: class_resolvefield_int *************************** + /* skip attribute length */ + suck_u4(cb); - This is an internally used helper function. Do not use this directly. + /* number of records */ + c->innerclasscount = suck_u2(cb); - Tries to resolve a field having the given name and type. - If the field cannot be resolved, NULL is returned. + if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount)) + return false; -*******************************************************************************/ + /* allocate memory for innerclass structure */ + c->innerclass = MNEW(innerclassinfo, c->innerclasscount); -static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc) -{ - s4 i; - fieldinfo *fi; + for (j = 0; j < c->innerclasscount; j++) { + /* The innerclass structure contains a class with an encoded + name, its defining scope, its simple name and a bitmask of + the access flags. If an inner class is not a member, its + outer_class is NULL, if a class is anonymous, its name is + NULL. */ + + innerclassinfo *info = c->innerclass + j; - /* 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]); - } - } + info->inner_class.ref = + innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); + info->outer_class.ref = + innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); + info->name = + innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + info->flags = suck_u2(cb); + } - /* try superinterfaces recursively */ - for (i = 0; i < c->interfacescount; ++i) { - fi = class_resolvefield_int(c->interfaces[i], name, desc); - if (fi) - return fi; - } + } else if (aname == utf_SourceFile) { + if (!check_classbuffer_size(cb, 4 + 2)) + return false; - /* try superclass */ - if (c->super) - return class_resolvefield_int(c->super, name, desc); + if (suck_u4(cb) != 2) { + *exceptionptr = + new_classformaterror(c, "Wrong size for VALUE attribute"); + return false; + } - /* not found */ - return NULL; -} + if (c->sourcefile) { + *exceptionptr = + new_classformaterror(c, "Multiple SourceFile attributes"); + return false; + } + if (!(c->sourcefile = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; -/********************* Function: class_resolvefield *************************** - - Resolves a reference from REFERER to a field with NAME and DESC in class C. + } else { + /* unknown attribute */ + if (!skipattributebody(cb)) + return false; + } + } - If the field cannot be resolved the return value is NULL. If EXCEPT is - true *exceptionptr is set, too. + return true; +} -*******************************************************************************/ -fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool except) -{ - fieldinfo *fi; +/* load_class_from_sysloader *************************************************** - /* XXX resolve class c */ - /* XXX check access from REFERER to C */ - - fi = class_resolvefield_int(c, name, desc); + Load the class with the given name using the system class loader - if (!fi) { - if (except) - *exceptionptr = - new_exception_utfmessage(string_java_lang_NoSuchFieldError, - name); + IN: + name.............the classname - return NULL; - } + RETURN VALUE: + the loaded class, or + NULL if an exception has been thrown - /* XXX check access rights */ +*******************************************************************************/ - return fi; -} +classinfo *load_class_from_sysloader(utf *name) +{ + 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 -/************************* Function: class_findmethod ************************** + LOADER_ASSERT(class_java_lang_Object); + LOADER_ASSERT(class_java_lang_ClassLoader); + LOADER_ASSERT(class_java_lang_ClassLoader->linked); - Searches a 'classinfo' structure for a method having the given name and - type and returns the index in the class info structure. - If type is NULL, it is ignored. - -*******************************************************************************/ - -s4 class_findmethodIndex(classinfo *c, utf *name, utf *desc) -{ - s4 i; + m = class_resolveclassmethod(class_java_lang_ClassLoader, + utf_getSystemClassLoader, + utf_void__java_lang_ClassLoader, + class_java_lang_Object, + false); - for (i = 0; i < c->methodscount; i++) { + if (!m) + return false; -/* utf_display_classname(c->name);printf("."); */ -/* utf_display(c->methods[i].name);printf("."); */ -/* utf_display(c->methods[i].descriptor); */ -/* printf("\n"); */ + cl = (java_objectheader *) asm_calljavafunction(m, NULL, NULL, NULL, NULL); + if (!cl) + return false; - if ((c->methods[i].name == name) && ((desc == NULL) || - (c->methods[i].descriptor == desc))) { - return i; - } - } + LOADER_INC(); + r = load_class_from_classloader(name, cl); + LOADER_DEC(); - return -1; + return r; } +/* load_class_from_classloader ************************************************* -/************************* Function: class_findmethod ************************** - - Searches a 'classinfo' structure for a method having the given name and - type. - If type is NULL, it is ignored. + Load the class with the given name using the given user-defined class loader. + + IN: + name.............the classname + cl...............user-defined class loader + + RETURN VALUE: + the loaded class, or + NULL if an exception has been thrown *******************************************************************************/ -methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc) +classinfo *load_class_from_classloader(utf *name, java_objectheader *cl) { - s4 idx = class_findmethodIndex(c, name, desc); - - if (idx == -1) - return NULL; + classinfo *r; - return &(c->methods[idx]); -} +#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 + LOADER_ASSERT(name); -/*********************** Function: class_fetchmethod ************************** - - like class_findmethod, but aborts with an error if the method is not found + /* lookup if this class has already been loaded */ -*******************************************************************************/ + r = classcache_lookup(cl, name); -methodinfo *class_fetchmethod(classinfo *c, utf *name, utf *desc) -{ - methodinfo *mi; +#ifdef LOADER_VERBOSE + if (r) + dolog(" cached -> %p",(void*)r); +#endif - mi = class_findmethod(c, name, desc); + if (r) + return r; - 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"); - } + /* if other class loader than bootstrap, call it */ - return mi; -} + if (cl) { + methodinfo *lc; + char *text; + s4 namelen; + text = name->text; + namelen = name->blength; -/*********************** Function: class_findmethod_w************************** + /* 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; + } - like class_findmethod, but logs a warning if the method is not found + u = utf_new(text + 2, namelen - 3); -*******************************************************************************/ + if (!(comp = load_class_from_classloader(u, cl))) + return false; -methodinfo *class_findmethod_w(classinfo *c, utf *name, utf *desc, char *from) -{ - 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(); - - if ( c->flags & ACC_PUBLIC ) log_plain(" PUBLIC "); - if ( c->flags & ACC_PRIVATE ) log_plain(" PRIVATE "); - if ( c->flags & ACC_PROTECTED ) log_plain(" PROTECTED "); - if ( c->flags & ACC_STATIC ) log_plain(" STATIC "); - if ( c->flags & ACC_FINAL ) log_plain(" FINAL "); - if ( c->flags & ACC_SYNCHRONIZED ) log_plain(" SYNCHRONIZED "); - if ( c->flags & ACC_VOLATILE ) log_plain(" VOLATILE "); - if ( c->flags & ACC_TRANSIENT ) log_plain(" TRANSIENT "); - if ( c->flags & ACC_NATIVE ) log_plain(" NATIVE "); - if ( c->flags & ACC_INTERFACE ) log_plain(" INTERFACE "); - if ( c->flags & ACC_ABSTRACT ) log_plain(" ABSTRACT "); - - log_plain(from); - log_plain(" : WARNING: Method not found");log_nl( ); - } - - return mi; -} + /* create the array class */ + return class_array_of(comp, false); + case '[': + /* load the component class */ -/************************* Function: class_findmethod_approx ****************** - - like class_findmethod but ignores the return value when comparing the - descriptor. + u = utf_new(text + 1, namelen - 1); -*******************************************************************************/ + if (!(comp = load_class_from_classloader(u, cl))) + return false; -methodinfo *class_findmethod_approx(classinfo *c, utf *name, utf *desc) -{ - s4 i; + /* create the array class */ + return class_array_of(comp, false); - 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 */ - } + 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); + } - return NULL; -} + 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 */ -/***************** Function: class_resolvemethod_approx *********************** - - Searches a class and every super class for a method (without paying - attention to the return value) + if (opt_verboseclass && (r != NULL) && (r->classloader == cl)) { + printf("[Loaded "); + utf_display_classname(name); + printf("]\n"); + } -*******************************************************************************/ + return r; + } -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; - } + LOADER_INC(); + r = load_class_bootstrap(name); + LOADER_DEC(); - return NULL; + return r; } -/************************* Function: class_resolvemethod *********************** +/* load_class_bootstrap ******************************************************** - Searches a class and every super class for a method. - -*******************************************************************************/ - -methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc) -{ - /*log_text("Trying to resolve a method"); - utf_display(c->name); - utf_display(name); - utf_display(desc);*/ - - while (c) { - /*log_text("Looking in:"); - utf_display(c->name);*/ - methodinfo *m = class_findmethod(c, name, desc); - if (m) return m; - /* search superclass */ - c = c->super; - } - /*log_text("method not found:");*/ - - return NULL; -} + Load the class with the given name using the bootstrap class loader. + IN: + name.............the classname -/****************** Function: class_resolveinterfacemethod_int **************** + RETURN VALUE: + loaded classinfo, or + NULL if an exception has been thrown - Internally used helper function. Do not use this directly. + SYNCHRONIZATION: + load_class_bootstrap is synchronized. It can be treated as an + atomic operation. *******************************************************************************/ -static -methodinfo *class_resolveinterfacemethod_int(classinfo *c, utf *name, utf *desc) +classinfo *load_class_bootstrap(utf *name) { - methodinfo *mi; - int i; - - mi = class_findmethod(c,name,desc); - if (mi) - return mi; - - /* try the superinterfaces */ - for (i=0; iinterfacescount; ++i) { - mi = class_resolveinterfacemethod_int(c->interfaces[i],name,desc); - if (mi) - return mi; - } - - return NULL; -} + classbuffer *cb; + classinfo *c; + classinfo *r; +#ifdef LOADER_VERBOSE + char logtext[MAXLOGTEXT]; +#endif -/******************** Function: class_resolveinterfacemethod ****************** + /* for debugging */ - Resolves a reference from REFERER to a method with NAME and DESC in - interface C. + LOADER_ASSERT(name); + LOADER_INC(); - If the method cannot be resolved the return value is NULL. If EXCEPT is - true *exceptionptr is set, too. + /* lookup if this class has already been loaded */ -*******************************************************************************/ + if ((r = classcache_lookup(NULL, name))) + goto success; -methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool except) -{ - methodinfo *mi; +#ifdef LOADER_VERBOSE + LOADER_INDENT(logtext); + strcat(logtext,"load_class_bootstrap("); + utf_sprint(logtext+strlen(logtext),name);strcat(logtext,")"); + log_text(logtext); +#endif - /* XXX resolve class c */ - /* XXX check access from REFERER to C */ + /* create the classinfo */ + + c = class_create_classinfo(name); - if (!(c->flags & ACC_INTERFACE)) { - if (except) - *exceptionptr = - new_exception(string_java_lang_IncompatibleClassChangeError); + /* handle array classes */ - return NULL; + 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; } - mi = class_resolveinterfacemethod_int(c, name, desc); +#if defined(STATISTICS) + /* measure time */ + + if (getcompilingtime) + compilingtime_stop(); - if (mi) - return mi; + if (getloadingtime) + loadingtime_start(); +#endif + + /* load classdata, throw exception on error */ - /* try class java.lang.Object */ - mi = class_findmethod(class_java_lang_Object, name, desc); + if ((cb = suck_start(c)) == NULL) { + /* this normally means, the classpath was not set properly */ - if (mi) - return mi; + if (name == utf_java_lang_Object) + throw_cacao_exception_exit(string_java_lang_NoClassDefFoundError, + "java/lang/Object"); - if (except) *exceptionptr = - new_exception_utfmessage(string_java_lang_NoSuchMethodError, name); + new_exception_utfmessage(string_java_lang_NoClassDefFoundError, + name); + goto return_exception; + } + + /* load the class from the buffer */ - return NULL; -} + r = load_class_from_classbuffer(cb); + if (!r) { + /* the class could not be loaded, free the classinfo struct */ -/********************* Function: class_resolveclassmethod ********************* - - Resolves a reference from REFERER to a method with NAME and DESC in - class C. + class_free(c); - If the method cannot be resolved the return value is NULL. If EXCEPT is - true *exceptionptr is set, too. + } 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); -methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc, - classinfo *referer, bool except) -{ - classinfo *cls; - methodinfo *mi; - s4 i; - char msg[MAXLOGTEXT]; + if (!res) { + /* exception */ + class_free(c); + } - /* 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; - do { - mi = class_findmethod(cls, name, desc); - if (mi) - goto found; - } while ((cls = cls->super) != NULL); /* try the superclass */ - - /* try the superinterfaces */ - for (i = 0; i < c->interfacescount; ++i) { - mi = class_resolveinterfacemethod_int(c->interfaces[i], name, desc); - if (mi) - goto found; + r = res; } - - if (except) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), "."); - utf_sprint(msg + strlen(msg), name); - utf_sprint(msg + strlen(msg), desc); - *exceptionptr = - new_exception_message(string_java_lang_NoSuchMethodError, msg); + /* SUN compatible -verbose:class output */ + + if (opt_verboseclass && r) { + printf("[Loaded "); + utf_display_classname(name); + printf(" from %s]\n", cb->path); } - return NULL; + /* free memory */ - found: - if ((mi->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) { - if (except) - *exceptionptr = new_exception(string_java_lang_AbstractMethodError); + suck_stop(cb); - return NULL; - } +#if defined(STATISTICS) + /* measure time */ + + if (getloadingtime) + loadingtime_stop(); - /* XXX check access rights */ + if (getcompilingtime) + compilingtime_start(); +#endif - return mi; -} + if (!r) + goto return_exception; +success: + LOADER_DEC(); -/************************* Function: class_issubclass ************************** + return r; - Checks if sub is a descendant of super. - -*******************************************************************************/ +return_exception: + LOADER_DEC(); -bool class_issubclass(classinfo *sub, classinfo *super) -{ - for (;;) { - if (!sub) return false; - if (sub == super) return true; - sub = sub->super; - } + return NULL; } -/****************** Initialization function for classes ****************** +/* load_class_from_classbuffer ************************************************* + + Loads everything interesting about a class from the class file. The + 'classinfo' structure must have been allocated previously. - In Java, every class can have a static initialization function. This - function has to be called BEFORE calling other methods or accessing static - variables. + 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! + *******************************************************************************/ -static classinfo *class_init_intern(classinfo *c); - -classinfo *class_init(classinfo *c) +classinfo *load_class_from_classbuffer(classbuffer *cb) { - classinfo *r; + classinfo *c; + utf *name; + utf *supername; + u4 i,j; + u4 ma, mi; + 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 (!makeinitializations) + if (c->loaded) return c; - /* enter a monitor on the class */ +#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 - builtin_monitorenter((java_objectheader *) c); +#if defined(STATISTICS) + if (opt_stat) + count_class_loads++; +#endif - /* maybe the class is already initalized or the current thread, which can - pass the monitor, is currently initalizing this class */ + /* output for debugging purposes */ - if (c->initialized || c->initializing) { - builtin_monitorexit((java_objectheader *) c); + if (loadverbose) + log_message_class("Loading class: ", c); + + /* mark start of dump memory area */ - return c; - } + dumpsize = dump_size(); - /* this initalizing run begins NOW */ - c->initializing = true; + /* class is somewhat loaded */ - /* call the internal function */ - r = class_init_intern(c); + c->loaded = true; - /* if return value is not NULL everything was ok and the class is - initialized */ - if (r) - c->initialized = true; + if (!check_classbuffer_size(cb, 4 + 2 + 2)) + goto return_exception; - /* this initalizing run is done */ - c->initializing = false; + /* check signature */ - /* leave the monitor */ + if (suck_u4(cb) != MAGIC) { + *exceptionptr = new_classformaterror(c, "Bad magic number"); - builtin_monitorexit((java_objectheader *) c); + goto return_exception; + } - return r; -} + /* check version */ + mi = suck_u2(cb); + ma = suck_u2(cb); -/* this function MUST NOT be called directly, because of thread - race conditions */ + if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) { + *exceptionptr = + new_unsupportedclassversionerror(c, + "Unsupported major.minor version %d.%d", + ma, mi); -static classinfo *class_init_intern(classinfo *c) -{ - methodinfo *m; - s4 i; -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - int b; -#endif + goto return_exception; + } - if (!c->loaded) - if (!class_load(c)) - return NULL; + /* create a new descriptor pool */ - if (!c->linked) - if (!class_link(c)) - return NULL; + descpool = descriptor_pool_new(c); -#if defined(STATISTICS) - if (opt_stat) - count_class_inits++; -#endif + /* load the constant pool */ - /* initialize super class */ - if (c->super) { - if (!c->super->loaded) - if (!class_load(c->super)) - return NULL; + if (!load_constantpool(cb, descpool)) + goto return_exception; - if (!c->super->linked) - if (!class_link(c->super)) - return NULL; + /*JOWENN*/ + c->erroneous_state = 0; + c->initializing_thread = 0; + /*JOWENN*/ + c->classUsed = NOTUSED; /* not used initially CO-RT */ + c->impldBy = NULL; - 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); - } + /* ACC flags */ - if (!class_init(c->super)) - return NULL; - } - } + if (!check_classbuffer_size(cb, 2)) + goto return_exception; - /* initialize interface classes */ - for (i = 0; i < c->interfacescount; i++) { - if (!c->interfaces[i]->loaded) - if (!class_load(c->interfaces[i])) - return NULL; + c->flags = suck_u2(cb); - if (!c->interfaces[i]->linked) - if (!class_link(c->interfaces[i])) - return NULL; + /* check ACC flags consistency */ - 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; + 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; } - } - m = class_findmethod(c, utf_clinit, utf_fidesc); + if (c->flags & ACC_FINAL) { + *exceptionptr = + new_classformaterror(c, + "Illegal class modifiers: 0x%X", c->flags); - 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); + goto return_exception; } - return c; + if (c->flags & ACC_SUPER) { + c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */ + } } - if (!(m->flags & ACC_STATIC)) - panic("Class initializer is not static!"); + if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) { + *exceptionptr = + new_classformaterror(c, "Illegal class modifiers: 0x%X", c->flags); - if (initverbose) - log_message_class("Starting static class initializer for class: ", c); + goto return_exception; + } -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - b = blockInts; - blockInts = 0; -#endif + if (!check_classbuffer_size(cb, 2 + 2)) + goto return_exception; - /* now call the initializer */ - asm_calljavafunction(m, NULL, NULL, NULL, NULL); + /* this class */ -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - assert(blockInts == 0); - blockInts = b; -#endif + i = suck_u2(cb); + if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class))) + goto return_exception; - /* we have an exception or error */ - if (*exceptionptr) { - /* is this an exception, than wrap it */ - if (builtin_instanceof(*exceptionptr, class_java_lang_Exception)) { - java_objectheader *xptr; - java_objectheader *cause; + if (c->name == utf_not_named_yet) { + /* we finally have a name for this class */ + c->name = name; + class_set_packagename(c); - /* class is NOT initialized */ - c->initialized = false; + } else if (name != c->name) { + char *msg; + s4 msglen; - /* get the cause */ - cause = *exceptionptr; + msglen = utf_strlen(c->name) + strlen(" (wrong name: ") + + utf_strlen(name) + strlen(")") + strlen("0"); - /* clear exception, because we are calling jit code again */ - *exceptionptr = NULL; + msg = MNEW(char, msglen); - /* wrap the exception */ - xptr = - new_exception_throwable(string_java_lang_ExceptionInInitializerError, - (java_lang_Throwable *) cause); + utf_sprint(msg, c->name); + strcat(msg, " (wrong name: "); + utf_strcat(msg, name); + strcat(msg, ")"); - /* XXX should we exit here? */ - if (*exceptionptr) - throw_exception(); + *exceptionptr = + new_exception_message(string_java_lang_NoClassDefFoundError, msg); - /* set new exception */ - *exceptionptr = xptr; - } + MFREE(msg, char, msglen); - return NULL; + goto return_exception; } + + /* retrieve superclass */ - if (initverbose) - log_message_class("Finished static class initializer for class: ", c); - - return c; -} + 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. */ -/********* Function: find_class_method_constant *********/ + if (c->name == utf_java_lang_Object) { + *exceptionptr = + new_exception_message(string_java_lang_ClassFormatError, + "java.lang.Object with superclass"); -int find_class_method_constant (classinfo *c, utf * c1, utf* m1, utf* d1) -{ - u4 i; - voidptr e; + goto return_exception; + } - for (i=0; icpcount; i++) { - - e = c -> cpinfos [i]; - if (e) { - - switch (c -> cptags [i]) { - case CONSTANT_Methodref: - { - constant_FMIref *fmi = e; - if ( (fmi->class->name == c1) - && (fmi->name == m1) - && (fmi->descriptor == d1)) { - - return i; - } - } - break; + /* Interfaces must have java.lang.Object as super class. */ - case CONSTANT_InterfaceMethodref: - { - constant_FMIref *fmi = e; - if ( (fmi->class->name == c1) - && (fmi->name == m1) - && (fmi->descriptor == d1)) { + if ((c->flags & ACC_INTERFACE) && + supername != utf_java_lang_Object) { + *exceptionptr = + new_exception_message(string_java_lang_ClassFormatError, + "Interfaces must have java.lang.Object as superclass"); - return i; - } - } - break; - } + goto return_exception; } - } - return -1; -} + } else { + supername = NULL; + /* This is only allowed for java.lang.Object. */ -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; + if (c->name != utf_java_lang_Object) { + *exceptionptr = new_classformaterror(c, "Bad superclass index"); - 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"); + goto return_exception; } } - printf("\n"); -} + + /* retrieve interfaces */ + + if (!check_classbuffer_size(cb, 2)) + goto return_exception; + + c->interfacescount = suck_u2(cb); + if (!check_classbuffer_size(cb, 2 * c->interfacescount)) + goto return_exception; -void class_showconstantpool (classinfo *c) -{ - u4 i; - voidptr e; + c->interfaces = MNEW(classref_or_classinfo, c->interfacescount); + for (i = 0; i < c->interfacescount; i++) { + /* the classrefs are created later */ + if (!(c->interfaces[i].any = (utf *) class_getconstant(c, suck_u2(cb), CONSTANT_Class))) + goto return_exception; + } - printf ("---- dump of constant pool ----\n"); + /* load fields */ + if (!check_classbuffer_size(cb, 2)) + goto return_exception; - 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; + c->fieldscount = suck_u2(cb); + 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)) + goto return_exception; + } - 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"); - } - } + /* load methods */ + if (!check_classbuffer_size(cb, 2)) + goto return_exception; - printf ("\n"); + 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]),descpool)) + goto return_exception; } -} + /* create the class reference table */ + c->classrefs = + descriptor_pool_create_classrefs(descpool, &(c->classrefcount)); -/********** Function: class_showmethods (debugging only) *************/ + /* allocate space for the parsed descriptors */ -void class_showmethods (classinfo *c) -{ - s4 i; - - printf ("--------- Fields and Methods ----------------\n"); - printf ("Flags: "); printflags (c->flags); printf ("\n"); + descriptor_pool_alloc_parsed_descriptors(descpool); + c->parseddescs = + descriptor_pool_get_parsed_descriptors(descpool, &(c->parseddescsize)); - 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); - } +#if defined(STATISTICS) + if (opt_stat) { + descriptor_pool_get_sizes(descpool, &classrefsize, &descsize); + count_classref_len += classrefsize; + count_parsed_desc_len += descsize; + } +#endif - printf ("fields:\n"); - for (i=0; i < c -> fieldscount; i++) { - field_display (&(c -> fields[i])); + /* 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); } + } - 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); + /* set the super class reference */ - method_display ( m ); + if (supername) { + c->super.ref = descriptor_pool_lookup_classref(descpool, supername); + if (!c->super.ref) + goto return_exception; + } - } + /* set the super interfaces references */ - printf ("Virtual function table:\n"); - for (i=0; ivftbl->vftbllength; i++) { - printf ("entry: %d, %ld\n", i, (long int) (c->vftbl->table[i]) ); - } + 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; + } -/******************************************************************************/ -/******************* General functions for the class loader *******************/ -/******************************************************************************/ + /* parse method descriptors */ -/**************** function: create_primitive_classes *************************** + 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; - create classes representing primitive types + 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; + } + } -void create_primitive_classes() -{ - int i; + /* parse the loaded descriptors */ - for (i = 0; i < PRIMITIVETYPE_COUNT; i++) { - /* create primitive class */ - classinfo *c = - class_new_intern(utf_new_char(primitivetype_table[i].name)); - c->classUsed = NOTUSED; /* not used initially CO-RT */ - c->impldBy = NULL; + for (i = 0; i < c->cpcount; i++) { + constant_FMIref *fmi; + s4 index; - /* prevent loader from loading primitive class */ - c->loaded = true; - class_link(c); - - primitivetype_table[i].class_primitive = c; - - /* create class for wrapping the primitive type */ - c = class_new_intern(utf_new_char(primitivetype_table[i].wrapname)); - primitivetype_table[i].class_wrap = c; - primitivetype_table[i].class_wrap->classUsed = NOTUSED; /* not used initially CO-RT */ - primitivetype_table[i].class_wrap->impldBy = NULL; - - /* create the primitive array class */ - if (primitivetype_table[i].arrayname) { - c = class_new_intern(utf_new_char(primitivetype_table[i].arrayname)); - primitivetype_table[i].arrayclass = c; - c->loaded = true; - if (!c->linked) - class_link(c); - primitivetype_table[i].arrayvftbl = c->vftbl; + 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; } } -} - -/**************** function: class_primitive_from_sig *************************** + /* Check if all fields and methods can be uniquely + * identified by (name,descriptor). */ - return the primitive class indicated by the given signature character + 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 */ + size_t len; + size_t hashlen; + u2 index; + u2 old; - If the descriptor does not indicate a valid primitive type the - return value is NULL. + /* Allocate hashtable */ + len = c->methodscount; + if (len < c->fieldscount) len = c->fieldscount; + hashlen = 5 * len; + hashtab = MNEW(u2,(hashlen + len)); + next = hashtab + hashlen; -********************************************************************************/ + /* Determine bitshift (to get good hash values) */ + if (!shift) { + len = sizeof(utf); + while (len) { + len >>= 1; + shift++; + } + } -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; -} + /* Check fields */ + memset(hashtab, 0, sizeof(u2) * (hashlen + len)); -/****************** function: class_from_descriptor **************************** + for (i = 0; i < c->fieldscount; ++i) { + fieldinfo *fi = c->fields + i; - return the class indicated by the given descriptor + /* It's ok if we lose bits here */ + index = ((((size_t) fi->name) + + ((size_t) fi->descriptor)) >> shift) % hashlen; - 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.) + if ((old = hashtab[index])) { + old--; + next[i] = old; + do { + if (c->fields[old].name == fi->name && + c->fields[old].descriptor == fi->descriptor) { + *exceptionptr = + new_classformaterror(c, + "Repetitive field name/signature"); - mode.......a combination (binary or) of the following flags: + goto return_exception; + } + } while ((old = next[old])); + } + hashtab[index] = i + 1; + } + + /* Check methods */ + memset(hashtab, 0, sizeof(u2) * (hashlen + hashlen/5)); - (Flags marked with * are the default settings.) + for (i = 0; i < c->methodscount; ++i) { + methodinfo *mi = c->methods + i; - What to do if a reference type descriptor is parsed successfully: + /* It's ok if we lose bits here */ + index = ((((size_t) mi->name) + + ((size_t) mi->descriptor)) >> shift) % hashlen; - CLASSLOAD_SKIP...skip it and return something != NULL - * CLASSLOAD_NEW....get classinfo * via class_new - CLASSLOAD_LOAD...get classinfo * via loader_load + /*{ JOWENN + int dbg; + for (dbg=0;dbgmethods[old].name == mi->name && + c->methods[old].descriptor == mi->descriptor) { + *exceptionptr = + new_classformaterror(c, + "Repetitive method name/signature"); - * CLASSLOAD_PRIMITIVE.......return primitive class (eg. "int") - CLASSLOAD_NULLPRIMITIVE...return NULL for primitive types + goto return_exception; + } + } while ((old = next[old])); + } + hashtab[index] = i + 1; + } + + MFREE(hashtab, u2, (hashlen + len)); + } - How to handle "V" descriptors: +#if defined(STATISTICS) + if (opt_stat) { + count_class_infos += sizeof(classinfo*) * c->interfacescount; + count_class_infos += sizeof(fieldinfo) * c->fieldscount; + count_class_infos += sizeof(methodinfo) * c->methodscount; + } +#endif - * CLASSLOAD_VOID.....handle it like other primitive types - CLASSLOAD_NOVOID...treat it as an error + /* load attribute structures */ - How to deal with extra characters after the end of the - descriptor: + if (!check_classbuffer_size(cb, 2)) + goto return_exception; - * CLASSLOAD_NOCHECKEND...ignore (useful for parameter lists) - CLASSLOAD_CHECKEND.....treat them as an error + if (!load_attributes(cb, suck_u2(cb))) + goto return_exception; - How to deal with errors: +#if 0 + /* Pre java 1.5 version don't check this. This implementation is like + java 1.5 do it: for class file version 45.3 we don't check it, older + versions are checked. + */ + if ((ma == 45 && mi > 3) || ma > 45) { + /* check if all data has been read */ + s4 classdata_left = ((cb->data + cb->size) - cb->pos - 1); - * CLASSLOAD_PANIC....abort execution with an error message - CLASSLOAD_NOPANIC..return NULL on error + if (classdata_left > 0) { + *exceptionptr = + new_classformaterror(c, "Extra bytes at the end of class file"); + goto return_exception; + } + } +#endif -*******************************************************************************/ + /* release dump area */ -classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr, - char **next, int mode) -{ - char *start = utf_ptr; - bool error = false; - utf *name; + dump_release(dumpsize); + + if (loadverbose) + log_message_class("Loading done class: ", c); - SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error); + LOADER_DEC(); + return c; - 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 */ - } - } - } +return_exception: + /* release dump area */ - /* An error occurred */ - if (mode & CLASSLOAD_NOPANIC) - return NULL; + dump_release(dumpsize); - log_plain("Invalid descriptor at beginning of '"); - log_plain_utf(utf_new(start, end_ptr - start)); - log_plain("'"); - log_nl(); - - panic("Invalid descriptor"); + /* an exception has been thrown */ - /* keep compiler happy */ + LOADER_DEC(); return NULL; } -/******************* function: type_from_descriptor **************************** +/* load_newly_created_array **************************************************** - return the basic type indicated by the given descriptor + Load a newly created array class. - This function parses a descriptor and returns its basic type as - TYPE_INT, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, TYPE_ADDRESS or TYPE_VOID. + 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 - cls...if non-NULL the referenced variable is set to the classinfo * - returned by class_from_descriptor. + Note: + This is an internal function. Do not use it unless you know exactly + what you are doing! - 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. + Use one of the load_class_... functions for general array class loading. -********************************************************************************/ +*******************************************************************************/ -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; +classinfo *load_newly_created_array(classinfo *c, java_objectheader *loader) +{ + 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 + + text = c->name->text; + namelen = c->name->blength; + + /* Check array class name */ + + if (namelen < 2 || text[0] != '[') { + *exceptionptr = new_noclassdeffounderror(c->name); + return NULL; } - return TYPE_ADDRESS; -} + /* Check the element type */ -/*************** function: create_pseudo_classes ******************************* + switch (text[1]) { + case '[': + /* c is an array of arrays. We have to create the component class. */ - create pseudo classes used by the typechecker + 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; -static void create_pseudo_classes() -{ - /* pseudo class for Arraystubs (extends java.lang.Object) */ - - pseudo_class_Arraystub = class_new_intern(utf_new_char("$ARRAYSTUB$")); - pseudo_class_Arraystub->loaded = true; - pseudo_class_Arraystub->super = class_java_lang_Object; - pseudo_class_Arraystub->interfacescount = 2; - pseudo_class_Arraystub->interfaces = MNEW(classinfo*, 2); - pseudo_class_Arraystub->interfaces[0] = class_java_lang_Cloneable; - pseudo_class_Arraystub->interfaces[1] = class_java_io_Serializable; - - class_link(pseudo_class_Arraystub); - - pseudo_class_Arraystub_vftbl = pseudo_class_Arraystub->vftbl; - - /* pseudo class representing the null type */ - - pseudo_class_Null = class_new_intern(utf_new_char("$NULL$")); - pseudo_class_Null->loaded = true; - pseudo_class_Null->super = class_java_lang_Object; - class_link(pseudo_class_Null); - - /* pseudo class representing new uninitialized objects */ - - pseudo_class_New = class_new_intern(utf_new_char("$NEW$")); - pseudo_class_New->loaded = true; - pseudo_class_New->linked = true; - pseudo_class_New->super = class_java_lang_Object; -/* class_link(pseudo_class_New); */ -} + case 'L': + /* c is an array of objects. */ + /* 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; + } -/********************** Function: loader_init ********************************** + u = utf_new(text + 2, namelen - 3); - Initializes all lists and loads all classes required for the system or the - compiler. + 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; -*******************************************************************************/ - -void loader_init(u1 *stackbottom) -{ - interfaceindex = 0; - - /* create utf-symbols for pointer comparison of frequently used strings */ - utf_innerclasses = utf_new_char("InnerClasses"); - utf_constantvalue = utf_new_char("ConstantValue"); - utf_code = utf_new_char("Code"); - utf_exceptions = utf_new_char("Exceptions"); - utf_linenumbertable = utf_new_char("LineNumberTable"); - utf_sourcefile = utf_new_char("SourceFile"); - utf_finalize = utf_new_char("finalize"); - utf_fidesc = utf_new_char("()V"); - utf_init = utf_new_char(""); - utf_clinit = utf_new_char(""); - utf_initsystemclass = utf_new_char("initializeSystemClass"); - utf_systemclass = utf_new_char("java/lang/System"); - utf_vmclassloader = utf_new_char("java/lang/VMClassLoader"); - utf_initialize = utf_new_char("initialize"); - utf_initializedesc = utf_new_char("(I)V"); - utf_vmclass = utf_new_char("java/lang/VMClass"); - utf_java_lang_Object= utf_new_char("java/lang/Object"); - array_packagename = utf_new_char(""); - utf_fillInStackTrace_name = utf_new_char("fillInStackTrace"); - utf_fillInStackTrace_desc = utf_new_char("()Ljava/lang/Throwable;"); - - /* create some important classes */ - /* These classes have to be created now because the classinfo - * pointers are used in the loading code. - */ - class_java_lang_Object = - class_new_intern(utf_java_lang_Object); - class_load(class_java_lang_Object); - class_link(class_java_lang_Object); + /* 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; - class_java_lang_String = - class_new_intern(utf_new_char("java/lang/String")); - class_load(class_java_lang_String); - class_link(class_java_lang_String); + default: + /* c is an array of a primitive type */ - class_java_lang_Cloneable = - class_new_intern(utf_new_char("java/lang/Cloneable")); - class_load(class_java_lang_Cloneable); - class_link(class_java_lang_Cloneable); + /* check for cases like `[II' */ + if (namelen > 2) { + *exceptionptr = new_noclassdeffounderror(c->name); + return NULL; + } - class_java_io_Serializable = - class_new_intern(utf_new_char("java/io/Serializable")); - class_load(class_java_io_Serializable); - class_link(class_java_io_Serializable); + /* the accessibility of the array class is public (VM Spec 5.3.3) */ + c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; + c->classloader = NULL; + } - /* create classes representing primitive types */ - create_primitive_classes(); + LOADER_ASSERT(class_java_lang_Object); + LOADER_ASSERT(class_java_lang_Cloneable); + LOADER_ASSERT(class_java_io_Serializable); - /* create classes used by the typechecker */ - create_pseudo_classes(); + /* setup the array class */ - /* correct vftbl-entries (retarded loading of class java/lang/String) */ - stringtable_update(); + c->super.cls = class_java_lang_Object; -#if defined(USE_THREADS) - if (stackbottom != 0) - initLocks(); -#endif -} + c->interfacescount = 2; + c->interfaces = MNEW(classref_or_classinfo, 2); + if (opt_eager) { + classinfo *tc; -static void loader_compute_class_values(classinfo *c) -{ - classinfo *subs; + tc = class_java_lang_Cloneable; + LOADER_ASSERT(tc->loaded); + list_addfirst(&unlinkedclasses, tc); + c->interfaces[0].cls = tc; - c->vftbl->baseval = ++classvalue; + tc = class_java_io_Serializable; + LOADER_ASSERT(tc->loaded); + list_addfirst(&unlinkedclasses, tc); + c->interfaces[1].cls = tc; - subs = c->sub; - while (subs != NULL) { - loader_compute_class_values(subs); - subs = subs->nextsub; + } else { + c->interfaces[0].cls = class_java_lang_Cloneable; + c->interfaces[1].cls = class_java_io_Serializable; } - c->vftbl->diffval = classvalue - c->vftbl->baseval; -} + c->methodscount = 1; + c->methods = MNEW(methodinfo, c->methodscount); + classrefs = MNEW(constant_classref, 2); + CLASSREF_INIT(classrefs[0], c, c->name); + CLASSREF_INIT(classrefs[1], c, utf_java_lang_Object); -void loader_compute_subclasses(classinfo *c) -{ -#if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - compiler_lock(); -#else - intsDisable(); -#endif + /* 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; + + /* create methodinfo */ + + clone = c->methods; + MSET(clone, 0, methodinfo, 1); + +#if defined(USE_THREADS) && defined(NATIVE_THREADS) + initObjectLock(&clone->header); #endif - if (!(c->flags & ACC_INTERFACE)) { - c->nextsub = 0; - c->sub = 0; - } + /* 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; - if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) { - c->nextsub = c->super->sub; - c->super->sub = c; - } + /* parse the descriptor to get the register allocation */ - classvalue = 0; + if (!descriptor_params_from_paramtypes(clonedesc, clone->flags)) + return false; - /* this is the java.lang.Object special case */ - if (!class_java_lang_Object) { - loader_compute_class_values(c); + clone->entrypoint = + codegen_createnativestub((functionptr) &builtin_clone_array, clone); - } else { - loader_compute_class_values(class_java_lang_Object); - } + /* XXX: field: length? */ -#if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - compiler_unlock(); -#else - intsRestore(); -#endif -#endif + /* array classes are not loaded from class files */ + + c->loaded = true; + c->parseddescs = (u1 *) clonedesc; + c->parseddescsize = sizeof(methodinfo); + c->classrefs = classrefs; + c->classrefcount = 1; + + /* insert class into the loaded class cache */ + /* XXX free classinfo if NULL returned? */ + + return classcache_store(loader,c,true); } -/******************** Function: loader_close *********************************** +/* loader_close **************************************************************** - Frees all resources + Frees all resources. *******************************************************************************/ -void loader_close() +void loader_close(void) { - 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 */ }