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 1096 2004-05-27 15:57:33Z twisti $
+ $Id: loader.c 1329 2004-07-21 15:36:33Z twisti $
*/
#include <string.h>
#include <assert.h>
#include <sys/stat.h>
+#include "exceptions.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/logging.h"
#include "threads/thread.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;
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;
classinfo *pseudo_class_Arraystub = NULL;
classinfo *pseudo_class_Null = NULL;
classinfo *pseudo_class_New = NULL;
-vftbl *pseudo_class_Arraystub_vftbl = NULL;
+vftbl_t *pseudo_class_Arraystub_vftbl = NULL;
utf *array_packagename = NULL;
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 */
+/* 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
if (sizeof(float) != 4) {
- *exceptionptr =
- new_exception_message(string_java_lang_InternalError,
- "Incompatible float-format");
+ *exceptionptr = new_exception_message(string_java_lang_InternalError,
+ "Incompatible float-format");
/* XXX should we exit in such a case? */
throw_exception_exit();
#endif
if (sizeof(double) != 8) {
- *exceptionptr =
- new_exception_message(string_java_lang_InternalError,
- "Incompatible double-format");
+ *exceptionptr = new_exception_message(string_java_lang_InternalError,
+ "Incompatible double-format");
/* XXX should we exit in such a case? */
throw_exception_exit();
isZip = 0;
filenamelen = end - start;
- if (filenamelen>3) {
+ if (filenamelen > 3) {
if (strncasecmp(end - 3, "zip", 3) == 0 ||
strncasecmp(end - 3, "jar", 3) == 0) {
isZip = 1;
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';
- tmp = 0;
+ tmp = NULL;
if (isZip) {
-#ifdef USE_ZLIB
+#if defined(USE_ZLIB)
unzFile uf = unzOpen(filename);
if (uf) {
tmp = (union classpath_info *) NEW(classpath_info);
tmp->archive.type = CLASSPATH_ARCHIVE;
tmp->archive.uf = uf;
- tmp->archive.next = 0;
- filename = 0;
+ tmp->archive.next = NULL;
+ filename = NULL;
}
#else
- panic("Zip/JAR not supported");
+ throw_cacao_exception_exit(string_java_lang_InternalError, "zip/jar files not supported");
#endif
} else {
tmp->filepath.filename = filename;
tmp->filepath.pathlen = filenamelen;
- filename = 0;
+ filename = NULL;
}
if (tmp) {
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;
filenamelen += 6;
for (currPos = classpath_entries; currPos != 0; currPos = currPos->filepath.next) {
-#ifdef USE_ZLIB
+#if defined(USE_ZLIB)
if (currPos->filepath.type == CLASSPATH_ARCHIVE) {
if (cacao_locate(currPos->archive.uf, c->name) == UNZ_OK) {
unz_file_info file_info;
return cb;
}
}
-#ifdef USE_ZLIB
+#if defined(USE_ZLIB)
}
#endif
}
}
-/************************* 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)
- panic("Invalid method descriptor: too many arguments");
+ if (argcount > 255) {
+ *exceptionptr =
+ new_classformaterror(c, "Too many arguments in signature");
+
+ 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 fieldinfo *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");
}
}
- /* just return fieldinfo* to signal everything was ok */
+ /* everything was ok */
- return f;
+ return true;
}
/******************************************************************************/
-/*********************** Function: method_load *********************************
+/* method_load *****************************************************************
- Loads a method from the class file and fills an existing 'methodinfo'
- structure. For native methods, the function pointer field is set to the
- real function pointer, for JavaVM methods a pointer to the compiler is used
- preliminarily.
+ Loads a method from the class file and fills an existing 'methodinfo'
+ structure. For native methods, the function pointer field is set to the
+ real function pointer, for JavaVM methods a pointer to the compiler is used
+ preliminarily.
*******************************************************************************/
-static methodinfo *method_load(classbuffer *cb, classinfo *c, methodinfo *m)
+static bool method_load(classbuffer *cb, classinfo *c, methodinfo *m)
{
- u4 attrnum, i, e;
s4 argcount;
- char msg[MAXLOGTEXT]; /* maybe we get an exception */
+ s4 i, j;
+ u4 attrnum;
+ u4 codeattrnum;
#ifdef STATISTICS
if (opt_stat)
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);
+ argcount = checkmethoddescriptor(c, m->descriptor);
+
if (!(m->flags & ACC_STATIC))
argcount++; /* count the 'this' argument */
/* 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))) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg), " (Illegal method modifiers: 0x%x)", m->flags);
-
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- msg);
+ new_classformaterror(c,
+ "Illegal method modifiers: 0x%x",
+ m->flags);
- return NULL;
+ return false;
}
}
}
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)) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg),
- " (Code attribute in native or abstract methods)");
-
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- msg);
+ new_classformaterror(c,
+ "Code attribute in native or abstract methods");
- return NULL;
+ return false;
}
if (m->jcode) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg), " (Multiple Code attributes)");
-
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- msg);
+ new_classformaterror(c, "Multiple Code attributes");
- return NULL;
+ return false;
}
+ if (!check_classbuffer_size(cb, 4 + 2 + 2))
+ return false;
+
suck_u4(cb);
m->maxstack = suck_u2(cb);
m->maxlocals = suck_u2(cb);
- if (m->maxlocals < argcount) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg),
- " (Arguments can't fit into locals)");
+ if (m->maxlocals < argcount) {
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- msg);
+ new_classformaterror(c, "Arguments can't fit into locals");
- return NULL;
+ return false;
}
- codelen = suck_u4(cb);
+ if (!check_classbuffer_size(cb, 4))
+ return false;
- if (codelen == 0)
- panic("bytecode has zero length");
+ m->jcodelength = suck_u4(cb);
- if (codelen > 65535) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg),
- " (Code of a method longer than 65535 bytes)");
+ if (m->jcodelength == 0) {
+ *exceptionptr =
+ new_classformaterror(c, "Code of a method has length 0");
+ return false;
+ }
+
+ if (m->jcodelength > 65535) {
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- msg);
+ new_classformaterror(c,
+ "Code of a method longer than 65535 bytes");
- return NULL;
+ return false;
}
- m->jcodelength = codelen;
+ if (!check_classbuffer_size(cb, m->jcodelength))
+ return false;
+
m->jcode = MNEW(u1, m->jcodelength);
suck_nbytes(m->jcode, cb, m->jcodelength);
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
m->exceptiontablelength = suck_u2(cb);
- m->exceptiontable =
- MNEW(exceptiontable, m->exceptiontablelength);
-#ifdef STATISTICS
+ 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))) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg), " (Missing Code attribute)");
-
- *exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError, msg);
+ *exceptionptr = new_classformaterror(c, "Missing Code attribute");
- return NULL;
+ return false;
}
- /* just return methodinfo* to signal everything was ok */
+ /* everything was ok */
- return m;
+ 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);
- nfc->next = forward_classes;
+ nfc->next = forward_classes;
forward_classes = nfc;
nfc->thisindex = idx;
/* reference to CONSTANT_NameAndType */
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
nfc->name_index = suck_u2(cb);
idx++;
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);
forward_strings = nfs;
nfs->thisindex = idx;
+
/* reference to CONSTANT_Utf8_info with string characters */
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
nfs->string_index = suck_u2(cb);
idx++;
forward_nameandtypes = nfn;
nfn->thisindex = idx;
+
+ if (!check_classbuffer_size(cb, 2 + 2))
+ return false;
+
/* reference to CONSTANT_Utf8_info containing simple name */
nfn->name_index = suck_u2(cb);
+
/* reference to CONSTANT_Utf8_info containing field or method
descriptor */
nfn->sig_index = suck_u2(cb);
case CONSTANT_Integer: {
constant_integer *ci = NEW(constant_integer);
-#ifdef STATISTICS
- count_const_pool_len += sizeof(constant_integer);
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_const_pool_len += sizeof(constant_integer);
#endif
+ if (!check_classbuffer_size(cb, 4))
+ return false;
+
ci->value = suck_s4(cb);
cptags[idx] = CONSTANT_Integer;
cpinfos[idx] = ci;
case CONSTANT_Float: {
constant_float *cf = NEW(constant_float);
-#ifdef STATISTICS
- count_const_pool_len += sizeof(constant_float);
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_const_pool_len += sizeof(constant_float);
#endif
+ if (!check_classbuffer_size(cb, 4))
+ return false;
+
cf->value = suck_float(cb);
cptags[idx] = CONSTANT_Float;
cpinfos[idx] = cf;
case CONSTANT_Long: {
constant_long *cl = NEW(constant_long);
-#ifdef STATISTICS
- count_const_pool_len += sizeof(constant_long);
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_const_pool_len += sizeof(constant_long);
#endif
+ if (!check_classbuffer_size(cb, 8))
+ return false;
+
cl->value = suck_s8(cb);
cptags[idx] = CONSTANT_Long;
cpinfos[idx] = cl;
case CONSTANT_Double: {
constant_double *cd = NEW(constant_double);
-#ifdef STATISTICS
- count_const_pool_len += sizeof(constant_double);
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_const_pool_len += sizeof(constant_double);
#endif
+ if (!check_classbuffer_size(cb, 8))
+ return false;
+
cd->value = suck_double(cb);
cptags[idx] = CONSTANT_Double;
cpinfos[idx] = cd;
}
case CONSTANT_Utf8: {
+ u4 length;
+
/* number of bytes in the bytes array (not string-length) */
- u4 length = suck_u2(cb);
+ if (!check_classbuffer_size(cb, 2))
+ return false;
+
+ length = suck_u2(cb);
cptags[idx] = CONSTANT_Utf8;
+
/* validate the string */
- ASSERT_LEFT(cb, length);
+ if (!check_classbuffer_size(cb, length))
+ return false;
+
if (opt_verify &&
!is_valid_utf(cb->pos + 1, cb->pos + 1 + length)) {
dolog("Invalid UTF-8 string (constant pool index %d)",idx);
panic("Invalid UTF-8 string");
}
/* insert utf-string into the utf-symboltable */
- cpinfos[idx] = utf_new_int(cb->pos + 1, length);
+ cpinfos[idx] = utf_new_intern(cb->pos + 1, length);
- /* skip bytes of the string */
+ /* skip bytes of the string (buffer size check above) */
skip_nbytes(cb, length);
idx++;
break;
cptags[forward_classes->thisindex] = CONSTANT_Class;
/* retrieve class from class-table */
- cpinfos[forward_classes->thisindex] = class_new(name);
+ if (opt_eager) {
+ classinfo *tc;
+ tc = class_new_intern(name);
+
+ if (!class_load(tc))
+ return false;
+
+ /* link the class later, 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_nameandtypes) {
constant_nameandtype *cn = NEW(constant_nameandtype);
-#ifdef STATISTICS
- count_const_pool_len += sizeof(constant_nameandtype);
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_const_pool_len += sizeof(constant_nameandtype);
#endif
/* resolve simple name and descriptor */
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,
break;
case CONSTANT_InterfaceMethodref:
case CONSTANT_Methodref: /* check validity of descriptor */
- checkmethoddescriptor(fmi->descriptor);
+ checkmethoddescriptor(c, fmi->descriptor);
break;
}
}
dump_release(dumpsize);
+
+ /* everything was ok */
+
+ return true;
}
s8 starttime;
s8 stoptime;
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
- compiler_lock();
- tables_lock();
-#else
- intsDisable();
-#endif
-#endif
+ /* enter a monitor on the class */
+
+ builtin_monitorenter((java_objectheader *) c);
/* 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
+ builtin_monitorexit((java_objectheader *) c);
return c;
}
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
+ builtin_monitorexit((java_objectheader *) c);
return NULL;
}
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);
loadingtime += (stoptime - starttime);
}
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
- tables_unlock();
- compiler_unlock();
-#else
- intsRestore();
-#endif
-#endif
+ /* leave the monitor */
+
+ builtin_monitorexit((java_objectheader *) c);
return r;
}
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 */
if (c->loaded)
return c;
-#ifdef STATISTICS
- count_class_loads++;
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_class_loads++;
#endif
/* output for debugging purposes */
/* class is somewhat loaded */
c->loaded = true;
+ if (!check_classbuffer_size(cb, 4 + 2 + 2))
+ return NULL;
+
/* check signature */
if (suck_u4(cb) != MAGIC) {
- utf_sprint_classname(msg, c->name);
- sprintf(msg + strlen(msg), " (Bad magic number)");
-
- *exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError, msg);
+ *exceptionptr = new_classformaterror(c, "Bad magic number");
return NULL;
}
mi = suck_u2(cb);
ma = suck_u2(cb);
- if (ma != MAJOR_VERSION && (ma != MAJOR_VERSION + 1 || mi != 0)) {
- utf_sprint_classname(msg, c->name);
- sprintf(msg + strlen(msg), " (Unsupported major.minor version %d.%d)",
- ma, mi);
-
+ if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) {
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- msg);
+ new_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_FINAL) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg),
- " (Illegal class modifiers: 0x%x)", c->flags);
-
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError, msg);
+ new_classformaterror(c,
+ "Illegal class modifiers: 0x%x", c->flags);
return NULL;
}
}
if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL)) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg),
- " (Illegal class modifiers: 0x%x)", c->flags);
-
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError, msg);
+ new_classformaterror(c, "Illegal class modifiers: 0x%x", c->flags);
return NULL;
}
+ if (!check_classbuffer_size(cb, 2 + 2))
+ return NULL;
+
/* this class */
i = suck_u2(cb);
if (class_getconstant(c, i, CONSTANT_Class) != c) {
/* This is only allowed for java.lang.Object. */
if (c->name != utf_java_lang_Object) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg), " (Bad superclass index)");
-
- *exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError, msg);
+ *exceptionptr = new_classformaterror(c, "Bad superclass index");
return NULL;
}
}
/* retrieve interfaces */
+ if (!check_classbuffer_size(cb, 2))
+ return NULL;
+
c->interfacescount = suck_u2(cb);
+
+ if (!check_classbuffer_size(cb, 2 * c->interfacescount))
+ return NULL;
+
c->interfaces = MNEW(classinfo*, c->interfacescount);
for (i = 0; i < c->interfacescount; i++) {
- c->interfaces[i] =
- class_getconstant(c, suck_u2(cb), CONSTANT_Class);
+ c->interfaces[i] = class_getconstant(c, suck_u2(cb), CONSTANT_Class);
}
/* load fields */
+ if (!check_classbuffer_size(cb, 2))
+ return NULL;
+
c->fieldscount = suck_u2(cb);
c->fields = GCNEW(fieldinfo, c->fieldscount);
/* c->fields = MNEW(fieldinfo, c->fieldscount); */
}
/* load methods */
+ if (!check_classbuffer_size(cb, 2))
+ return NULL;
+
c->methodscount = suck_u2(cb);
c->methods = GCNEW(methodinfo, c->methodscount);
/* c->methods = MNEW(methodinfo, c->methodscount); */
/* Check fields */
memset(hashtab, 0, sizeof(u2) * (hashlen + len));
+
for (i = 0; i < c->fieldscount; ++i) {
fieldinfo *fi = c->fields + i;
+
/* It's ok if we lose bits here */
index = ((((size_t) fi->name) +
((size_t) fi->descriptor)) >> shift) % hashlen;
+
if ((old = hashtab[index])) {
old--;
next[i] = old;
do {
if (c->fields[old].name == fi->name &&
c->fields[old].descriptor == fi->descriptor) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg), " (Repetitive field name/signature)");
-
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- msg);
+ new_classformaterror(c,
+ "Repetitive field name/signature");
return NULL;
}
/* 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) {
- utf_sprint(msg, c->name);
- sprintf(msg + strlen(msg), " (Repetitive method name/signature)");
-
*exceptionptr =
- new_exception_message(string_java_lang_ClassFormatError,
- msg);
+ new_classformaterror(c,
+ "Repetitive method name/signature");
return NULL;
}
MFREE(hashtab, u2, (hashlen + len));
}
-#ifdef STATISTICS
+#if defined(STATISTICS)
if (opt_stat) {
count_class_infos += sizeof(classinfo*) * c->interfacescount;
count_class_infos += sizeof(fieldinfo) * c->fieldscount;
#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 */
{
s4 j, m;
s4 i = ic->index;
- vftbl *vftbl = c->vftbl;
+ vftbl_t *vftbl = c->vftbl;
if (i >= vftbl->interfacetablelength)
panic ("Inernal error: interfacetable overflow");
/* Check the component type */
switch (c->name->text[1]) {
- case '[':
- /* c is an array of arrays. We have to create the component class. */
- comp = class_new(utf_new_int(c->name->text + 1, namelen - 1));
- break;
+ case '[':
+ /* c is an array of arrays. We have to create the component class. */
+ if (opt_eager) {
+ comp = class_new_intern(utf_new_intern(c->name->text + 1,
+ namelen - 1));
+ class_load(comp);
+ list_addfirst(&unlinkedclasses, comp);
- case 'L':
- /* c is an array of objects. */
- if (namelen < 4 || c->name->text[namelen - 1] != ';')
- panic("Invalid array class name");
- comp = class_new(utf_new_int(c->name->text + 2, namelen - 3));
- break;
+ } else {
+ comp = class_new(utf_new_intern(c->name->text + 1, namelen - 1));
+ }
+ break;
+
+ case 'L':
+ /* c is an array of objects. */
+ if (namelen < 4 || c->name->text[namelen - 1] != ';')
+ panic("Invalid array class name");
+
+ if (opt_eager) {
+ comp = class_new_intern(utf_new_intern(c->name->text + 2,
+ namelen - 3));
+ class_load(comp);
+ list_addfirst(&unlinkedclasses, comp);
+
+ } else {
+ comp = class_new(utf_new_intern(c->name->text + 2, namelen - 3));
+ }
+ break;
}
/* Setup the array class */
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);
classinfo *comp = NULL;
s4 namelen = c->name->blength;
arraydescriptor *desc;
- vftbl *compvftbl;
+ vftbl_t *compvftbl;
/* Check the component type */
switch (c->name->text[1]) {
case '[':
/* c is an array of arrays. */
-/* comp = class_get(utf_new_int(c->name->text + 1, namelen - 1)); */
- comp = class_new(utf_new_int(c->name->text + 1, namelen - 1));
+/* comp = class_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)); */
- comp = class_new(utf_new_int(c->name->text + 2, namelen - 3));
+/* 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;
s8 starttime;
s8 stoptime;
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
- compiler_lock();
- tables_lock();
-#else
- intsDisable();
-#endif
-#endif
+ /* enter a monitor on the class */
+
+ builtin_monitorenter((java_objectheader *) c);
/* 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
+ builtin_monitorexit((java_objectheader *) c);
- return;
+ return c;
}
/* measure time */
loadingtime += (stoptime - starttime);
}
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
- tables_unlock();
- compiler_unlock();
-#else
- intsRestore();
-#endif
-#endif
+ /* leave the monitor */
+
+ builtin_monitorexit((java_objectheader *) c);
+
+ return r;
}
s4 interfacetablelength; /* interface table length */
classinfo *super = c->super; /* super class */
classinfo *ic, *c2; /* intermediate class variables */
- vftbl *v; /* vftbl of current class */
+ vftbl_t *v; /* vftbl of current class */
s4 i; /* interface/method/field counter */
arraydescriptor *arraydesc = NULL; /* descriptor for array classes */
}
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");
}
}
-#ifdef STATISTICS
+#if defined(STATISTICS)
if (opt_stat)
count_vftbl_len +=
- sizeof(vftbl) + (sizeof(methodptr) * (vftbllength - 1));
+ sizeof(vftbl_t) + (sizeof(methodptr) * (vftbllength - 1));
#endif
/* compute interfacetable length */
/* allocate virtual function table */
- v = (vftbl*) mem_alloc(sizeof(vftbl) + sizeof(methodptr) *
+ v = (vftbl_t*) mem_alloc(sizeof(vftbl_t) + sizeof(methodptr) *
(vftbllength - 1) + sizeof(methodptr*) *
(interfacetablelength - (interfacetablelength > 0)));
- v = (vftbl*) (((methodptr*) v) + (interfacetablelength - 1) *
+ v = (vftbl_t*) (((methodptr*) v) + (interfacetablelength - 1) *
(interfacetablelength > 1));
c->header.vftbl = c->vftbl = v;
/* utf_display_classname(c->name);printf(", c->header.vftbl=%p\n", c->header.vftbl); */
v->interfacevftbllength = MNEW(s4, interfacetablelength);
-#ifdef STATISTICS
+#if defined(STATISTICS)
if (opt_stat)
count_vftbl_len += (4 + sizeof(s4)) * v->interfacetablelength;
#endif
u4 tag;
voidptr info;
- for (idx=0; idx < c->cpcount; idx++) {
- tag = c->cptags[idx];
- info = c->cpinfos[idx];
+ if (c->cptags && c->cpinfos) {
+ for (idx = 0; idx < c->cpcount; idx++) {
+ tag = c->cptags[idx];
+ info = c->cpinfos[idx];
- if (info != NULL) {
- switch (tag) {
- case CONSTANT_Fieldref:
- case CONSTANT_Methodref:
- case CONSTANT_InterfaceMethodref:
- FREE(info, constant_FMIref);
- break;
- case CONSTANT_Integer:
- FREE(info, constant_integer);
- break;
- case CONSTANT_Float:
- FREE(info, constant_float);
- break;
- case CONSTANT_Long:
- FREE(info, constant_long);
- break;
- case CONSTANT_Double:
- FREE(info, constant_double);
- break;
- case CONSTANT_NameAndType:
- FREE(info, constant_nameandtype);
- break;
+ if (info != NULL) {
+ switch (tag) {
+ case CONSTANT_Fieldref:
+ case CONSTANT_Methodref:
+ case CONSTANT_InterfaceMethodref:
+ FREE(info, constant_FMIref);
+ break;
+ case CONSTANT_Integer:
+ FREE(info, constant_integer);
+ break;
+ case CONSTANT_Float:
+ FREE(info, constant_float);
+ break;
+ case CONSTANT_Long:
+ FREE(info, constant_long);
+ break;
+ case CONSTANT_Double:
+ FREE(info, constant_double);
+ break;
+ case CONSTANT_NameAndType:
+ FREE(info, constant_nameandtype);
+ break;
+ }
}
}
}
- MFREE(c->cptags, u1, c->cpcount);
- MFREE(c->cpinfos, voidptr, c->cpcount);
+ if (c->cptags)
+ MFREE(c->cptags, u1, c->cpcount);
+
+ if (c->cpinfos)
+ MFREE(c->cpinfos, voidptr, c->cpcount);
}
*******************************************************************************/
-static void class_free(classinfo *c)
+void class_free(classinfo *c)
{
s4 i;
- vftbl *v;
+ vftbl_t *v;
class_freecpool(c);
- MFREE(c->interfaces, classinfo*, c->interfacescount);
+ if (c->interfaces)
+ MFREE(c->interfaces, classinfo*, c->interfacescount);
- for (i = 0; i < c->fieldscount; i++)
- field_free(&(c->fields[i]));
+ if (c->fields) {
+ for (i = 0; i < c->fieldscount; i++)
+ field_free(&(c->fields[i]));
+/* MFREE(c->fields, fieldinfo, c->fieldscount); */
+ }
- for (i = 0; i < c->methodscount; i++)
- method_free(&(c->methods[i]));
- MFREE(c->methods, methodinfo, c->methodscount);
+ if (c->methods) {
+ for (i = 0; i < c->methodscount; i++)
+ method_free(&(c->methods[i]));
+/* MFREE(c->methods, methodinfo, c->methodscount); */
+ }
if ((v = c->vftbl) != NULL) {
if (v->arraydesc)
}
MFREE(v->interfacevftbllength, s4, v->interfacetablelength);
- i = sizeof(vftbl) + sizeof(methodptr) * (v->vftbllength - 1) +
+ i = sizeof(vftbl_t) + sizeof(methodptr) * (v->vftbllength - 1) +
sizeof(methodptr*) * (v->interfacetablelength -
(v->interfacetablelength > 0));
- v = (vftbl*) (((methodptr*) v) - (v->interfacetablelength - 1) *
+ v = (vftbl_t*) (((methodptr*) v) - (v->interfacetablelength - 1) *
(v->interfacetablelength > 1));
mem_free(v, i);
}
- if (c->innerclasscount)
+ if (c->innerclass)
MFREE(c->innerclass, innerclassinfo, c->innerclasscount);
/* if (c->classvftbl)
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;
}
*******************************************************************************/
+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;
+ }
- /* class is somewhat initialized */
- c->initialized = true;
+ /* 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 <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)
if (!class_load(c))
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(string_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;
}
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$"));
+ 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 representing the null type */
- pseudo_class_Null = class_new_int(utf_new_char("$NULL$"));
+ 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_int(utf_new_char("$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;
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);
void loader_compute_subclasses(classinfo *c)
{
-#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+ compiler_lock();
+#else
intsDisable();
+#endif
#endif
if (!(c->flags & ACC_INTERFACE)) {
loader_compute_class_values(class_java_lang_Object);
}
-#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+ compiler_unlock();
+#else
intsRestore();
#endif
+#endif
}
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;
+ }
+ }
}