Contact: cacao@complang.tuwien.ac.at
Authors: Reinhard Grafl
+
Changes: Andreas Krall
Roman Obermaiser
Mark Probst
- Edwin Steiner
+ Edwin Steiner
+ Christian Thalinger
- $Id: loader.c 1058 2004-05-16 13:14:41Z twisti $
+ $Id: loader.c 1237 2004-06-30 19:54:59Z twisti $
*/
#include <sys/stat.h>
#include "global.h"
#include "loader.h"
-#include "main.h"
+#include "options.h"
#include "native.h"
#include "tables.h"
#include "builtin.h"
-#include "jit.h"
+#include "jit/jit.h"
#include "asmpart.h"
+#include "options.h"
+#include "statistics.h"
#include "toolbox/memory.h"
-#include "toolbox/loging.h"
+#include "toolbox/logging.h"
#include "threads/thread.h"
#include "threads/locks.h"
#include "nat/java_lang_Throwable.h"
/* global variables ***********************************************************/
-int count_class_infos = 0; /* variables for measurements */
-int count_const_pool_len = 0;
-int count_vftbl_len = 0;
-int count_all_methods = 0;
-int count_vmcode_len = 0;
-int count_extable_len = 0;
-int count_class_loads = 0;
-int count_class_inits = 0;
-
static s4 interfaceindex; /* sequential numbering of interfaces */
static s4 classvalue;
/* utf-symbols for pointer comparison of frequently used strings */
-static utf *utf_innerclasses; /* InnerClasses */
-static utf *utf_constantvalue; /* ConstantValue */
-static utf *utf_code; /* Code */
-static utf *utf_exceptions; /* Exceptions */
-static utf *utf_linenumbertable; /* LineNumberTable */
-static utf *utf_sourcefile; /*SourceFile*/
-static utf *utf_finalize; /* finalize */
-static utf *utf_fidesc; /* ()V changed */
-static utf *utf_init; /* <init> */
-static utf *utf_clinit; /* <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_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; /* <init> */
+static utf *utf_clinit; /* <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 */
-
-
+static utf *utf_java_lang_Object; /* java/lang/Object */
+utf *utf_fillInStackTrace_name;
+utf *utf_fillInStackTrace_desc;
utf* clinit_desc(){
return utf_fidesc;
classinfo *class_java_lang_Object;
classinfo *class_java_lang_String;
-
-classinfo *class_java_lang_Throwable;
classinfo *class_java_lang_Cloneable;
classinfo *class_java_io_Serializable;
static char *classpath = ""; /* searchpath for classfiles */
-/* assert that at least <len> bytes are left to read */
-/* <len> is limited to the range of non-negative s4 values */
+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);
+
+ sprintf(cfmessage + strlen(cfmessage), ")");
+
+ return new_exception_message(string_java_lang_ClassFormatError, cfmessage);
+}
+
+
+/* check_classbuffer_size ******************************************************
+
+ assert that at least <len> bytes are left to read
+ <len> 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 *****************************************************************
-#define ASSERT_LEFT(cb, len) \
- do { \
- if (((s4) (len)) < 0 || \
- (((cb)->data + (cb)->size) - (cb)->pos - 1) < (len)) { \
- char message[MAXLOGTEXT]; \
- utf_sprint_classname(message, (cb)->class->name); \
- sprintf(message + strlen(message), " (Truncated class file)"); \
- *exceptionptr = \
- new_exception_message(string_java_lang_ClassFormatError, \
- message); \
- throw_exception_exit(); \
- } \
- } while (0)
+ transfer block of classfile data into a buffer
+*******************************************************************************/
-/* 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;
+}
-#define suck_nbytes(buffer, cb, len) \
- do { \
- ASSERT_LEFT((cb), (len)); \
- memcpy((buffer), (cb)->pos + 1, (len)); \
- (cb)->pos += (len); \
- } while (0)
+/* skip_nbytes ****************************************************************
-/* skip block of classfile data */
+ skip block of classfile data
-#define skip_nbytes(cb, len) \
- do { \
- ASSERT_LEFT((cb), (len)); \
- (cb)->pos += (len); \
- } while (0)
+*******************************************************************************/
+
+inline void skip_nbytes(classbuffer *cb, s4 len)
+{
+ cb->pos += len;
+}
inline u1 suck_u1(classbuffer *cb)
{
- ASSERT_LEFT(cb, 1);
return *++(cb->pos);
}
buffer[3 - i] = suck_u1(cb);
memcpy((u1*) (&f), buffer, 4);
-#else
+#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;
}
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;
}
panic("path length >= MAXFILENAME in suck_init");
if (!filename)
- filename = MNEW(char*, CLASSPATH_MAXFILENAME);
+ filename = MNEW(char, CLASSPATH_MAXFILENAME);
strncpy(filename, start, filenamelen);
filename[filenamelen + 1] = '\0';
else
start = end;
- if (filename)
- MFREE(filename, char*, CLASSPATH_MAXFILENAME);
+ if (filename) {
+ MFREE(filename, char, CLASSPATH_MAXFILENAME);
+ filename = NULL;
+ }
}
}
for (cpi = classpath_entries; cpi != 0; cpi = cpi->filepath.next) {
#if defined(USE_ZLIB)
- unz_file_info file_info;
if (cpi->filepath.type == CLASSPATH_ARCHIVE) {
cacao_entry_s *ce;
unz_s *s;
utf_ptr = c->name->text;
while (utf_ptr < utf_end(c->name)) {
- PANICIF (filenamelen >= CLASSPATH_MAXFILENAME, "Filename too long");
+ if (filenamelen >= CLASSPATH_MAXFILENAME) {
+ *exceptionptr =
+ new_exception_message(string_java_lang_InternalError,
+ "Filename too long");
+
+ /* XXX should we exit in such a case? */
+ throw_exception_exit();
+ }
+
ch = *utf_ptr++;
if ((ch <= ' ' || ch > 'z') && (ch != '/')) /* invalid character */
ch = '?';
} else {
MFREE(cb->data, u1, cb->size);
-FREE(cb, classbuffer);
+ FREE(cb, classbuffer);
log_text("Error while unzipping");
}
} else log_text("Error while opening file in archive");
/* determine size of classfile */
/* dolog("File: %s",filename); */
-
err = stat(currPos->filepath.filename, &buffer);
if (!err) { /* read classfile data */
cb->pos = cb->data - 1;
fread(cb->data, 1, cb->size, classfile);
fclose(classfile);
+
return cb;
}
}
}
-/************************* Function: skipattribute *****************************
-
- skips a (1) 'attribute' structure in the class file
-
-*******************************************************************************/
-
-static void skipattribute(classbuffer *cb)
-{
- u4 len;
- suck_u2(cb);
- len = suck_u4(cb);
- skip_nbytes(cb, len);
-}
-
-
/********************** Function: skipattributebody ****************************
skips an attribute after the 16 bit reference to attribute_name has already
*******************************************************************************/
-static void skipattributebody(classbuffer *cb)
+static bool skipattributebody(classbuffer *cb)
{
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;
}
*******************************************************************************/
-static void skipattributes(classbuffer *cb, u4 num)
+static bool skipattributes(classbuffer *cb, u4 num)
{
u4 i;
- for (i = 0; i < num; i++)
- skipattribute(cb);
+ 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;
}
*******************************************************************************/
-static void attribute_load(classbuffer *cb, classinfo *c, u4 num)
+static bool attribute_load(classbuffer *cb, classinfo *c, u4 num)
{
u4 i, j;
for (i = 0; i < num; i++) {
+ utf *aname;
+
/* retrieve attribute name */
- utf *aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
+ 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(cb);
+ suck_u4(cb);
+
/* number of records */
c->innerclasscount = suck_u2(cb);
+
+ if (!check_classbuffer_size(cb, (2 + 2 + 2 + 2) * c->innerclasscount))
+ return false;
+
/* allocate memory for innerclass structure */
c->innerclass = MNEW(innerclassinfo, c->innerclasscount);
for (j = 0; j < c->innerclasscount; j++) {
- /* The innerclass structure contains a class with an encoded name,
- its defining scope, its simple name and a bitmask of the access flags.
- If an inner class is not a member, its outer_class is NULL,
- if a class is anonymous, its name is NULL. */
+ /* The innerclass structure contains a class with an encoded
+ name, its defining scope, its simple name and a bitmask of
+ the access flags. If an inner class is not a member, its
+ outer_class is NULL, if a class is anonymous, its name is
+ NULL. */
innerclassinfo *info = c->innerclass + j;
- info->inner_class = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); /* CONSTANT_Class_info index */
- info->outer_class = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class); /* CONSTANT_Class_info index */
- info->name = innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8); /* CONSTANT_Utf8_info index */
- info->flags = suck_u2(cb); /* access_flags bitmask */
+ info->inner_class =
+ innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class);
+ info->outer_class =
+ innerclass_getconstant(c, suck_u2(cb), CONSTANT_Class);
+ info->name =
+ innerclass_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
+ info->flags = suck_u2(cb);
}
- } else if (aname==utf_sourcefile) {
+
+ } else if (aname == utf_sourcefile) {
+ if (!check_classbuffer_size(cb, 4 + 2))
+ return false;
+
suck_u4(cb);
- /*log_text("source file attribute found");*/
c->sourcefile = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
+
} else {
/* unknown attribute */
- skipattributebody(cb);
+ if (!skipattributebody(cb))
+ return false;
}
}
+
+ return true;
}
*******************************************************************************/
-static int checkmethoddescriptor (utf *d)
+static int checkmethoddescriptor(classinfo *c, utf *descriptor)
{
- char *utf_ptr = d->text; /* current position in utf text */
- char *end_pos = utf_end(d); /* points behind utf string */
- int argcount = 0; /* number of arguments */
+ char *utf_ptr; /* current position in utf text */
+ char *end_pos; /* points behind utf string */
+ s4 argcount = 0; /* number of arguments */
+
+ utf_ptr = descriptor->text;
+ end_pos = utf_end(descriptor);
/* method descriptor must start with parenthesis */
- if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+ if (utf_ptr == end_pos || *utf_ptr++ != '(')
+ panic ("Missing '(' in method descriptor");
/* check arguments */
while (utf_ptr != end_pos && *utf_ptr != ')') {
| CLASSLOAD_NOVOID);
}
- if (utf_ptr == end_pos) panic("Missing ')' in method descriptor");
+ if (utf_ptr == end_pos)
+ panic("Missing ')' in method descriptor");
+
utf_ptr++; /* skip ')' */
- class_from_descriptor(utf_ptr,end_pos,NULL,
- CLASSLOAD_NEW
- | CLASSLOAD_NULLPRIMITIVE
- | CLASSLOAD_CHECKEND);
+ class_from_descriptor(utf_ptr,
+ end_pos,
+ NULL,
+ CLASSLOAD_NEW |
+ CLASSLOAD_NULLPRIMITIVE |
+ CLASSLOAD_CHECKEND);
+
+ if (argcount > 255) {
+ *exceptionptr =
+ new_classformaterror(c, "Too many arguments in signature");
- if (argcount > 255)
- panic("Invalid method descriptor: too many arguments");
+ return 0;
+ }
return argcount;
/******************************************************************************/
-/************************ Function: field_load *********************************
+/* field_load ******************************************************************
- Load everything about a class field from the class file and fill a
- 'fieldinfo' structure. For static fields, space in the data segment is
- allocated.
+ Load everything about a class field from the class file and fill a
+ 'fieldinfo' structure. For static fields, space in the data segment is
+ allocated.
*******************************************************************************/
#define field_load_NOVALUE 0xffffffff /* must be bigger than any u2 value! */
-static void field_load(classbuffer *cb, classinfo *c, fieldinfo *f)
+static bool field_load(classbuffer *cb, classinfo *c, fieldinfo *f)
{
u4 attrnum,i;
u4 jtype;
- u4 pindex = field_load_NOVALUE; /* constantvalue_index */
+ u4 pindex = field_load_NOVALUE; /* constantvalue_index */
- f->flags = suck_u2(cb); /* ACC flags */
- f->name = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); /* name of field */
- f->descriptor = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8); /* JavaVM descriptor */
+ if (!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 */
/* 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");
}
/* check descriptor */
- checkfielddescriptor(f->descriptor->text,utf_end(f->descriptor));
+ checkfielddescriptor(f->descriptor->text, utf_end(f->descriptor));
}
- f->type = jtype = desc_to_type(f->descriptor); /* data type */
- f->offset = 0; /* offset from start of object */
+ f->type = jtype = desc_to_type(f->descriptor); /* data type */
+ f->offset = 0; /* offset from start of object */
f->class = c;
f->xta = NULL;
switch (f->type) {
- case TYPE_INT: f->value.i = 0; break;
- case TYPE_FLOAT: f->value.f = 0.0; break;
- case TYPE_DOUBLE: f->value.d = 0.0; break;
- case TYPE_ADDRESS: f->value.a = NULL; break;
+ case TYPE_INT: f->value.i = 0; break;
+ case TYPE_FLOAT: f->value.f = 0.0; break;
+ case TYPE_DOUBLE: f->value.d = 0.0; break;
+ case TYPE_ADDRESS: f->value.a = NULL; break;
case TYPE_LONG:
#if U8_AVAILABLE
f->value.l = 0; break;
}
/* read attributes */
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
attrnum = suck_u2(cb);
for (i = 0; i < attrnum; i++) {
utf *aname;
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
if (aname != utf_constantvalue) {
/* unknown attribute */
- skipattributebody(cb);
+ if (!skipattributebody(cb))
+ return false;
} else {
/* constant value attribute */
-
if (pindex != field_load_NOVALUE)
panic("Field has more than one ConstantValue attribute");
+ if (!check_classbuffer_size(cb, 4 + 2))
+ return false;
+
/* check attribute length */
if (suck_u4(cb) != 2)
panic("ConstantValue attribute has invalid length");
}
}
}
+
+ /* everything was ok */
+
+ return true;
}
/********************** function: field_free **********************************/
-static void field_free (fieldinfo *f)
+static void field_free(fieldinfo *f)
{
/* empty */
}
/******************************************************************************/
-/************************* 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(classbuffer *cb, classinfo *c, methodinfo *m)
+static bool method_load(classbuffer *cb, classinfo *c, methodinfo *m)
{
- u4 attrnum, i, e;
- int argcount;
-
+ s4 argcount;
+ s4 i, j;
+ u4 attrnum;
+ u4 codeattrnum;
+
#ifdef STATISTICS
- count_all_methods++;
+ if (opt_stat)
+ count_all_methods++;
#endif
- m->thrownexceptionscount=0;
- m->linenumbercount=0;
- m->linenumbers=0;
+
+ m->thrownexceptionscount = 0;
+ m->linenumbercount = 0;
+ m->linenumbers = 0;
m->class = c;
+ m->nativelyoverloaded = false;
+ if (!check_classbuffer_size(cb, 2 + 2 + 2))
+ return false;
+
m->flags = suck_u2(cb);
m->name = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
+ m->descriptor = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
if (opt_verify) {
if (!is_valid_name_utf(m->name))
panic("Method with invalid name");
+
if (m->name->text[0] == '<'
&& m->name != utf_init && m->name != utf_clinit)
panic("Method with invalid special name");
}
- m->descriptor = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
- argcount = checkmethoddescriptor(m->descriptor);
- if ((m->flags & ACC_STATIC) == 0)
+ argcount = checkmethoddescriptor(c, m->descriptor);
+
+ if (!(m->flags & ACC_STATIC))
argcount++; /* count the 'this' argument */
if (opt_verify) {
if (argcount > 255)
- panic("Method has more than 255 arguments");
+ 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)) != 0)
- panic("Abstract method has invalid flags set");
+ 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)
}
m->jcode = NULL;
+ m->basicblockcount = 0;
+ m->basicblocks = NULL;
+ m->basicblockindex = NULL;
+ m->instructioncount = 0;
+ m->instructions = NULL;
+ m->stackcount = 0;
+ m->stack = NULL;
m->exceptiontable = NULL;
- m->entrypoint = NULL;
- m->mcode = NULL;
+ m->registerdata = NULL;
m->stubroutine = NULL;
+ m->mcode = NULL;
+ m->entrypoint = NULL;
m->methodUsed = NOTUSED;
m->monoPoly = MONO;
m->subRedefs = 0;
}
}
+ if (!check_classbuffer_size(cb, 2))
+ return false;
attrnum = suck_u2(cb);
for (i = 0; i < attrnum; i++) {
utf *aname;
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
if (aname != utf_code) {
if (aname == utf_exceptions) {
- u2 exceptionCount;
- u2 exceptionID;
+ s4 j;
+
+ if (!check_classbuffer_size(cb, 4 + 2))
+ return false;
+
suck_u4(cb); /*length*/
- exceptionCount=suck_u2(cb);
- m->thrownexceptionscount=exceptionCount;
- m->thrownexceptions=MNEW(classinfo*,exceptionCount);
- for (exceptionID=0;exceptionID<exceptionCount;exceptionID++) {
- (m->thrownexceptions)[exceptionID]=class_getconstant(c,suck_u2(cb),CONSTANT_Class);
+ m->thrownexceptionscount = suck_u2(cb);
+
+ if (!check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
+ return false;
+
+ m->thrownexceptions = MNEW(classinfo*, m->thrownexceptionscount);
+
+ for (j = 0; j < m->thrownexceptionscount; j++) {
+ (m->thrownexceptions)[j] =
+ class_getconstant(c, suck_u2(cb), CONSTANT_Class);
}
+
+ } else {
+ if (!skipattributebody(cb))
+ return false;
}
- else
- skipattributebody(cb);
} else {
- u4 codelen;
- if ((m->flags & (ACC_ABSTRACT | ACC_NATIVE)) != 0)
- panic("Code attribute for native or abstract method");
+ if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
+ *exceptionptr =
+ new_classformaterror(c,
+ "Code attribute in native or abstract methods");
+
+ return false;
+ }
- if (m->jcode)
- panic("Method has more than one Code attribute");
+ if (m->jcode) {
+ *exceptionptr =
+ new_classformaterror(c, "Multiple Code attributes");
+
+ return false;
+ }
+
+ if (!check_classbuffer_size(cb, 4 + 2 + 2))
+ return false;
suck_u4(cb);
m->maxstack = suck_u2(cb);
m->maxlocals = suck_u2(cb);
- if (m->maxlocals < argcount)
- panic("max_locals is smaller than the number of arguments");
+
+ if (m->maxlocals < argcount) {
+ *exceptionptr =
+ new_classformaterror(c, "Arguments can't fit into locals");
+
+ return false;
+ }
- codelen = suck_u4(cb);
+ if (!check_classbuffer_size(cb, 4))
+ return false;
+
+ m->jcodelength = suck_u4(cb);
- if (codelen == 0)
+ if (m->jcodelength == 0)
panic("bytecode has zero length");
- if (codelen > 65536)
- panic("bytecode too long");
+ 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->jcodelength = codelen;
m->jcode = MNEW(u1, m->jcodelength);
suck_nbytes(m->jcode, cb, m->jcodelength);
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
m->exceptiontablelength = suck_u2(cb);
- m->exceptiontable =
- MNEW(exceptiontable, m->exceptiontablelength);
-#ifdef STATISTICS
- count_vmcode_len += m->jcodelength + 18;
- count_extable_len += 8 * m->exceptiontablelength;
+ 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(cb);
- m->exceptiontable[e].endpc = suck_u2(cb);
- m->exceptiontable[e].handlerpc = suck_u2(cb);
+ m->exceptiontable[j].startpc = suck_u2(cb);
+ m->exceptiontable[j].endpc = suck_u2(cb);
+ m->exceptiontable[j].handlerpc = suck_u2(cb);
idx = suck_u2(cb);
if (!idx) {
- m->exceptiontable[e].catchtype = NULL;
+ m->exceptiontable[j].catchtype = NULL;
} else {
- m->exceptiontable[e].catchtype =
+ m->exceptiontable[j].catchtype =
class_getconstant(c, idx, CONSTANT_Class);
}
- }
- {
- u2 codeattrnum;
- for (codeattrnum=suck_u2(cb);codeattrnum>0;codeattrnum--) {
- utf * caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
- if (caname==utf_linenumbertable) {
- u2 lncid;
- /*log_text("LineNumberTable found");*/
- suck_u4(cb);
- m->linenumbercount=suck_u2(cb);
- /*printf("length:%d\n",m->linenumbercount);*/
- m->linenumbers=MNEW(lineinfo,m->linenumbercount);
- for (lncid=0;lncid<m->linenumbercount;lncid++) {
- m->linenumbers[lncid].start_pc=suck_u2(cb);
- m->linenumbers[lncid].line_number=suck_u2(cb);
- }
- codeattrnum--;
- skipattributes(cb, codeattrnum);
- break;
- } else skipattributebody(cb);
+ }
+
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
+ codeattrnum = suck_u2(cb);
+
+ for (; codeattrnum > 0; codeattrnum--) {
+ utf *caname;
+
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
+ caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8);
+
+ if (caname == utf_linenumbertable) {
+ u2 lncid;
+
+ if (!check_classbuffer_size(cb, 4 + 2))
+ return false;
+
+ suck_u4(cb);
+ m->linenumbercount = suck_u2(cb);
+
+ if (!check_classbuffer_size(cb,
+ (2 + 2) * m->linenumbercount))
+ return false;
+
+ m->linenumbers = MNEW(lineinfo, m->linenumbercount);
- }
+ for (lncid = 0; lncid < m->linenumbercount; lncid++) {
+ m->linenumbers[lncid].start_pc = suck_u2(cb);
+ m->linenumbers[lncid].line_number = suck_u2(cb);
+ }
+ codeattrnum--;
+
+ if (!skipattributes(cb, codeattrnum))
+ return false;
+
+ break;
+ } else {
+ if (!skipattributebody(cb))
+ return false;
+ }
}
}
}
- if (!m->jcode && (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) == 0)
- panic("Method missing Code attribute");
+ if (!m->jcode && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
+ *exceptionptr = new_classformaterror(c, "Missing Code attribute");
+
+ return false;
+ }
+
+ /* everything was ok */
+
+ return true;
}
*******************************************************************************/
-static void class_loadcpool(classbuffer *cb, classinfo *c)
+static bool class_loadcpool(classbuffer *cb, classinfo *c)
{
/* The following structures are used to save information which cannot be
forward_nameandtype *forward_nameandtypes = NULL;
forward_fieldmethint *forward_fieldmethints = NULL;
+ u4 cpcount;
+ u1 *cptags;
+ voidptr *cpinfos;
+
/* number of entries in the constant_pool table plus one */
- u4 cpcount = c->cpcount = suck_u2(cb);
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
+ cpcount = c->cpcount = suck_u2(cb);
/* allocate memory */
- u1 *cptags = c->cptags = MNEW(u1, cpcount);
- voidptr *cpinfos = c->cpinfos = MNEW(voidptr, cpcount);
+ cptags = c->cptags = MNEW(u1, cpcount);
+ cpinfos = c->cpinfos = MNEW(voidptr, cpcount);
if (!cpcount)
panic("Invalid constant_pool_count (0)");
-#ifdef STATISTICS
- count_const_pool_len += (sizeof(voidptr) + 1) * cpcount;
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_const_pool_len += (sizeof(voidptr) + 1) * cpcount;
#endif
/* initialize constantpool */
idx = 1;
while (idx < cpcount) {
+ u4 t;
+
/* get constant type */
- u4 t = suck_u1(cb);
+ if (!check_classbuffer_size(cb, 1))
+ return false;
+
+ t = suck_u1(cb);
switch (t) {
- case CONSTANT_Class: {
- forward_class *nfc = DNEW(forward_class);
+ case CONSTANT_Class: {
+ forward_class *nfc = DNEW(forward_class);
- nfc -> next = forward_classes;
- forward_classes = nfc;
+ nfc->next = forward_classes;
+ forward_classes = nfc;
- nfc -> thisindex = idx;
- /* reference to CONSTANT_NameAndType */
- nfc -> name_index = suck_u2(cb);
+ nfc->thisindex = idx;
+ /* reference to CONSTANT_NameAndType */
+ if (!check_classbuffer_size(cb, 2))
+ return false;
- idx++;
- break;
- }
+ 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(cb);
- /* name and descriptor of the field or method */
- nff -> nameandtype_index = suck_u2(cb);
-
- 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(cb);
+ 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(cb);
- /* reference to CONSTANT_Utf8_info containing field or method descriptor */
- nfn -> sig_index = suck_u2(cb);
+ 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(cb);
- 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(cb);
- 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(cb);
- cptags [idx] = CONSTANT_Long;
- cpinfos [idx] = cl;
- idx += 2;
- if (idx > cpcount)
- panic("Long constant exceeds constant pool");
- 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(cb);
- cptags [idx] = CONSTANT_Double;
- cpinfos [idx] = cd;
- idx += 2;
- if (idx > cpcount)
- panic("Double constant exceeds constant pool");
- 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(cb);
- cptags [idx] = CONSTANT_Utf8;
- /* validate the string */
- ASSERT_LEFT(cb, length);
- 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_int(cb->pos + 1, length);
+ case CONSTANT_Utf8: {
+ u4 length;
- /* skip bytes of the string */
- skip_nbytes(cb, length);
- idx++;
- break;
- }
+ /* number of bytes in the bytes array (not string-length) */
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
+ length = suck_u2(cb);
+ cptags[idx] = CONSTANT_Utf8;
+
+ /* validate the string */
+ if (!check_classbuffer_size(cb, length))
+ return false;
+
+ if (opt_verify &&
+ !is_valid_utf(cb->pos + 1, cb->pos + 1 + length)) {
+ dolog("Invalid UTF-8 string (constant pool index %d)",idx);
+ panic("Invalid UTF-8 string");
+ }
+ /* insert utf-string into the utf-symboltable */
+ cpinfos[idx] = utf_new_intern(cb->pos + 1, length);
+
+ /* skip bytes of the string (buffer size check above) */
+ skip_nbytes(cb, length);
+ idx++;
+ break;
+ }
- default:
- error ("Unkown constant type: %d",(int) t);
-
- } /* end switch */
-
- } /* end while */
-
+ 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);
+ class_getconstant(c, forward_classes->name_index, CONSTANT_Utf8);
if (opt_verify && !is_valid_name_utf(name))
panic("Class reference with invalid name");
- cptags [forward_classes -> thisindex] = CONSTANT_Class;
+ cptags[forward_classes->thisindex] = CONSTANT_Class;
/* retrieve class from class-table */
- cpinfos [forward_classes -> thisindex] = class_new_int (name);
+ if (opt_eager) {
+ classinfo *tc;
+ tc = class_new_intern(name);
- forward_classes = forward_classes -> next;
-
+ 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);
+ 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 */
panic("NameAndType with invalid special name");
}
- cptags [forward_nameandtypes -> thisindex] = CONSTANT_NameAndType;
- cpinfos [forward_nameandtypes -> thisindex] = cn;
+ cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType;
+ cpinfos[forward_nameandtypes->thisindex] = cn;
- forward_nameandtypes = forward_nameandtypes -> next;
- }
-
+ forward_nameandtypes = forward_nameandtypes->next;
+ }
- while (forward_fieldmethints) {
+ while (forward_fieldmethints) {
constant_nameandtype *nat;
constant_FMIref *fmi = NEW(constant_FMIref);
-#ifdef STATISTICS
- count_const_pool_len += sizeof(constant_FMIref);
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_const_pool_len += sizeof(constant_FMIref);
#endif
/* resolve simple name and descriptor */
nat = class_getconstant(c,
switch (forward_fieldmethints->tag) {
case CONSTANT_Fieldref: /* check validity of descriptor */
- checkfielddescriptor(fmi->descriptor->text,utf_end(fmi->descriptor));
+ checkfielddescriptor(fmi->descriptor->text,
+ utf_end(fmi->descriptor));
break;
- case CONSTANT_InterfaceMethodref:
+ case CONSTANT_InterfaceMethodref:
case CONSTANT_Methodref: /* check validity of descriptor */
- checkmethoddescriptor(fmi->descriptor);
+ checkmethoddescriptor(c, fmi->descriptor);
break;
}
forward_fieldmethints = forward_fieldmethints->next;
}
-/* class_showconstantpool(c); */
-
dump_release(dumpsize);
+
+ /* everything was ok */
+
+ return true;
}
if ((cb = suck_start(c)) == NULL) {
/* this means, the classpath was not set properly */
- if (c->name == utf_java_lang_Object) {
- printf("Exception in thread \"main\" java.lang.NoClassDefFoundError: java/lang/Object\n");
- exit(1);
- }
+ 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,
r = class_load_intern(cb);
/* if return value is NULL, we had a problem and the class is not loaded */
- if (!r)
+ if (!r) {
c->loaded = false;
+ /* now free the allocated memory, otherwise we could ran into a DOS */
+ class_remove(c);
+ }
+
/* free memory */
suck_stop(cb);
classinfo *c;
u4 i;
u4 mi, ma;
- s4 classdata_left;
+/* s4 classdata_left; */
+ char msg[MAXLOGTEXT]; /* maybe we get an exception */
/* get the classbuffer's class */
c = cb->class;
if (c->loaded)
return c;
-#ifdef STATISTICS
- count_class_loads++;
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_class_loads++;
#endif
/* output for debugging purposes */
- if (loadverbose) {
- char logtext[MAXLOGTEXT];
- sprintf(logtext, "Loading class: ");
- utf_sprint_classname(logtext + strlen(logtext), c->name);
- log_text(logtext);
- }
+ if (loadverbose)
+ log_message_class("Loading class: ", c);
/* class is somewhat loaded */
c->loaded = true;
+ if (!check_classbuffer_size(cb, 4 + 2 + 2))
+ return NULL;
+
/* check signature */
if (suck_u4(cb) != MAGIC) {
- char logtext[MAXLOGTEXT];
- utf_sprint_classname(logtext, c->name);
- sprintf(logtext + strlen(logtext), " (Bad magic number)");
-
- *exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- logtext);
+ *exceptionptr = new_classformaterror(c, "Bad magic number");
return NULL;
}
mi = suck_u2(cb);
ma = suck_u2(cb);
- if (ma != MAJOR_VERSION && (ma != MAJOR_VERSION + 1 || mi != 0)) {
- char logtext[MAXLOGTEXT];
- utf_sprint_classname(logtext, c->name);
- sprintf(logtext + strlen(logtext),
- " (Unsupported major.minor version %d.%d)", ma, mi);
-
+ if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) {
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- logtext);
+ new_classformaterror(c,
+ "Unsupported major.minor version %d.%d",
+ ma, mi);
return NULL;
}
- class_loadcpool(cb, c);
+ if (!class_loadcpool(cb, c))
+ return NULL;
+
/*JOWENN*/
c->erroneous_state = 0;
c->initializing_thread = 0;
c->impldBy = NULL;
/* ACC flags */
- c->flags = suck_u2(cb);
+ if (!check_classbuffer_size(cb, 2))
+ return NULL;
+
+ c->flags = suck_u2(cb);
/*if (!(c->flags & ACC_PUBLIC)) { log_text("CLASS NOT PUBLIC"); } JOWENN*/
/* check ACC flags consistency */
- if ((c->flags & ACC_INTERFACE) != 0) {
- if ((c->flags & ACC_ABSTRACT) == 0) {
+ 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)) != 0)
- panic("Interface class has invalid flags");
- if ((c->flags & (ACC_SUPER)) != 0)
+
+ 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 ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL))
- panic("Class is declared both abstract and final");
+
+ if (!check_classbuffer_size(cb, 2 + 2))
+ return NULL;
/* this class */
i = suck_u2(cb);
if (class_getconstant(c, i, CONSTANT_Class) != c) {
- char message[MAXLOGTEXT];
- utf_sprint(message, c->name);
- sprintf(message + strlen(message), " (wrong name: ");
- utf_sprint(message + strlen(message),
+ 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(message + strlen(message), ")");
+ sprintf(msg + strlen(msg), ")");
*exceptionptr =
- new_exception_message(string_java_lang_NoClassDefFoundError,
- message);
+ new_exception_message(string_java_lang_NoClassDefFoundError, msg);
return NULL;
}
c->super = class_getconstant(c, i, CONSTANT_Class);
/* java.lang.Object may not have a super class. */
- if (c->name == utf_java_lang_Object)
- panic("java.lang.Object with super class");
+ if (c->name == utf_java_lang_Object) {
+ *exceptionptr =
+ new_exception_message(string_java_lang_ClassFormatError,
+ "java.lang.Object with superclass");
- /* Interfaces must have j.l.O as super class. */
+ return NULL;
+ }
+
+ /* Interfaces must have java.lang.Object as super class. */
if ((c->flags & ACC_INTERFACE) &&
c->super->name != utf_java_lang_Object) {
- panic("Interface with super class other than java.lang.Object");
+ *exceptionptr =
+ new_exception_message(string_java_lang_ClassFormatError,
+ "Interfaces must have java.lang.Object as superclass");
+
+ return NULL;
}
} else {
c->super = NULL;
/* This is only allowed for java.lang.Object. */
- if (c->name != utf_java_lang_Object)
- panic("Class (not java.lang.Object) without super class");
+ if (c->name != utf_java_lang_Object) {
+ *exceptionptr = new_classformaterror(c, "Bad superclass index");
+
+ return NULL;
+ }
+
}
/* retrieve interfaces */
+ if (!check_classbuffer_size(cb, 2))
+ return NULL;
+
c->interfacescount = suck_u2(cb);
+
+ if (!check_classbuffer_size(cb, 2 * c->interfacescount))
+ return NULL;
+
c->interfaces = MNEW(classinfo*, c->interfacescount);
for (i = 0; i < c->interfacescount; i++) {
- c->interfaces[i] =
- class_getconstant(c, suck_u2(cb), CONSTANT_Class);
+ c->interfaces[i] = class_getconstant(c, suck_u2(cb), CONSTANT_Class);
}
/* load fields */
- c->fieldscount = suck_u2(cb);
+ 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++) {
- field_load(cb, c, &(c->fields[i]));
+ if (!field_load(cb, c, &(c->fields[i])))
+ return NULL;
}
/* load methods */
+ if (!check_classbuffer_size(cb, 2))
+ return NULL;
+
c->methodscount = suck_u2(cb);
- c->methods = MNEW(methodinfo, c->methodscount);
+ c->methods = GCNEW(methodinfo, c->methodscount);
+/* c->methods = MNEW(methodinfo, c->methodscount); */
for (i = 0; i < c->methodscount; i++) {
- method_load(cb, c, &(c->methods[i]));
+ if (!method_load(cb, c, &(c->methods[i])))
+ return NULL;
}
/* Check if all fields and methods can be uniquely
/* 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]) != 0) {
+ index = ((((size_t) fi->name) +
+ ((size_t) fi->descriptor)) >> shift) % hashlen;
+
+ if ((old = hashtab[index])) {
old--;
- /* dolog("HASHHIT %d --> %d",index,old); */
next[i] = old;
do {
- /* dolog("HASHCHECK %d",old); */
if (c->fields[old].name == fi->name &&
c->fields[old].descriptor == fi->descriptor) {
- dolog("Duplicate field (%d,%d):",i,old);
- log_utf(fi->name); log_utf(fi->descriptor);
- panic("Fields with same name and descriptor");
+ *exceptionptr =
+ new_classformaterror(c,
+ "Repetitive field name/signature");
+
+ return NULL;
}
- } while ((old = next[old]) != 0);
+ } while ((old = next[old]));
}
- /* else dolog("HASHLUCKY"); */
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]) != 0) {
+ index = ((((size_t) mi->name) +
+ ((size_t) mi->descriptor)) >> shift) % hashlen;
+
+ if ((old = hashtab[index])) {
old--;
- /* dolog("HASHHIT %d --> %d",index,old); */
next[i] = old;
do {
- /* dolog("HASHCHECK %d",old); */
if (c->methods[old].name == mi->name &&
c->methods[old].descriptor == mi->descriptor) {
- dolog("Duplicate method (%d,%d):",i,old);
- log_utf(mi->name); log_utf(mi->descriptor);
- panic("Methods with same name and descriptor");
+ *exceptionptr =
+ new_classformaterror(c,
+ "Repetitive method name/signature");
+
+ return NULL;
}
- } while ((old = next[old]) != 0);
+ } while ((old = next[old]));
}
- /* else dolog("HASHLUCKY"); */
hashtab[index] = i + 1;
}
- MFREE(hashtab,u2,(hashlen + len));
+ MFREE(hashtab, u2, (hashlen + len));
}
-#ifdef STATISTICS
- count_class_infos += sizeof(classinfo*) * c->interfacescount;
- count_class_infos += sizeof(fieldinfo) * c->fieldscount;
- count_class_infos += sizeof(methodinfo) * c->methodscount;
+#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(cb, c, suck_u2(cb));
+ if (!check_classbuffer_size(cb, 2))
+ return NULL;
+
+ if (!attribute_load(cb, c, suck_u2(cb)))
+ return NULL;
#if 0
/* XXX TWISTI is this still in the JVM spec? SUN and IBM don't complain about it */
}
#endif
+ if (loadverbose)
+ log_message_class("Loading done class: ", c);
+
return 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;
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; j<ic->methodscount; 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]);
/* Check the component type */
switch (c->name->text[1]) {
- case '[':
- /* c is an array of arrays. We have to create the component class. */
- comp = class_new_int(utf_new_int(c->name->text + 1,namelen - 1));
- break;
+ case '[':
+ /* c is an array of arrays. We have to create the component class. */
+ if (opt_eager) {
+ comp = class_new_intern(utf_new_intern(c->name->text + 1,
+ namelen - 1));
+ class_load(comp);
+ list_addfirst(&unlinkedclasses, comp);
- case 'L':
- /* c is an array of objects. */
- if (namelen < 4 || c->name->text[namelen - 1] != ';')
- panic("Invalid array class name");
- comp = class_new_int(utf_new_int(c->name->text + 2,namelen - 3));
- break;
+ } else {
+ comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1));
+ }
+ break;
+
+ case 'L':
+ /* c is an array of objects. */
+ if (namelen < 4 || c->name->text[namelen - 1] != ';')
+ panic("Invalid array class name");
+
+ if (opt_eager) {
+ comp = class_new_intern(utf_new_intern(c->name->text + 2,
+ namelen - 3));
+ class_load(comp);
+ list_addfirst(&unlinkedclasses, comp);
+
+ } else {
+ comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3));
+ }
+ break;
}
/* Setup the array class */
c->interfacescount = 2;
c->interfaces = MNEW(classinfo*, 2);
- c->interfaces[0] = class_new(utf_new_char("java/lang/Cloneable"));
- c->interfaces[1] = class_new(utf_new_char("java/io/Serializable"));
+
+ if (opt_eager) {
+ classinfo *tc;
+
+ tc = class_new_intern(utf_new_char("java/lang/Cloneable"));
+ class_load(tc);
+ list_addfirst(&unlinkedclasses, tc);
+ c->interfaces[0] = tc;
+
+ tc = class_new_intern(utf_new_char("java/io/Serializable"));
+ class_load(tc);
+ list_addfirst(&unlinkedclasses, tc);
+ c->interfaces[1] = tc;
+
+ } else {
+ c->interfaces[0] = class_new(utf_new_char("java/lang/Cloneable"));
+ c->interfaces[1] = class_new(utf_new_char("java/io/Serializable"));
+ }
c->methodscount = 1;
c->methods = MNEW(methodinfo, c->methodscount);
static arraydescriptor *class_link_array(classinfo *c)
{
classinfo *comp = NULL;
- int namelen = c->name->blength;
+ s4 namelen = c->name->blength;
arraydescriptor *desc;
vftbl *compvftbl;
switch (c->name->text[1]) {
case '[':
/* c is an array of arrays. */
- comp = class_get(utf_new_int(c->name->text + 1, namelen - 1));
- if (!comp) panic("Could not find component array class.");
+/* 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_int(c->name->text + 2, namelen - 3));
- if (!comp) panic("Could not find component class.");
+/* 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;
}
/* c is an array of references */
desc->arraytype = ARRAYTYPE_OBJECT;
desc->componentsize = sizeof(void*);
- desc->dataoffset = OFFSET(java_objectarray,data);
+ desc->dataoffset = OFFSET(java_objectarray, data);
compvftbl = comp->vftbl;
if (!compvftbl)
static classinfo *class_link_intern(classinfo *c);
-void class_link(classinfo *c)
+classinfo *class_link(classinfo *c)
{
classinfo *r;
s8 starttime;
#endif
#endif
- return;
+ return c;
}
/* measure time */
intsRestore();
#endif
#endif
+
+ return r;
}
if (c->linked)
return c;
- if (linkverbose) {
- char logtext[MAXLOGTEXT];
- sprintf(logtext, "Linking class: ");
- utf_sprint_classname(logtext + strlen(logtext), c->name);
- log_text(logtext);
- }
+ if (linkverbose)
+ log_message_class("Linking class: ", c);
/* ok, this class is somewhat linked */
c->linked = true;
}
if (!ic->loaded)
- class_load(ic);
+ if (!class_load(ic))
+ return NULL;
if (!ic->linked)
- class_link(ic);
+ if (!class_link(ic))
+ return NULL;
if (!(ic->flags & ACC_INTERFACE)) {
dolog("Specified interface is not declared as interface:");
}
if (!super->loaded)
- class_load(super);
+ if (!class_load(super))
+ return NULL;
if (!super->linked)
- class_link(super);
+ if (!class_link(super))
+ return NULL;
if (super->flags & ACC_INTERFACE)
panic("Interface specified as super class");
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)
}
#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 */
v = (vftbl*) (((methodptr*) v) + (interfacetablelength - 1) *
(interfacetablelength > 1));
c->header.vftbl = c->vftbl = v;
+/* utf_display_classname(c->name);printf(", c->header.vftbl=%p\n", c->header.vftbl); */
v->class = c;
v->vftbllength = vftbllength;
v->interfacetablelength = interfacetablelength;
v->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++) {
loader_compute_subclasses(c);
- /* just return c to show that we don't had a problem */
+ if (linkverbose)
+ log_message_class("Linking done class: ", c);
+
+ /* just return c to show that we didn't had a problem */
return c;
}
*******************************************************************************/
-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;
- }
+ 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);
}
*******************************************************************************/
-static void class_free(classinfo *c)
+void class_free(classinfo *c)
{
s4 i;
vftbl *v;
class_freecpool(c);
- MFREE(c->interfaces, classinfo*, c->interfacescount);
+ if (c->interfaces)
+ MFREE(c->interfaces, classinfo*, c->interfacescount);
- for (i = 0; i < c->fieldscount; i++)
- field_free(&(c->fields[i]));
+ if (c->fields) {
+ for (i = 0; i < c->fieldscount; i++)
+ field_free(&(c->fields[i]));
+/* MFREE(c->fields, fieldinfo, c->fieldscount); */
+ }
- for (i = 0; i < c->methodscount; i++)
- method_free(&(c->methods[i]));
- MFREE(c->methods, methodinfo, c->methodscount);
+ if (c->methods) {
+ for (i = 0; i < c->methodscount; i++)
+ method_free(&(c->methods[i]));
+/* MFREE(c->methods, methodinfo, c->methodscount); */
+ }
if ((v = c->vftbl) != NULL) {
if (v->arraydesc)
mem_free(v, i);
}
- if (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)); */
- GCFREE(c);
+/* GCFREE(c); */
}
if (!fi) {
if (except)
- *exceptionptr = new_exception("java/lang/NoSuchFieldError");
+ *exceptionptr =
+ new_exception_utfmessage(string_java_lang_NoSuchFieldError,
+ name);
+
return NULL;
}
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 i;
methodinfo *class_resolvemethod(classinfo *c, utf *name, utf *desc)
{
+ /*log_text("Trying to resolve a method");
+ utf_display(c->name);
+ utf_display(name);
+ utf_display(desc);*/
+
while (c) {
+ /*log_text("Looking in:");
+ utf_display(c->name);*/
methodinfo *m = class_findmethod(c, name, desc);
if (m) return m;
/* search superclass */
c = c->super;
}
+ /*log_text("method not found:");*/
return NULL;
}
/* XXX resolve class c */
/* XXX check access from REFERER to C */
- if ((c->flags & ACC_INTERFACE) == 0) {
+ if (!(c->flags & ACC_INTERFACE)) {
if (except)
- *exceptionptr = new_exception("java/lang/IncompatibleClassChangeError");
+ *exceptionptr =
+ new_exception(string_java_lang_IncompatibleClassChangeError);
+
return NULL;
}
return mi;
/* try class java.lang.Object */
- mi = class_findmethod(class_java_lang_Object,name,desc);
+ mi = class_findmethod(class_java_lang_Object, name, desc);
if (mi)
return mi;
if (except)
- *exceptionptr = new_exception_utfmessage("java/lang/NoSuchMethodError",
- name);
+ *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
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) != 0) {
- if (except)
- *exceptionptr =
- new_exception("java/lang/IncompatibleClassChangeError");
- return NULL;
- }
+/* if (c->flags & ACC_INTERFACE) { */
+/* if (except) */
+/* *exceptionptr = */
+/* new_exception(string_java_lang_IncompatibleClassChangeError); */
+/* return NULL; */
+/* } */
/* try class c and its superclasses */
cls = c;
goto found;
}
- if (except)
- *exceptionptr = new_exception_utfmessage("java/lang/NoSuchMethodError",
- name);
+ 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) != 0 && (c->flags & ACC_ABSTRACT) == 0) {
+ if ((mi->flags & ACC_ABSTRACT) && !(c->flags & ACC_ABSTRACT)) {
if (except)
- *exceptionptr = new_exception("java/lang/AbstractMethodError");
+ *exceptionptr = new_exception(string_java_lang_AbstractMethodError);
+
return NULL;
}
*******************************************************************************/
+static classinfo *class_init_intern(classinfo *c);
+
classinfo *class_init(classinfo *c)
{
- methodinfo *m;
- s4 i;
-#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
- int b;
-#endif
+ classinfo *r;
if (!makeinitializations)
return c;
- if (c->initialized)
+ /* 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;
+ }
+
+ /* this initalizing run begins NOW */
+ c->initializing = true;
+
+ /* call the internal function */
+ r = class_init_intern(c);
- /* class is somewhat initialized */
- c->initialized = true;
+ /* 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 <clinit>
+ race conditions */
+
+static classinfo *class_init_intern(classinfo *c)
+{
+ methodinfo *m;
+ s4 i;
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
+ int b;
+#endif
if (!c->loaded)
- class_load(c);
+ if (!class_load(c))
+ return NULL;
if (!c->linked)
- class_link(c);
-
-#ifdef STATISTICS
+ if (!class_link(c))
+ return NULL;
- count_class_inits++;
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_class_inits++;
#endif
/* initialize super class */
if (c->super) {
if (!c->super->loaded)
- class_load(c->super);
+ if (!class_load(c->super))
+ return NULL;
if (!c->super->linked)
- class_link(c->super);
+ if (!class_link(c->super))
+ return NULL;
if (!c->super->initialized) {
if (initverbose) {
log_text(logtext);
}
- (void) class_init(c->super);
+ if (!class_init(c->super))
+ return NULL;
}
}
/* initialize interface classes */
for (i = 0; i < c->interfacescount; i++) {
if (!c->interfaces[i]->loaded)
- class_load(c->interfaces[i]);
+ if (!class_load(c->interfaces[i]))
+ return NULL;
if (!c->interfaces[i]->linked)
- class_link(c->interfaces[i]);
+ if (!class_link(c->interfaces[i]))
+ return NULL;
if (!c->interfaces[i]->initialized) {
if (initverbose) {
log_text(logtext);
}
- (void) class_init(c->interfaces[i]);
+ if (!class_init(c->interfaces[i]))
+ return NULL;
}
}
if (!(m->flags & ACC_STATIC))
panic("Class initializer is not static!");
- if (initverbose) {
- char logtext[MAXLOGTEXT];
- sprintf(logtext, "Starting static class initializer for class: ");
- utf_sprint_classname(logtext + strlen(logtext), c->name);
- log_text(logtext);
- }
+ if (initverbose)
+ log_message_class("Starting static class initializer for class: ", c);
#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
b = blockInts;
blockInts = b;
#endif
- /* we have an exception */
+ /* we have an exception or error */
if (*exceptionptr) {
- java_objectheader *xptr;
- java_objectheader *cause;
+ /* 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;
+ /* class is NOT initialized */
+ c->initialized = false;
- /* get the cause */
- cause = *exceptionptr;
+ /* get the cause */
+ cause = *exceptionptr;
- /* clear exception, because we are calling jit code again */
- *exceptionptr = NULL;
+ /* clear exception, because we are calling jit code again */
+ *exceptionptr = NULL;
- /* wrap the exception */
- xptr = new_exception_throwable("java/lang/ExceptionInInitializerError",
- (java_lang_Throwable *) cause);
+ /* wrap the exception */
+ xptr =
+ new_exception_throwable(string_java_lang_ExceptionInInitializerError,
+ (java_lang_Throwable *) cause);
- if (*exceptionptr) {
- panic("problem");
- }
+ /* XXX should we exit here? */
+ if (*exceptionptr)
+ throw_exception();
- /* set new exception */
- *exceptionptr = xptr;
+ /* set new exception */
+ *exceptionptr = xptr;
+ }
return NULL;
}
- if (initverbose) {
- char logtext[MAXLOGTEXT];
- sprintf(logtext, "Finished static class initializer for class: ");
- utf_sprint_classname(logtext + strlen(logtext), c->name);
- log_text(logtext);
- }
+ if (initverbose)
+ log_message_class("Finished static class initializer for class: ", c);
return c;
}
for (i = 0; i < PRIMITIVETYPE_COUNT; i++) {
/* create primitive class */
- classinfo *c = class_new_int(utf_new_char(primitivetype_table[i].name));
+ classinfo *c =
+ class_new_intern(utf_new_char(primitivetype_table[i].name));
c->classUsed = NOTUSED; /* not used initially CO-RT */
c->impldBy = NULL;
primitivetype_table[i].class_primitive = c;
/* create class for wrapping the primitive type */
- c = class_new_int(utf_new_char(primitivetype_table[i].wrapname));
+ c = class_new_intern(utf_new_char(primitivetype_table[i].wrapname));
primitivetype_table[i].class_wrap = c;
primitivetype_table[i].class_wrap->classUsed = NOTUSED; /* not used initially CO-RT */
primitivetype_table[i].class_wrap->impldBy = NULL;
/* create the primitive array class */
if (primitivetype_table[i].arrayname) {
- c = class_new_int(utf_new_char(primitivetype_table[i].arrayname));
+ c = class_new_intern(utf_new_char(primitivetype_table[i].arrayname));
primitivetype_table[i].arrayclass = c;
c->loaded = true;
if (!c->linked)
* CLASSLOAD_PANIC....abort execution with an error message
CLASSLOAD_NOPANIC..return NULL on error
-********************************************************************************/
+*******************************************************************************/
classinfo *class_from_descriptor(char *utf_ptr, char *end_ptr,
char **next, int mode)
case '[':
if (mode & CLASSLOAD_SKIP) return class_java_lang_Object;
name = utf_new(start, utf_ptr - start);
- return (mode & CLASSLOAD_LOAD)
- ? class_load(class_new(name)) : class_new(name); /* XXX handle errors */
+ if (opt_eager) {
+ classinfo *tc;
+
+ tc = class_new_intern(name);
+ class_load(tc);
+ list_addfirst(&unlinkedclasses, tc);
+
+ return tc;
+
+ } else {
+ return (mode & CLASSLOAD_LOAD)
+ ? class_load(class_new(name)) : class_new(name); /* XXX handle errors */
+ }
}
}
{
/* pseudo class for Arraystubs (extends java.lang.Object) */
- pseudo_class_Arraystub = class_new_int(utf_new_char("$ARRAYSTUB$"));
-/* list_remove(&unloadedclasses, pseudo_class_Arraystub); */
+ 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;
-/* list_addlast(&unlinkedclasses, pseudo_class_Arraystub); */
class_link(pseudo_class_Arraystub);
pseudo_class_Arraystub_vftbl = pseudo_class_Arraystub->vftbl;
/* pseudo class representing the null type */
- pseudo_class_Null = class_new_int(utf_new_char("$NULL$"));
-/* list_remove(&unloadedclasses, pseudo_class_Null); */
+ pseudo_class_Null = class_new_intern(utf_new_char("$NULL$"));
pseudo_class_Null->loaded = true;
-
pseudo_class_Null->super = class_java_lang_Object;
-
-/* list_addlast(&unlinkedclasses, pseudo_class_Null); */
class_link(pseudo_class_Null);
/* pseudo class representing new uninitialized objects */
- pseudo_class_New = class_new_int(utf_new_char("$NEW$"));
-/* list_remove(&unloadedclasses, pseudo_class_New); */
+ 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;
-
-/* list_addlast(&unlinkedclasses, pseudo_class_New); */
- class_link(pseudo_class_New);
+/* class_link(pseudo_class_New); */
}
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("<the array package>");
+ utf_fillInStackTrace_name = utf_new_char("fillInStackTrace");
+ utf_fillInStackTrace_desc = utf_new_char("()Ljava/lang/Throwable;");
/* create some important classes */
/* These classes have to be created now because the classinfo
* pointers are used in the loading code.
*/
class_java_lang_Object =
- class_new_int(utf_java_lang_Object);
+ class_new_intern(utf_java_lang_Object);
class_load(class_java_lang_Object);
class_link(class_java_lang_Object);
class_java_lang_String =
- class_new_int(utf_new_char("java/lang/String"));
+ class_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_int(utf_new_char("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_int(utf_new_char("java/io/Serializable"));
+ class_new_intern(utf_new_char("java/io/Serializable"));
class_load(class_java_io_Serializable);
class_link(class_java_io_Serializable);
- class_java_lang_Throwable =
- class_new(utf_new_char("java/lang/Throwable"));
- class_load(class_java_lang_Throwable);
- class_link(class_java_lang_Throwable);
-
/* create classes representing primitive types */
create_primitive_classes();
classvalue = 0;
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- cast_lock();
-#endif
-
/* this is the java.lang.Object special case */
if (!class_java_lang_Object) {
loader_compute_class_values(c);
loader_compute_class_values(class_java_lang_Object);
}
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- cast_unlock();
-#endif
-
#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
intsRestore();
#endif
void loader_close()
{
-/* classinfo *c; */
+ classinfo *c;
+ s4 slot;
-/* while ((c = list_first(&unloadedclasses))) { */
-/* list_remove(&unloadedclasses, c); */
-/* class_free(c); */
-/* } */
-/* while ((c = list_first(&unlinkedclasses))) { */
-/* list_remove(&unlinkedclasses, c); */
-/* class_free(c); */
-/* } */
-/* while ((c = list_first(&linkedclasses))) { */
-/* list_remove(&linkedclasses, c); */
-/* class_free(c); */
-/* } */
+ for (slot = 0; slot < class_hash.size; slot++) {
+ c = class_hash.ptr[slot];
+
+ while (c) {
+ class_free(c);
+ c = c->hashlink;
+ }
+ }
}