X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Floader.c;h=2a4681af59d61a9e554dc78ed3b8a0762f6fb612;hb=bc29a17a12edc896584d24c996c773545796859f;hp=4b094d28db29760a2f64246ee2d96b93e020d71d;hpb=2c6545cefe86723a99d9d1b8bb0fe48c7b01e0f7;p=cacao.git diff --git a/src/vm/loader.c b/src/vm/loader.c index 4b094d28d..2a4681af5 100644 --- a/src/vm/loader.c +++ b/src/vm/loader.c @@ -1,9 +1,9 @@ -/* loader.c - class loader functions +/* 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. @@ -25,12 +25,14 @@ Contact: cacao@complang.tuwien.ac.at Authors: Reinhard Grafl + Changes: Andreas Krall Roman Obermaiser Mark Probst - Edwin Steiner + Edwin Steiner + Christian Thalinger - $Id: loader.c 1112 2004-05-31 15:47:20Z jowenn $ + $Id: loader.c 1936 2005-02-10 11:04:10Z twisti $ */ @@ -39,95 +41,57 @@ #include #include #include -#include "global.h" -#include "loader.h" -#include "main.h" -#include "native.h" -#include "tables.h" -#include "builtin.h" -#include "jit.h" -#include "asmpart.h" -#include "toolbox/memory.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 "vm/exceptions.h" +#include "vm/builtin.h" +#include "vm/global.h" +#include "vm/loader.h" +#include "vm/options.h" +#include "vm/statistics.h" +#include "vm/stringlocal.h" +#include "vm/tables.h" -#ifdef USE_ZLIB -#include "unzip.h" +#if defined(USE_ZLIB) +# include "vm/unzip.h" #endif +#include "vm/jit/asmpart.h" +#include "vm/jit/jit.h" + + #undef JOWENN_DEBUG #undef JOWENN_DEBUG1 #undef JOWENN_DEBUG2 /* global variables ***********************************************************/ -int count_class_infos = 0; /* variables for measurements */ -int count_const_pool_len = 0; -int count_vftbl_len = 0; -int count_all_methods = 0; -int count_vmcode_len = 0; -int count_extable_len = 0; -int count_class_loads = 0; -int count_class_inits = 0; - 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; -} - - -/* important system classes ***************************************************/ - -classinfo *class_java_lang_Object; -classinfo *class_java_lang_String; -classinfo *class_java_lang_Cloneable; -classinfo *class_java_io_Serializable; - -/* Pseudo classes for the typechecker */ -classinfo *pseudo_class_Arraystub = NULL; -classinfo *pseudo_class_Null = NULL; -classinfo *pseudo_class_New = NULL; -vftbl *pseudo_class_Arraystub_vftbl = NULL; - -utf *array_packagename = NULL; +vftbl_t *pseudo_class_Arraystub_vftbl = NULL; /******************************************************************** list of classpath entries (either filesystem directories or ZIP/JAR archives ********************************************************************/ -static classpath_info *classpath_entries=0; + +static classpath_info *classpath_entries = NULL; /****************************************************************************** @@ -154,11 +118,6 @@ primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT] = { }; -/* instances of important system classes **************************************/ - -java_objectheader *proto_java_lang_NullPointerException; - - /************* functions for reading classdata ********************************* getting classdata in blocks of variable size @@ -166,49 +125,53 @@ java_objectheader *proto_java_lang_NullPointerException; *******************************************************************************/ -static char *classpath = ""; /* searchpath for classfiles */ +/* check_classbuffer_size ****************************************************** + + assert that at least bytes are left to read + is limited to the range of non-negative s4 values + +*******************************************************************************/ + +static inline bool check_classbuffer_size(classbuffer *cb, s4 len) +{ + if (len < 0 || ((cb->data + cb->size) - cb->pos - 1) < len) { + *exceptionptr = + new_classformaterror((cb)->class, "Truncated class file"); + + return false; + } + + return true; +} + +/* suck_nbytes ***************************************************************** -/* assert that at least bytes are left to read */ -/* is limited to the range of non-negative s4 values */ + transfer block of classfile data into a buffer -#define ASSERT_LEFT(cb, len) \ - do { \ - if (((s4) (len)) < 0 || \ - (((cb)->data + (cb)->size) - (cb)->pos - 1) < (len)) { \ - char message[MAXLOGTEXT]; \ - utf_sprint_classname(message, (cb)->class->name); \ - sprintf(message + strlen(message), " (Truncated class file)"); \ - *exceptionptr = \ - new_exception_message(string_java_lang_ClassFormatError, \ - message); \ - throw_exception_exit(); \ - } \ - } while (0) +*******************************************************************************/ +inline void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len) +{ + memcpy(buffer, cb->pos + 1, len); + cb->pos += len; +} -/* transfer block of classfile data into a buffer */ -#define suck_nbytes(buffer, cb, len) \ - do { \ - ASSERT_LEFT((cb), (len)); \ - memcpy((buffer), (cb)->pos + 1, (len)); \ - (cb)->pos += (len); \ - } while (0) +/* skip_nbytes **************************************************************** + skip block of classfile data -/* skip block of classfile data */ +*******************************************************************************/ -#define skip_nbytes(cb, len) \ - do { \ - ASSERT_LEFT((cb), (len)); \ - (cb)->pos += (len); \ - } while (0) +inline void skip_nbytes(classbuffer *cb, s4 len) +{ + cb->pos += len; +} inline u1 suck_u1(classbuffer *cb) { - ASSERT_LEFT(cb, 1); return *++(cb->pos); } @@ -230,11 +193,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) @@ -253,6 +211,12 @@ static u8 suck_u8(classbuffer *cb) } +#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 float from classfile data */ static float suck_float(classbuffer *cb) { @@ -266,14 +230,13 @@ static float suck_float(classbuffer *cb) buffer[3 - i] = suck_u1(cb); memcpy((u1*) (&f), buffer, 4); -#else +#else suck_nbytes((u1*) (&f), cb, 4); #endif if (sizeof(float) != 4) { - *exceptionptr = - new_exception_message(string_java_lang_InternalError, - "Incompatible float-format"); + *exceptionptr = new_exception_message(string_java_lang_InternalError, + "Incompatible float-format"); /* XXX should we exit in such a case? */ throw_exception_exit(); @@ -301,9 +264,8 @@ static double suck_double(classbuffer *cb) #endif if (sizeof(double) != 8) { - *exceptionptr = - new_exception_message(string_java_lang_InternalError, - "Incompatible double-format"); + *exceptionptr = new_exception_message(string_java_lang_InternalError, + "Incompatible double-format"); /* XXX should we exit in such a case? */ throw_exception_exit(); @@ -319,97 +281,100 @@ 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; + char *filename; + s4 filenamelen; + bool is_zip; + classpath_info *cpi; + classpath_info *lastcpi; - if (!cpath) - return; + /* search for last classpath entry (only if there already some) */ - classpath = cpath; - - if (classpath_entries) - panic("suck_init should be called only once"); + 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 (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"); - - if (!filename) - filename = MNEW(char*, CLASSPATH_MAXFILENAME); + /* allocate memory for filename and fill it */ + filename = MNEW(char, filenamelen + 2); /* 2 = "/\0" */ strncpy(filename, start, filenamelen); filename[filenamelen + 1] = '\0'; - tmp = 0; + cpi = NULL; - if (isZip) { -#ifdef USE_ZLIB + 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 = 0; - filename = 0; + cpi = NEW(classpath_info); + cpi->type = CLASSPATH_ARCHIVE; + cpi->uf = uf; + cpi->next = NULL; + cpi->pd = NULL; /* ProtectionDomain not set yet */ + cpi->path = filename; } + #else - panic("Zip/JAR 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; + cpi->pd = NULL; /* ProtectionDomain not set yet */ 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 = 0; + + 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); + } } } @@ -418,14 +383,13 @@ void create_all_classes() { classpath_info *cpi; - for (cpi = classpath_entries; cpi != 0; cpi = cpi->filepath.next) { + for (cpi = classpath_entries; cpi != 0; cpi = cpi->next) { #if defined(USE_ZLIB) - unz_file_info file_info; - 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) { @@ -453,100 +417,130 @@ void create_all_classes() 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 *utf_ptr; */ +/* char ch; */ + 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) + 7; /* 7 = ".class\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"); + + /* walk through all classpath entries */ + + for (cpi = classpath_entries; cpi != NULL && cb == NULL; cpi = cpi->next) { +#if defined(USE_ZLIB) + if (cpi->type == CLASSPATH_ARCHIVE) { + +#if defined(USE_THREADS) + /* enter a monitor on zip/jar archives */ - strcpy(filename + filenamelen, ".class"); - filenamelen += 6; + builtin_monitorenter((java_objectheader *) cpi); +#endif - for (currPos = classpath_entries; currPos != 0; currPos = currPos->filepath.next) { -#ifdef USE_ZLIB - if (currPos->filepath.type == CLASSPATH_ARCHIVE) { - if (cacao_locate(currPos->archive.uf, c->name) == UNZ_OK) { + 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; + /* We need this later in use_class_as_object to set a */ + /* correct ProtectionDomain and CodeSource. */ + c->pd = (struct java_security_ProtectionDomain *) cpi; - } 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 /* USE_ZLIB */ + + path = MNEW(char, cpi->pathlen + filenamelen + 1); + 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); + /* We need this later in use_class_as_object to set a */ + /* correct ProtectionDomain and CodeSource. */ + c->pd = (struct java_security_ProtectionDomain *) cpi; + + /* read class data */ + len = fread(cb->data, 1, cb->size, classfile); - return cb; + if (len != buffer.st_size) { + suck_stop(cb); +/* if (ferror(classfile)) { */ +/* } */ + + } else { + found = true; + } } } -#ifdef USE_ZLIB + + MFREE(path, char, cpi->pathlen + filenamelen + 1); +#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; + MFREE(filename, char, filenamelen); + + return cb; } @@ -605,47 +599,76 @@ void printflags(u2 f) } -/************************* Function: skipattribute ***************************** - - skips a (1) 'attribute' structure in the class file +/********************** Function: skipattributebody **************************** + skips an attribute after the 16 bit reference to attribute_name has already + been read + *******************************************************************************/ -static void skipattribute(classbuffer *cb) +static bool skipattributebody(classbuffer *cb) { u4 len; - suck_u2(cb); + + if (!check_classbuffer_size(cb, 4)) + return false; + len = suck_u4(cb); + + if (!check_classbuffer_size(cb, len)) + return false; + skip_nbytes(cb, len); + + return true; } -/********************** Function: skipattributebody **************************** +/************************* Function: skipattributes **************************** - skips an attribute after the 16 bit reference to attribute_name has already - been read + skips num attribute structures *******************************************************************************/ -static void skipattributebody(classbuffer *cb) +static bool skipattributes(classbuffer *cb, u4 num) { + u4 i; u4 len; - len = suck_u4(cb); - skip_nbytes(cb, len); + + for (i = 0; i < num; i++) { + if (!check_classbuffer_size(cb, 2 + 4)) + return false; + + suck_u2(cb); + len = suck_u4(cb); + + if (!check_classbuffer_size(cb, len)) + return false; + + skip_nbytes(cb, len); + } + + return true; } -/************************* Function: skipattributes **************************** +/******************** 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 - skips num attribute structures - *******************************************************************************/ -static void skipattributes(classbuffer *cb, u4 num) +voidptr class_getconstant(classinfo *c, u4 pos, u4 ctype) { - u4 i; - for (i = 0; i < num; i++) - skipattribute(cb); + /* check index and type of constantpool entry */ + /* (pos == 0 is caught by type comparison) */ + if (pos >= c->cpcount || c->cptags[pos] != ctype) { + *exceptionptr = new_classformaterror(c, "Illegal constant pool index"); + return NULL; + } + + return c->cpinfos[pos]; } @@ -655,11 +678,13 @@ static void skipattributes(classbuffer *cb, u4 num) *******************************************************************************/ -voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype) +voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype) { /* invalid position in constantpool */ - if (pos >= c->cpcount) - panic("Attempt to access constant outside range"); + if (pos >= c->cpcount) { + *exceptionptr = new_classformaterror(c, "Illegal constant pool index"); + return NULL; + } /* constantpool entry of type 0 */ if (!c->cptags[pos]) @@ -667,63 +692,118 @@ voidptr innerclass_getconstant(classinfo *c, u4 pos, u4 ctype) /* 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] ); + *exceptionptr = new_classformaterror(c, "Illegal constant pool index"); + return NULL; } return c->cpinfos[pos]; } +/********************* Function: class_constanttype **************************** + + Determines the type of a class entry in the ConstantPool + +*******************************************************************************/ + +u4 class_constanttype(classinfo *c, u4 pos) +{ + if (pos <= 0 || pos >= c->cpcount) { + *exceptionptr = new_classformaterror(c, "Illegal constant pool index"); + return 0; + } + + return c->cptags[pos]; +} + + /************************ function: attribute_load **************************** read attributes from classfile *******************************************************************************/ -static void attribute_load(classbuffer *cb, classinfo *c, u4 num) +static bool attribute_load(classbuffer *cb, classinfo *c, u4 num) { + utf *aname; u4 i, j; for (i = 0; i < num; i++) { /* retrieve attribute name */ - utf *aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + if (!check_classbuffer_size(cb, 2)) + return false; - if (aname == utf_innerclasses) { - /* innerclasses attribute */ + if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; - if (c->innerclass != NULL) - panic("Class has more than one InnerClasses attribute"); + if (aname == utf_InnerClasses) { + /* innerclasses attribute */ + if (c->innerclass) { + *exceptionptr = + new_classformaterror(c, "Multiple InnerClasses attributes"); + return false; + } - /* skip attribute length */ - suck_u4(cb); + if (!check_classbuffer_size(cb, 4 + 2)) + return false; + + /* skip attribute length */ + suck_u4(cb); + /* number of records */ c->innerclasscount = suck_u2(cb); + + if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount)) + return false; + /* allocate memory for innerclass structure */ c->innerclass = MNEW(innerclassinfo, c->innerclasscount); 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. */ + /* 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); /* CONSTANT_Class_info index */ - info->outer_class = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); /* CONSTANT_Class_info index */ - info->name = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8); /* CONSTANT_Utf8_info index */ - info->flags = suck_u2(cb); /* access_flags bitmask */ + 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) { - suck_u4(cb); - /*log_text("source file attribute found");*/ - c->sourcefile = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + + } else if (aname == utf_SourceFile) { + if (!check_classbuffer_size(cb, 4 + 2)) + return false; + + if (suck_u4(cb) != 2) { + *exceptionptr = + new_classformaterror(c, "Wrong size for VALUE attribute"); + return false; + } + + 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; + } else { /* unknown attribute */ - skipattributebody(cb); + if (!skipattributebody(cb)) + return false; } } + + return true; } @@ -786,14 +866,18 @@ static void checkfielddescriptor (char *utf_ptr, char *end_pos) *******************************************************************************/ -static int checkmethoddescriptor (utf *d) +static int checkmethoddescriptor(classinfo *c, utf *descriptor) { - char *utf_ptr = d->text; /* current position in utf text */ - char *end_pos = utf_end(d); /* points behind utf string */ - int argcount = 0; /* number of arguments */ + 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"); + if (utf_ptr == end_pos || *utf_ptr++ != '(') + panic ("Missing '(' in method descriptor"); /* check arguments */ while (utf_ptr != end_pos && *utf_ptr != ')') { @@ -809,16 +893,24 @@ static int checkmethoddescriptor (utf *d) | CLASSLOAD_NOVOID); } - if (utf_ptr == end_pos) panic("Missing ')' in method descriptor"); + if (utf_ptr == end_pos) + panic("Missing ')' in method descriptor"); + utf_ptr++; /* skip ')' */ - class_from_descriptor(utf_ptr,end_pos,NULL, - CLASSLOAD_NEW - | CLASSLOAD_NULLPRIMITIVE - | CLASSLOAD_CHECKEND); + class_from_descriptor(utf_ptr, + end_pos, + NULL, + CLASSLOAD_NEW | + CLASSLOAD_NULLPRIMITIVE | + CLASSLOAD_CHECKEND); + + if (argcount > 255) { + *exceptionptr = + new_classformaterror(c, "Too many arguments in signature"); - if (argcount > 255) - panic("Invalid method descriptor: too many arguments"); + return 0; + } return argcount; @@ -905,59 +997,79 @@ void print_arraydescriptor(FILE *file, arraydescriptor *desc) /******************************************************************************/ -/************************ Function: field_load ********************************* +/* field_load ****************************************************************** - 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. + 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. *******************************************************************************/ #define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */ -static fieldinfo *field_load(classbuffer *cb, classinfo *c, fieldinfo *f) +static bool field_load(classbuffer *cb, classinfo *c, fieldinfo *f) { - u4 attrnum,i; + u4 attrnum, i; u4 jtype; - u4 pindex = field_load_NOVALUE; /* constantvalue_index */ + u4 pindex = field_load_NOVALUE; /* constantvalue_index */ + utf *u; + + if (!check_classbuffer_size(cb, 2 + 2 + 2)) + return false; + + f->flags = suck_u2(cb); + + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + f->name = u; + + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + f->descriptor = u; - f->flags = suck_u2(cb); /* ACC flags */ - f->name = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); /* name of field */ - f->descriptor = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); /* JavaVM descriptor */ - 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)); - if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) - panic("Field has invalid access flags"); - if ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE)) - panic("Field is declared final and volatile"); - 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"); - if ((f->flags & ACC_TRANSIENT) != 0) - panic("Interface field declared transient"); + i = f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED); + + 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 (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; + } } /* check descriptor */ - checkfielddescriptor(f->descriptor->text,utf_end(f->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->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_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; @@ -967,25 +1079,35 @@ static fieldinfo *field_load(classbuffer *cb, classinfo *c, fieldinfo *f) } /* 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 */ - skipattributebody(cb); + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; - } else { - /* constant value attribute */ + if (u == utf_ConstantValue) { + if (!check_classbuffer_size(cb, 4 + 2)) + return false; - if (pindex != field_load_NOVALUE) - panic("Field has more than one ConstantValue attribute"); - /* check attribute length */ - if (suck_u4(cb) != 2) - panic("ConstantValue attribute has invalid 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); @@ -993,49 +1115,67 @@ static fieldinfo *field_load(classbuffer *cb, classinfo *c, fieldinfo *f) /* initialize field with value from constantpool */ switch (jtype) { case TYPE_INT: { - constant_integer *ci = - class_getconstant(c, pindex, CONSTANT_Integer); + constant_integer *ci; + + if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer))) + return false; + f->value.i = ci->value; } break; case TYPE_LONG: { - constant_long *cl = - class_getconstant(c, pindex, CONSTANT_Long); + constant_long *cl; + + if (!(cl = class_getconstant(c, pindex, CONSTANT_Long))) + return false; + f->value.l = cl->value; } break; case TYPE_FLOAT: { - constant_float *cf = - class_getconstant(c, pindex, CONSTANT_Float); + constant_float *cf; + + if (!(cf = class_getconstant(c, pindex, CONSTANT_Float))) + return false; + f->value.f = cf->value; } break; case TYPE_DOUBLE: { - constant_double *cd = - class_getconstant(c, pindex, CONSTANT_Double); + constant_double *cd; + + if (!(cd = class_getconstant(c, pindex, CONSTANT_Double))) + return false; + f->value.d = cd->value; } break; - case TYPE_ADDRESS: { - utf *u = class_getconstant(c, pindex, CONSTANT_String); - /* create javastring from compressed utf8-string */ + case TYPE_ADDRESS: + if (!(u = class_getconstant(c, pindex, CONSTANT_String))) + return false; + + /* create javastring from compressed utf8-string */ f->value.a = literalstring_new(u); - } - break; + break; default: - log_text ("Invalid Constant - Type"); + log_text("Invalid Constant - Type"); } + + } else { + /* unknown attribute */ + if (!skipattributebody(cb)) + return false; } } - /* just return fieldinfo* to signal everything was ok */ + /* everything was ok */ - return f; + return true; } @@ -1066,20 +1206,26 @@ void field_display(fieldinfo *f) /******************************************************************************/ -/*********************** Function: method_load ********************************* +/* 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. + 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 methodinfo *method_load(classbuffer *cb, classinfo *c, methodinfo *m) +static bool method_load(classbuffer *cb, classinfo *c, methodinfo *m) { - u4 attrnum, i, e; s4 argcount; - char msg[MAXLOGTEXT]; /* maybe we get an exception */ + s4 i, j; + u4 attrnum; + u4 codeattrnum; + utf *u; + +#if defined(USE_THREADS) && defined(NATIVE_THREADS) + initObjectLock(&m->header); +#endif #ifdef STATISTICS if (opt_stat) @@ -1090,66 +1236,95 @@ static methodinfo *method_load(classbuffer *cb, classinfo *c, methodinfo *m) 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); + + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + m->name = u; + + if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + m->descriptor = u; 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"); } - m->descriptor = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - argcount = checkmethoddescriptor(m->descriptor); + 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"); + if (argcount > 255) { + *exceptionptr = + new_classformaterror(c, "Too many arguments in signature"); + return false; + } /* 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 (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))) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), " (Illegal method modifiers: 0x%x)", m->flags); - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - msg); - - return NULL; + 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 (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 (m->name == utf_init) { - if ((m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED - | ACC_NATIVE | ACC_ABSTRACT)) != 0) + if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED | + ACC_NATIVE | ACC_ABSTRACT)) 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->entrypoint = NULL; - m->mcode = NULL; m->stubroutine = NULL; + m->mcode = NULL; + m->entrypoint = NULL; m->methodUsed = NOTUSED; m->monoPoly = MONO; m->subRedefs = 0; @@ -1161,160 +1336,209 @@ static methodinfo *method_load(classbuffer *cb, classinfo *c, methodinfo *m) m->stubroutine = createcompilerstub(m); } else { + /*if (useinlining) { + log_text("creating native stub:"); + method_display(m); + }*/ functionptr f = native_findfunction(c->name, m->name, m->descriptor, - (m->flags & ACC_STATIC) != 0); - if (f) { + (m->flags & ACC_STATIC) != 0); +#ifdef STATIC_CLASSPATH + if (f) +#endif + { 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; - aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - - if (aname != utf_code) { - if (aname == utf_exceptions) { - u2 exceptionCount; - u2 exceptionID; - suck_u4(cb); /*length*/ - exceptionCount=suck_u2(cb); - m->thrownexceptionscount=exceptionCount; - m->thrownexceptions=MNEW(classinfo*,exceptionCount); - for (exceptionID=0;exceptionIDthrownexceptions)[exceptionID]=class_getconstant(c,suck_u2(cb),CONSTANT_Class); - } - } - else - skipattributebody(cb); + if (!check_classbuffer_size(cb, 2)) + return false; - } else { - u4 codelen; - if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), - " (Code attribute in native or abstract methods)"); + if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + if (aname == utf_Code) { + if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) { *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - msg); + new_classformaterror(c, + "Code attribute in native or abstract methods"); - return NULL; + return false; } if (m->jcode) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), " (Multiple Code attributes)"); - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - msg); + new_classformaterror(c, "Multiple Code attributes"); - return NULL; + 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) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), - " (Arguments can't fit into locals)"); + if (m->maxlocals < argcount) { *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - msg); + new_classformaterror(c, "Arguments can't fit into locals"); - return NULL; + return false; } - codelen = suck_u4(cb); + if (!check_classbuffer_size(cb, 4)) + return false; - if (codelen == 0) - panic("bytecode has zero length"); + m->jcodelength = suck_u4(cb); - if (codelen > 65535) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), - " (Code of a method longer than 65535 bytes)"); + if (m->jcodelength == 0) { + *exceptionptr = + new_classformaterror(c, "Code of a method has length 0"); + return false; + } + + if (m->jcodelength > 65535) { *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - msg); + new_classformaterror(c, + "Code of a method longer than 65535 bytes"); - return NULL; + return false; } - m->jcodelength = codelen; + 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); - m->exceptiontable = - MNEW(exceptiontable, m->exceptiontablelength); + if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->exceptiontablelength)) + return false; -#ifdef STATISTICS + 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 (e = 0; e < m->exceptiontablelength; e++) { + for (j = 0; j < m->exceptiontablelength; j++) { u4 idx; - m->exceptiontable[e].startpc = suck_u2(cb); - m->exceptiontable[e].endpc = suck_u2(cb); - m->exceptiontable[e].handlerpc = suck_u2(cb); + 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[e].catchtype = NULL; + m->exceptiontable[j].catchtype = NULL; } else { - m->exceptiontable[e].catchtype = - class_getconstant(c, idx, CONSTANT_Class); + if (!(m->exceptiontable[j].catchtype = + class_getconstant(c, idx, CONSTANT_Class))) + return false; } - } - { - u2 codeattrnum; - for (codeattrnum=suck_u2(cb);codeattrnum>0;codeattrnum--) { - utf * caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); - if (caname==utf_linenumbertable) { - u2 lncid; - /*log_text("LineNumberTable found");*/ - suck_u4(cb); - m->linenumbercount=suck_u2(cb); - /*printf("length:%d\n",m->linenumbercount);*/ - m->linenumbers=MNEW(lineinfo,m->linenumbercount); - for (lncid=0;lncidlinenumbercount;lncid++) { - m->linenumbers[lncid].start_pc=suck_u2(cb); - m->linenumbers[lncid].line_number=suck_u2(cb); - } - codeattrnum--; - skipattributes(cb, codeattrnum); - break; - } else skipattributebody(cb); + } + + if (!check_classbuffer_size(cb, 2)) + return false; + + codeattrnum = suck_u2(cb); + + for (; codeattrnum > 0; codeattrnum--) { + utf *caname; + + if (!check_classbuffer_size(cb, 2)) + return false; + + if (!(caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8))) + return false; + + 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; + } + } + + } else if (aname == utf_Exceptions) { + s4 j; + + if (m->thrownexceptions) { + *exceptionptr = + new_classformaterror(c, "Multiple Exceptions attributes"); + return false; + } + + 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++) { + if (!((m->thrownexceptions)[j] = + class_getconstant(c, suck_u2(cb), CONSTANT_Class))) + return false; } + + } else { + if (!skipattributebody(cb)) + return false; } } if (!m->jcode && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), " (Missing Code attribute)"); + *exceptionptr = new_classformaterror(c, "Missing Code attribute"); - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, msg); - - return NULL; + return false; } - /* just return methodinfo* to signal everything was ok */ + /* everything was ok */ - return m; + return true; } @@ -1359,6 +1583,24 @@ void method_display(methodinfo *m) printf("\n"); } +/************** Function: method_display_w_class (debugging only) **************/ + +void method_display_w_class(methodinfo *m) +{ + printflags(m->class->flags); + printf(" "); fflush(stdout); + utf_display(m->class->name); + printf(".");fflush(stdout); + + printf(" "); + printflags(m->flags); + printf(" "); fflush(stdout); + utf_display(m->name); + printf(" "); fflush(stdout); + utf_display(m->descriptor); + printf("\n"); fflush(stdout); +} + /************** Function: method_display_flags_last (debugging only) **************/ void method_display_flags_last(methodinfo *m) @@ -1389,52 +1631,6 @@ static bool method_canoverwrite(methodinfo *m, methodinfo *old) } -/******************************************************************************/ -/************************ 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, @@ -1444,7 +1640,7 @@ u4 class_constanttype(classinfo *c, u4 pos) *******************************************************************************/ -static void class_loadcpool(classbuffer *cb, classinfo *c) +static bool class_loadcpool(classbuffer *cb, classinfo *c) { /* The following structures are used to save information which cannot be @@ -1452,17 +1648,17 @@ static void class_loadcpool(classbuffer *cb, classinfo *c) 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; + /* CONSTANT_Class 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; @@ -1475,7 +1671,7 @@ static void class_loadcpool(classbuffer *cb, classinfo *c) } forward_nameandtype; /* CONSTANT_Fieldref, CONSTANT_Methodref or CONSTANT_InterfaceMethodref */ - typedef struct forward_fieldmethint { + typedef struct forward_fieldmethint { struct forward_fieldmethint *next; u2 thisindex; u1 tag; @@ -1485,25 +1681,39 @@ static void class_loadcpool(classbuffer *cb, classinfo *c) 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; + forward_class *nfc; + forward_string *nfs; + forward_nameandtype *nfn; + forward_fieldmethint *nff; + + u4 cpcount; + u1 *cptags; + voidptr *cpinfos; + /* number of entries in the constant_pool table plus one */ - u4 cpcount = c->cpcount = suck_u2(cb); + if (!check_classbuffer_size(cb, 2)) + return false; + + cpcount = c->cpcount = suck_u2(cb); /* allocate memory */ - u1 *cptags = c->cptags = MNEW(u1, cpcount); - voidptr *cpinfos = c->cpinfos = MNEW(voidptr, cpcount); + cptags = c->cptags = MNEW(u1, cpcount); + cpinfos = c->cpinfos = MNEW(voidptr, cpcount); - if (!cpcount) - panic("Invalid constant_pool_count (0)"); + if (cpcount < 1) { + *exceptionptr = new_classformaterror(c, "Illegal constant pool size"); + return false; + } -#ifdef STATISTICS - count_const_pool_len += (sizeof(voidptr) + 1) * cpcount; +#if defined(STATISTICS) + if (opt_stat) + count_const_pool_len += (sizeof(voidptr) + 1) * cpcount; #endif /* initialize constantpool */ @@ -1519,83 +1729,105 @@ static void class_loadcpool(classbuffer *cb, classinfo *c) idx = 1; while (idx < cpcount) { + u4 t; + /* get constant type */ - u4 t = suck_u1(cb); + if (!check_classbuffer_size(cb, 1)) + return false; + + t = suck_u1(cb); switch (t) { - case CONSTANT_Class: { - forward_class *nfc = DNEW(forward_class); + case CONSTANT_Class: + nfc = NEW(forward_class); - nfc->next = forward_classes; + 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; - /* 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); + case CONSTANT_String: + nfs = NEW(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); + case CONSTANT_NameAndType: + nfn = NEW(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_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + nff = NEW(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_Integer: { constant_integer *ci = NEW(constant_integer); -#ifdef STATISTICS - count_const_pool_len += sizeof(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; @@ -1607,10 +1839,14 @@ static void class_loadcpool(classbuffer *cb, classinfo *c) case CONSTANT_Float: { constant_float *cf = NEW(constant_float); -#ifdef STATISTICS - count_const_pool_len += sizeof(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; @@ -1622,57 +1858,82 @@ static void class_loadcpool(classbuffer *cb, classinfo *c) case CONSTANT_Long: { constant_long *cl = NEW(constant_long); -#ifdef STATISTICS - count_const_pool_len += sizeof(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"); + if (idx > cpcount) { + *exceptionptr = + new_classformaterror(c, "Invalid constant pool entry"); + return false; + } break; } case CONSTANT_Double: { constant_double *cd = NEW(constant_double); -#ifdef STATISTICS - count_const_pool_len += sizeof(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"); + if (idx > cpcount) { + *exceptionptr = + new_classformaterror(c, "Invalid constant pool entry"); + return false; + } break; } case CONSTANT_Utf8: { + u4 length; + /* number of bytes in the bytes array (not string-length) */ - u4 length = suck_u2(cb); + if (!check_classbuffer_size(cb, 2)) + return false; + + length = suck_u2(cb); cptags[idx] = CONSTANT_Utf8; + /* validate the string */ - ASSERT_LEFT(cb, length); + if (!check_classbuffer_size(cb, length)) + return false; + if (opt_verify && - !is_valid_utf(cb->pos + 1, cb->pos + 1 + length)) { + !is_valid_utf((char *) (cb->pos + 1), + (char *) (cb->pos + 1 + length))) { dolog("Invalid UTF-8 string (constant pool index %d)",idx); panic("Invalid UTF-8 string"); } /* insert utf-string into the utf-symboltable */ - cpinfos[idx] = utf_new_int(cb->pos + 1, length); + cpinfos[idx] = utf_new_intern((char *) (cb->pos + 1), length); - /* skip bytes of the string */ + /* skip bytes of the string (buffer size check above) */ skip_nbytes(cb, length); idx++; break; } default: - error("Unkown constant type: %d",(int) t); + *exceptionptr = + new_classformaterror(c, "Illegal constant pool type"); + return false; } /* end switch */ } /* end while */ @@ -1688,27 +1949,47 @@ static void class_loadcpool(classbuffer *cb, classinfo *c) cptags[forward_classes->thisindex] = CONSTANT_Class; /* retrieve class from class-table */ - cpinfos[forward_classes->thisindex] = class_new(name); + if (opt_eager) { + classinfo *tc; + tc = class_new_intern(name); + + if (!class_load(tc)) + return false; + + /* link the class later, because we cannot link the class currently + loading */ + list_addfirst(&unlinkedclasses, tc); + + cpinfos[forward_classes->thisindex] = tc; + } else { + cpinfos[forward_classes->thisindex] = class_new(name); + } + + nfc = forward_classes; forward_classes = forward_classes->next; + FREE(nfc, forward_class); } while (forward_strings) { utf *text = class_getconstant(c, forward_strings->string_index, CONSTANT_Utf8); - /* resolve utf-string */ + /* resolve utf-string */ cptags[forward_strings->thisindex] = CONSTANT_String; cpinfos[forward_strings->thisindex] = text; + nfs = forward_strings; forward_strings = forward_strings->next; + FREE(nfs, forward_string); } while (forward_nameandtypes) { constant_nameandtype *cn = NEW(constant_nameandtype); -#ifdef STATISTICS - count_const_pool_len += sizeof(constant_nameandtype); +#if defined(STATISTICS) + if (opt_stat) + count_const_pool_len += sizeof(constant_nameandtype); #endif /* resolve simple name and descriptor */ @@ -1722,25 +2003,37 @@ static void class_loadcpool(classbuffer *cb, classinfo *c) if (opt_verify) { /* check name */ - if (!is_valid_name_utf(cn->name)) - panic("NameAndType with invalid name"); + if (!is_valid_name_utf(cn->name)) { + *exceptionptr = + new_exception_utfmessage(string_java_lang_InternalError, + cn->name); + return false; + } + /* disallow referencing among others */ - if (cn->name->text[0] == '<' && cn->name != utf_init) - panic("NameAndType with invalid special name"); + if (cn->name->text[0] == '<' && cn->name != utf_init) { + *exceptionptr = + new_exception_utfmessage(string_java_lang_InternalError, + cn->name); + return false; + } } cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType; cpinfos[forward_nameandtypes->thisindex] = cn; - + + nfn = forward_nameandtypes; forward_nameandtypes = forward_nameandtypes->next; + FREE(nfn, forward_nameandtype); } while (forward_fieldmethints) { constant_nameandtype *nat; constant_FMIref *fmi = NEW(constant_FMIref); -#ifdef STATISTICS - count_const_pool_len += sizeof(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, @@ -1763,14 +2056,18 @@ static void class_loadcpool(classbuffer *cb, classinfo *c) break; case CONSTANT_InterfaceMethodref: case CONSTANT_Methodref: /* check validity of descriptor */ - checkmethoddescriptor(fmi->descriptor); + checkmethoddescriptor(c, fmi->descriptor); break; } + nff = forward_fieldmethints; forward_fieldmethints = forward_fieldmethints->next; + FREE(nff, forward_fieldmethint); } - dump_release(dumpsize); + /* everything was ok */ + + return true; } @@ -1793,35 +2090,29 @@ classinfo *class_load(classinfo *c) { classbuffer *cb; classinfo *r; - s8 starttime; - s8 stoptime; #if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - compiler_lock(); - tables_lock(); -#else - intsDisable(); -#endif + /* enter a monitor on the class */ + + builtin_monitorenter((java_objectheader *) c); #endif /* maybe the class is already loaded */ if (c->loaded) { #if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - tables_unlock(); - compiler_unlock(); -#else - intsRestore(); -#endif + builtin_monitorexit((java_objectheader *) c); #endif return c; } /* measure time */ + + if (getcompilingtime) + compilingtime_stop(); + if (getloadingtime) - starttime = getcputime(); + loadingtime_start(); /* load classdata, throw exception on error */ @@ -1834,14 +2125,9 @@ classinfo *class_load(classinfo *c) *exceptionptr = new_exception_utfmessage(string_java_lang_NoClassDefFoundError, c->name); -/* log_text("Leaving class_load with NoClassDefFoundError");*/ + #if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - tables_unlock(); - compiler_unlock(); -#else - intsRestore(); -#endif + builtin_monitorexit((java_objectheader *) c); #endif return NULL; @@ -1851,25 +2137,28 @@ classinfo *class_load(classinfo *c) r = class_load_intern(cb); /* if return value is NULL, we had a problem and the class is not loaded */ - if (!r) + 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); - } + + if (getloadingtime) + loadingtime_stop(); + + if (getcompilingtime) + compilingtime_start(); #if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - tables_unlock(); - compiler_unlock(); -#else - intsRestore(); -#endif + /* leave the monitor */ + + builtin_monitorexit((java_objectheader *) c); #endif return r; @@ -1879,9 +2168,9 @@ classinfo *class_load(classinfo *c) classinfo *class_load_intern(classbuffer *cb) { classinfo *c; + classinfo *tc; u4 i; - u4 mi, ma; - s4 classdata_left; + u4 ma, mi; char msg[MAXLOGTEXT]; /* maybe we get an exception */ /* get the classbuffer's class */ @@ -1891,8 +2180,9 @@ classinfo *class_load_intern(classbuffer *cb) if (c->loaded) return c; -#ifdef STATISTICS - count_class_loads++; +#if defined(STATISTICS) + if (opt_stat) + count_class_loads++; #endif /* output for debugging purposes */ @@ -1902,13 +2192,12 @@ classinfo *class_load_intern(classbuffer *cb) /* class is somewhat loaded */ c->loaded = true; + if (!check_classbuffer_size(cb, 4 + 2 + 2)) + return NULL; + /* check signature */ if (suck_u4(cb) != MAGIC) { - utf_sprint_classname(msg, c->name); - sprintf(msg + strlen(msg), " (Bad magic number)"); - - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, msg); + *exceptionptr = new_classformaterror(c, "Bad magic number"); return NULL; } @@ -1917,19 +2206,19 @@ classinfo *class_load_intern(classbuffer *cb) mi = suck_u2(cb); ma = suck_u2(cb); - if (ma != MAJOR_VERSION && (ma != MAJOR_VERSION + 1 || mi != 0)) { - utf_sprint_classname(msg, c->name); - sprintf(msg + strlen(msg), " (Unsupported major.minor version %d.%d)", - ma, mi); - + if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) { *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - msg); + new_unsupportedclassversionerror(c, + "Unsupported major.minor version %d.%d", + ma, mi); return NULL; } - class_loadcpool(cb, c); + /* load the constant pool */ + if (!class_loadcpool(cb, c)) + return NULL; + /*JOWENN*/ c->erroneous_state = 0; c->initializing_thread = 0; @@ -1938,7 +2227,10 @@ classinfo *class_load_intern(classbuffer *cb) c->impldBy = NULL; /* ACC flags */ - c->flags = suck_u2(cb); + 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 */ @@ -1952,12 +2244,9 @@ classinfo *class_load_intern(classbuffer *cb) } if (c->flags & ACC_FINAL) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), - " (Illegal class modifiers: 0x%x)", c->flags); - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, msg); + new_classformaterror(c, + "Illegal class modifiers: 0x%X", c->flags); return NULL; } @@ -1968,23 +2257,24 @@ classinfo *class_load_intern(classbuffer *cb) } if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), - " (Illegal class modifiers: 0x%x)", c->flags); - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, msg); + 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) { + if (!(tc = class_getconstant(c, i, CONSTANT_Class))) + return NULL; + + if (tc != 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); + utf_sprint(msg + strlen(msg), tc->name); sprintf(msg + strlen(msg), ")"); *exceptionptr = @@ -1995,7 +2285,8 @@ classinfo *class_load_intern(classbuffer *cb) /* retrieve superclass */ if ((i = suck_u2(cb))) { - c->super = class_getconstant(c, i, CONSTANT_Class); + if (!(c->super = class_getconstant(c, i, CONSTANT_Class))) + return NULL; /* java.lang.Object may not have a super class. */ if (c->name == utf_java_lang_Object) { @@ -2021,26 +2312,31 @@ classinfo *class_load_intern(classbuffer *cb) /* This is only allowed for java.lang.Object. */ if (c->name != utf_java_lang_Object) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), " (Bad superclass index)"); - - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, msg); + *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); + if (!(c->interfaces[i] = class_getconstant(c, suck_u2(cb), CONSTANT_Class))) + return NULL; } /* 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); */ @@ -2050,6 +2346,9 @@ classinfo *class_load_intern(classbuffer *cb) } /* 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); */ @@ -2090,23 +2389,23 @@ classinfo *class_load_intern(classbuffer *cb) /* 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) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), " (Repetitive field name/signature)"); - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - msg); + new_classformaterror(c, + "Repetitive field name/signature"); return NULL; } @@ -2116,24 +2415,31 @@ classinfo *class_load_intern(classbuffer *cb) } /* Check methods */ - memset(hashtab, 0, sizeof(u2) * (hashlen + len)); + memset(hashtab, 0, sizeof(u2) * (hashlen + hashlen/5)); + for (i = 0; i < c->methodscount; ++i) { methodinfo *mi = c->methods + i; + /* It's ok if we lose bits here */ index = ((((size_t) mi->name) + ((size_t) mi->descriptor)) >> shift) % hashlen; + + /*{ JOWENN + int dbg; + for (dbg=0;dbgmethods[old].name == mi->name && c->methods[old].descriptor == mi->descriptor) { - utf_sprint(msg, c->name); - sprintf(msg + strlen(msg), " (Repetitive method name/signature)"); - *exceptionptr = - new_exception_message(string_java_lang_ClassFormatError, - msg); + new_classformaterror(c, + "Repetitive method name/signature"); return NULL; } @@ -2145,7 +2451,7 @@ classinfo *class_load_intern(classbuffer *cb) MFREE(hashtab, u2, (hashlen + len)); } -#ifdef STATISTICS +#if defined(STATISTICS) if (opt_stat) { count_class_infos += sizeof(classinfo*) * c->interfacescount; count_class_infos += sizeof(fieldinfo) * c->fieldscount; @@ -2153,20 +2459,27 @@ classinfo *class_load_intern(classbuffer *cb) } #endif - /* load variable-length attribute structures */ - attribute_load(cb, c, suck_u2(cb)); + /* load attribute structures */ + if (!check_classbuffer_size(cb, 2)) + return NULL; + + if (!attribute_load(cb, c, suck_u2(cb))) + return NULL; #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"); + /* 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); + + if (classdata_left > 0) { + *exceptionptr = + new_classformaterror(c, "Extra bytes at the end of class file"); + return NULL; + } } #endif @@ -2190,13 +2503,8 @@ 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); - } - + /* check for ACC_INTERFACE bit already done in class_link_intern */ + h = c->index; for (i = 0; i < c->interfacescount; i++) { s4 h2 = class_highestinterface(c->interfaces[i]); @@ -2209,33 +2517,33 @@ static s4 class_highestinterface(classinfo *c) /* class_addinterface ********************************************************** - Is needed by class_link for adding a VTBL to a class. All interfaces - implemented by ic are added as well. + Is needed by class_link for adding a VTBL to a class. All interfaces + implemented by ic are added as well. *******************************************************************************/ static void class_addinterface(classinfo *c, classinfo *ic) { s4 j, m; - s4 i = ic->index; - vftbl *vftbl = c->vftbl; + s4 i = ic->index; + vftbl_t *v = c->vftbl; - if (i >= vftbl->interfacetablelength) + if (i >= v->interfacetablelength) panic ("Inernal error: interfacetable overflow"); - if (vftbl->interfacetable[-i]) + if (v->interfacetable[-i]) return; 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; + v->interfacevftbllength[i] = 1; + v->interfacetable[-i] = MNEW(methodptr, 1); + v->interfacetable[-i][0] = NULL; } else { - vftbl->interfacevftbllength[i] = ic->methodscount; - vftbl->interfacetable[-i] = MNEW(methodptr, ic->methodscount); + v->interfacevftbllength[i] = ic->methodscount; + v->interfacetable[-i] = MNEW(methodptr, ic->methodscount); -#ifdef STATISTICS +#if defined(STATISTICS) if (opt_stat) count_vftbl_len += sizeof(methodptr) * (ic->methodscount + (ic->methodscount == 0)); @@ -2247,8 +2555,7 @@ static void class_addinterface(classinfo *c, classinfo *ic) 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]; + v->interfacetable[-i][j] = v->table[mi->vftblindex]; goto foundmethod; } } @@ -2283,17 +2590,34 @@ void class_new_array(classinfo *c) /* Check the component type */ switch (c->name->text[1]) { - case '[': - /* c is an array of arrays. We have to create the component class. */ - comp = class_new(utf_new_int(c->name->text + 1, namelen - 1)); - break; + 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); - case 'L': - /* c is an array of objects. */ - if (namelen < 4 || c->name->text[namelen - 1] != ';') - panic("Invalid array class name"); - comp = class_new(utf_new_int(c->name->text + 2, namelen - 3)); - break; + } else { + comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1)); + } + break; + + case 'L': + /* c is an array of objects. */ + if (namelen < 4 || c->name->text[namelen - 1] != ';') + panic("Invalid array class name"); + + if (opt_eager) { + comp = class_new_intern(utf_new_intern(c->name->text + 2, + namelen - 3)); + class_load(comp); + list_addfirst(&unlinkedclasses, comp); + + } else { + comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3)); + } + break; } /* Setup the array class */ @@ -2302,8 +2626,24 @@ void class_new_array(classinfo *c) c->interfacescount = 2; c->interfaces = MNEW(classinfo*, 2); - c->interfaces[0] = class_new(utf_new_char("java/lang/Cloneable")); - c->interfaces[1] = class_new(utf_new_char("java/io/Serializable")); + + if (opt_eager) { + classinfo *tc; + + 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; + + } else { + c->interfaces[0] = class_new(utf_new_char("java/lang/Cloneable")); + c->interfaces[1] = class_new(utf_new_char("java/io/Serializable")); + } c->methodscount = 1; c->methods = MNEW(methodinfo, c->methodscount); @@ -2339,22 +2679,20 @@ static arraydescriptor *class_link_array(classinfo *c) classinfo *comp = NULL; s4 namelen = c->name->blength; arraydescriptor *desc; - vftbl *compvftbl; + vftbl_t *compvftbl; /* Check the component type */ switch (c->name->text[1]) { case '[': /* c is an array of arrays. */ -/* comp = class_get(utf_new_int(c->name->text + 1, namelen - 1)); */ - comp = class_new(utf_new_int(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; case 'L': /* c is an array of objects. */ -/* comp = class_get(utf_new_int(c->name->text + 2, namelen - 3)); */ - comp = class_new(utf_new_int(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; @@ -2363,8 +2701,11 @@ static arraydescriptor *class_link_array(classinfo *c) /* 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 (!class_load(comp)) + return NULL; + + if (!class_link(comp)) + return NULL; } /* Allocate the arraydescriptor */ @@ -2472,35 +2813,29 @@ static classinfo *class_link_intern(classinfo *c); classinfo *class_link(classinfo *c) { classinfo *r; - s8 starttime; - s8 stoptime; #if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - compiler_lock(); - tables_lock(); -#else - intsDisable(); -#endif + /* enter a monitor on the class */ + + builtin_monitorenter((java_objectheader *) c); #endif /* maybe the class is already linked */ if (c->linked) { #if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - tables_unlock(); - compiler_unlock(); -#else - intsRestore(); -#endif + builtin_monitorexit((java_objectheader *) c); #endif return c; } /* measure time */ + + if (getcompilingtime) + compilingtime_stop(); + if (getloadingtime) - starttime = getcputime(); + loadingtime_start(); /* call the internal function */ r = class_link_intern(c); @@ -2510,20 +2845,20 @@ classinfo *class_link(classinfo *c) c->linked = false; /* measure time */ - if (getloadingtime) { - stoptime = getcputime(); - loadingtime += (stoptime - starttime); - } + + if (getloadingtime) + loadingtime_stop(); + + if (getcompilingtime) + compilingtime_start(); #if defined(USE_THREADS) -#if defined(NATIVE_THREADS) - tables_unlock(); - compiler_unlock(); -#else - intsRestore(); -#endif + /* leave the monitor */ + + builtin_monitorexit((java_objectheader *) c); #endif - if (c->linked) return c; else return 0; + + return r; } @@ -2532,52 +2867,61 @@ 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 *v; /* vftbl of current class */ + classinfo *super; /* super class */ + classinfo *tc; /* temporary class variable */ + vftbl_t *v; /* vftbl of current class */ s4 i; /* interface/method/field counter */ - arraydescriptor *arraydesc = NULL; /* descriptor for array classes */ + arraydescriptor *arraydesc; /* descriptor for array classes */ /* maybe the class is already linked */ if (c->linked) return c; + /* maybe the class is not loaded */ + if (!c->loaded) + if (!class_load(c)) + return NULL; + if (linkverbose) log_message_class("Linking class: ", c); /* ok, this class is somewhat linked */ c->linked = true; + arraydesc = NULL; + /* check interfaces */ for (i = 0; i < c->interfacescount; i++) { - ic = c->interfaces[i]; + tc = c->interfaces[i]; /* detect circularity */ - if (ic == c) { + if (tc == c) { *exceptionptr = new_exception_utfmessage(string_java_lang_ClassCircularityError, c->name); - return NULL; } - if (!ic->loaded) - class_load(ic); - - if (!ic->linked) - class_link(ic); + if (!tc->loaded) + if (!class_load(tc)) + return NULL; - 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 (!(tc->flags & ACC_INTERFACE)) { + *exceptionptr = + new_exception_message(string_java_lang_IncompatibleClassChangeError, + "Implementing class"); + return NULL; } + + if (!tc->linked) + if (!class_link(tc)) + return NULL; } - /* check super class */ + /* check super class */ + + super = c->super; if (super == NULL) { /* class java.lang.Object */ c->index = 0; @@ -2595,31 +2939,35 @@ static classinfo *class_link_intern(classinfo *c) *exceptionptr = new_exception_utfmessage(string_java_lang_ClassCircularityError, c->name); - return NULL; } if (!super->loaded) - class_load(super); - - if (!super->linked) - class_link(super); + if (!class_load(super)) + return NULL; - if (super->flags & ACC_INTERFACE) + if (super->flags & ACC_INTERFACE) { + /* java.lang.IncompatibleClassChangeError: class a has interface java.lang.Cloneable as super class */ panic("Interface specified as super class"); - - /* 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"); - } } /* Don't allow extending final classes */ - if (super->flags & ACC_FINAL) - panic("Trying to extend final class"); + if (super->flags & ACC_FINAL) { + *exceptionptr = + new_exception_message(string_java_lang_VerifyError, + "Cannot inherit from final class"); + return NULL; + } + if (!super->linked) + if (!class_link(super)) + return NULL; + + /* handle array classes */ + if (c->name->text[0] == '[') + if (!(arraydesc = class_link_array(c))) + return NULL; + if (c->flags & ACC_INTERFACE) c->index = interfaceindex++; else @@ -2638,26 +2986,26 @@ static classinfo *class_link_intern(classinfo *c) methodinfo *m = &(c->methods[i]); if (!(m->flags & ACC_STATIC)) { /* is instance method */ - classinfo *sc = super; - while (sc) { + tc = super; + + while (tc) { s4 j; - for (j = 0; j < sc->methodscount; j++) { - if (method_canoverwrite(m, &(sc->methods[j]))) { - if ((sc->methods[j].flags & ACC_PRIVATE) != 0) + for (j = 0; j < tc->methodscount; j++) { + if (method_canoverwrite(m, &(tc->methods[j]))) { + if (tc->methods[j].flags & ACC_PRIVATE) 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"); + if (tc->methods[j].flags & ACC_FINAL) { + /* class a overrides final method . */ + *exceptionptr = + new_exception(string_java_lang_VerifyError); + return NULL; } - m->vftblindex = sc->methods[j].vftblindex; + m->vftblindex = tc->methods[j].vftblindex; goto foundvftblindex; } } - sc = sc->super; + tc = tc->super; } notfoundvftblindex: m->vftblindex = (vftbllength++); @@ -2666,38 +3014,37 @@ static classinfo *class_link_intern(classinfo *c) } } -#ifdef STATISTICS +#if defined(STATISTICS) if (opt_stat) count_vftbl_len += - sizeof(vftbl) + (sizeof(methodptr) * (vftbllength - 1)); + sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1)); #endif /* compute interfacetable length */ interfacetablelength = 0; - c2 = c; - while (c2) { - for (i = 0; i < c2->interfacescount; i++) { - s4 h = class_highestinterface(c2->interfaces[i]) + 1; + tc = c; + while (tc) { + for (i = 0; i < tc->interfacescount; i++) { + s4 h = class_highestinterface(tc->interfaces[i]) + 1; if (h > interfacetablelength) interfacetablelength = h; } - c2 = c2->super; + tc = tc->super; } /* allocate virtual function table */ - v = (vftbl*) mem_alloc(sizeof(vftbl) + sizeof(methodptr) * + v = (vftbl_t*) mem_alloc(sizeof(vftbl_t) + sizeof(methodptr) * (vftbllength - 1) + sizeof(methodptr*) * (interfacetablelength - (interfacetablelength > 0))); - v = (vftbl*) (((methodptr*) v) + (interfacetablelength - 1) * + 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; + v->arraydesc = arraydesc; /* store interface index in vftbl */ if (c->flags & ACC_INTERFACE) @@ -2735,7 +3082,7 @@ static classinfo *class_link_intern(classinfo *c) v->interfacevftbllength = MNEW(s4, interfacetablelength); -#ifdef STATISTICS +#if defined(STATISTICS) if (opt_stat) count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength; #endif @@ -2747,29 +3094,20 @@ static classinfo *class_link_intern(classinfo *c) /* add interfaces */ - for (c2 = c; c2 != NULL; c2 = c2->super) - for (i = 0; i < c2->interfacescount; i++) { - class_addinterface(c, c2->interfaces[i]); - } + for (tc = c; tc != NULL; tc = tc->super) + for (i = 0; i < tc->interfacescount; i++) + class_addinterface(c, tc->interfaces[i]); /* add finalizer method (not for java.lang.Object) */ - if (super != NULL) { + if (super) { methodinfo *fi; - static utf *finame = NULL; - static utf *fidesc = NULL; - if (finame == NULL) - finame = utf_finalize; - if (fidesc == NULL) - fidesc = utf_fidesc; + fi = class_findmethod(c, utf_finalize, utf_void__void); - fi = class_findmethod(c, finame, fidesc); - if (fi != NULL) { - if (!(fi->flags & ACC_STATIC)) { + if (fi) + if (!(fi->flags & ACC_STATIC)) c->finalizer = fi; - } - } } /* final tasks */ @@ -2797,38 +3135,43 @@ static void class_freecpool(classinfo *c) u4 tag; voidptr info; - for (idx=0; idx < c->cpcount; idx++) { - tag = c->cptags[idx]; - info = c->cpinfos[idx]; + 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); - break; + 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); + break; + } } } } - MFREE(c->cptags, u1, c->cpcount); - MFREE(c->cpinfos, voidptr, c->cpcount); + if (c->cptags) + MFREE(c->cptags, u1, c->cpcount); + + if (c->cpinfos) + MFREE(c->cpinfos, voidptr, c->cpcount); } @@ -2838,21 +3181,27 @@ static void class_freecpool(classinfo *c) *******************************************************************************/ -static void class_free(classinfo *c) +void class_free(classinfo *c) { s4 i; - vftbl *v; + vftbl_t *v; class_freecpool(c); - MFREE(c->interfaces, classinfo*, c->interfacescount); + if (c->interfaces) + MFREE(c->interfaces, classinfo*, c->interfacescount); - for (i = 0; i < c->fieldscount; i++) - field_free(&(c->fields[i])); + if (c->fields) { + for (i = 0; i < c->fieldscount; i++) + field_free(&(c->fields[i])); +/* MFREE(c->fields, fieldinfo, c->fieldscount); */ + } - for (i = 0; i < c->methodscount; i++) - method_free(&(c->methods[i])); - MFREE(c->methods, methodinfo, c->methodscount); + if (c->methods) { + for (i = 0; i < c->methodscount; i++) + method_free(&(c->methods[i])); +/* MFREE(c->methods, methodinfo, c->methodscount); */ + } if ((v = c->vftbl) != NULL) { if (v->arraydesc) @@ -2863,15 +3212,15 @@ static void class_free(classinfo *c) } MFREE(v->interfacevftbllength, s4, v->interfacetablelength); - i = sizeof(vftbl) + sizeof(methodptr) * (v->vftbllength - 1) + + i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) + sizeof(methodptr*) * (v->interfacetablelength - (v->interfacetablelength > 0)); - v = (vftbl*) (((methodptr*) v) - (v->interfacetablelength - 1) * + v = (vftbl_t*) (((methodptr*) v) - (v->interfacetablelength - 1) * (v->interfacetablelength > 1)); mem_free(v, i); } - if (c->innerclasscount) + if (c->innerclass) MFREE(c->innerclass, innerclassinfo, c->innerclasscount); /* if (c->classvftbl) @@ -3340,27 +3689,78 @@ bool class_issubclass(classinfo *sub, classinfo *super) *******************************************************************************/ +static classinfo *class_init_intern(classinfo *c); + classinfo *class_init(classinfo *c) { - methodinfo *m; - s4 i; -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) - int b; -#endif + classinfo *r; if (!makeinitializations) return c; - if (c->initialized) +#if defined(USE_THREADS) + /* enter a monitor on the class */ + + builtin_monitorenter((java_objectheader *) c); +#endif + + /* maybe the class is already initalized or the current thread, which can + pass the monitor, is currently initalizing this class */ + + /* JOWENN: In future we need an additinal flag: initializationfailed, + since further access to the class should cause a NoClassDefFound, + if the static initializer failed once + */ + + if (c->initialized || c->initializing) { +#if defined(USE_THREADS) + builtin_monitorexit((java_objectheader *) c); +#endif + return c; + } + + /* this initalizing run begins NOW */ + c->initializing = true; + + /* call the internal function */ + r = class_init_intern(c); + + /* if return value is not NULL everything was ok and the class is + initialized */ + if (r) + c->initialized = true; + + /* this initalizing run is done */ + c->initializing = false; + +#if defined(USE_THREADS) + /* leave the monitor */ + + builtin_monitorexit((java_objectheader *) c); +#endif + + return r; +} + + +/* this function MUST NOT be called directly, because of thread + race conditions */ - /* class is somewhat initialized */ - c->initialized = true; +static classinfo *class_init_intern(classinfo *c) +{ + methodinfo *m; + s4 i; +#if defined(USE_THREADS) && !defined(NATIVE_THREADS) + int b; +#endif + /* maybe the class is not already loaded */ if (!c->loaded) if (!class_load(c)) return NULL; + /* maybe the class is not already linked */ if (!c->linked) if (!class_link(c)) return NULL; @@ -3371,15 +3771,8 @@ classinfo *class_init(classinfo *c) #endif /* initialize super class */ - if (c->super) { - if (!c->super->loaded) - if (!class_load(c->super)) - return NULL; - - if (!c->super->linked) - if (!class_link(c->super)) - return NULL; + if (c->super) { if (!c->super->initialized) { if (initverbose) { char logtext[MAXLOGTEXT]; @@ -3396,15 +3789,8 @@ classinfo *class_init(classinfo *c) } /* initialize interface classes */ - for (i = 0; i < c->interfacescount; i++) { - if (!c->interfaces[i]->loaded) - if (!class_load(c->interfaces[i])) - return NULL; - - if (!c->interfaces[i]->linked) - if (!class_link(c->interfaces[i])) - return NULL; + for (i = 0; i < c->interfacescount; i++) { if (!c->interfaces[i]->initialized) { if (initverbose) { char logtext[MAXLOGTEXT]; @@ -3420,7 +3806,7 @@ classinfo *class_init(classinfo *c) } } - m = class_findmethod(c, utf_clinit, utf_fidesc); + m = class_findmethod(c, utf_clinit, utf_void__void); if (!m) { if (initverbose) { @@ -3434,8 +3820,9 @@ classinfo *class_init(classinfo *c) return c; } - if (!(m->flags & ACC_STATIC)) - panic("Class initializer is not static!"); + /* Sun's and IBM's JVM don't care about the static flag */ +/* if (!(m->flags & ACC_STATIC)) { */ +/* panic("Class initializer is not static!"); */ if (initverbose) log_message_class("Starting static class initializer for class: ", c); @@ -3453,31 +3840,34 @@ classinfo *class_init(classinfo *c) blockInts = b; #endif - /* we have an exception */ + /* we have an exception or error */ if (*exceptionptr) { - java_objectheader *xptr; - java_objectheader *cause; - /* class is NOT initialized */ c->initialized = false; - /* get the cause */ - cause = *exceptionptr; + /* is this an exception, than wrap it */ + if (builtin_instanceof(*exceptionptr, class_java_lang_Exception)) { + java_objectheader *xptr; + java_objectheader *cause; - /* clear exception, because we are calling jit code again */ - *exceptionptr = NULL; + /* get the cause */ + cause = *exceptionptr; - /* wrap the exception */ - xptr = - new_exception_throwable(string_java_lang_ExceptionInInitializerError, - (java_lang_Throwable *) cause); + /* clear exception, because we are calling jit code again */ + *exceptionptr = NULL; - if (*exceptionptr) { - panic("problem"); - } + /* wrap the exception */ + xptr = + new_exception_throwable(string_java_lang_ExceptionInInitializerError, + (java_lang_Throwable *) cause); + + /* XXX should we exit here? */ + if (*exceptionptr) + throw_exception(); - /* set new exception */ - *exceptionptr = xptr; + /* set new exception */ + *exceptionptr = xptr; + } return NULL; } @@ -3748,38 +4138,43 @@ void class_showmethods (classinfo *c) *******************************************************************************/ -void create_primitive_classes() +static bool create_primitive_classes() { - int i; + s4 i; for (i = 0; i < PRIMITIVETYPE_COUNT; i++) { /* create primitive class */ - classinfo *c = class_new_int(utf_new_char(primitivetype_table[i].name)); + classinfo *c = + class_new_intern(utf_new_char(primitivetype_table[i].name)); c->classUsed = NOTUSED; /* not used initially CO-RT */ c->impldBy = NULL; /* prevent loader from loading primitive class */ c->loaded = true; - class_link(c); + if (!class_link(c)) + return false; primitivetype_table[i].class_primitive = c; /* create class for wrapping the primitive type */ - c = class_new_int(utf_new_char(primitivetype_table[i].wrapname)); + 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_int(utf_new_char(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); + if (!class_link(c)) + return false; primitivetype_table[i].arrayvftbl = c->vftbl; } } + + return true; } @@ -3848,7 +4243,7 @@ classinfo *class_primitive_from_sig(char sig) * CLASSLOAD_PANIC....abort execution with an error message CLASSLOAD_NOPANIC..return NULL on error -********************************************************************************/ +*******************************************************************************/ classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr, char **next, int mode) @@ -3889,8 +4284,19 @@ classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr, case '[': if (mode & CLASSLOAD_SKIP) return class_java_lang_Object; name = utf_new(start, utf_ptr - start); - return (mode & CLASSLOAD_LOAD) - ? class_load(class_new(name)) : class_new(name); /* XXX handle errors */ + 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 */ + } } } @@ -3962,7 +4368,6 @@ static void create_pseudo_classes() { /* pseudo class for Arraystubs (extends java.lang.Object) */ - pseudo_class_Arraystub = class_new_int(utf_new_char("$ARRAYSTUB$")); pseudo_class_Arraystub->loaded = true; pseudo_class_Arraystub->super = class_java_lang_Object; pseudo_class_Arraystub->interfacescount = 2; @@ -3976,18 +4381,15 @@ static void create_pseudo_classes() /* pseudo class representing the null type */ - pseudo_class_Null = class_new_int(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_int(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); */ } @@ -3998,55 +4400,41 @@ static void create_pseudo_classes() *******************************************************************************/ -void loader_init(u1 *stackbottom) +bool loader_init(u1 *stackbottom) { + classpath_info *cpi; + + /* reset interface index */ + 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_int(utf_java_lang_Object); - class_load(class_java_lang_Object); - class_link(class_java_lang_Object); - - class_java_lang_String = - class_new_int(utf_new_char("java/lang/String")); - class_load(class_java_lang_String); - class_link(class_java_lang_String); - - class_java_lang_Cloneable = - class_new_int(utf_new_char("java/lang/Cloneable")); - class_load(class_java_lang_Cloneable); - class_link(class_java_lang_Cloneable); - - class_java_io_Serializable = - class_new_int(utf_new_char("java/io/Serializable")); - class_load(class_java_io_Serializable); - class_link(class_java_io_Serializable); +#if defined(USE_THREADS) && defined(NATIVE_THREADS) + /* Initialize the monitor pointer for zip/jar file locking. */ + + for (cpi = classpath_entries; cpi != NULL; cpi = cpi->next) { + if (cpi->type == CLASSPATH_ARCHIVE) + initObjectLock(&cpi->header); + } +#endif + + /* Create some important classes. These classes have to be created now */ + /* because the classinfo pointers are used in the loading code. */ + + if (!class_load(class_java_lang_Object) || + !class_link(class_java_lang_Object)) + return false; + + if (!class_load(class_java_lang_String) || + !class_link(class_java_lang_String)) + return false; + + if (!class_load(class_java_lang_Cloneable) || + !class_link(class_java_lang_Cloneable)) + return false; + + if (!class_load(class_java_io_Serializable) || + !class_link(class_java_io_Serializable)) + return false; /* create classes representing primitive types */ create_primitive_classes(); @@ -4061,29 +4449,27 @@ void loader_init(u1 *stackbottom) if (stackbottom != 0) initLocks(); #endif -} + return true; +} -static void loader_compute_class_values(classinfo *c) -{ - classinfo *subs; - c->vftbl->baseval = ++classvalue; +/* loader_compute_subclasses *************************************************** - subs = c->sub; - while (subs != NULL) { - loader_compute_class_values(subs); - subs = subs->nextsub; - } + XXX - c->vftbl->diffval = classvalue - c->vftbl->baseval; -} +*******************************************************************************/ +static void loader_compute_class_values(classinfo *c); void loader_compute_subclasses(classinfo *c) { -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) +#if defined(USE_THREADS) +#if defined(NATIVE_THREADS) + compiler_lock(); +#else intsDisable(); +#endif #endif if (!(c->flags & ACC_INTERFACE)) { @@ -4099,6 +4485,7 @@ void loader_compute_subclasses(classinfo *c) classvalue = 0; /* this is the java.lang.Object special case */ + if (!class_java_lang_Object) { loader_compute_class_values(c); @@ -4106,9 +4493,35 @@ void loader_compute_subclasses(classinfo *c) loader_compute_class_values(class_java_lang_Object); } -#if defined(USE_THREADS) && !defined(NATIVE_THREADS) +#if defined(USE_THREADS) +#if defined(NATIVE_THREADS) + compiler_unlock(); +#else intsRestore(); #endif +#endif +} + + +/* loader_compute_class_values ************************************************* + + XXX + +*******************************************************************************/ + +static void loader_compute_class_values(classinfo *c) +{ + classinfo *subs; + + c->vftbl->baseval = ++classvalue; + + subs = c->sub; + while (subs) { + loader_compute_class_values(subs); + subs = subs->nextsub; + } + + c->vftbl->diffval = classvalue - c->vftbl->baseval; } @@ -4120,20 +4533,17 @@ void loader_compute_subclasses(classinfo *c) void loader_close() { -/* classinfo *c; */ + classinfo *c; + s4 slot; -/* while ((c = list_first(&unloadedclasses))) { */ -/* list_remove(&unloadedclasses, c); */ -/* class_free(c); */ -/* } */ -/* while ((c = list_first(&unlinkedclasses))) { */ -/* list_remove(&unlinkedclasses, c); */ -/* class_free(c); */ -/* } */ -/* while ((c = list_first(&linkedclasses))) { */ -/* list_remove(&linkedclasses, c); */ -/* class_free(c); */ -/* } */ + for (slot = 0; slot < class_hash.size; slot++) { + c = class_hash.ptr[slot]; + + while (c) { + class_free(c); + c = c->hashlink; + } + } }