X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=loader.c;h=7ab8528484318fe55f2168857a50fa575cc159f9;hb=b3a250324c396e1bd203347f8f5a2137855a6b0c;hp=bc2919c347be28c60a045b96a89795eb64669d97;hpb=f238282995c07e1dbe4d88b043fbdaff6398be5c;p=cacao.git diff --git a/loader.c b/loader.c index bc2919c34..7ab852848 100644 --- a/loader.c +++ b/loader.c @@ -1,96 +1,128 @@ +/* loader.c - class loader functions -/* loader.c ******************************************************************** + 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) 1999 A. Krall, R. Grafl, R. Obermaiser, M. Probst + This file is part of CACAO. - See file COPYRIGHT for information on usage and disclaimer of warranties + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. - Contains the functions of the class loader. + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. - Author: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at - Changes: Andreas Krall EMAIL: cacao@complang.tuwien.ac.at - Roman Obermaiser EMAIL: cacao@complang.tuwien.ac.at - Mark Probst EMAIL: cacao@complang.tuwien.ac.at + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. - Last Change: 1999/11/08 + Contact: cacao@complang.tuwien.ac.at -*******************************************************************************/ + Authors: Reinhard Grafl + Changes: Andreas Krall + Roman Obermaiser + Mark Probst + Edwin Steiner + Christian Thalinger -#include + $Id: loader.c 1237 2004-06-30 19:54:59Z twisti $ + +*/ + +#include +#include +#include +#include #include "global.h" #include "loader.h" +#include "options.h" #include "native.h" #include "tables.h" #include "builtin.h" -#include "jit.h" -#ifdef OLD_COMPILER -#include "compiler.h" -#endif +#include "jit/jit.h" #include "asmpart.h" - -#ifdef USE_BOEHM +#include "options.h" +#include "statistics.h" #include "toolbox/memory.h" -#endif - +#include "toolbox/logging.h" #include "threads/thread.h" -#include - -/* global variables ***********************************************************/ - -extern bool newcompiler; /* true if new compiler is used */ - -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; +#include "threads/locks.h" +#include "nat/java_lang_Throwable.h" -bool loadverbose = false; /* switches for debug messages */ -bool linkverbose = false; -bool initverbose = false; - -bool makeinitializations = true; +#ifdef USE_ZLIB +#include "unzip.h" +#endif -bool getloadingtime = false; /* to measure the runtime */ -long int loadingtime = 0; +#undef JOWENN_DEBUG +#undef JOWENN_DEBUG1 +#undef JOWENN_DEBUG2 -static s4 interfaceindex; /* sequential numbering of interfaces */ +/* global variables ***********************************************************/ -list unloadedclasses; /* list of all referenced but not loaded classes */ -list unlinkedclasses; /* list of all loaded but not linked classes */ -list linkedclasses; /* list of all completely linked classes */ +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_finalize; /* finalize */ -static utf *utf_fidesc; /* ()V */ -static utf *utf_clinit; /* */ -static utf *utf_initsystemclass; /* initializeSystemClass */ -static utf *utf_systemclass; /* java/lang/System */ +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_ClassCastException; -classinfo *class_java_lang_NullPointerException; -classinfo *class_java_lang_ArrayIndexOutOfBoundsException; -classinfo *class_java_lang_NegativeArraySizeException; -classinfo *class_java_lang_OutOfMemoryError; -classinfo *class_java_lang_ArithmeticException; -classinfo *class_java_lang_ArrayStoreException; -classinfo *class_java_lang_ThreadDeath; -classinfo *class_array = NULL; +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; + + +/******************************************************************** + list of classpath entries (either filesystem directories or + ZIP/JAR archives +********************************************************************/ +static classpath_info *classpath_entries=0; /****************************************************************************** @@ -100,29 +132,26 @@ classinfo *class_array = NULL; the one character type signature and the name of the primitive class ******************************************************************************/ - + +/* CAUTION: Don't change the order of the types. This table is indexed + * by the ARRAYTYPE_ constants (expcept ARRAYTYPE_OBJECT). + */ primitivetypeinfo primitivetype_table[PRIMITIVETYPE_COUNT] = { - { NULL, NULL, "java/lang/Double", 'D', "double" }, - { NULL, NULL, "java/lang/Float", 'F', "float" }, - { NULL, NULL, "java/lang/Character", 'C', "char" }, - { NULL, NULL, "java/lang/Integer", 'I', "int" }, - { NULL, NULL, "java/lang/Long", 'J', "long" }, - { NULL, NULL, "java/lang/Byte", 'B', "byte" }, - { NULL, NULL, "java/lang/Short", 'S', "short" }, - { NULL, NULL, "java/lang/Boolean", 'Z', "boolean" }, - { NULL, NULL, "java/lang/Void", 'V', "void" }}; + { NULL, NULL, "java/lang/Integer", 'I', "int" , "[I", NULL, NULL }, + { NULL, NULL, "java/lang/Long", 'J', "long" , "[J", NULL, NULL }, + { NULL, NULL, "java/lang/Float", 'F', "float" , "[F", NULL, NULL }, + { NULL, NULL, "java/lang/Double", 'D', "double" , "[D", NULL, NULL }, + { NULL, NULL, "java/lang/Byte", 'B', "byte" , "[B", NULL, NULL }, + { NULL, NULL, "java/lang/Character", 'C', "char" , "[C", NULL, NULL }, + { NULL, NULL, "java/lang/Short", 'S', "short" , "[S", NULL, NULL }, + { NULL, NULL, "java/lang/Boolean", 'Z', "boolean" , "[Z", NULL, NULL }, + { NULL, NULL, "java/lang/Void", 'V', "void" , NULL, NULL, NULL } +}; /* instances of important system classes **************************************/ -java_objectheader *proto_java_lang_ClassCastException; java_objectheader *proto_java_lang_NullPointerException; -java_objectheader *proto_java_lang_ArrayIndexOutOfBoundsException; -java_objectheader *proto_java_lang_NegativeArraySizeException; -java_objectheader *proto_java_lang_OutOfMemoryError; -java_objectheader *proto_java_lang_ArithmeticException; -java_objectheader *proto_java_lang_ArrayStoreException; -java_objectheader *proto_java_lang_ThreadDeath; /************* functions for reading classdata ********************************* @@ -133,105 +162,302 @@ java_objectheader *proto_java_lang_ThreadDeath; *******************************************************************************/ static char *classpath = ""; /* searchpath for classfiles */ -static u1 *classbuffer = NULL; /* pointer to buffer with classfile-data */ -static u1 *classbuf_pos; /* current position in classfile buffer */ -static int classbuffer_size; /* size of classfile-data */ -/* transfer block of classfile data into a buffer */ -#define suck_nbytes(buffer,len) memcpy(buffer,classbuf_pos+1,len); \ - classbuf_pos+=len; +static java_objectheader *new_classformaterror(classinfo *c, char *message, ...) +{ + char cfmessage[MAXLOGTEXT]; + va_list ap; + + utf_sprint_classname(cfmessage, c->name); + sprintf(cfmessage + strlen(cfmessage), " ("); + + va_start(ap, message); + vsprintf(cfmessage + strlen(cfmessage), message, ap); + va_end(ap); -/* skip block of classfile data */ + sprintf(cfmessage + strlen(cfmessage), ")"); -#define skip_nbytes(len) classbuf_pos+=len; + return new_exception_message(string_java_lang_ClassFormatError, cfmessage); +} + + +/* 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 ***************************************************************** -inline u1 suck_u1() + transfer block of classfile data into a buffer + +*******************************************************************************/ + +inline void suck_nbytes(u1 *buffer, classbuffer *cb, s4 len) +{ + memcpy(buffer, cb->pos + 1, len); + cb->pos += len; +} + + +/* skip_nbytes **************************************************************** + + skip block of classfile data + +*******************************************************************************/ + +inline void skip_nbytes(classbuffer *cb, s4 len) { - return *++classbuf_pos; + cb->pos += len; } -inline u2 suck_u2() + + +inline u1 suck_u1(classbuffer *cb) { - u1 a=suck_u1(), b=suck_u1(); - return ((u2)a<<8)+(u2)b; + return *++(cb->pos); } -inline u4 suck_u4() + + +inline u2 suck_u2(classbuffer *cb) { - u1 a=suck_u1(), b=suck_u1(), c=suck_u1(), d=suck_u1(); - return ((u4)a<<24)+((u4)b<<16)+((u4)c<<8)+(u4)d; + u1 a = suck_u1(cb); + u1 b = suck_u1(cb); + return ((u2) a << 8) + (u2) b; } -#define suck_s8() (s8) suck_u8() -#define suck_s2() (s2) suck_u2() -#define suck_s4() (s4) suck_u4() -#define suck_s1() (s1) suck_u1() -/* get u8 from classfile data */ +inline u4 suck_u4(classbuffer *cb) +{ + u1 a = suck_u1(cb); + u1 b = suck_u1(cb); + u1 c = suck_u1(cb); + u1 d = suck_u1(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)) + -static u8 suck_u8 () +/* get u8 from classfile data */ +static u8 suck_u8(classbuffer *cb) { #if U8_AVAILABLE - u8 lo,hi; - hi = suck_u4(); - lo = suck_u4(); - return (hi<<32) + lo; + u8 lo, hi; + hi = suck_u4(cb); + lo = suck_u4(cb); + return (hi << 32) + lo; #else u8 v; - v.high = suck_u4(); - v.low = suck_u4(); + v.high = suck_u4(cb); + v.low = suck_u4(cb); return v; #endif } -/* get float from classfile data */ -static float suck_float () +/* get float from classfile data */ +static float suck_float(classbuffer *cb) { float f; #if !WORDS_BIGENDIAN - u1 buffer[4]; - u2 i; - for (i=0; i<4; i++) buffer[3-i] = suck_u1 (); - memcpy ( (u1*) (&f), buffer, 4); -#else - suck_nbytes ( (u1*) (&f), 4 ); + u1 buffer[4]; + u2 i; + + for (i = 0; i < 4; i++) + buffer[3 - i] = suck_u1(cb); + + memcpy((u1*) (&f), buffer, 4); +#else + suck_nbytes((u1*) (&f), cb, 4); #endif - PANICIF (sizeof(float) != 4, "Incompatible float-format"); + if (sizeof(float) != 4) { + *exceptionptr = new_exception_message(string_java_lang_InternalError, + "Incompatible float-format"); + + /* XXX should we exit in such a case? */ + throw_exception_exit(); + } return f; } + /* get double from classfile data */ -static double suck_double () +static double suck_double(classbuffer *cb) { double d; #if !WORDS_BIGENDIAN - u1 buffer[8]; - u2 i; - for (i=0; i<8; i++) buffer[7-i] = suck_u1 (); - memcpy ( (u1*) (&d), buffer, 8); + u1 buffer[8]; + u2 i; + + for (i = 0; i < 8; i++) + buffer[7 - i] = suck_u1(cb); + + memcpy((u1*) (&d), buffer, 8); #else - suck_nbytes ( (u1*) (&d), 8 ); + suck_nbytes((u1*) (&d), cb, 8); #endif - PANICIF (sizeof(double) != 8, "Incompatible double-format" ); + if (sizeof(double) != 8) { + *exceptionptr = new_exception_message(string_java_lang_InternalError, + "Incompatible double-format"); + + /* XXX should we exit in such a case? */ + throw_exception_exit(); + } return d; } + /************************** function suck_init ********************************* called once at startup, sets the searchpath for the classfiles *******************************************************************************/ -void suck_init (char *cpath) +void suck_init(char *cpath) +{ + char *filename=0; + char *start; + char *end; + int isZip; + int filenamelen; + union classpath_info *tmp; + union classpath_info *insertAfter=0; + + if (!cpath) + return; + + classpath = cpath; + + if (classpath_entries) + panic("suck_init should be called only once"); + + for (start = classpath; (*start) != '\0';) { + for (end = start; ((*end) != '\0') && ((*end) != ':'); end++); + + if (start != end) { + isZip = 0; + filenamelen = end - start; + + if (filenamelen>3) { + if (strncasecmp(end - 3, "zip", 3) == 0 || + strncasecmp(end - 3, "jar", 3) == 0) { + isZip = 1; + } + } + + if (filenamelen >= (CLASSPATH_MAXFILENAME - 1)) + panic("path length >= MAXFILENAME in suck_init"); + + if (!filename) + filename = MNEW(char, CLASSPATH_MAXFILENAME); + + strncpy(filename, start, filenamelen); + filename[filenamelen + 1] = '\0'; + tmp = 0; + + if (isZip) { +#ifdef 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; + } +#else + panic("Zip/JAR not supported"); +#endif + + } else { + tmp = (union classpath_info *) NEW(classpath_info); + tmp->filepath.type = CLASSPATH_PATH; + tmp->filepath.next = 0; + + 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; + } + + if (tmp) { + if (insertAfter) { + insertAfter->filepath.next = tmp; + + } else { + classpath_entries = tmp; + } + insertAfter = tmp; + } + } + + if ((*end) == ':') + start = end + 1; + else + start = end; + + if (filename) { + MFREE(filename, char, CLASSPATH_MAXFILENAME); + filename = NULL; + } + } +} + + +void create_all_classes() { - classpath = cpath; - classbuffer = NULL; + classpath_info *cpi; + + for (cpi = classpath_entries; cpi != 0; cpi = cpi->filepath.next) { +#if defined(USE_ZLIB) + if (cpi->filepath.type == CLASSPATH_ARCHIVE) { + cacao_entry_s *ce; + unz_s *s; + + s = (unz_s *) cpi->archive.uf; + ce = s->cacao_dir_list; + + while (ce) { + (void) class_new(ce->name); + ce = ce->next; + } + + } else { +#endif +#if defined(USE_ZLIB) + } +#endif + } } @@ -244,79 +470,102 @@ void suck_init (char *cpath) *******************************************************************************/ - -bool suck_start (utf *classname) { - -#define MAXFILENAME 1000 /* maximum length of a filename */ - - char filename[MAXFILENAME+10]; /* room for '.class' */ - char *pathpos; /* position in searchpath */ - char c, *utf_ptr; /* pointer to the next utf8-character */ +classbuffer *suck_start(classinfo *c) +{ + classpath_info *currPos; + char *utf_ptr; + char ch; + char filename[CLASSPATH_MAXFILENAME+10]; /* room for '.class' */ + int filenamelen=0; FILE *classfile; - int filenamelen, err; + int err; struct stat buffer; - - if (classbuffer) /* classbuffer is already valid */ - return true; + classbuffer *cb; - pathpos = classpath; - - while (*pathpos) { + utf_ptr = c->name->text; - /* skip path separator */ + while (utf_ptr < utf_end(c->name)) { + if (filenamelen >= CLASSPATH_MAXFILENAME) { + *exceptionptr = + new_exception_message(string_java_lang_InternalError, + "Filename too long"); - while (*pathpos == ':') - pathpos++; - - /* extract directory from searchpath */ + /* XXX should we exit in such a case? */ + throw_exception_exit(); + } - filenamelen = 0; - while ((*pathpos) && (*pathpos!=':')) { - PANICIF (filenamelen >= MAXFILENAME, "Filename too long") ; - filename[filenamelen++] = *(pathpos++); - } + ch = *utf_ptr++; + if ((ch <= ' ' || ch > 'z') && (ch != '/')) /* invalid character */ + ch = '?'; + filename[filenamelen++] = ch; + } - filename[filenamelen++] = '/'; - - /* add classname to filename */ - - utf_ptr = classname->text; - while (utf_ptr < utf_end(classname)) { - PANICIF (filenamelen >= MAXFILENAME, "Filename too long"); - c = *utf_ptr++; - if ((c <= ' ' || c > 'z') && (c != '/')) /* invalid character */ - c = '?'; - filename[filenamelen++] = c; + strcpy(filename + filenamelen, ".class"); + filenamelen += 6; + + 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) { + 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) { + 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; + + } else { + MFREE(cb->data, u1, cb->size); + FREE(cb, classbuffer); + log_text("Error while unzipping"); + } + } else log_text("Error while opening file in archive"); + } else log_text("Error while retrieving fileinfo"); } - - /* add suffix */ - - strcpy (filename+filenamelen, ".class"); + unzCloseCurrentFile(currPos->archive.uf); - classfile = fopen(filename, "r"); - if (classfile) { /* file exists */ - - /* determine size of classfile */ - - err = stat (filename, &buffer); - - if (!err) { /* read classfile data */ - classbuffer_size = buffer.st_size; - classbuffer = MNEW(u1, classbuffer_size); - classbuf_pos = classbuffer-1; - fread(classbuffer, 1, classbuffer_size, classfile); - fclose(classfile); - return true; + } else { +#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 */ + + /* dolog("File: %s",filename); */ + err = stat(currPos->filepath.filename, &buffer); + + if (!err) { /* 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); + + return cb; + } } +#ifdef USE_ZLIB } +#endif } if (verbose) { - sprintf (logtext, "Warning: Can not open class file '%s'", filename); - dolog(); + dolog("Warning: Can not open class file '%s'", filename); } - return false; + return NULL; } @@ -328,33 +577,38 @@ bool suck_start (utf *classname) { *******************************************************************************/ -void suck_stop () { - - /* determine amount of classdata not retrieved by suck-operations */ - - int classdata_left = ((classbuffer+classbuffer_size)-classbuf_pos-1); - - if (classdata_left > 0) { - /* surplus */ - sprintf (logtext,"There are %d access bytes at end of classfile", - classdata_left); - dolog(); - } - +void suck_stop(classbuffer *cb) +{ /* free memory */ - MFREE(classbuffer, u1, classbuffer_size); - classbuffer = NULL; + MFREE(cb->data, u1, cb->size); + FREE(cb, classbuffer); } + /******************************************************************************/ /******************* Some support functions ***********************************/ /******************************************************************************/ +void fprintflags (FILE *fp, u2 f) +{ + if ( f & ACC_PUBLIC ) fprintf (fp," PUBLIC"); + if ( f & ACC_PRIVATE ) fprintf (fp," PRIVATE"); + if ( f & ACC_PROTECTED ) fprintf (fp," PROTECTED"); + if ( f & ACC_STATIC ) fprintf (fp," STATIC"); + if ( f & ACC_FINAL ) fprintf (fp," FINAL"); + if ( f & ACC_SYNCHRONIZED ) fprintf (fp," SYNCHRONIZED"); + if ( f & ACC_VOLATILE ) fprintf (fp," VOLATILE"); + if ( f & ACC_TRANSIENT ) fprintf (fp," TRANSIENT"); + if ( f & ACC_NATIVE ) fprintf (fp," NATIVE"); + if ( f & ACC_INTERFACE ) fprintf (fp," INTERFACE"); + if ( f & ACC_ABSTRACT ) fprintf (fp," ABSTRACT"); +} + /********** internal function: printflags (only for debugging) ***************/ -static void printflags (u2 f) +void printflags(u2 f) { if ( f & ACC_PUBLIC ) printf (" PUBLIC"); if ( f & ACC_PRIVATE ) printf (" PRIVATE"); @@ -370,18 +624,6 @@ static void printflags (u2 f) } -/************************* Function: skipattribute ***************************** - - skips a (1) 'attribute' structure in the class file - -*******************************************************************************/ - -static void skipattribute () -{ - suck_u2 (); - skip_nbytes(suck_u4()); -} - /********************** Function: skipattributebody **************************** skips an attribute after the 16 bit reference to attribute_name has already @@ -389,35 +631,63 @@ static void skipattribute () *******************************************************************************/ -static void skipattributebody () +static bool skipattributebody(classbuffer *cb) { - skip_nbytes(suck_u4()); + u4 len; + + 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: skipattributes **************************** skips num attribute structures *******************************************************************************/ -static void skipattributes (u4 num) +static bool skipattributes(classbuffer *cb, u4 num) { u4 i; - for (i = 0; i < num; i++) - skipattribute(); + u4 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: innerclass_getconstant ************************ - like class_getconstant, but if cptags is ZERO null is returned + like class_getconstant, but if cptags is ZERO null is returned *******************************************************************************/ -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) + panic("Attempt to access constant outside range"); /* constantpool entry of type 0 */ if (!c->cptags[pos]) @@ -425,59 +695,89 @@ voidptr innerclass_getconstant (classinfo *c, u4 pos, u4 ctype) /* check type of constantpool entry */ if (c->cptags[pos] != ctype) { - sprintf (logtext, "Type mismatch on constant: %d requested, %d here", - (int) ctype, (int) c->cptags[pos] ); - error(); - } + error("Type mismatch on constant: %d requested, %d here (innerclass_getconstant)", + (int) ctype, (int) c->cptags[pos] ); + } return c->cpinfos[pos]; } + /************************ function: attribute_load **************************** read attributes from classfile *******************************************************************************/ -static void attribute_load (u4 num, classinfo *c) +static bool attribute_load(classbuffer *cb, classinfo *c, u4 num) { - u4 i,j; + u4 i, j; for (i = 0; i < num; i++) { - /* retrieve attribute name */ - utf *aname = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + utf *aname; - if ( aname == utf_innerclasses) { + /* retrieve attribute name */ + if (!check_classbuffer_size(cb, 2)) + return false; + + aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + + if (aname == utf_innerclasses) { /* innerclasses attribute */ + if (c->innerclass != NULL) + panic("Class has more than one InnerClasses attribute"); + if (!check_classbuffer_size(cb, 4 + 2)) + return false; + /* skip attribute length */ - suck_u4(); + suck_u4(cb); + /* number of records */ - c->innerclasscount = suck_u2(); - /* allocate memory for innerclass structure */ - c->innerclass = MNEW (innerclassinfo, c->innerclasscount); + c->innerclasscount = suck_u2(cb); - for (j=0;jinnerclasscount;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. */ + 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. */ innerclassinfo *info = c->innerclass + j; - info->inner_class = innerclass_getconstant(c, suck_u2(), CONSTANT_Class); /* CONSTANT_Class_info index */ - info->outer_class = innerclass_getconstant(c, suck_u2(), CONSTANT_Class); /* CONSTANT_Class_info index */ - info->name = innerclass_getconstant(c, suck_u2(), CONSTANT_Utf8); /* CONSTANT_Utf8_info index */ - info->flags = suck_u2 (); /* 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) { + if (!check_classbuffer_size(cb, 4 + 2)) + return false; + + suck_u4(cb); + c->sourcefile = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + } else { /* unknown attribute */ - skipattributebody (); + if (!skipattributebody(cb)) + return false; } } + + return true; } + /******************* function: checkfielddescriptor **************************** checks whether a field-descriptor is valid and aborts otherwise @@ -487,76 +787,43 @@ static void attribute_load (u4 num, classinfo *c) static void checkfielddescriptor (char *utf_ptr, char *end_pos) { + class_from_descriptor(utf_ptr,end_pos,NULL, + CLASSLOAD_NEW + | CLASSLOAD_NULLPRIMITIVE + | CLASSLOAD_NOVOID + | CLASSLOAD_CHECKEND); + + /* XXX use the following if -noverify */ +#if 0 char *tstart; /* pointer to start of classname */ char ch; - - switch (*utf_ptr++) { - case 'B': - case 'C': - case 'I': - case 'S': - case 'Z': - case 'J': - case 'F': - case 'D': - /* primitive type */ - break; - - case 'L': - /* save start of classname */ - tstart = utf_ptr; - - /* determine length of classname */ - while ( *utf_ptr++ != ';' ) - if (utf_ptr>=end_pos) - panic ("Missing ';' in objecttype-descriptor"); - - /* cause loading of referenced class */ - class_new ( utf_new(tstart, utf_ptr-tstart-1) ); - break; - - case '[' : - /* array type */ - while ((ch = *utf_ptr++)=='[') - /* skip */ ; - - /* component type of array */ - switch (ch) { - case 'B': - case 'C': - case 'I': - case 'S': - case 'Z': - case 'J': - case 'F': - case 'D': - /* primitive type */ - break; - - case 'L': - /* save start of classname */ - tstart = utf_ptr; - - /* determine length of classname */ - while ( *utf_ptr++ != ';' ) - if (utf_ptr>=end_pos) - panic ("Missing ';' in objecttype-descriptor"); - - /* cause loading of referenced class */ - class_new ( utf_new(tstart, utf_ptr-tstart-1) ); - break; + char *start = utf_ptr; - default: - panic ("Ill formed methodtype-descriptor"); - } - break; - - default: - panic ("Ill formed methodtype-descriptor"); + switch (*utf_ptr++) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': + case 'J': + case 'F': + case 'D': + /* primitive type */ + break; + + case '[': + case 'L': + if (!class_from_descriptor(start,end_pos,&utf_ptr,CLASSLOAD_NEW)) + panic ("Ill formed descriptor"); + break; + + default: + panic ("Ill formed descriptor"); } - - /* exceeding characters */ + + /* exceeding characters */ if (utf_ptr!=end_pos) panic ("descriptor has exceeding chars"); +#endif } @@ -564,21 +831,66 @@ static void checkfielddescriptor (char *utf_ptr, char *end_pos) checks whether a method-descriptor is valid and aborts otherwise. All referenced classes are inserted into the list of unloaded classes. + + The number of arguments is returned. A long or double argument is counted + as two arguments. *******************************************************************************/ -static void 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 */ - char *tstart; /* pointer to start of classname */ - char c,ch; + 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++ != '(') 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 != ')') { + /* We cannot count the this argument here because + * we don't know if the method is static. */ + if (*utf_ptr == 'J' || *utf_ptr == 'D') + argcount+=2; + else + argcount++; + class_from_descriptor(utf_ptr,end_pos,&utf_ptr, + CLASSLOAD_NEW + | CLASSLOAD_NULLPRIMITIVE + | CLASSLOAD_NOVOID); + } + + if (utf_ptr == end_pos) + panic("Missing ')' in method descriptor"); + + utf_ptr++; /* skip ')' */ + + 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"); + + return 0; + } + + return argcount; + /* XXX use the following if -noverify */ +#if 0 /* check arguments */ while ((c = *utf_ptr++) != ')') { + start = utf_ptr-1; + switch (c) { case 'B': case 'C': @@ -591,58 +903,15 @@ static void checkmethoddescriptor (utf *d) /* primitive type */ break; + case '[': case 'L': - /* save start of classname */ - tstart = utf_ptr; - - /* determine length of classname */ - while ( *utf_ptr++ != ';' ) - if (utf_ptr>=end_pos) - panic ("Missing ';' in objecttype-descriptor"); - - /* cause loading of referenced class */ - class_new ( utf_new(tstart, utf_ptr-tstart-1) ); - break; - - case '[' : - /* array type */ - while ((ch = *utf_ptr++)=='[') - /* skip */ ; - - /* component type of array */ - switch (ch) { - case 'B': - case 'C': - case 'I': - case 'S': - case 'Z': - case 'J': - case 'F': - case 'D': - /* primitive type */ - break; - - case 'L': - /* save start of classname */ - tstart = utf_ptr; - - /* determine length of classname */ - while ( *utf_ptr++ != ';' ) - if (utf_ptr>=end_pos) - panic ("Missing ';' in objecttype-descriptor"); - - /* cause loading of referenced class */ - class_new ( utf_new(tstart, utf_ptr-tstart-1) ); - break; - - default: - panic ("Ill formed methodtype-descriptor"); - } + if (!class_from_descriptor(start,end_pos,&utf_ptr,CLASSLOAD_NEW)) + panic ("Ill formed method descriptor"); break; default: panic ("Ill formed methodtype-descriptor"); - } + } } /* check returntype */ @@ -653,201 +922,205 @@ static void checkmethoddescriptor (utf *d) else /* treat as field-descriptor */ checkfielddescriptor (utf_ptr,end_pos); -} - - -/******************** Function: buildarraydescriptor *************************** - - creates a constant_arraydescriptor structure for the array type named by an - utf string - -*******************************************************************************/ - -constant_arraydescriptor * buildarraydescriptor(char *utf_ptr, u4 namelen) -{ - constant_arraydescriptor *d; - - if (*utf_ptr++ != '[') panic ("Attempt to build arraydescriptor for non-array"); - - d = NEW (constant_arraydescriptor); - d -> objectclass = NULL; - d -> elementdescriptor = NULL; - -#ifdef STATISTICS - count_const_pool_len += sizeof(constant_arraydescriptor); #endif - - switch (*utf_ptr) { - case 'Z': d -> arraytype = ARRAYTYPE_BOOLEAN; break; - case 'B': d -> arraytype = ARRAYTYPE_BYTE; break; - case 'C': d -> arraytype = ARRAYTYPE_CHAR; break; - case 'D': d -> arraytype = ARRAYTYPE_DOUBLE; break; - case 'F': d -> arraytype = ARRAYTYPE_FLOAT; break; - case 'I': d -> arraytype = ARRAYTYPE_INT; break; - case 'J': d -> arraytype = ARRAYTYPE_LONG; break; - case 'S': d -> arraytype = ARRAYTYPE_SHORT; break; - - case '[': - d -> arraytype = ARRAYTYPE_ARRAY; - d -> elementdescriptor = buildarraydescriptor (utf_ptr, namelen-1); - break; - - case 'L': - d -> arraytype = ARRAYTYPE_OBJECT; - d -> objectclass = class_new ( utf_new(utf_ptr+1, namelen-3) ); - break; - } - return d; } -/******************* Function: freearraydescriptor ***************************** +/***************** Function: print_arraydescriptor **************************** - removes a structure created by buildarraydescriptor from memory + Debugging helper for displaying an arraydescriptor *******************************************************************************/ -static void freearraydescriptor (constant_arraydescriptor *d) +void print_arraydescriptor(FILE *file, arraydescriptor *desc) { - while (d) { - constant_arraydescriptor *n = d->elementdescriptor; - FREE (d, constant_arraydescriptor); - d = n; - } -} - -/*********************** Function: displayarraydescriptor *********************/ + if (!desc) { + fprintf(file, ""); + return; + } -static void displayarraydescriptor (constant_arraydescriptor *d) -{ - switch (d->arraytype) { - case ARRAYTYPE_BOOLEAN: printf ("boolean[]"); break; - case ARRAYTYPE_BYTE: printf ("byte[]"); break; - case ARRAYTYPE_CHAR: printf ("char[]"); break; - case ARRAYTYPE_DOUBLE: printf ("double[]"); break; - case ARRAYTYPE_FLOAT: printf ("float[]"); break; - case ARRAYTYPE_INT: printf ("int[]"); break; - case ARRAYTYPE_LONG: printf ("long[]"); break; - case ARRAYTYPE_SHORT: printf ("short[]"); break; - case ARRAYTYPE_ARRAY: displayarraydescriptor(d->elementdescriptor); printf("[]"); break; - case ARRAYTYPE_OBJECT: utf_display(d->objectclass->name); printf("[]"); break; + fprintf(file, "{"); + if (desc->componentvftbl) { + if (desc->componentvftbl->class) + utf_fprint(file, desc->componentvftbl->class->name); + else + fprintf(file, ""); } + else + fprintf(file, "0"); + + fprintf(file, ","); + if (desc->elementvftbl) { + if (desc->elementvftbl->class) + utf_fprint(file, desc->elementvftbl->class->name); + else + fprintf(file, ""); + } + else + fprintf(file, "0"); + fprintf(file, ",%d,%d,%d,%d}", desc->arraytype, desc->dimension, + desc->dataoffset, desc->componentsize); } - /******************************************************************************/ /************************** Functions for fields ****************************/ /******************************************************************************/ -/************************ 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. *******************************************************************************/ -static void field_load (fieldinfo *f, classinfo *c) +#define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */ + +static bool field_load(classbuffer *cb, classinfo *c, fieldinfo *f) { u4 attrnum,i; u4 jtype; + u4 pindex = field_load_NOVALUE; /* constantvalue_index */ + + if (!check_classbuffer_size(cb, 2 + 2 + 2)) + return false; + + f->flags = suck_u2(cb); + f->name = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + f->descriptor = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + + if (opt_verify) { + /* check name */ + if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') + panic("Field with invalid name"); + + /* check flag consistency */ + i = (f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)); + + 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"); + } - f -> flags = suck_u2 (); /* ACC flags */ - f -> name = class_getconstant (c, suck_u2(), CONSTANT_Utf8); /* name of field */ - f -> descriptor = class_getconstant (c, suck_u2(), CONSTANT_Utf8); /* JavaVM descriptor */ - f -> type = jtype = desc_to_type (f->descriptor); /* data type */ - f -> offset = 0; /* offset from start of object */ + /* check descriptor */ + checkfielddescriptor(f->descriptor->text, utf_end(f->descriptor)); + } + + f->type = jtype = desc_to_type(f->descriptor); /* data type */ + f->offset = 0; /* offset from start of object */ + f->class = c; + f->xta = NULL; switch (f->type) { - case TYPE_INT: f->value.i = 0; break; - case TYPE_FLOAT: f->value.f = 0.0; break; - case TYPE_DOUBLE: f->value.d = 0.0; break; - case TYPE_ADDRESS: f->value.a = NULL; - heap_addreference (&(f->value.a)); /* make global reference (GC) */ - 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; #else f->value.l.low = 0; f->value.l.high = 0; break; -#endif +#endif } /* read attributes */ - attrnum = suck_u2(); - for (i=0; ivalue.i = ci -> value; - } - break; + case TYPE_INT: { + constant_integer *ci = + class_getconstant(c, pindex, CONSTANT_Integer); + f->value.i = ci->value; + } + break; - case TYPE_LONG: { - constant_long *cl = - class_getconstant(c, pindex, CONSTANT_Long); - - f->value.l = cl -> value; - } - break; + case TYPE_LONG: { + constant_long *cl = + class_getconstant(c, pindex, CONSTANT_Long); + f->value.l = cl->value; + } + break; - case TYPE_FLOAT: { - constant_float *cf = - class_getconstant(c, pindex, CONSTANT_Float); - - f->value.f = cf->value; - } - break; + case TYPE_FLOAT: { + constant_float *cf = + class_getconstant(c, pindex, CONSTANT_Float); + f->value.f = cf->value; + } + break; - case TYPE_DOUBLE: { - constant_double *cd = - class_getconstant(c, pindex, CONSTANT_Double); - - f->value.d = cd->value; - } - break; + case TYPE_DOUBLE: { + constant_double *cd = + class_getconstant(c, pindex, CONSTANT_Double); + f->value.d = cd->value; + } + break; - case TYPE_ADDRESS: { - utf *u = class_getconstant(c, pindex, CONSTANT_String); - /* create javastring from compressed utf8-string */ - f->value.a = literalstring_new(u); - } - break; + case TYPE_ADDRESS: { + utf *u = class_getconstant(c, pindex, CONSTANT_String); + /* create javastring from compressed utf8-string */ + f->value.a = literalstring_new(u); + } + break; - default: - log_text ("Invalid Constant - Type"); - - } - + default: + log_text ("Invalid Constant - Type"); } } + } + + /* everything was ok */ + + return true; } /********************** function: field_free **********************************/ -static void field_free (fieldinfo *f) +static void field_free(fieldinfo *f) { /* empty */ } @@ -855,150 +1128,371 @@ static void field_free (fieldinfo *f) /**************** Function: field_display (debugging only) ********************/ -static void field_display (fieldinfo *f) +void field_display(fieldinfo *f) { - printf (" "); - printflags (f -> flags); - printf (" "); - utf_display (f -> name); - printf (" "); - utf_display (f -> descriptor); - printf (" offset: %ld\n", (long int) (f -> offset) ); + printf(" "); + printflags(f->flags); + printf(" "); + utf_display(f->name); + printf(" "); + utf_display(f->descriptor); + printf(" offset: %ld\n", (long int) (f->offset)); } /******************************************************************************/ -/************************* Functions for methods ******************************/ +/************************* Functions for methods ******************************/ /******************************************************************************/ -/*********************** 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 void method_load (methodinfo *m, classinfo *c) +static bool method_load(classbuffer *cb, classinfo *c, methodinfo *m) { - u4 attrnum,i,e; - + s4 argcount; + s4 i, j; + u4 attrnum; + u4 codeattrnum; + #ifdef STATISTICS - count_all_methods++; + if (opt_stat) + count_all_methods++; #endif - m -> class = c; - - m -> flags = suck_u2 (); - m -> name = class_getconstant (c, suck_u2(), CONSTANT_Utf8); - m -> descriptor = class_getconstant (c, suck_u2(), CONSTANT_Utf8); + m->thrownexceptionscount = 0; + m->linenumbercount = 0; + m->linenumbers = 0; + m->class = c; + m->nativelyoverloaded = false; - m -> jcode = NULL; - m -> exceptiontable = NULL; - m -> entrypoint = NULL; - m -> mcode = NULL; - m -> stubroutine = NULL; + if (!check_classbuffer_size(cb, 2 + 2 + 2)) + return false; + + m->flags = suck_u2(cb); + m->name = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + m->descriptor = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + + if (opt_verify) { + if (!is_valid_name_utf(m->name)) + panic("Method with invalid name"); + + if (m->name->text[0] == '<' + && m->name != utf_init && m->name != utf_clinit) + panic("Method with invalid special name"); + } - if (! (m->flags & ACC_NATIVE) ) { - m -> stubroutine = createcompilerstub (m); + argcount = checkmethoddescriptor(c, m->descriptor); + + if (!(m->flags & ACC_STATIC)) + argcount++; /* count the 'this' argument */ + + if (opt_verify) { + if (argcount > 255) + panic("Too many arguments in signature"); + + /* check flag consistency */ + if (m->name != utf_clinit) { + i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)); + + if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) + panic("Method has invalid access flags"); + + if ((m->flags & ACC_ABSTRACT) != 0) { + if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE | + ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) { + *exceptionptr = + new_classformaterror(c, + "Illegal method modifiers: 0x%x", + m->flags); + + return false; + } + } + + if ((c->flags & ACC_INTERFACE) != 0) { + if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) + != (ACC_ABSTRACT | ACC_PUBLIC)) + panic("Interface method is not declared abstract and public"); + } + + if (m->name == utf_init) { + if ((m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED + | ACC_NATIVE | ACC_ABSTRACT)) != 0) + panic("Instance initialization method has invalid flags set"); + } } - else { + } + + m->jcode = NULL; + m->basicblockcount = 0; + m->basicblocks = NULL; + m->basicblockindex = NULL; + m->instructioncount = 0; + m->instructions = NULL; + m->stackcount = 0; + m->stack = NULL; + m->exceptiontable = NULL; + m->registerdata = NULL; + m->stubroutine = NULL; + m->mcode = NULL; + m->entrypoint = NULL; + m->methodUsed = NOTUSED; + m->monoPoly = MONO; + m->subRedefs = 0; + m->subRedefsUsed = 0; + + m->xta = NULL; + + if (!(m->flags & ACC_NATIVE)) { + m->stubroutine = createcompilerstub(m); - functionptr f = native_findfunction - (c->name, m->name, m->descriptor, (m->flags & ACC_STATIC) != 0); + } else { + functionptr f = native_findfunction(c->name, m->name, m->descriptor, + (m->flags & ACC_STATIC) != 0); if (f) { -#ifdef OLD_COMPILER - if (newcompiler) -#endif - m -> stubroutine = createnativestub (f, m); -#ifdef OLD_COMPILER - else - m -> stubroutine = oldcreatenativestub (f, m); -#endif - } + m->stubroutine = createnativestub(f, m); } + } + if (!check_classbuffer_size(cb, 2)) + return false; - attrnum = suck_u2(); - for (i=0; ithrownexceptionscount = suck_u2(cb); + + if (!check_classbuffer_size(cb, 2 * m->thrownexceptionscount)) + return false; + + m->thrownexceptions = MNEW(classinfo*, m->thrownexceptionscount); + + for (j = 0; j < m->thrownexceptionscount; j++) { + (m->thrownexceptions)[j] = + class_getconstant(c, suck_u2(cb), CONSTANT_Class); + } + + } else { + if (!skipattributebody(cb)) + return false; + } + + } else { + if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) { + *exceptionptr = + new_classformaterror(c, + "Code attribute in native or abstract methods"); - if ( aname != utf_code) { - skipattributebody (); + return false; } - else { - if (m -> jcode) panic ("Two code-attributes for one method!"); - suck_u4(); - m -> maxstack = suck_u2(); - m -> maxlocals = suck_u2(); - m -> jcodelength = suck_u4(); - m -> jcode = MNEW (u1, m->jcodelength); - suck_nbytes (m->jcode, m->jcodelength); - m -> exceptiontablelength = suck_u2 (); - m -> exceptiontable = - MNEW (exceptiontable, m->exceptiontablelength); + if (m->jcode) { + *exceptionptr = + new_classformaterror(c, "Multiple Code attributes"); -#ifdef STATISTICS - count_vmcode_len += m->jcodelength + 18; - count_extable_len += 8 * m->exceptiontablelength; + return false; + } + + if (!check_classbuffer_size(cb, 4 + 2 + 2)) + return false; + + suck_u4(cb); + m->maxstack = suck_u2(cb); + m->maxlocals = suck_u2(cb); + + if (m->maxlocals < argcount) { + *exceptionptr = + new_classformaterror(c, "Arguments can't fit into locals"); + + return false; + } + + if (!check_classbuffer_size(cb, 4)) + return false; + + m->jcodelength = suck_u4(cb); + + if (m->jcodelength == 0) + panic("bytecode has zero length"); + + if (m->jcodelength > 65535) { + *exceptionptr = + new_classformaterror(c, + "Code of a method longer than 65535 bytes"); + + return false; + } + + if (!check_classbuffer_size(cb, m->jcodelength)) + return false; + + m->jcode = MNEW(u1, m->jcodelength); + suck_nbytes(m->jcode, cb, m->jcodelength); + + if (!check_classbuffer_size(cb, 2)) + return false; + + m->exceptiontablelength = suck_u2(cb); + + if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->exceptiontablelength)) + return false; + + m->exceptiontable = MNEW(exceptiontable, m->exceptiontablelength); + +#if defined(STATISTICS) + if (opt_stat) { + count_vmcode_len += m->jcodelength + 18; + count_extable_len += 8 * m->exceptiontablelength; + } #endif - for (e=0; e < m->exceptiontablelength; e++) { + for (j = 0; j < m->exceptiontablelength; j++) { u4 idx; - m -> exceptiontable[e].startpc = suck_u2(); - m -> exceptiontable[e].endpc = suck_u2(); - m -> exceptiontable[e].handlerpc = suck_u2(); - - idx = suck_u2(); - if (!idx) m -> exceptiontable[e].catchtype = NULL; - else { - m -> exceptiontable[e].catchtype = - class_getconstant (c, idx, CONSTANT_Class); + m->exceptiontable[j].startpc = suck_u2(cb); + m->exceptiontable[j].endpc = suck_u2(cb); + m->exceptiontable[j].handlerpc = suck_u2(cb); + + idx = suck_u2(cb); + if (!idx) { + m->exceptiontable[j].catchtype = NULL; + + } else { + m->exceptiontable[j].catchtype = + class_getconstant(c, idx, CONSTANT_Class); + } + } + + if (!check_classbuffer_size(cb, 2)) + return false; + + codeattrnum = suck_u2(cb); + + for (; codeattrnum > 0; codeattrnum--) { + utf *caname; + + if (!check_classbuffer_size(cb, 2)) + return false; + + caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); + + if (caname == utf_linenumbertable) { + u2 lncid; + + if (!check_classbuffer_size(cb, 4 + 2)) + return false; + + suck_u4(cb); + m->linenumbercount = suck_u2(cb); + + if (!check_classbuffer_size(cb, + (2 + 2) * m->linenumbercount)) + return false; + + m->linenumbers = MNEW(lineinfo, m->linenumbercount); + + for (lncid = 0; lncid < m->linenumbercount; lncid++) { + m->linenumbers[lncid].start_pc = suck_u2(cb); + m->linenumbers[lncid].line_number = suck_u2(cb); } - } + codeattrnum--; - skipattributes ( suck_u2() ); + if (!skipattributes(cb, codeattrnum)) + return false; + + break; + } else { + if (!skipattributebody(cb)) + return false; + } } - } + } + + if (!m->jcode && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) { + *exceptionptr = new_classformaterror(c, "Missing Code attribute"); + + return false; + } + + /* everything was ok */ + return true; } + /********************* Function: method_free *********************************** frees all memory that was allocated for this method *******************************************************************************/ -static void method_free (methodinfo *m) +static void method_free(methodinfo *m) { - if (m->jcode) MFREE (m->jcode, u1, m->jcodelength); - if (m->exceptiontable) - MFREE (m->exceptiontable, exceptiontable, m->exceptiontablelength); - if (m->mcode) CFREE (m->mcode, m->mcodelength); + if (m->jcode) + MFREE(m->jcode, u1, m->jcodelength); + + if (m->exceptiontable) + MFREE(m->exceptiontable, exceptiontable, m->exceptiontablelength); + + if (m->mcode) + CFREE(m->mcode, m->mcodelength); + if (m->stubroutine) { - if (m->flags & ACC_NATIVE) removenativestub (m->stubroutine); - else removecompilerstub (m->stubroutine); + if (m->flags & ACC_NATIVE) { + removenativestub(m->stubroutine); + + } else { + removecompilerstub(m->stubroutine); } + } } /************** Function: method_display (debugging only) **************/ -void method_display (methodinfo *m) +void method_display(methodinfo *m) +{ + printf(" "); + printflags(m->flags); + printf(" "); + utf_display(m->name); + printf(" "); + utf_display(m->descriptor); + printf("\n"); +} + +/************** Function: method_display_flags_last (debugging only) **************/ + +void method_display_flags_last(methodinfo *m) { - printf (" "); - printflags (m -> flags); - printf (" "); - utf_display (m -> name); - printf (" "); - utf_display (m -> descriptor); - printf ("\n"); + printf(" "); + utf_display(m->name); + printf(" "); + utf_display(m->descriptor); + printf(" "); + printflags(m->flags); + printf("\n"); } @@ -1007,9 +1501,9 @@ void method_display (methodinfo *m) Check if m and old are identical with respect to type and name. This means that old can be overwritten with m. -*******************************************************************************/ +*******************************************************************************/ -static bool method_canoverwrite (methodinfo *m, methodinfo *old) +static bool method_canoverwrite(methodinfo *m, methodinfo *old) { if (m->name != old->name) return false; if (m->descriptor != old->descriptor) return false; @@ -1018,32 +1512,32 @@ static bool method_canoverwrite (methodinfo *m, methodinfo *old) } - - /******************************************************************************/ /************************ Functions for class *********************************/ /******************************************************************************/ -/******************** function: class_getconstant ****************************** +/******************** 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) +voidptr class_getconstant(classinfo *c, u4 pos, u4 ctype) { - /* invalid position in constantpool */ - if (pos >= c->cpcount) - panic ("Attempt to access constant outside range"); + /* 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) { - sprintf (logtext, "Type mismatch on constant: %d requested, %d here", - (int) ctype, (int) c->cptags[pos] ); - error(); - } + class_showconstantpool(c); + error("Type mismatch on constant: %d requested, %d here (class_getconstant)", + (int) ctype, (int) c->cptags[pos]); + } return c->cpinfos[pos]; } @@ -1055,10 +1549,11 @@ voidptr class_getconstant (classinfo *c, u4 pos, u4 ctype) *******************************************************************************/ -u4 class_constanttype (classinfo *c, u4 pos) +u4 class_constanttype(classinfo *c, u4 pos) { - if (pos >= c->cpcount) - panic ("Attempt to access constant outside range"); + if (pos >= c->cpcount) + panic("Attempt to access constant outside range"); + return c->cptags[pos]; } @@ -1072,7 +1567,7 @@ u4 class_constanttype (classinfo *c, u4 pos) *******************************************************************************/ -static void class_loadcpool (classinfo *c) +static bool class_loadcpool(classbuffer *cb, classinfo *c) { /* The following structures are used to save information which cannot be @@ -1120,267 +1615,360 @@ static void class_loadcpool (classinfo *c) forward_nameandtype *forward_nameandtypes = NULL; forward_fieldmethint *forward_fieldmethints = NULL; - /* number of entries in the constant_pool table */ - u4 cpcount = c -> cpcount = suck_u2(); + u4 cpcount; + u1 *cptags; + voidptr *cpinfos; + + /* number of entries in the constant_pool table plus one */ + if (!check_classbuffer_size(cb, 2)) + return false; + + cpcount = c->cpcount = suck_u2(cb); + /* allocate memory */ - 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); -#ifdef STATISTICS - count_const_pool_len += (sizeof(voidptr) + 1) * cpcount; + if (!cpcount) + panic("Invalid constant_pool_count (0)"); + +#if defined(STATISTICS) + if (opt_stat) + count_const_pool_len += (sizeof(voidptr) + 1) * cpcount; #endif /* initialize constantpool */ - for (idx=0; idx next = forward_classes; - forward_classes = nfc; + switch (t) { + case CONSTANT_Class: { + forward_class *nfc = DNEW(forward_class); - nfc -> thisindex = idx; - /* reference to CONSTANT_NameAndType */ - nfc -> name_index = suck_u2 (); + nfc->next = forward_classes; + forward_classes = nfc; - idx++; - break; - } + 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); + 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 (); - /* name and descriptor of the field or method */ - nff -> nameandtype_index = suck_u2 (); - - idx ++; - break; - } + nff->next = forward_fieldmethints; + forward_fieldmethints = nff; + + nff->thisindex = idx; + /* constant type */ + nff->tag = t; + + if (!check_classbuffer_size(cb, 2 + 2)) + return false; + + /* class or interface type that contains the declaration of the + field or method */ + nff->class_index = suck_u2(cb); + + /* name and descriptor of the field or method */ + nff->nameandtype_index = suck_u2(cb); + + idx++; + break; + } - case CONSTANT_String: { - forward_string *nfs = DNEW (forward_string); + case CONSTANT_String: { + forward_string *nfs = DNEW(forward_string); - nfs -> next = forward_strings; - forward_strings = nfs; + nfs->next = forward_strings; + forward_strings = nfs; - nfs -> thisindex = idx; - /* reference to CONSTANT_Utf8_info with string characters */ - nfs -> string_index = suck_u2 (); + 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; - } + idx++; + break; + } - case CONSTANT_NameAndType: { - forward_nameandtype *nfn = DNEW (forward_nameandtype); + case CONSTANT_NameAndType: { + forward_nameandtype *nfn = DNEW(forward_nameandtype); - nfn -> next = forward_nameandtypes; - forward_nameandtypes = nfn; + nfn->next = forward_nameandtypes; + forward_nameandtypes = nfn; - nfn -> thisindex = idx; - /* reference to CONSTANT_Utf8_info containing simple name */ - nfn -> name_index = suck_u2 (); - /* reference to CONSTANT_Utf8_info containing field or method descriptor */ - nfn -> sig_index = suck_u2 (); + 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; - } + idx++; + break; + } - case CONSTANT_Integer: { - constant_integer *ci = NEW (constant_integer); + 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 - ci -> value = suck_s4 (); - cptags [idx] = CONSTANT_Integer; - cpinfos [idx] = ci; - idx ++; - - break; - } + if (!check_classbuffer_size(cb, 4)) + return false; + + ci->value = suck_s4(cb); + cptags[idx] = CONSTANT_Integer; + cpinfos[idx] = ci; + + idx++; + break; + } - case CONSTANT_Float: { - constant_float *cf = NEW (constant_float); + 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 - cf -> value = suck_float (); - cptags [idx] = CONSTANT_Float; - cpinfos[idx] = cf; - idx ++; - break; - } + if (!check_classbuffer_size(cb, 4)) + return false; + + cf->value = suck_float(cb); + cptags[idx] = CONSTANT_Float; + cpinfos[idx] = cf; + + idx++; + break; + } - case CONSTANT_Long: { - constant_long *cl = NEW(constant_long); + 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 - cl -> value = suck_s8 (); - cptags [idx] = CONSTANT_Long; - cpinfos [idx] = cl; - idx += 2; - break; - } + if (!check_classbuffer_size(cb, 8)) + return false; + + cl->value = suck_s8(cb); + cptags[idx] = CONSTANT_Long; + cpinfos[idx] = cl; + idx += 2; + if (idx > cpcount) + panic("Long constant exceeds constant pool"); + break; + } - case CONSTANT_Double: { - constant_double *cd = NEW(constant_double); + 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 - cd -> value = suck_double (); - cptags [idx] = CONSTANT_Double; - cpinfos [idx] = cd; - idx += 2; - break; - } + if (!check_classbuffer_size(cb, 8)) + return false; + + cd->value = suck_double(cb); + cptags[idx] = CONSTANT_Double; + cpinfos[idx] = cd; + idx += 2; + if (idx > cpcount) + panic("Double constant exceeds constant pool"); + break; + } - case CONSTANT_Utf8: { - - /* number of bytes in the bytes array (not string-length) */ - u4 length = suck_u2(); - cptags [idx] = CONSTANT_Utf8; - /* insert utf-string into the utf-symboltable */ - cpinfos [idx] = utf_new(classbuf_pos+1, length); - /* skip bytes of the string */ - skip_nbytes(length); - idx++; - break; - } + case CONSTANT_Utf8: { + u4 length; + + /* number of bytes in the bytes array (not string-length) */ + if (!check_classbuffer_size(cb, 2)) + return false; + + length = suck_u2(cb); + cptags[idx] = CONSTANT_Utf8; + + /* validate the string */ + if (!check_classbuffer_size(cb, length)) + return false; + + if (opt_verify && + !is_valid_utf(cb->pos + 1, cb->pos + 1 + length)) { + dolog("Invalid UTF-8 string (constant pool index %d)",idx); + panic("Invalid UTF-8 string"); + } + /* insert utf-string into the utf-symboltable */ + cpinfos[idx] = utf_new_intern(cb->pos + 1, length); + + /* skip bytes of the string (buffer size check above) */ + skip_nbytes(cb, length); + idx++; + break; + } - default: - sprintf (logtext, "Unkown constant type: %d",(int) t); - error (); - - } /* end switch */ - - } /* end while */ - + default: + error("Unkown constant type: %d",(int) t); + } /* end switch */ + } /* end while */ - /* resolve entries in temporary structures */ + /* resolve entries in temporary structures */ while (forward_classes) { utf *name = - class_getconstant (c, forward_classes -> name_index, CONSTANT_Utf8); - - if ( (name->blength>0) && (name->text[0]=='[') ) { - /* check validity of descriptor */ - checkfielddescriptor (name->text, utf_end(name)); + class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8); - cptags [forward_classes -> thisindex] = CONSTANT_Arraydescriptor; - cpinfos [forward_classes -> thisindex] = - buildarraydescriptor(name->text, name->blength); + if (opt_verify && !is_valid_name_utf(name)) + panic("Class reference with invalid name"); - } - else { - cptags [forward_classes -> thisindex] = CONSTANT_Class; - /* retrieve class from class-table */ - cpinfos [forward_classes -> thisindex] = class_new (name); - } - forward_classes = forward_classes -> next; - + cptags[forward_classes->thisindex] = CONSTANT_Class; + /* retrieve class from class-table */ + if (opt_eager) { + classinfo *tc; + tc = class_new_intern(name); + + if (!class_load(tc)) + return false; + + /* link the class later, so we cannot link the currently loaded + class */ + list_addfirst(&unlinkedclasses, tc); + + cpinfos[forward_classes->thisindex] = tc; + + } else { + cpinfos[forward_classes->thisindex] = class_new(name); } + forward_classes = forward_classes->next; + } + while (forward_strings) { - utf *text = - class_getconstant (c, forward_strings -> string_index, CONSTANT_Utf8); - + utf *text = + class_getconstant(c, forward_strings->string_index, CONSTANT_Utf8); + /* resolve utf-string */ - cptags [forward_strings -> thisindex] = CONSTANT_String; - cpinfos [forward_strings -> thisindex] = text; + cptags[forward_strings->thisindex] = CONSTANT_String; + cpinfos[forward_strings->thisindex] = text; - forward_strings = forward_strings -> next; - } + forward_strings = forward_strings->next; + } while (forward_nameandtypes) { - constant_nameandtype *cn = NEW (constant_nameandtype); + 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 */ - cn -> name = class_getconstant - (c, forward_nameandtypes -> name_index, CONSTANT_Utf8); - cn -> descriptor = class_getconstant - (c, forward_nameandtypes -> sig_index, CONSTANT_Utf8); - - cptags [forward_nameandtypes -> thisindex] = CONSTANT_NameAndType; - cpinfos [forward_nameandtypes -> thisindex] = cn; - - forward_nameandtypes = forward_nameandtypes -> next; + cn->name = class_getconstant(c, + forward_nameandtypes->name_index, + CONSTANT_Utf8); + + cn->descriptor = class_getconstant(c, + forward_nameandtypes->sig_index, + CONSTANT_Utf8); + + if (opt_verify) { + /* check name */ + if (!is_valid_name_utf(cn->name)) + panic("NameAndType with invalid name"); + /* disallow referencing among others */ + if (cn->name->text[0] == '<' && cn->name != utf_init) + panic("NameAndType with invalid special name"); } + cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType; + cpinfos[forward_nameandtypes->thisindex] = cn; + + forward_nameandtypes = forward_nameandtypes->next; + } - while (forward_fieldmethints) { + while (forward_fieldmethints) { constant_nameandtype *nat; - constant_FMIref *fmi = NEW (constant_FMIref); + 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, forward_fieldmethints -> nameandtype_index, CONSTANT_NameAndType); - - fmi -> class = class_getconstant - (c, forward_fieldmethints -> class_index, CONSTANT_Class); - fmi -> name = nat -> name; - fmi -> descriptor = nat -> descriptor; - - cptags [forward_fieldmethints -> thisindex] = forward_fieldmethints -> tag; - cpinfos [forward_fieldmethints -> thisindex] = fmi; + nat = class_getconstant(c, + forward_fieldmethints->nameandtype_index, + CONSTANT_NameAndType); + + fmi->class = class_getconstant(c, + forward_fieldmethints->class_index, + CONSTANT_Class); + fmi->name = nat->name; + fmi->descriptor = nat->descriptor; + + cptags[forward_fieldmethints->thisindex] = forward_fieldmethints->tag; + cpinfos[forward_fieldmethints->thisindex] = fmi; - switch (forward_fieldmethints -> tag) { + switch (forward_fieldmethints->tag) { case CONSTANT_Fieldref: /* check validity of descriptor */ - checkfielddescriptor (fmi->descriptor->text,utf_end(fmi->descriptor)); - break; - case CONSTANT_InterfaceMethodref: + checkfielddescriptor(fmi->descriptor->text, + utf_end(fmi->descriptor)); + break; + case CONSTANT_InterfaceMethodref: case CONSTANT_Methodref: /* check validity of descriptor */ - checkmethoddescriptor (fmi->descriptor); - break; - } + checkmethoddescriptor(c, fmi->descriptor); + break; + } - forward_fieldmethints = forward_fieldmethints -> next; + forward_fieldmethints = forward_fieldmethints->next; + } - } + dump_release(dumpsize); + /* everything was ok */ - dump_release (dumpsize); + return true; } @@ -1397,126 +1985,436 @@ static void class_loadcpool (classinfo *c) *******************************************************************************/ -static int class_load (classinfo *c) +classinfo *class_load_intern(classbuffer *cb); + +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 +#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 +#endif + + return c; + } + + /* measure time */ + if (getloadingtime) + starttime = getcputime(); + + /* load classdata, throw exception on error */ + + if ((cb = suck_start(c)) == NULL) { + /* this means, the classpath was not set properly */ + if (c->name == utf_java_lang_Object) + throw_cacao_exception_exit(string_java_lang_NoClassDefFoundError, + "java/lang/Object"); + + *exceptionptr = + new_exception_utfmessage(string_java_lang_NoClassDefFoundError, + c->name); + +#if defined(USE_THREADS) +#if defined(NATIVE_THREADS) + tables_unlock(); + compiler_unlock(); +#else + intsRestore(); +#endif +#endif + + return NULL; + } + + /* call the internal function */ + r = class_load_intern(cb); + + /* if return value is NULL, we had a problem and the class is not loaded */ + if (!r) { + c->loaded = false; + + /* now free the allocated memory, otherwise we could ran into a DOS */ + class_remove(c); + } + + /* free memory */ + suck_stop(cb); + + /* measure time */ + if (getloadingtime) { + stoptime = getcputime(); + loadingtime += (stoptime - starttime); + } + +#if defined(USE_THREADS) +#if defined(NATIVE_THREADS) + tables_unlock(); + compiler_unlock(); +#else + intsRestore(); +#endif +#endif + + return r; +} + + +classinfo *class_load_intern(classbuffer *cb) { + classinfo *c; u4 i; - u4 mi,ma; + u4 mi, ma; +/* s4 classdata_left; */ + char msg[MAXLOGTEXT]; /* maybe we get an exception */ -#ifdef STATISTICS - count_class_loads++; + /* get the classbuffer's class */ + c = cb->class; + + /* maybe the class is already loaded */ + if (c->loaded) + return c; + +#if defined(STATISTICS) + if (opt_stat) + count_class_loads++; #endif /* output for debugging purposes */ - if (loadverbose) { - sprintf (logtext, "Loading class: "); - utf_sprint (logtext+strlen(logtext), c->name ); - dolog(); - } + if (loadverbose) + log_message_class("Loading class: ", c); - /* load classdata, throw exception on error */ - if (!suck_start (c->name)) { - throw_classnotfoundexception(); - return false; + /* class is somewhat loaded */ + c->loaded = true; + + if (!check_classbuffer_size(cb, 4 + 2 + 2)) + return NULL; + + /* check signature */ + if (suck_u4(cb) != MAGIC) { + *exceptionptr = new_classformaterror(c, "Bad magic number"); + + return NULL; } - - /* check signature */ - if (suck_u4() != MAGIC) panic("Can not find class-file signature"); + /* check version */ - mi = suck_u2(); - ma = suck_u2(); - if (ma != MAJOR_VERSION && (ma != MAJOR_VERSION+1 || mi != 0)) { - sprintf (logtext, "File version %d.%d is not supported", - (int) ma, (int) mi); - error(); - } + mi = suck_u2(cb); + ma = suck_u2(cb); + if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) { + *exceptionptr = + new_classformaterror(c, + "Unsupported major.minor version %d.%d", + ma, mi); + + return NULL; + } + + if (!class_loadcpool(cb, c)) + return NULL; + + /*JOWENN*/ + c->erroneous_state = 0; + c->initializing_thread = 0; + /*JOWENN*/ + c->classUsed = NOTUSED; /* not used initially CO-RT */ + c->impldBy = NULL; - class_loadcpool (c); - /* ACC flags */ - c -> flags = suck_u2 (); + if (!check_classbuffer_size(cb, 2)) + return NULL; + + c->flags = suck_u2(cb); + /*if (!(c->flags & ACC_PUBLIC)) { log_text("CLASS NOT PUBLIC"); } JOWENN*/ + + /* check ACC flags consistency */ + if (c->flags & ACC_INTERFACE) { + if (!(c->flags & ACC_ABSTRACT)) { + /* We work around this because interfaces in JDK 1.1 are + * not declared abstract. */ + + c->flags |= ACC_ABSTRACT; + /* panic("Interface class not declared abstract"); */ + } + + if (c->flags & ACC_FINAL) { + *exceptionptr = + new_classformaterror(c, + "Illegal class modifiers: 0x%x", c->flags); + + return NULL; + } + + if (c->flags & ACC_SUPER) { + c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */ + } + } + + if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) { + *exceptionptr = + new_classformaterror(c, "Illegal class modifiers: 0x%x", c->flags); + + return NULL; + } + + if (!check_classbuffer_size(cb, 2 + 2)) + return NULL; + /* this class */ - suck_u2 (); + i = suck_u2(cb); + if (class_getconstant(c, i, CONSTANT_Class) != c) { + utf_sprint(msg, c->name); + sprintf(msg + strlen(msg), " (wrong name: "); + utf_sprint(msg + strlen(msg), + ((classinfo *) class_getconstant(c, i, CONSTANT_Class))->name); + sprintf(msg + strlen(msg), ")"); + + *exceptionptr = + new_exception_message(string_java_lang_NoClassDefFoundError, msg); + + return NULL; + } /* retrieve superclass */ - if ( (i = suck_u2 () ) ) { - c -> super = class_getconstant (c, i, CONSTANT_Class); + if ((i = suck_u2(cb))) { + c->super = class_getconstant(c, i, CONSTANT_Class); + + /* java.lang.Object may not have a super class. */ + if (c->name == utf_java_lang_Object) { + *exceptionptr = + new_exception_message(string_java_lang_ClassFormatError, + "java.lang.Object with superclass"); + + return NULL; + } + + /* Interfaces must have java.lang.Object as super class. */ + if ((c->flags & ACC_INTERFACE) && + c->super->name != utf_java_lang_Object) { + *exceptionptr = + new_exception_message(string_java_lang_ClassFormatError, + "Interfaces must have java.lang.Object as superclass"); + + return NULL; } - else { - c -> super = NULL; + + } else { + c->super = NULL; + + /* This is only allowed for java.lang.Object. */ + if (c->name != utf_java_lang_Object) { + *exceptionptr = new_classformaterror(c, "Bad superclass index"); + + return NULL; } + + } /* retrieve interfaces */ - c -> interfacescount = suck_u2 (); - c -> interfaces = MNEW (classinfo*, c -> interfacescount); - for (i=0; i < c -> interfacescount; i++) { - c -> interfaces [i] = - class_getconstant (c, suck_u2(), CONSTANT_Class); - } + if (!check_classbuffer_size(cb, 2)) + return NULL; + + c->interfacescount = suck_u2(cb); + + if (!check_classbuffer_size(cb, 2 * c->interfacescount)) + return NULL; + + c->interfaces = MNEW(classinfo*, c->interfacescount); + for (i = 0; i < c->interfacescount; i++) { + c->interfaces[i] = class_getconstant(c, suck_u2(cb), CONSTANT_Class); + } /* load fields */ - c -> fieldscount = suck_u2 (); -#ifdef USE_BOEHM - c -> fields = GCNEW (fieldinfo, c -> fieldscount); -#else - c -> fields = MNEW (fieldinfo, c -> fieldscount); -#endif - for (i=0; i < c -> fieldscount; i++) { - field_load (&(c->fields[i]), c); - } + if (!check_classbuffer_size(cb, 2)) + return NULL; + + c->fieldscount = suck_u2(cb); + c->fields = GCNEW(fieldinfo, c->fieldscount); +/* c->fields = MNEW(fieldinfo, c->fieldscount); */ + for (i = 0; i < c->fieldscount; i++) { + if (!field_load(cb, c, &(c->fields[i]))) + return NULL; + } /* load methods */ - c -> methodscount = suck_u2 (); - c -> methods = MNEW (methodinfo, c -> methodscount); - for (i=0; i < c -> methodscount; i++) { - method_load (&(c -> methods [i]), c); + if (!check_classbuffer_size(cb, 2)) + return NULL; + + c->methodscount = suck_u2(cb); + c->methods = GCNEW(methodinfo, c->methodscount); +/* c->methods = MNEW(methodinfo, c->methodscount); */ + for (i = 0; i < c->methodscount; i++) { + if (!method_load(cb, c, &(c->methods[i]))) + return NULL; + } + + /* Check if all fields and methods can be uniquely + * identified by (name,descriptor). */ + if (opt_verify) { + /* We use a hash table here to avoid making the + * average case quadratic in # of methods, fields. + */ + static int shift = 0; + u2 *hashtab; + u2 *next; /* for chaining colliding hash entries */ + size_t len; + size_t hashlen; + u2 index; + u2 old; + + /* Allocate hashtable */ + len = c->methodscount; + if (len < c->fieldscount) len = c->fieldscount; + hashlen = 5 * len; + hashtab = MNEW(u2,(hashlen + len)); + next = hashtab + hashlen; + + /* Determine bitshift (to get good hash values) */ + if (!shift) { + len = sizeof(utf); + while (len) { + len >>= 1; + shift++; + } } -#ifdef STATISTICS - count_class_infos += sizeof(classinfo*) * c -> interfacescount; - count_class_infos += sizeof(fieldinfo) * c -> fieldscount; - count_class_infos += sizeof(methodinfo) * c -> methodscount; + /* Check fields */ + memset(hashtab, 0, sizeof(u2) * (hashlen + len)); + + for (i = 0; i < c->fieldscount; ++i) { + fieldinfo *fi = c->fields + i; + + /* It's ok if we lose bits here */ + index = ((((size_t) fi->name) + + ((size_t) fi->descriptor)) >> shift) % hashlen; + + if ((old = hashtab[index])) { + old--; + next[i] = old; + do { + if (c->fields[old].name == fi->name && + c->fields[old].descriptor == fi->descriptor) { + *exceptionptr = + new_classformaterror(c, + "Repetitive field name/signature"); + + return NULL; + } + } while ((old = next[old])); + } + hashtab[index] = i + 1; + } + + /* Check methods */ + memset(hashtab, 0, sizeof(u2) * (hashlen + len)); + + 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; + + if ((old = hashtab[index])) { + old--; + next[i] = old; + do { + if (c->methods[old].name == mi->name && + c->methods[old].descriptor == mi->descriptor) { + *exceptionptr = + new_classformaterror(c, + "Repetitive method name/signature"); + + return NULL; + } + } while ((old = next[old])); + } + hashtab[index] = i + 1; + } + + MFREE(hashtab, u2, (hashlen + len)); + } + +#if defined(STATISTICS) + if (opt_stat) { + count_class_infos += sizeof(classinfo*) * c->interfacescount; + count_class_infos += sizeof(fieldinfo) * c->fieldscount; + count_class_infos += sizeof(methodinfo) * c->methodscount; + } #endif /* load variable-length attribute structures */ - attribute_load (suck_u2(), c); + if (!check_classbuffer_size(cb, 2)) + return NULL; - /* free memory */ - suck_stop (); + if (!attribute_load(cb, c, suck_u2(cb))) + return NULL; - /* remove class from list of unloaded classes and - add to list of unlinked classes */ - list_remove (&unloadedclasses, c); - list_addlast (&unlinkedclasses, c); +#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); - return true; + if (classdata_left > 0) { + /* surplus */ + dolog("There are %d extra bytes at end of classfile", classdata_left); + /* The JVM spec disallows extra bytes. */ + panic("Extra bytes at end of classfile"); + } +#endif + + if (loadverbose) + log_message_class("Loading done class: ", c); + + return c; } -/************** internal Function: class_highestinterface *********************** +/************** internal Function: class_highestinterface ********************** Used by the function class_link to determine the amount of memory needed for the interface table. *******************************************************************************/ -static s4 class_highestinterface (classinfo *c) +static s4 class_highestinterface(classinfo *c) { s4 h; s4 i; - if ( ! (c->flags & ACC_INTERFACE) ) { - sprintf (logtext, "Interface-methods count requested for non-interface: "); - utf_sprint (logtext+strlen(logtext), c->name); - error(); - } + if (!(c->flags & ACC_INTERFACE)) { + char logtext[MAXLOGTEXT]; + sprintf(logtext, "Interface-methods count requested for non-interface: "); + utf_sprint(logtext + strlen(logtext), c->name); + error("%s",logtext); + } h = c->index; - for (i=0; iinterfacescount; i++) { - s4 h2 = class_highestinterface (c->interfaces[i]); - if (h2>h) h=h2; - } + for (i = 0; i < c->interfacescount; i++) { + s4 h2 = class_highestinterface(c->interfaces[i]); + if (h2 > h) h = h2; + } + return h; } @@ -1526,16 +2424,17 @@ static s4 class_highestinterface (classinfo *c) 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) +static void class_addinterface(classinfo *c, classinfo *ic) { s4 j, m; s4 i = ic->index; vftbl *vftbl = c->vftbl; - + if (i >= vftbl->interfacetablelength) panic ("Inernal error: interfacetable overflow"); + if (vftbl->interfacetable[-i]) return; @@ -1543,55 +2442,338 @@ static void class_addinterface (classinfo *c, classinfo *ic) vftbl->interfacevftbllength[i] = 1; vftbl->interfacetable[-i] = MNEW(methodptr, 1); vftbl->interfacetable[-i][0] = NULL; - } - else { + + } else { vftbl->interfacevftbllength[i] = ic->methodscount; - vftbl->interfacetable[-i] = MNEW(methodptr, ic->methodscount); + vftbl->interfacetable[-i] = MNEW(methodptr, ic->methodscount); #ifdef STATISTICS - count_vftbl_len += sizeof(methodptr) * - (ic->methodscount + (ic->methodscount == 0)); + if (opt_stat) + count_vftbl_len += sizeof(methodptr) * + (ic->methodscount + (ic->methodscount == 0)); #endif - for (j=0; jmethodscount; j++) { + for (j = 0; j < ic->methodscount; j++) { classinfo *sc = c; while (sc) { for (m = 0; m < sc->methodscount; m++) { methodinfo *mi = &(sc->methods[m]); if (method_canoverwrite(mi, &(ic->methods[j]))) { - vftbl->interfacetable[-i][j] = - vftbl->table[mi->vftblindex]; + vftbl->interfacetable[-i][j] = + vftbl->table[mi->vftblindex]; goto foundmethod; - } } - sc = sc->super; } - foundmethod: ; + sc = sc->super; } + foundmethod: + ; } + } for (j = 0; j < ic->interfacescount; j++) class_addinterface(c, ic->interfaces[j]); } +/******************* Function: class_new_array ********************************* + + This function is called by class_new to setup an array class. + +*******************************************************************************/ + +void class_new_array(classinfo *c) +{ + classinfo *comp = NULL; + methodinfo *clone; + int namelen; + + /* Check array class name */ + namelen = c->name->blength; + if (namelen < 2 || c->name->text[0] != '[') + panic("Invalid array class name"); + + /* Check the component type */ + switch (c->name->text[1]) { + case '[': + /* c is an array of arrays. We have to create the component class. */ + if (opt_eager) { + comp = class_new_intern(utf_new_intern(c->name->text + 1, + namelen - 1)); + class_load(comp); + list_addfirst(&unlinkedclasses, comp); + + } else { + comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1)); + } + 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 */ + c->super = class_java_lang_Object; + c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; + + c->interfacescount = 2; + c->interfaces = MNEW(classinfo*, 2); + + 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); + + clone = c->methods; + memset(clone, 0, sizeof(methodinfo)); + clone->flags = ACC_PUBLIC; + clone->name = utf_new_char("clone"); + clone->descriptor = utf_new_char("()Ljava/lang/Object;"); + clone->class = c; + clone->stubroutine = createnativestub((functionptr) &builtin_clone_array, clone); + clone->monoPoly = MONO; + + /* XXX: field: length? */ + + /* array classes are not loaded from class files */ + c->loaded = true; +} + + +/****************** Function: class_link_array ********************************* + + This function is called by class_link to create the + arraydescriptor for an array class. + + This function returns NULL if the array cannot be linked because + the component type has not been linked yet. + +*******************************************************************************/ + +static arraydescriptor *class_link_array(classinfo *c) +{ + classinfo *comp = NULL; + s4 namelen = c->name->blength; + arraydescriptor *desc; + vftbl *compvftbl; + + /* Check the component type */ + switch (c->name->text[1]) { + case '[': + /* c is an array of arrays. */ +/* comp = class_get(utf_new_intern(c->name->text + 1, namelen - 1)); */ + comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1)); + if (!comp) + panic("Could not find component array class."); + break; + + case 'L': + /* c is an array of objects. */ +/* comp = class_get(utf_new_intern(c->name->text + 2, namelen - 3)); */ + comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3)); + if (!comp) + panic("Could not find component class."); + break; + } + + /* If the component type has not been linked, link it now */ + if (comp && !comp->linked) { + if (!comp->loaded) + class_load(comp); + class_link(comp); + } + + /* Allocate the arraydescriptor */ + desc = NEW(arraydescriptor); + + if (comp) { + /* c is an array of references */ + desc->arraytype = ARRAYTYPE_OBJECT; + desc->componentsize = sizeof(void*); + desc->dataoffset = OFFSET(java_objectarray, data); + + compvftbl = comp->vftbl; + if (!compvftbl) + panic("Component class has no vftbl"); + desc->componentvftbl = compvftbl; + + if (compvftbl->arraydesc) { + desc->elementvftbl = compvftbl->arraydesc->elementvftbl; + if (compvftbl->arraydesc->dimension >= 255) + panic("Creating array of dimension >255"); + desc->dimension = compvftbl->arraydesc->dimension + 1; + desc->elementtype = compvftbl->arraydesc->elementtype; + + } else { + desc->elementvftbl = compvftbl; + desc->dimension = 1; + desc->elementtype = ARRAYTYPE_OBJECT; + } + + } else { + /* c is an array of a primitive type */ + switch (c->name->text[1]) { + case 'Z': + desc->arraytype = ARRAYTYPE_BOOLEAN; + desc->dataoffset = OFFSET(java_booleanarray,data); + desc->componentsize = sizeof(u1); + break; + + case 'B': + desc->arraytype = ARRAYTYPE_BYTE; + desc->dataoffset = OFFSET(java_bytearray,data); + desc->componentsize = sizeof(u1); + break; + + case 'C': + desc->arraytype = ARRAYTYPE_CHAR; + desc->dataoffset = OFFSET(java_chararray,data); + desc->componentsize = sizeof(u2); + break; + + case 'D': + desc->arraytype = ARRAYTYPE_DOUBLE; + desc->dataoffset = OFFSET(java_doublearray,data); + desc->componentsize = sizeof(double); + break; + + case 'F': + desc->arraytype = ARRAYTYPE_FLOAT; + desc->dataoffset = OFFSET(java_floatarray,data); + desc->componentsize = sizeof(float); + break; + + case 'I': + desc->arraytype = ARRAYTYPE_INT; + desc->dataoffset = OFFSET(java_intarray,data); + desc->componentsize = sizeof(s4); + break; + + case 'J': + desc->arraytype = ARRAYTYPE_LONG; + desc->dataoffset = OFFSET(java_longarray,data); + desc->componentsize = sizeof(s8); + break; + + case 'S': + desc->arraytype = ARRAYTYPE_SHORT; + desc->dataoffset = OFFSET(java_shortarray,data); + desc->componentsize = sizeof(s2); + break; + + default: + panic("Invalid array class name"); + } + + desc->componentvftbl = NULL; + desc->elementvftbl = NULL; + desc->dimension = 1; + desc->elementtype = desc->arraytype; + } + + return desc; +} + + /********************** Function: class_link *********************************** - Tries to link a class. The super class and every implemented interface must - already have been linked. The function calculates the length in bytes that + Tries to link a class. The function calculates the length in bytes that an instance of this class requires as well as the VTBL for methods and interface methods. - If the class can be linked, it is removed from the list 'unlinkedclasses' - and added to 'linkedclasses'. Otherwise, it is moved to the end of - 'unlinkedclasses'. +*******************************************************************************/ - Attention: If cyclical class definitions are encountered, the program gets - into an infinite loop (we'll have to work that out) +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 +#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 +#endif + + return c; + } + + /* measure time */ + if (getloadingtime) + starttime = getcputime(); + + /* call the internal function */ + r = class_link_intern(c); -static void class_link (classinfo *c) + /* if return value is NULL, we had a problem and the class is not linked */ + if (!r) + c->linked = false; + + /* measure time */ + if (getloadingtime) { + stoptime = getcputime(); + loadingtime += (stoptime - starttime); + } + +#if defined(USE_THREADS) +#if defined(NATIVE_THREADS) + tables_unlock(); + compiler_unlock(); +#else + intsRestore(); +#endif +#endif + + return r; +} + + +static classinfo *class_link_intern(classinfo *c) { s4 supervftbllength; /* vftbllegnth of super class */ s4 vftbllength; /* vftbllength of current class */ @@ -1599,40 +2781,95 @@ static void class_link (classinfo *c) classinfo *super = c->super; /* super class */ classinfo *ic, *c2; /* intermediate class variables */ vftbl *v; /* vftbl of current class */ - s4 i; /* interface/method/field counter */ + s4 i; /* interface/method/field counter */ + arraydescriptor *arraydesc = NULL; /* descriptor for array classes */ + + /* maybe the class is already linked */ + if (c->linked) + return c; + if (linkverbose) + log_message_class("Linking class: ", c); - /* check if all superclasses are already linked, if not put c at end of - unlinked list and return. Additionally initialize class fields. */ + /* ok, this class is somewhat linked */ + c->linked = true; - /* check interfaces */ + /* check interfaces */ for (i = 0; i < c->interfacescount; i++) { ic = c->interfaces[i]; - if (!ic->linked) { - list_remove(&unlinkedclasses, c); - list_addlast(&unlinkedclasses, c); - return; - } + + /* detect circularity */ + if (ic == c) { + *exceptionptr = + new_exception_utfmessage(string_java_lang_ClassCircularityError, + c->name); + + return NULL; } + + if (!ic->loaded) + if (!class_load(ic)) + return NULL; + + if (!ic->linked) + if (!class_link(ic)) + 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"); + } + } /* check super class */ - if (super == NULL) { /* class java.long.Object */ + if (super == NULL) { /* class java.lang.Object */ c->index = 0; + c->classUsed = USED; /* Object class is always used CO-RT*/ + c->impldBy = NULL; c->instancesize = sizeof(java_objectheader); vftbllength = supervftbllength = 0; c->finalizer = NULL; + + } else { + /* detect circularity */ + if (super == c) { + *exceptionptr = + new_exception_utfmessage(string_java_lang_ClassCircularityError, + c->name); + + return NULL; } - else { - if (!super->linked) { - list_remove(&unlinkedclasses, c); - list_addlast(&unlinkedclasses, c); - return; + + if (!super->loaded) + if (!class_load(super)) + return NULL; + + if (!super->linked) + if (!class_link(super)) + return NULL; + + if (super->flags & ACC_INTERFACE) + 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 (c->flags & ACC_INTERFACE) c->index = interfaceindex++; else @@ -1643,14 +2880,7 @@ static void class_link (classinfo *c) vftbllength = supervftbllength = super->vftbl->vftbllength; c->finalizer = super->finalizer; - } - - - if (linkverbose) { - sprintf (logtext, "Linking Class: "); - utf_sprint (logtext+strlen(logtext), c->name ); - dolog (); - } + } /* compute vftbl length */ @@ -1660,22 +2890,36 @@ static void class_link (classinfo *c) if (!(m->flags & ACC_STATIC)) { /* is instance method */ classinfo *sc = super; while (sc) { - int j; + s4 j; for (j = 0; j < sc->methodscount; j++) { if (method_canoverwrite(m, &(sc->methods[j]))) { + if ((sc->methods[j].flags & ACC_PRIVATE) != 0) + goto notfoundvftblindex; + + if ((sc->methods[j].flags & ACC_FINAL) != 0) { + log_utf(c->name); + log_utf(sc->name); + log_utf(sc->methods[j].name); + log_utf(sc->methods[j].descriptor); + panic("Trying to overwrite final method"); + } m->vftblindex = sc->methods[j].vftblindex; goto foundvftblindex; - } } - sc = sc->super; } - m->vftblindex = (vftbllength++); -foundvftblindex: ; + sc = sc->super; } - } + notfoundvftblindex: + m->vftblindex = (vftbllength++); + foundvftblindex: + ; + } + } #ifdef STATISTICS - count_vftbl_len += sizeof(vftbl) + sizeof(methodptr)*(vftbllength-1); + if (opt_stat) + count_vftbl_len += + sizeof(vftbl) + (sizeof(methodptr) * (vftbllength - 1)); #endif /* compute interfacetable length */ @@ -1684,29 +2928,35 @@ foundvftblindex: ; c2 = c; while (c2) { for (i = 0; i < c2->interfacescount; i++) { - s4 h = class_highestinterface (c2->interfaces[i]) + 1; + s4 h = class_highestinterface(c2->interfaces[i]) + 1; if (h > interfacetablelength) - interfacetablelength = h; - } - c2 = c2->super; + interfacetablelength = h; } + c2 = c2->super; + } /* allocate virtual function table */ v = (vftbl*) mem_alloc(sizeof(vftbl) + sizeof(methodptr) * - (vftbllength - 1) + sizeof(methodptr*) * - (interfacetablelength - (interfacetablelength > 0))); + (vftbllength - 1) + sizeof(methodptr*) * + (interfacetablelength - (interfacetablelength > 0))); v = (vftbl*) (((methodptr*) v) + (interfacetablelength - 1) * - (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; + + /* store interface index in vftbl */ + if (c->flags & ACC_INTERFACE) + v->baseval = -(c->index); /* copy virtual function table of super class */ for (i = 0; i < supervftbllength; i++) - v->table[i] = super->vftbl->table[i]; + v->table[i] = super->vftbl->table[i]; /* add method stubs into virtual function table */ @@ -1714,8 +2964,8 @@ foundvftblindex: ; methodinfo *m = &(c->methods[i]); if (!(m->flags & ACC_STATIC)) { v->table[m->vftblindex] = m->stubroutine; - } } + } /* compute instance size and offset of each field */ @@ -1723,33 +2973,34 @@ foundvftblindex: ; s4 dsize; fieldinfo *f = &(c->fields[i]); - if (!(f->flags & ACC_STATIC) ) { - dsize = desc_typesize (f->descriptor); - c->instancesize = ALIGN (c->instancesize, dsize); + if (!(f->flags & ACC_STATIC)) { + dsize = desc_typesize(f->descriptor); + c->instancesize = ALIGN(c->instancesize, dsize); f->offset = c->instancesize; c->instancesize += dsize; - } } + } /* initialize interfacetable and interfacevftbllength */ - v->interfacevftbllength = MNEW (s4, interfacetablelength); + v->interfacevftbllength = MNEW(s4, interfacetablelength); #ifdef STATISTICS - count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength; + if (opt_stat) + count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength; #endif for (i = 0; i < interfacetablelength; i++) { v->interfacevftbllength[i] = 0; v->interfacetable[-i] = NULL; - } + } /* add interfaces */ for (c2 = c; c2 != NULL; c2 = c2->super) for (i = 0; i < c2->interfacescount; i++) { - class_addinterface (c, c2->interfaces[i]); - } + class_addinterface(c, c2->interfaces[i]); + } /* add finalizer method (not for java.lang.Object) */ @@ -1763,20 +3014,24 @@ foundvftblindex: ; if (fidesc == NULL) fidesc = utf_fidesc; - fi = class_findmethod (c, finame, fidesc); + fi = class_findmethod(c, finame, fidesc); if (fi != NULL) { if (!(fi->flags & ACC_STATIC)) { c->finalizer = fi; - } } } + } /* final tasks */ - c->linked = true; + loader_compute_subclasses(c); + + if (linkverbose) + log_message_class("Linking done class: ", c); + + /* just return c to show that we didn't had a problem */ - list_remove (&unlinkedclasses, c); - list_addlast (&linkedclasses, c); + return c; } @@ -1786,47 +3041,49 @@ foundvftblindex: ; *******************************************************************************/ -static void class_freecpool (classinfo *c) +static void class_freecpool(classinfo *c) { u4 idx; 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; - case CONSTANT_Arraydescriptor: - freearraydescriptor (info); - 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; + } } } + } + + if (c->cptags) + MFREE(c->cptags, u1, c->cpcount); - MFREE (c -> cptags, u1, c -> cpcount); - MFREE (c -> cpinfos, voidptr, c -> cpcount); + if (c->cpinfos) + MFREE(c->cpinfos, voidptr, c->cpcount); } @@ -1836,48 +3093,55 @@ static void class_freecpool (classinfo *c) *******************************************************************************/ -static void class_free (classinfo *c) +void class_free(classinfo *c) { s4 i; vftbl *v; - class_freecpool (c); + 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])); -#ifndef USE_BOEHM - MFREE (c->fields, fieldinfo, c->fieldscount); -#endif + 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) + mem_free(v->arraydesc,sizeof(arraydescriptor)); + for (i = 0; i < v->interfacetablelength; i++) { - MFREE (v->interfacetable[-i], methodptr, v->interfacevftbllength[i]); - } - MFREE (v->interfacevftbllength, s4, v->interfacetablelength); + MFREE(v->interfacetable[-i], methodptr, v->interfacevftbllength[i]); + } + MFREE(v->interfacevftbllength, s4, v->interfacetablelength); i = sizeof(vftbl) + sizeof(methodptr) * (v->vftbllength - 1) + sizeof(methodptr*) * (v->interfacetablelength - (v->interfacetablelength > 0)); v = (vftbl*) (((methodptr*) v) - (v->interfacetablelength - 1) * (v->interfacetablelength > 1)); - mem_free (v, i); - } + mem_free(v, i); + } - if (c->innerclasscount) - MFREE (c->innerclass, innerclassinfo, c->innerclasscount); + if (c->innerclass) + MFREE(c->innerclass, innerclassinfo, c->innerclasscount); - if (c->classvftbl) - mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); + /* if (c->classvftbl) + mem_free(c->header.vftbl, sizeof(vftbl) + sizeof(methodptr)*(c->vftbl->vftbllength-1)); */ - FREE (c, classinfo); +/* GCFREE(c); */ } + /************************* Function: class_findfield *************************** Searches a 'classinfo' structure for a field having the given name and @@ -1885,8 +3149,7 @@ static void class_free (classinfo *c) *******************************************************************************/ - -fieldinfo *class_findfield (classinfo *c, utf *name, utf *desc) +fieldinfo *class_findfield(classinfo *c, utf *name, utf *desc) { s4 i; @@ -1895,30 +3158,191 @@ fieldinfo *class_findfield (classinfo *c, utf *name, utf *desc) return &(c->fields[i]); } - panic ("Can not find field given in CONSTANT_Fieldref"); + panic("Can not find field given in CONSTANT_Fieldref"); + + /* keep compiler happy */ + return NULL; +} + + +/****************** Function: class_resolvefield_int *************************** + + This is an internally used helper function. Do not use this directly. + + Tries to resolve a field having the given name and type. + If the field cannot be resolved, NULL is returned. + +*******************************************************************************/ + +static fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc) +{ + s4 i; + fieldinfo *fi; + + /* search for field in class c */ + for (i = 0; i < c->fieldscount; i++) { + if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc)) { + return &(c->fields[i]); + } + } + + /* try superinterfaces recursively */ + for (i = 0; i < c->interfacescount; ++i) { + fi = class_resolvefield_int(c->interfaces[i], name, desc); + if (fi) + return fi; + } + + /* try superclass */ + if (c->super) + return class_resolvefield_int(c->super, name, desc); + + /* not found */ return NULL; } +/********************* Function: class_resolvefield *************************** + + Resolves a reference from REFERER to a field with NAME and DESC in class C. + + If the field cannot be resolved the return value is NULL. If EXCEPT is + true *exceptionptr is set, too. + +*******************************************************************************/ + +fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc, + classinfo *referer, bool except) +{ + fieldinfo *fi; + + /* XXX resolve class c */ + /* XXX check access from REFERER to C */ + + fi = class_resolvefield_int(c, name, desc); + + if (!fi) { + if (except) + *exceptionptr = + new_exception_utfmessage(string_java_lang_NoSuchFieldError, + name); + + return NULL; + } + + /* XXX check access rights */ + + return fi; +} + + /************************* Function: class_findmethod ************************** Searches a 'classinfo' structure for a method having the given name and - type. + type and returns the index in the class info structure. If type is NULL, it is ignored. *******************************************************************************/ -methodinfo *class_findmethod (classinfo *c, utf *name, utf *desc) +s4 class_findmethodIndex(classinfo *c, utf *name, utf *desc) { s4 i; + for (i = 0; i < c->methodscount; i++) { + +/* utf_display_classname(c->name);printf("."); */ +/* utf_display(c->methods[i].name);printf("."); */ +/* utf_display(c->methods[i].descriptor); */ +/* printf("\n"); */ + if ((c->methods[i].name == name) && ((desc == NULL) || - (c->methods[i].descriptor == desc))) - return &(c->methods[i]); + (c->methods[i].descriptor == desc))) { + return i; } - return NULL; + } + + return -1; +} + + +/************************* Function: class_findmethod ************************** + + Searches a 'classinfo' structure for a method having the given name and + type. + If type is NULL, it is ignored. + +*******************************************************************************/ + +methodinfo *class_findmethod(classinfo *c, utf *name, utf *desc) +{ + s4 idx = class_findmethodIndex(c, name, desc); + + if (idx == -1) + return NULL; + + return &(c->methods[idx]); +} + + +/*********************** Function: class_fetchmethod ************************** + + like class_findmethod, but aborts with an error if the method is not found + +*******************************************************************************/ + +methodinfo *class_fetchmethod(classinfo *c, utf *name, utf *desc) +{ + methodinfo *mi; + + mi = class_findmethod(c, name, desc); + + if (!mi) { + log_plain("Class: "); if (c) log_plain_utf(c->name); log_nl(); + log_plain("Method: "); if (name) log_plain_utf(name); log_nl(); + log_plain("Descriptor: "); if (desc) log_plain_utf(desc); log_nl(); + panic("Method not found"); + } + + return mi; +} + + +/*********************** Function: class_findmethod_w************************** + + like class_findmethod, but logs a warning if the method is not found + +*******************************************************************************/ + +methodinfo *class_findmethod_w(classinfo *c, utf *name, utf *desc, char *from) +{ + methodinfo *mi; + mi = class_findmethod(c, name, desc); + + if (!mi) { + log_plain("Class: "); if (c) log_plain_utf(c->name); log_nl(); + log_plain("Method: "); if (name) log_plain_utf(name); log_nl(); + log_plain("Descriptor: "); if (desc) log_plain_utf(desc); log_nl(); + + if ( c->flags & ACC_PUBLIC ) log_plain(" PUBLIC "); + if ( c->flags & ACC_PRIVATE ) log_plain(" PRIVATE "); + if ( c->flags & ACC_PROTECTED ) log_plain(" PROTECTED "); + if ( c->flags & ACC_STATIC ) log_plain(" STATIC "); + if ( c->flags & ACC_FINAL ) log_plain(" FINAL "); + if ( c->flags & ACC_SYNCHRONIZED ) log_plain(" SYNCHRONIZED "); + if ( c->flags & ACC_VOLATILE ) log_plain(" VOLATILE "); + if ( c->flags & ACC_TRANSIENT ) log_plain(" TRANSIENT "); + if ( c->flags & ACC_NATIVE ) log_plain(" NATIVE "); + if ( c->flags & ACC_INTERFACE ) log_plain(" INTERFACE "); + if ( c->flags & ACC_ABSTRACT ) log_plain(" ABSTRACT "); + + log_plain(from); + log_plain(" : WARNING: Method not found");log_nl( ); + } + + return mi; } + /************************* Function: class_findmethod_approx ****************** like class_findmethod but ignores the return value when comparing the @@ -1926,11 +3350,11 @@ methodinfo *class_findmethod (classinfo *c, utf *name, utf *desc) *******************************************************************************/ -methodinfo *class_findmethod_approx (classinfo *c, utf *name, utf *desc) +methodinfo *class_findmethod_approx(classinfo *c, utf *name, utf *desc) { s4 i; - for (i = 0; i < c->methodscount; i++) + for (i = 0; i < c->methodscount; i++) { if (c->methods[i].name == name) { utf *meth_descr = c->methods[i].descriptor; @@ -1939,29 +3363,31 @@ methodinfo *class_findmethod_approx (classinfo *c, utf *name, utf *desc) return &(c->methods[i]); if (desc->blength <= meth_descr->blength) { - /* current position in utf text */ - char *desc_utf_ptr = desc->text; - char *meth_utf_ptr = meth_descr->text; - /* points behind utf strings */ - char *desc_end = utf_end(desc); - char *meth_end = utf_end(meth_descr); - char ch; - - /* compare argument types */ - while (desc_utf_ptrmethods[i]); /* all parameter types equal */ - } + /* current position in utf text */ + char *desc_utf_ptr = desc->text; + char *meth_utf_ptr = meth_descr->text; + /* points behind utf strings */ + char *desc_end = utf_end(desc); + char *meth_end = utf_end(meth_descr); + char ch; + + /* compare argument types */ + while (desc_utf_ptr < desc_end && meth_utf_ptr < meth_end) { + + if ((ch = *desc_utf_ptr++) != (*meth_utf_ptr++)) + break; /* no match */ + + if (ch == ')') + return &(c->methods[i]); /* all parameter types equal */ + } } } + } return NULL; } + /***************** Function: class_resolvemethod_approx *********************** Searches a class and every super class for a method (without paying @@ -1969,16 +3395,17 @@ methodinfo *class_findmethod_approx (classinfo *c, utf *name, utf *desc) *******************************************************************************/ -methodinfo *class_resolvemethod_approx (classinfo *c, utf *name, utf *desc) +methodinfo *class_resolvemethod_approx(classinfo *c, utf *name, utf *desc) { while (c) { /* search for method (ignore returntype) */ - methodinfo *m = class_findmethod_approx (c, name, desc); + methodinfo *m = class_findmethod_approx(c, name, desc); /* method found */ if (m) return m; /* search superclass */ c = c->super; - } + } + return NULL; } @@ -1989,18 +3416,165 @@ methodinfo *class_resolvemethod_approx (classinfo *c, utf *name, utf *desc) *******************************************************************************/ - -methodinfo *class_resolvemethod (classinfo *c, utf *name, utf *desc) +methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc) { + /*log_text("Trying to resolve a method"); + utf_display(c->name); + utf_display(name); + utf_display(desc);*/ + while (c) { - methodinfo *m = class_findmethod (c, name, desc); + /*log_text("Looking in:"); + utf_display(c->name);*/ + methodinfo *m = class_findmethod(c, name, desc); if (m) return m; /* search superclass */ c = c->super; - } + } + /*log_text("method not found:");*/ + + return NULL; +} + + +/****************** Function: class_resolveinterfacemethod_int **************** + + Internally used helper function. Do not use this directly. + +*******************************************************************************/ + +static +methodinfo *class_resolveinterfacemethod_int(classinfo *c, utf *name, utf *desc) +{ + methodinfo *mi; + int i; + + mi = class_findmethod(c,name,desc); + if (mi) + return mi; + + /* try the superinterfaces */ + for (i=0; iinterfacescount; ++i) { + mi = class_resolveinterfacemethod_int(c->interfaces[i],name,desc); + if (mi) + return mi; + } + + return NULL; +} + +/******************** Function: class_resolveinterfacemethod ****************** + + Resolves a reference from REFERER to a method with NAME and DESC in + interface C. + + If the method cannot be resolved the return value is NULL. If EXCEPT is + true *exceptionptr is set, too. + +*******************************************************************************/ + +methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc, + classinfo *referer, bool except) +{ + methodinfo *mi; + + /* XXX resolve class c */ + /* XXX check access from REFERER to C */ + + if (!(c->flags & ACC_INTERFACE)) { + if (except) + *exceptionptr = + new_exception(string_java_lang_IncompatibleClassChangeError); + + return NULL; + } + + mi = class_resolveinterfacemethod_int(c, name, desc); + + if (mi) + return mi; + + /* try class java.lang.Object */ + mi = class_findmethod(class_java_lang_Object, name, desc); + + if (mi) + return mi; + + if (except) + *exceptionptr = + new_exception_utfmessage(string_java_lang_NoSuchMethodError, name); + return NULL; } + + +/********************* Function: class_resolveclassmethod ********************* + + Resolves a reference from REFERER to a method with NAME and DESC in + class C. + + If the method cannot be resolved the return value is NULL. If EXCEPT is + true *exceptionptr is set, too. + +*******************************************************************************/ + +methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc, + classinfo *referer, bool except) +{ + classinfo *cls; + methodinfo *mi; + s4 i; + char msg[MAXLOGTEXT]; + + /* XXX resolve class c */ + /* XXX check access from REFERER to C */ + +/* if (c->flags & ACC_INTERFACE) { */ +/* if (except) */ +/* *exceptionptr = */ +/* new_exception(string_java_lang_IncompatibleClassChangeError); */ +/* return NULL; */ +/* } */ + + /* try class c and its superclasses */ + cls = c; + do { + mi = class_findmethod(cls, name, desc); + if (mi) + goto found; + } while ((cls = cls->super) != NULL); /* try the superclass */ + + /* try the superinterfaces */ + for (i = 0; i < c->interfacescount; ++i) { + mi = class_resolveinterfacemethod_int(c->interfaces[i], name, desc); + if (mi) + goto found; + } + if (except) { + utf_sprint(msg, c->name); + sprintf(msg + strlen(msg), "."); + utf_sprint(msg + strlen(msg), name); + utf_sprint(msg + strlen(msg), desc); + + *exceptionptr = + new_exception_message(string_java_lang_NoSuchMethodError, msg); + } + + return NULL; + + found: + if ((mi->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) { + if (except) + *exceptionptr = new_exception(string_java_lang_AbstractMethodError); + + return NULL; + } + + /* XXX check access rights */ + + return mi; +} /************************* Function: class_issubclass ************************** @@ -2009,17 +3583,16 @@ methodinfo *class_resolvemethod (classinfo *c, utf *name, utf *desc) *******************************************************************************/ -bool class_issubclass (classinfo *sub, classinfo *super) +bool class_issubclass(classinfo *sub, classinfo *super) { for (;;) { if (!sub) return false; - if (sub==super) return true; - sub = sub -> super; - } + if (sub == super) return true; + sub = sub->super; + } } - /****************** Initialization function for classes ****************** In Java, every class can have a static initialization function. This @@ -2028,121 +3601,315 @@ bool class_issubclass (classinfo *sub, classinfo *super) *******************************************************************************/ -#ifdef USE_THREADS -extern int blockInts; -#endif +static classinfo *class_init_intern(classinfo *c); + +classinfo *class_init(classinfo *c) +{ + classinfo *r; + + if (!makeinitializations) + return c; + + /* enter a monitor on the class */ + + builtin_monitorenter((java_objectheader *) c); + + /* maybe the class is already initalized or the current thread, which can + pass the monitor, is currently initalizing this class */ + + if (c->initialized || c->initializing) { + builtin_monitorexit((java_objectheader *) c); + + return c; + } -void class_init (classinfo *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; + + /* leave the monitor */ + + builtin_monitorexit((java_objectheader *) c); + + return r; +} + + +/* this function MUST NOT be called directly, because of thread + race conditions */ + +static classinfo *class_init_intern(classinfo *c) { - methodinfo *m; - java_objectheader *exceptionptr; + methodinfo *m; s4 i; +#if defined(USE_THREADS) && !defined(NATIVE_THREADS) int b; +#endif - if (!makeinitializations) - return; - if (c->initialized) - return; - c -> initialized = true; - -#ifdef STATISTICS - count_class_inits++; + if (!c->loaded) + if (!class_load(c)) + return NULL; + + if (!c->linked) + if (!class_link(c)) + return NULL; + +#if defined(STATISTICS) + if (opt_stat) + count_class_inits++; #endif - if (c->super) - class_init (c->super); - for (i=0; i < c->interfacescount; i++) - class_init(c->interfaces[i]); + /* 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->initialized) { + if (initverbose) { + char logtext[MAXLOGTEXT]; + sprintf(logtext, "Initialize super class "); + utf_sprint_classname(logtext + strlen(logtext), c->super->name); + sprintf(logtext + strlen(logtext), " from "); + utf_sprint_classname(logtext + strlen(logtext), c->name); + log_text(logtext); + } + + if (!class_init(c->super)) + return NULL; + } + } + + /* initialize interface classes */ + for (i = 0; i < c->interfacescount; i++) { + if (!c->interfaces[i]->loaded) + if (!class_load(c->interfaces[i])) + return NULL; + + if (!c->interfaces[i]->linked) + if (!class_link(c->interfaces[i])) + return NULL; + + if (!c->interfaces[i]->initialized) { + if (initverbose) { + char logtext[MAXLOGTEXT]; + sprintf(logtext, "Initialize interface class "); + utf_sprint_classname(logtext + strlen(logtext), c->interfaces[i]->name); + sprintf(logtext + strlen(logtext), " from "); + utf_sprint_classname(logtext + strlen(logtext), c->name); + log_text(logtext); + } + + if (!class_init(c->interfaces[i])) + return NULL; + } + } + + m = class_findmethod(c, utf_clinit, utf_fidesc); - m = class_findmethod (c, utf_clinit, utf_fidesc); if (!m) { if (initverbose) { - sprintf (logtext, "Class "); - utf_sprint (logtext+strlen(logtext), c->name); - sprintf (logtext+strlen(logtext), " has no initializer"); - dolog (); - } - return; + char logtext[MAXLOGTEXT]; + sprintf(logtext, "Class "); + utf_sprint_classname(logtext + strlen(logtext), c->name); + sprintf(logtext + strlen(logtext), " has no static class initializer"); + log_text(logtext); } - - if (! (m->flags & ACC_STATIC)) - panic ("Class initializer is not static!"); - - if (initverbose) { - sprintf (logtext, "Starting initializer for class: "); - utf_sprint (logtext+strlen(logtext), c->name); - dolog (); + + return c; } -#ifdef USE_THREADS + if (!(m->flags & ACC_STATIC)) + panic("Class initializer is not static!"); + + if (initverbose) + log_message_class("Starting static class initializer for class: ", c); + +#if defined(USE_THREADS) && !defined(NATIVE_THREADS) b = blockInts; blockInts = 0; #endif - exceptionptr = asm_calljavamethod (m, NULL,NULL,NULL,NULL); + /* now call the initializer */ + asm_calljavafunction(m, NULL, NULL, NULL, NULL); -#ifdef USE_THREADS +#if defined(USE_THREADS) && !defined(NATIVE_THREADS) assert(blockInts == 0); blockInts = b; #endif - if (exceptionptr) { - printf ("#### Initializer of "); - utf_display (c->name); - printf (" has thrown: "); - utf_display (exceptionptr->vftbl->class->name); - printf ("\n"); - fflush (stdout); + /* we have an exception or error */ + if (*exceptionptr) { + /* is this an exception, than wrap it */ + if (builtin_instanceof(*exceptionptr, class_java_lang_Exception)) { + java_objectheader *xptr; + java_objectheader *cause; + + /* class is NOT initialized */ + c->initialized = false; + + /* get the cause */ + cause = *exceptionptr; + + /* clear exception, because we are calling jit code again */ + *exceptionptr = NULL; + + /* wrap the exception */ + xptr = + new_exception_throwable(string_java_lang_ExceptionInInitializerError, + (java_lang_Throwable *) cause); + + /* XXX should we exit here? */ + if (*exceptionptr) + throw_exception(); + + /* set new exception */ + *exceptionptr = xptr; } - if (initverbose) { - sprintf (logtext, "Finished initializer for class: "); - utf_sprint (logtext+strlen(logtext), c->name); - dolog (); + return NULL; } - if (c->name == utf_systemclass) { - /* class java.lang.System requires explicit initialization */ - - if (initverbose) - printf ("#### Initializing class System"); + if (initverbose) + log_message_class("Finished static class initializer for class: ", c); - /* find initializing method */ - m = class_findmethod (c, - utf_initsystemclass, - utf_fidesc); + return c; +} - if (!m) { - /* no method found */ - log("initializeSystemClass failed"); - return; - } - #ifdef USE_THREADS - b = blockInts; - blockInts = 0; - #endif +/********* Function: find_class_method_constant *********/ + +int find_class_method_constant (classinfo *c, utf * c1, utf* m1, utf* d1) +{ + u4 i; + voidptr e; - exceptionptr = asm_calljavamethod (m, NULL,NULL,NULL,NULL); + for (i=0; icpcount; i++) { + + e = c -> cpinfos [i]; + if (e) { + + switch (c -> cptags [i]) { + case CONSTANT_Methodref: + { + constant_FMIref *fmi = e; + if ( (fmi->class->name == c1) + && (fmi->name == m1) + && (fmi->descriptor == d1)) { + + return i; + } + } + break; - #ifdef USE_THREADS - assert(blockInts == 0); - blockInts = b; - #endif + case CONSTANT_InterfaceMethodref: + { + constant_FMIref *fmi = e; + if ( (fmi->class->name == c1) + && (fmi->name == m1) + && (fmi->descriptor == d1)) { - if (exceptionptr) { - printf ("#### initializeSystemClass has thrown: "); - utf_display (exceptionptr->vftbl->class->name); - printf ("\n"); - fflush (stdout); + return i; + } + } + break; + } } } + + return -1; } +void class_showconstanti(classinfo *c, int ii) +{ + u4 i = ii; + voidptr e; + + e = c->cpinfos [i]; + printf ("#%d: ", (int) i); + if (e) { + switch (c->cptags [i]) { + case CONSTANT_Class: + printf("Classreference -> "); + utf_display(((classinfo*)e)->name); + break; + + case CONSTANT_Fieldref: + printf("Fieldref -> "); goto displayFMIi; + case CONSTANT_Methodref: + printf("Methodref -> "); goto displayFMIi; + case CONSTANT_InterfaceMethodref: + printf("InterfaceMethod -> "); goto displayFMIi; + displayFMIi: + { + constant_FMIref *fmi = e; + utf_display(fmi->class->name); + printf("."); + utf_display(fmi->name); + printf(" "); + utf_display(fmi->descriptor); + } + break; + case CONSTANT_String: + printf("String -> "); + utf_display(e); + break; + case CONSTANT_Integer: + printf("Integer -> %d", (int) (((constant_integer*)e)->value)); + break; + case CONSTANT_Float: + printf("Float -> %f", ((constant_float*)e)->value); + break; + case CONSTANT_Double: + printf("Double -> %f", ((constant_double*)e)->value); + break; + case CONSTANT_Long: + { + u8 v = ((constant_long*)e)->value; +#if U8_AVAILABLE + printf("Long -> %ld", (long int) v); +#else + printf("Long -> HI: %ld, LO: %ld\n", + (long int) v.high, (long int) v.low); +#endif + } + break; + case CONSTANT_NameAndType: + { + constant_nameandtype *cnt = e; + printf("NameAndType: "); + utf_display(cnt->name); + printf(" "); + utf_display(cnt->descriptor); + } + break; + case CONSTANT_Utf8: + printf("Utf8 -> "); + utf_display(e); + break; + default: + panic("Invalid type of ConstantPool-Entry"); + } + } + printf("\n"); +} -/********* Function: class_showconstantpool (debugging only) *********/ void class_showconstantpool (classinfo *c) { @@ -2158,78 +3925,72 @@ void class_showconstantpool (classinfo *c) if (e) { switch (c -> cptags [i]) { - case CONSTANT_Class: - printf ("Classreference -> "); - utf_display ( ((classinfo*)e) -> name ); - break; + case CONSTANT_Class: + printf ("Classreference -> "); + utf_display ( ((classinfo*)e) -> name ); + break; - case CONSTANT_Fieldref: - printf ("Fieldref -> "); goto displayFMI; - case CONSTANT_Methodref: - printf ("Methodref -> "); goto displayFMI; - case CONSTANT_InterfaceMethodref: - printf ("InterfaceMethod -> "); goto displayFMI; - displayFMI: - { + case CONSTANT_Fieldref: + printf ("Fieldref -> "); goto displayFMI; + case CONSTANT_Methodref: + printf ("Methodref -> "); goto displayFMI; + case CONSTANT_InterfaceMethodref: + printf ("InterfaceMethod -> "); goto displayFMI; + displayFMI: + { constant_FMIref *fmi = e; utf_display ( fmi->class->name ); printf ("."); utf_display ( fmi->name); printf (" "); utf_display ( fmi->descriptor ); - } - break; + } + break; - case CONSTANT_String: - printf ("String -> "); - utf_display (e); - break; - case CONSTANT_Integer: - printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) ); - break; - case CONSTANT_Float: - printf ("Float -> %f", ((constant_float*)e) -> value); - break; - case CONSTANT_Double: - printf ("Double -> %f", ((constant_double*)e) -> value); - break; - case CONSTANT_Long: - { + case CONSTANT_String: + printf ("String -> "); + utf_display (e); + break; + case CONSTANT_Integer: + printf ("Integer -> %d", (int) ( ((constant_integer*)e) -> value) ); + break; + case CONSTANT_Float: + printf ("Float -> %f", ((constant_float*)e) -> value); + break; + case CONSTANT_Double: + printf ("Double -> %f", ((constant_double*)e) -> value); + break; + case CONSTANT_Long: + { u8 v = ((constant_long*)e) -> value; #if U8_AVAILABLE printf ("Long -> %ld", (long int) v); #else printf ("Long -> HI: %ld, LO: %ld\n", - (long int) v.high, (long int) v.low); + (long int) v.high, (long int) v.low); #endif - } - break; - case CONSTANT_NameAndType: - { constant_nameandtype *cnt = e; - printf ("NameAndType: "); - utf_display (cnt->name); - printf (" "); - utf_display (cnt->descriptor); - } - break; - case CONSTANT_Utf8: - printf ("Utf8 -> "); - utf_display (e); - break; - case CONSTANT_Arraydescriptor: { - printf ("Arraydescriptor: "); - displayarraydescriptor (e); - } - break; - default: - panic ("Invalid type of ConstantPool-Entry"); } - + break; + case CONSTANT_NameAndType: + { + constant_nameandtype *cnt = e; + printf ("NameAndType: "); + utf_display (cnt->name); + printf (" "); + utf_display (cnt->descriptor); + } + break; + case CONSTANT_Utf8: + printf ("Utf8 -> "); + utf_display (e); + break; + default: + panic ("Invalid type of ConstantPool-Entry"); } + } printf ("\n"); - } - + } } @@ -2279,112 +4040,271 @@ void class_showmethods (classinfo *c) } - /******************************************************************************/ /******************* General functions for the class loader *******************/ /******************************************************************************/ -static int loader_inited = 0; - -/********************* Function: loader_load *********************************** +/**************** function: create_primitive_classes *************************** - Loads and links the class desired class and each class and interface - referenced by it. - Returns: a pointer to this class + create classes representing primitive types *******************************************************************************/ -classinfo *loader_load (utf *topname) -{ - classinfo *top; - classinfo *c; - long int starttime=0,stoptime=0; - - intsDisable(); /* schani */ - - if (getloadingtime) - starttime = getcputime(); +void create_primitive_classes() +{ + int i; - top = class_new (topname); + for (i = 0; i < PRIMITIVETYPE_COUNT; i++) { + /* create primitive class */ + classinfo *c = + class_new_intern(utf_new_char(primitivetype_table[i].name)); + c->classUsed = NOTUSED; /* not used initially CO-RT */ + c->impldBy = NULL; + + /* prevent loader from loading primitive class */ + c->loaded = true; + class_link(c); - /* load classes */ - while ( (c = list_first(&unloadedclasses)) ) { - if (!class_load (c)) { - list_remove (&unloadedclasses, c); - top=NULL; - } - } + primitivetype_table[i].class_primitive = c; - /* link classes */ - while ( (c = list_first(&unlinkedclasses)) ) { - class_link (c); + /* create class for wrapping the primitive type */ + c = class_new_intern(utf_new_char(primitivetype_table[i].wrapname)); + primitivetype_table[i].class_wrap = c; + primitivetype_table[i].class_wrap->classUsed = NOTUSED; /* not used initially CO-RT */ + primitivetype_table[i].class_wrap->impldBy = NULL; + + /* create the primitive array class */ + if (primitivetype_table[i].arrayname) { + c = class_new_intern(utf_new_char(primitivetype_table[i].arrayname)); + primitivetype_table[i].arrayclass = c; + c->loaded = true; + if (!c->linked) + class_link(c); + primitivetype_table[i].arrayvftbl = c->vftbl; } + } +} - if (loader_inited) - loader_compute_subclasses(); - /* measure time */ - if (getloadingtime) { - stoptime = getcputime(); - loadingtime += (stoptime-starttime); - } +/**************** function: class_primitive_from_sig *************************** + + return the primitive class indicated by the given signature character - intsRestore(); /* schani */ + If the descriptor does not indicate a valid primitive type the + return value is NULL. + +********************************************************************************/ - return top; +classinfo *class_primitive_from_sig(char sig) +{ + switch (sig) { + case 'I': return primitivetype_table[PRIMITIVETYPE_INT].class_primitive; + case 'J': return primitivetype_table[PRIMITIVETYPE_LONG].class_primitive; + case 'F': return primitivetype_table[PRIMITIVETYPE_FLOAT].class_primitive; + case 'D': return primitivetype_table[PRIMITIVETYPE_DOUBLE].class_primitive; + case 'B': return primitivetype_table[PRIMITIVETYPE_BYTE].class_primitive; + case 'C': return primitivetype_table[PRIMITIVETYPE_CHAR].class_primitive; + case 'S': return primitivetype_table[PRIMITIVETYPE_SHORT].class_primitive; + case 'Z': return primitivetype_table[PRIMITIVETYPE_BOOLEAN].class_primitive; + case 'V': return primitivetype_table[PRIMITIVETYPE_VOID].class_primitive; + } + return NULL; } +/****************** function: class_from_descriptor **************************** -/**************** function: create_primitive_classes *************************** + return the class indicated by the given descriptor - create classes representing primitive types + utf_ptr....first character of descriptor + end_ptr....first character after the end of the string + next.......if non-NULL, *next is set to the first character after + the descriptor. (Undefined if an error occurs.) -********************************************************************************/ + mode.......a combination (binary or) of the following flags: + (Flags marked with * are the default settings.) -void create_primitive_classes() -{ - int i; + What to do if a reference type descriptor is parsed successfully: - for (i=0;i super = class_java_lang_Object; - class_link (c); + switch (*start) { + case 'V': + if (mode & CLASSLOAD_NOVOID) + break; + /* FALLTHROUGH! */ + case 'I': + case 'J': + case 'F': + case 'D': + case 'B': + case 'C': + case 'S': + case 'Z': + return (mode & CLASSLOAD_NULLPRIMITIVE) + ? NULL + : class_primitive_from_sig(*start); + + case 'L': + start++; + utf_ptr--; + /* FALLTHROUGH! */ + case '[': + if (mode & CLASSLOAD_SKIP) return class_java_lang_Object; + name = utf_new(start, utf_ptr - start); + if (opt_eager) { + classinfo *tc; + + tc = class_new_intern(name); + class_load(tc); + list_addfirst(&unlinkedclasses, tc); + + return tc; + + } else { + return (mode & CLASSLOAD_LOAD) + ? class_load(class_new(name)) : class_new(name); /* XXX handle errors */ + } + } + } - primitivetype_table[i].class_primitive = c; + /* An error occurred */ + if (mode & CLASSLOAD_NOPANIC) + return NULL; - /* create class for wrapping the primitive type */ - primitivetype_table[i].class_wrap = - class_new( utf_new_char(primitivetype_table[i].wrapname) ); + log_plain("Invalid descriptor at beginning of '"); + log_plain_utf(utf_new(start, end_ptr - start)); + log_plain("'"); + log_nl(); + + panic("Invalid descriptor"); + + /* keep compiler happy */ + return NULL; +} + + +/******************* function: type_from_descriptor **************************** + + return the basic type indicated by the given descriptor + + This function parses a descriptor and returns its basic type as + TYPE_INT, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, TYPE_ADDRESS or TYPE_VOID. + + cls...if non-NULL the referenced variable is set to the classinfo * + returned by class_from_descriptor. + + For documentation of the arguments utf_ptr, end_ptr, next and mode + see class_from_descriptor. The only difference is that + type_from_descriptor always uses CLASSLOAD_PANIC. + +********************************************************************************/ + +int type_from_descriptor(classinfo **cls, char *utf_ptr, char *end_ptr, + char **next, int mode) +{ + classinfo *mycls; + if (!cls) cls = &mycls; + *cls = class_from_descriptor(utf_ptr, end_ptr, next, mode & (~CLASSLOAD_NOPANIC)); + switch (*utf_ptr) { + case 'B': + case 'C': + case 'I': + case 'S': + case 'Z': + return TYPE_INT; + case 'D': + return TYPE_DOUBLE; + case 'F': + return TYPE_FLOAT; + case 'J': + return TYPE_LONG; + case 'V': + return TYPE_VOID; } + return TYPE_ADDRESS; } -/***************** function: create_array_class ******************************** - create class representing an array +/*************** function: create_pseudo_classes ******************************* + + create pseudo classes used by the typechecker ********************************************************************************/ +static void create_pseudo_classes() +{ + /* pseudo class for Arraystubs (extends java.lang.Object) */ + + pseudo_class_Arraystub = class_new_intern(utf_new_char("$ARRAYSTUB$")); + pseudo_class_Arraystub->loaded = true; + pseudo_class_Arraystub->super = class_java_lang_Object; + pseudo_class_Arraystub->interfacescount = 2; + pseudo_class_Arraystub->interfaces = MNEW(classinfo*, 2); + pseudo_class_Arraystub->interfaces[0] = class_java_lang_Cloneable; + pseudo_class_Arraystub->interfaces[1] = class_java_io_Serializable; -classinfo *create_array_class(utf *u) -{ - classinfo *c = class_new (u); - /* prevent loader from loading the array class */ - list_remove (&unloadedclasses, c); - /* add to unlinked classes */ - list_addlast (&unlinkedclasses, c); - c -> super = class_java_lang_Object; - class_link(c); + class_link(pseudo_class_Arraystub); - return c; + pseudo_class_Arraystub_vftbl = pseudo_class_Arraystub->vftbl; + + /* pseudo class representing the null type */ + + pseudo_class_Null = class_new_intern(utf_new_char("$NULL$")); + pseudo_class_Null->loaded = true; + pseudo_class_Null->super = class_java_lang_Object; + class_link(pseudo_class_Null); + + /* pseudo class representing new uninitialized objects */ + + pseudo_class_New = class_new_intern(utf_new_char("$NEW$")); + pseudo_class_New->loaded = true; + pseudo_class_New->linked = true; + pseudo_class_New->super = class_java_lang_Object; +/* class_link(pseudo_class_New); */ } + /********************** Function: loader_init ********************************** Initializes all lists and loads all classes required for the system or the @@ -2392,199 +4312,117 @@ classinfo *create_array_class(utf *u) *******************************************************************************/ -void loader_init () +void loader_init(u1 *stackbottom) { - utf *string_class; interfaceindex = 0; - list_init (&unloadedclasses, OFFSET(classinfo, listnode) ); - list_init (&unlinkedclasses, OFFSET(classinfo, listnode) ); - list_init (&linkedclasses, OFFSET(classinfo, listnode) ); - /* 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_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"); - - /* create class for arrays */ - class_array = class_new ( utf_new_char ("The_Array_Class") ); - list_remove (&unloadedclasses, class_array); - - /* create class for strings, load it after class Object was loaded */ - string_class = utf_new_char ("java/lang/String"); - class_java_lang_String = class_new(string_class); - list_remove (&unloadedclasses, class_java_lang_String); - - class_java_lang_Object = - loader_load ( utf_new_char ("java/lang/Object") ); - - list_addlast(&unloadedclasses, class_java_lang_String); - - class_java_lang_String = - loader_load ( string_class ); - class_java_lang_ClassCastException = - loader_load ( utf_new_char ("java/lang/ClassCastException") ); - class_java_lang_NullPointerException = - loader_load ( utf_new_char ("java/lang/NullPointerException") ); - class_java_lang_ArrayIndexOutOfBoundsException = loader_load ( - utf_new_char ("java/lang/ArrayIndexOutOfBoundsException") ); - class_java_lang_NegativeArraySizeException = loader_load ( - utf_new_char ("java/lang/NegativeArraySizeException") ); - class_java_lang_OutOfMemoryError = loader_load ( - utf_new_char ("java/lang/OutOfMemoryError") ); - class_java_lang_ArrayStoreException = - loader_load ( utf_new_char ("java/lang/ArrayStoreException") ); - class_java_lang_ArithmeticException = - loader_load ( utf_new_char ("java/lang/ArithmeticException") ); - class_java_lang_ThreadDeath = /* schani */ - loader_load ( utf_new_char ("java/lang/ThreadDeath") ); - - /* link class for arrays */ - list_addlast (&unlinkedclasses, class_array); - class_array -> super = class_java_lang_Object; - class_link (class_array); - - /* correct vftbl-entries (retarded loading of class java/lang/String) */ - stringtable_update(); + utf_vmclassloader = utf_new_char("java/lang/VMClassLoader"); + utf_initialize = utf_new_char("initialize"); + utf_initializedesc = utf_new_char("(I)V"); + utf_vmclass = utf_new_char("java/lang/VMClass"); + utf_java_lang_Object= utf_new_char("java/lang/Object"); + array_packagename = utf_new_char(""); + utf_fillInStackTrace_name = utf_new_char("fillInStackTrace"); + utf_fillInStackTrace_desc = utf_new_char("()Ljava/lang/Throwable;"); + + /* create some important classes */ + /* These classes have to be created now because the classinfo + * pointers are used in the loading code. + */ + class_java_lang_Object = + class_new_intern(utf_java_lang_Object); + class_load(class_java_lang_Object); + class_link(class_java_lang_Object); + + class_java_lang_String = + class_new_intern(utf_new_char("java/lang/String")); + class_load(class_java_lang_String); + class_link(class_java_lang_String); + + class_java_lang_Cloneable = + class_new_intern(utf_new_char("java/lang/Cloneable")); + class_load(class_java_lang_Cloneable); + class_link(class_java_lang_Cloneable); + + class_java_io_Serializable = + class_new_intern(utf_new_char("java/io/Serializable")); + class_load(class_java_io_Serializable); + class_link(class_java_io_Serializable); /* create classes representing primitive types */ create_primitive_classes(); - - proto_java_lang_ClassCastException = - builtin_new(class_java_lang_ClassCastException); - heap_addreference ( (void**) &proto_java_lang_ClassCastException); - - proto_java_lang_NullPointerException = - builtin_new(class_java_lang_NullPointerException); - heap_addreference ( (void**) &proto_java_lang_NullPointerException); - - proto_java_lang_ArrayIndexOutOfBoundsException = - builtin_new(class_java_lang_ArrayIndexOutOfBoundsException); - heap_addreference ( (void**) &proto_java_lang_ArrayIndexOutOfBoundsException); - - proto_java_lang_NegativeArraySizeException = - builtin_new(class_java_lang_NegativeArraySizeException); - heap_addreference ( (void**) &proto_java_lang_NegativeArraySizeException); - - proto_java_lang_OutOfMemoryError = - builtin_new(class_java_lang_OutOfMemoryError); - heap_addreference ( (void**) &proto_java_lang_OutOfMemoryError); - - proto_java_lang_ArithmeticException = - builtin_new(class_java_lang_ArithmeticException); - heap_addreference ( (void**) &proto_java_lang_ArithmeticException); - - proto_java_lang_ArrayStoreException = - builtin_new(class_java_lang_ArrayStoreException); - heap_addreference ( (void**) &proto_java_lang_ArrayStoreException); - - proto_java_lang_ThreadDeath = /* schani */ - builtin_new(class_java_lang_ThreadDeath); - heap_addreference ( (void**) &proto_java_lang_ThreadDeath); - - loader_inited = 1; -} - - - - -/********************* Function: loader_initclasses **************************** - Initializes all loaded but uninitialized classes + /* create classes used by the typechecker */ + create_pseudo_classes(); -*******************************************************************************/ - -void loader_initclasses () -{ - classinfo *c; - - intsDisable(); /* schani */ - - if (makeinitializations) { - c = list_first (&linkedclasses); - while (c) { - class_init (c); - c = list_next (&linkedclasses, c); - } - } + /* correct vftbl-entries (retarded loading of class java/lang/String) */ + stringtable_update(); - intsRestore(); /* schani */ +#if defined(USE_THREADS) + if (stackbottom != 0) + initLocks(); +#endif } -static s4 classvalue; -static void loader_compute_class_values (classinfo *c) +static void loader_compute_class_values(classinfo *c) { classinfo *subs; c->vftbl->baseval = ++classvalue; + subs = c->sub; while (subs != NULL) { loader_compute_class_values(subs); subs = subs->nextsub; - } - c->vftbl->diffval = classvalue - c->vftbl->baseval; -/* - { - int i; - for (i = 0; i < c->index; i++) - printf(" "); - printf("%3d %3d ", (int) c->vftbl->baseval, c->vftbl->diffval); - utf_display(c->name); - printf("\n"); } -*/ + + c->vftbl->diffval = classvalue - c->vftbl->baseval; } -void loader_compute_subclasses () +void loader_compute_subclasses(classinfo *c) { - classinfo *c; - - intsDisable(); /* schani */ +#if defined(USE_THREADS) && !defined(NATIVE_THREADS) + intsDisable(); +#endif - c = list_first (&linkedclasses); - while (c) { - if (!(c->flags & ACC_INTERFACE)) { - c->nextsub = 0; - c->sub = 0; - } - c = list_next (&linkedclasses, c); - } + if (!(c->flags & ACC_INTERFACE)) { + c->nextsub = 0; + c->sub = 0; + } - c = list_first (&linkedclasses); - while (c) { - if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) { - c->nextsub = c->super->sub; - c->super->sub = c; - } - c = list_next (&linkedclasses, c); - } + if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) { + c->nextsub = c->super->sub; + c->super->sub = c; + } classvalue = 0; - loader_compute_class_values(class_java_lang_Object); - - intsRestore(); /* schani */ -} - + /* this is the java.lang.Object special case */ + if (!class_java_lang_Object) { + loader_compute_class_values(c); -/******************** function classloader_buffer ****************************** - - sets buffer for reading classdata - -*******************************************************************************/ + } else { + loader_compute_class_values(class_java_lang_Object); + } -void classload_buffer(u1 *buf, int len) -{ - classbuffer = buf; - classbuffer_size = len; - classbuf_pos = buf - 1; +#if defined(USE_THREADS) && !defined(NATIVE_THREADS) + intsRestore(); +#endif } @@ -2594,22 +4432,19 @@ void classload_buffer(u1 *buf, int len) *******************************************************************************/ -void loader_close () +void loader_close() { 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; } + } } @@ -2625,4 +4460,3 @@ void loader_close () * tab-width: 4 * End: */ -