Mark Probst
Edwin Steiner
- $Id: loader.c 867 2004-01-07 22:05:04Z edwin $
+ $Id: loader.c 991 2004-03-29 11:22:34Z stefan $
*/
#include "toolbox/loging.h"
#include "threads/thread.h"
#include "threads/locks.h"
-#include <sys/stat.h>
+#include "nat/java_lang_Throwable.h"
#ifdef USE_ZLIB
#include "unzip.h"
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 classinfo *class_java_lang_ArrayStoreException;
static classinfo *class_java_lang_ThreadDeath;
+utf *array_packagename = NULL;
+
static int loader_inited = 0;
do {ASSERT_LEFT(len); \
classbuf_pos+=len;} while(0)
+
inline u1 suck_u1()
{
ASSERT_LEFT(1);
return *++classbuf_pos;
}
+
+
inline u2 suck_u2()
{
- u1 a=suck_u1(), b=suck_u1();
- return ((u2)a<<8)+(u2)b;
+ u1 a = suck_u1();
+ u1 b = suck_u1();
+ return ((u2) a << 8) + (u2) b;
}
+
+
inline u4 suck_u4()
{
- u1 a=suck_u1(), b=suck_u1(), c=suck_u1(), d=suck_u1();
- return ((u4)a<<24)+((u4)b<<16)+((u4)c<<8)+(u4)d;
+ u1 a = suck_u1();
+ u1 b = suck_u1();
+ u1 c = suck_u1();
+ u1 d = suck_u1();
+ return ((u4) a << 24) + ((u4) b << 16) + ((u4) c << 8) + (u4) d;
}
+
#define suck_s8() (s8) suck_u8()
#define suck_s2() (s2) suck_u2()
#define suck_s4() (s4) suck_u4()
info->name = innerclass_getconstant(c, suck_u2(), CONSTANT_Utf8); /* CONSTANT_Utf8_info index */
info->flags = suck_u2(); /* access_flags bitmask */
}
-
+ } else if (aname==utf_sourcefile) {
+ suck_u4();
+ /*log_text("source file attribute found");*/
+ c->sourcefile = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
} else {
/* unknown attribute */
skipattributebody();
checks whether a method-descriptor is valid and aborts otherwise.
All referenced classes are inserted into the list of unloaded classes.
+
+ The number of arguments is returned. A long or double argument is counted
+ as two arguments.
*******************************************************************************/
-static void checkmethoddescriptor (utf *d)
+static int checkmethoddescriptor (utf *d)
{
char *utf_ptr = d->text; /* current position in utf text */
char *end_pos = utf_end(d); /* points behind utf string */
/* check arguments */
while (utf_ptr != end_pos && *utf_ptr != ')') {
- /* XXX we cannot count the this argument here because
+ /* We cannot count the this argument here because
* we don't know if the method is static. */
if (*utf_ptr == 'J' || *utf_ptr == 'D')
+ argcount+=2;
+ else
argcount++;
- if (++argcount > 255)
- panic("Invalid method descriptor: too many arguments");
class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
CLASSLOAD_NEW
| CLASSLOAD_NULLPRIMITIVE
| CLASSLOAD_NULLPRIMITIVE
| CLASSLOAD_CHECKEND);
+ if (argcount > 255)
+ panic("Invalid method descriptor: too many arguments");
+
+ return argcount;
+
/* XXX use the following if -noverify */
#if 0
- /* XXX check length */
/* check arguments */
while ((c = *utf_ptr++) != ')') {
start = utf_ptr-1;
f->flags = suck_u2(); /* ACC flags */
f->name = class_getconstant(c, suck_u2(), CONSTANT_Utf8); /* name of field */
f->descriptor = class_getconstant(c, suck_u2(), CONSTANT_Utf8); /* JavaVM descriptor */
- f->type = jtype = desc_to_type(f->descriptor); /* data type */
- f->offset = 0; /* offset from start of object */
- f->class = c;
- f->xta = NULL;
- /* check flag consistency */
if (opt_verify) {
+ /* check name */
+ if (!is_valid_name_utf(f->name) || f->name->text[0] == '<')
+ panic("Field with invalid name");
+
+ /* check flag consistency */
i = (f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
if (i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED)
panic("Field has invalid access flags");
if ((f->flags & (ACC_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));
}
+ 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;
static void method_load(methodinfo *m, classinfo *c)
{
u4 attrnum, i, e;
+ int argcount;
#ifdef STATISTICS
count_all_methods++;
#endif
-
+ m->thrownexceptionscount=0;
+ m->linenumbercount=0;
+ m->linenumbers=0;
m->class = c;
m->flags = suck_u2();
m->name = class_getconstant(c, suck_u2(), 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(), CONSTANT_Utf8);
- checkmethoddescriptor(m->descriptor);
+ argcount = checkmethoddescriptor(m->descriptor);
+ if ((m->flags & ACC_STATIC) == 0)
+ argcount++; /* count the 'this' argument */
- /* check flag consistency */
if (opt_verify) {
- /* XXX could check if <clinit> is STATIC */
+ if (argcount > 255)
+ panic("Method has more than 255 arguments");
+
+ /* 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)
aname = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
if (aname != utf_code) {
+ if (aname == utf_exceptions) {
+ u2 exceptionCount;
+ u2 exceptionID;
+ suck_u4(); /*length*/
+ exceptionCount=suck_u2();
+ m->thrownexceptionscount=exceptionCount;
+ m->thrownexceptions=MNEW(classinfo*,exceptionCount);
+ for (exceptionID=0;exceptionID<exceptionCount;exceptionID++) {
+ (m->thrownexceptions)[exceptionID]=class_getconstant(c,suck_u2(),CONSTANT_Class);
+ }
+ }
+ else
skipattributebody();
} else {
suck_u4();
m->maxstack = suck_u2();
m->maxlocals = suck_u2();
+ if (m->maxlocals < argcount)
+ panic("max_locals is smaller than the number of arguments");
+
codelen = suck_u4();
if (codelen == 0)
panic("bytecode has zero length");
class_getconstant(c, idx, CONSTANT_Class);
}
}
-
- skipattributes(suck_u2());
+ {
+ u2 codeattrnum;
+ for (codeattrnum=suck_u2();codeattrnum>0;codeattrnum--) {
+ utf * caname = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
+ if (caname==utf_linenumbertable) {
+ u2 lncid;
+ /*log_text("LineNumberTable found");*/
+ suck_u4();
+ m->linenumbercount=suck_u2();
+ /*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();
+ m->linenumbers[lncid].line_number=suck_u2();
+ }
+ codeattrnum--;
+ skipattributes(codeattrnum);
+ break;
+ } else skipattributebody();
+
+ }
+ }
}
}
printf("\n");
}
+/************** Function: method_display_flags_last (debugging only) **************/
+
+void method_display_flags_last(methodinfo *m)
+{
+ printf(" ");
+ utf_display(m->name);
+ printf(" ");
+ utf_display(m->descriptor);
+ printf(" ");
+ printflags(m->flags);
+ printf("\n");
+}
+
/******************** Function: method_canoverwrite ****************************
*******************************************************************************/
-static bool method_canoverwrite (methodinfo *m, methodinfo *old)
+static bool method_canoverwrite(methodinfo *m, methodinfo *old)
{
if (m->name != old->name) return false;
if (m->descriptor != old->descriptor) return false;
forward_fieldmethint *forward_fieldmethints = NULL;
/* number of entries in the constant_pool table plus one */
- u4 cpcount = c -> cpcount = suck_u2();
+ u4 cpcount = c->cpcount = suck_u2();
+
/* allocate memory */
- u1 *cptags = c -> cptags = MNEW (u1, cpcount);
- voidptr *cpinfos = c -> cpinfos = MNEW (voidptr, cpcount);
+ u1 *cptags = c->cptags = MNEW(u1, cpcount);
+ voidptr *cpinfos = c->cpinfos = MNEW(voidptr, cpcount);
if (!cpcount)
panic("Invalid constant_pool_count (0)");
#endif
/* initialize constantpool */
- for (idx=0; idx<cpcount; idx++) {
+ for (idx = 0; idx < cpcount; idx++) {
cptags[idx] = CONSTANT_UNUSED;
cpinfos[idx] = NULL;
- }
+ }
- /******* first pass *******/
- /* entries which cannot be resolved now are written into
- temporary structures and traversed again later */
+ /******* first pass *******/
+ /* entries which cannot be resolved now are written into
+ temporary structures and traversed again later */
idx = 1;
while (idx < cpcount) {
/* get constant type */
- u4 t = suck_u1 ();
- switch ( t ) {
+ u4 t = suck_u1();
+ switch (t) {
case CONSTANT_Class: {
forward_class *nfc = DNEW(forward_class);
}
case CONSTANT_String: {
- forward_string *nfs = DNEW (forward_string);
+ forward_string *nfs = DNEW(forward_string);
- nfs -> next = forward_strings;
+ nfs->next = forward_strings;
forward_strings = nfs;
- nfs -> thisindex = idx;
+ nfs->thisindex = idx;
/* reference to CONSTANT_Utf8_info with string characters */
- nfs -> string_index = suck_u2 ();
+ nfs->string_index = suck_u2();
idx ++;
break;
ASSERT_LEFT(length);
if (opt_verify &&
!is_valid_utf(classbuf_pos+1, classbuf_pos+1+length))
- panic("Invalid UTF-8 string");
+ {
+ 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(classbuf_pos+1, length);
/* skip bytes of the string */
utf *name =
class_getconstant (c, forward_classes -> name_index, CONSTANT_Utf8);
+ if (opt_verify && !is_valid_name_utf(name))
+ panic("Class reference with invalid name");
+
cptags [forward_classes -> thisindex] = CONSTANT_Class;
/* retrieve class from class-table */
cpinfos [forward_classes -> thisindex] = class_new (name);
(c, forward_nameandtypes -> name_index, CONSTANT_Utf8);
cn -> descriptor = class_getconstant
(c, forward_nameandtypes -> sig_index, CONSTANT_Utf8);
-
+
+ if (opt_verify) {
+ /* check name */
+ if (!is_valid_name_utf(cn->name))
+ panic("NameAndType with invalid name");
+ /* disallow referencing <clinit> among others */
+ if (cn->name->text[0] == '<' && cn->name != utf_init)
+ panic("NameAndType with invalid special name");
+ }
+
cptags [forward_nameandtypes -> thisindex] = CONSTANT_NameAndType;
cpinfos [forward_nameandtypes -> thisindex] = cn;
break;
case CONSTANT_InterfaceMethodref:
case CONSTANT_Methodref: /* check validity of descriptor */
- /* XXX check special names (<init>) */
checkmethoddescriptor (fmi->descriptor);
break;
}
}
-/* class_showconstantpool(c); */
+/* class_showconstantpool(c); */
- dump_release (dumpsize);
+ dump_release(dumpsize);
}
return false;
}
- /* check signature */
- if (suck_u4() != MAGIC) panic("Can not find class-file signature");
+ /* check signature */
+ if (suck_u4() != MAGIC)
+ panic("Can not find class-file signature");
+
/* check version */
- mi = suck_u2();
+ mi = suck_u2();
ma = suck_u2();
+#if 0
if (ma != MAJOR_VERSION && (ma != MAJOR_VERSION+1 || mi != 0)) {
error("File version %d.%d is not supported", (int) ma, (int) mi);
}
+#endif
class_loadcpool(c);
/*JOWENN*/
/* check ACC flags consistency */
if ((c->flags & ACC_INTERFACE) != 0) {
- if ((c->flags & ACC_ABSTRACT) == 0)
- panic("Interface class not declared abstract");
- if ((c->flags & (ACC_FINAL | ACC_SUPER)) != 0)
+ if ((c->flags & ACC_ABSTRACT) == 0) {
+ /* 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)
+ c->flags &= ~ACC_SUPER; /* kjc seems to set this on interfaces */
}
+ if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL))
+ panic("Class is declared both abstract and final");
/* this class */
i = suck_u2();
- if (class_getconstant(c, i, CONSTANT_Class) != c)
+ 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), class_getconstant(c, i, CONSTANT_Class)); */
+/* sprintf(message + strlen(message), ")"); */
+
+/* *exceptionptr = new_exception_message("java/lang/NoClassDefFoundError", */
+/* message); */
+/* return false; */
panic("Invalid this_class in class file");
+ }
/* retrieve superclass */
if ((i = suck_u2())) {
c->interfacescount = suck_u2();
c->interfaces = MNEW(classinfo*, c->interfacescount);
for (i = 0; i < c->interfacescount; i++) {
- c->interfaces [i] =
+ c->interfaces[i] =
class_getconstant(c, suck_u2(), CONSTANT_Class);
}
method_load(&(c->methods[i]), c);
}
+ /* Check if all fields and methods can be uniquely
+ * identified by (name,descriptor). */
+ if (opt_verify) {
+ /* We use a hash table here to avoid making the
+ * average case quadratic in # of methods, fields.
+ */
+ static int shift = 0;
+ u2 *hashtab;
+ u2 *next; /* for chaining colliding hash entries */
+ size_t len;
+ size_t hashlen;
+ u2 index;
+ u2 old;
+
+ /* Allocate hashtable */
+ len = c->methodscount;
+ if (len < c->fieldscount) len = c->fieldscount;
+ hashlen = 5 * len;
+ hashtab = MNEW(u2,(hashlen + len));
+ next = hashtab + hashlen;
+
+ /* Determine bitshift (to get good hash values) */
+ if (!shift) {
+ len = sizeof(utf);
+ while (len) {
+ len >>= 1;
+ shift++;
+ }
+ }
+
+ /* 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) {
+ 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");
+ }
+ } while ((old = next[old]) != 0);
+ }
+ /* 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) {
+ 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");
+ }
+ } while ((old = next[old]) != 0);
+ }
+ /* else dolog("HASHLUCKY"); */
+ hashtab[index] = i+1;
+ }
+
+ MFREE(hashtab,u2,(hashlen + len));
+ }
+
#ifdef STATISTICS
count_class_infos += sizeof(classinfo*) * c->interfacescount;
count_class_infos += sizeof(fieldinfo) * c->fieldscount;
methodinfo *clone;
int namelen;
- /* XXX remove */ /* dolog("class_new_array: %s",c->name->text); */
+ /* DEBUG */ /* dolog("class_new_array: %s",c->name->text); */
/* Array classes are not loaded from classfiles. */
list_remove(&unloadedclasses, c);
c->flags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
c->interfacescount = 2;
- c->interfaces = MNEW(classinfo*,2); /* XXX use GC? */
+ c->interfaces = MNEW(classinfo*,2);
c->interfaces[0] = class_java_lang_Cloneable;
c->interfaces[1] = class_java_io_Serializable;
c->methodscount = 1;
- c->methods = MNEW (methodinfo, c->methodscount); /* XXX use GC? */
+ c->methods = MNEW (methodinfo, c->methodscount);
clone = c->methods;
memset(clone, 0, sizeof(methodinfo));
- clone->flags = ACC_PUBLIC; /* XXX protected? */
+ clone->flags = ACC_PUBLIC;
clone->name = utf_new_char("clone");
clone->descriptor = utf_new_char("()Ljava/lang/Object;");
clone->class = c;
clone->stubroutine = createnativestub((functionptr) &builtin_clone_array, clone);
- clone->monoPoly = MONO; /* XXX should be poly? */
+ clone->monoPoly = MONO;
/* XXX: field: length? */
list_addlast(&unlinkedclasses, c);
return;
}
- if ((ic->flags & ACC_INTERFACE) == 0)
+ if ((ic->flags & ACC_INTERFACE) == 0) {
+ dolog("Specified interface is not declared as interface:");
+ log_utf(ic->name);
+ dolog("in");
+ log_utf(c->name);
panic("Specified interface is not declared as interface");
+ }
}
/* check super class */
- if (super == NULL) { /* class java.long.Object */
+ if (super == NULL) { /* class java.lang.Object */
c->index = 0;
c->classUsed = USED; /* Object class is always used CO-RT*/
c->impldBy = NULL;
return;
}
- if ((super->flags & ACC_INTERFACE) != 0)
+ if (super->flags & ACC_INTERFACE)
panic("Interface specified as super class");
/* handle array classes */
}
/* Don't allow extending final classes */
- if ((super->flags & ACC_FINAL) != 0)
+ if (super->flags & ACC_FINAL)
panic("Trying to extend final class");
if (c->flags & ACC_INTERFACE)
int j;
for (j = 0; j < sc->methodscount; j++) {
if (method_canoverwrite(m, &(sc->methods[j]))) {
- if ((sc->methods[j].flags & ACC_FINAL) != 0)
+ if ((sc->methods[j].flags & ACC_PRIVATE) != 0)
+ goto notfoundvftblindex;
+ if ((sc->methods[j].flags & ACC_FINAL) != 0) {
+ log_utf(c->name);
+ log_utf(sc->name);
+ log_utf(sc->methods[j].name);
+ log_utf(sc->methods[j].descriptor);
panic("Trying to overwrite final method");
+ }
m->vftblindex = sc->methods[j].vftblindex;
goto foundvftblindex;
}
}
sc = sc->super;
}
+ notfoundvftblindex:
m->vftblindex = (vftbllength++);
foundvftblindex: ;
}
}
+/****************** Function: class_resolvefield_int ***************************
+
+ This is an internally used helper function. Do not use this directly.
+
+ Tries to resolve a field having the given name and type.
+ If the field cannot be resolved, NULL is returned.
+
+*******************************************************************************/
+
+static
+fieldinfo *class_resolvefield_int(classinfo *c, utf *name, utf *desc)
+{
+ s4 i;
+ fieldinfo *fi;
+
+ /* search for field in class c */
+ for (i = 0; i < c->fieldscount; i++) {
+ if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc))
+ return &(c->fields[i]);
+ }
+
+ /* try superinterfaces recursively */
+ for (i=0; i<c->interfacescount; ++i) {
+ fi = class_resolvefield_int(c->interfaces[i],name,desc);
+ if (fi)
+ return fi;
+ }
+
+ /* try superclass */
+ if (c->super)
+ return class_resolvefield_int(c->super,name,desc);
+
+ /* not found */
+ return NULL;
+}
+
+
+/********************* Function: class_resolvefield ***************************
+
+ Resolves a reference from REFERER to a field with NAME and DESC in class C.
+ If the field cannot be resolved this function panics.
+
+*******************************************************************************/
+
+fieldinfo *class_resolvefield(classinfo *c, utf *name, utf *desc,
+ classinfo *referer)
+{
+ fieldinfo *fi;
+
+ /* XXX resolve class c */
+ /* XXX check access from REFERER to C */
+
+ fi = class_resolvefield_int(c,name,desc);
+
+ if (!fi) {
+ log_utf(c->name);
+ log_utf(name);
+ log_utf(desc);
+ panic("Cannot find field given in CONSTANT_Fieldref");
+ /* XXX should throw NoSuchFieldError */
+ }
+
+ /* XXX check access rights */
+
+ return fi;
+}
+
+
/************************* Function: class_findmethod **************************
Searches a 'classinfo' structure for a method having the given name and
s4 class_findmethodIndex(classinfo *c, utf *name, utf *desc)
{
s4 i;
+ //#define JOWENN_DEBUG1
+ //#define JOWENN_DEBUG2
#if defined(JOWENN_DEBUG1) || defined(JOWENN_DEBUG2)
char *buffer;
int buffer_len, pos;
#endif
+
#ifdef JOWENN_DEBUG1
buffer_len =
}
+/*********************** Function: class_findmethod_w**************************
+
+ like class_findmethod, but logs a warning if the method is not found
+
+*******************************************************************************/
+
+methodinfo *class_findmethod_w(classinfo *c, utf *name, utf *desc, char *from)
+{
+ methodinfo *mi;
+ mi = class_findmethod(c, name, desc);
+
+ if (!mi) {
+ log_plain("Class: "); if (c) log_plain_utf(c->name); log_nl();
+ log_plain("Method: "); if (name) log_plain_utf(name); log_nl();
+ log_plain("Descriptor: "); if (desc) log_plain_utf(desc); log_nl();
+
+ if ( c->flags & ACC_PUBLIC ) log_plain(" PUBLIC ");
+ if ( c->flags & ACC_PRIVATE ) log_plain(" PRIVATE ");
+ if ( c->flags & ACC_PROTECTED ) log_plain(" PROTECTED ");
+ if ( c->flags & ACC_STATIC ) log_plain(" STATIC ");
+ if ( c->flags & ACC_FINAL ) log_plain(" FINAL ");
+ if ( c->flags & ACC_SYNCHRONIZED ) log_plain(" SYNCHRONIZED ");
+ if ( c->flags & ACC_VOLATILE ) log_plain(" VOLATILE ");
+ if ( c->flags & ACC_TRANSIENT ) log_plain(" TRANSIENT ");
+ if ( c->flags & ACC_NATIVE ) log_plain(" NATIVE ");
+ if ( c->flags & ACC_INTERFACE ) log_plain(" INTERFACE ");
+ if ( c->flags & ACC_ABSTRACT ) log_plain(" ABSTRACT ");
+
+ log_plain(from);
+ log_plain(" : WARNING: Method not found");log_nl( );
+ }
+
+ return mi;
+}
+
+
/************************* Function: class_findmethod_approx ******************
like class_findmethod but ignores the return value when comparing the
}
+/****************** Function: class_resolveinterfacemethod_int ****************
+
+ Internally used helper function. Do not use this directly.
+
+*******************************************************************************/
+
+static
+methodinfo *class_resolveinterfacemethod_int(classinfo *c, utf *name, utf *desc)
+{
+ methodinfo *mi;
+ int i;
+
+ mi = class_findmethod(c,name,desc);
+ if (mi)
+ return mi;
+
+ /* try the superinterfaces */
+ for (i=0; i<c->interfacescount; ++i) {
+ mi = class_resolveinterfacemethod_int(c->interfaces[i],name,desc);
+ if (mi)
+ return mi;
+ }
+
+ return NULL;
+}
+
+/******************** Function: class_resolveinterfacemethod ******************
+
+ Resolves a reference from REFERER to a method with NAME and DESC in
+ interface C.
+
+*******************************************************************************/
+
+methodinfo *class_resolveinterfacemethod(classinfo *c, utf *name, utf *desc,
+ classinfo *referer)
+{
+ methodinfo *mi;
+
+ /* XXX resolve class c */
+ /* XXX check access from REFERER to C */
+
+ if ((c->flags & ACC_INTERFACE) == 0)
+ return NULL; /* should throw IncompatibleClassChangeError */
+
+ mi = class_resolveinterfacemethod_int(c,name,desc);
+ if (mi)
+ goto found;
+
+ /* try class java.lang.Object */
+ mi = class_findmethod(class_java_lang_Object,name,desc);
+ if (mi)
+ goto found;
+
+ return NULL; /* should throw NoSuchMethodError */
+
+ found:
+ return mi;
+}
+
+/********************* Function: class_resolveclassmethod *********************
+
+ Resolves a reference from REFERER to a method with NAME and DESC in
+ class C.
+
+*******************************************************************************/
+
+methodinfo *class_resolveclassmethod(classinfo *c, utf *name, utf *desc,
+ classinfo *referer)
+{
+ methodinfo *mi;
+ int i;
+ classinfo *cls;
+
+ /* XXX resolve class c */
+ /* XXX check access from REFERER to C */
+
+ if ((c->flags & ACC_INTERFACE) != 0)
+ return NULL; /* should throw IncompatibleClassChangeError */
+
+ /* try class c and its superclasses */
+ cls = c;
+ do {
+ mi = class_findmethod(cls,name,desc);
+ if (mi)
+ goto found;
+ } while ((cls = cls->super) != NULL); /* try the superclass */
+
+ /* try the superinterfaces */
+ for (i=0; i<c->interfacescount; ++i) {
+ mi = class_resolveinterfacemethod_int(c->interfaces[i],name,desc);
+ if (mi)
+ goto found;
+ }
+
+ return NULL; /* should throw NoSuchMethodError */
+
+ found:
+ if ((mi->flags & ACC_ABSTRACT) != 0 &&
+ (c->flags & ACC_ABSTRACT) == 0)
+ return NULL; /* should throw AbstractMethodError */
+
+ /* XXX check access rights */
+
+ return mi;
+}
+
+
/************************* Function: class_issubclass **************************
Checks if sub is a descendant of super.
{
methodinfo *m;
s4 i;
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
int b;
#endif
log_text(logtext);
}
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
b = blockInts;
blockInts = 0;
#endif
/* now call the initializer */
asm_calljavafunction(m, NULL, NULL, NULL, NULL);
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
assert(blockInts == 0);
blockInts = b;
#endif
printf("Exception in thread \"main\" java.lang.ExceptionInInitializerError\n");
printf("Caused by: ");
utf_display((*exceptionptr)->vftbl->class->name);
+
+ /* do we have a detail message? */
+ if (((java_lang_Throwable *) *exceptionptr)->detailMessage) {
+ printf(": ");
+ utf_display(javastring_toutf(((java_lang_Throwable *) *exceptionptr)->detailMessage, false));
+ }
+
printf("\n");
fflush(stdout);
exit(1);
return;
}
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
b = blockInts;
blockInts = 0;
#endif
asm_calljavafunction(m, NULL, NULL, NULL, NULL);
-#ifdef USE_THREADS
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
assert(blockInts == 0);
blockInts = b;
#endif
s8 stoptime = 0;
classinfo *notlinkable;
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- pthread_mutex_lock(&compiler_mutex);
-#endif
-
/* avoid recursive calls */
if (loader_load_running)
return class_new(topname);
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ compiler_lock();
+#endif
+
loader_load_running++;
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
intsDisable();
+#endif
if (getloadingtime)
starttime = getcputime();
if (linkverbose)
dolog("Linking...");
- /* XXX added a hack to break infinite linking loops. A better
+ /* Added a hack to break infinite linking loops. A better
* linking algorithm would be nice. -Edwin */
notlinkable = NULL;
while ((c = list_first(&unlinkedclasses))) {
}
}
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
intsRestore();
+#endif
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- pthread_mutex_unlock(&compiler_mutex);
+ compiler_unlock();
#endif
- /* XXX DEBUG */ if (linkverbose && !top) dolog("returning NULL from loader_load");
+ /* DEBUG */ /*if (linkverbose && !top) dolog("returning NULL from loader_load");*/
return top;
}
********************************************************************************/
-
void create_primitive_classes()
{
int i;
bool error = false;
utf *name;
- SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,error);
+ SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr, end_ptr, error);
if (mode & CLASSLOAD_CHECKEND)
error |= (utf_ptr != end_ptr);
/* FALLTHROUGH! */
case '[':
if (mode & CLASSLOAD_SKIP) return class_java_lang_Object;
- name = utf_new(start,utf_ptr-start);
+ name = utf_new(start, utf_ptr - start);
return (mode & CLASSLOAD_LOAD)
- ? loader_load(name) : class_new(name); /* XXX */
+ ? loader_load(name) : class_new(name); /* XXX handle errors */
}
}
return NULL;
log_plain("Invalid descriptor at beginning of '");
- log_plain_utf(utf_new(start, end_ptr-start));
+ log_plain_utf(utf_new(start, end_ptr - start));
log_plain("'");
log_nl();
}
+
+/*************** function: create_system_exception_classes *******************************
+
+ create system exception classes needed by default
+
+********************************************************************************/
+
+static void create_system_exception_classes()
+{
+ if (verbose)
+ log_text("loader_init: create_system_exception_classs: loader_load: java/lang/ClassCastException");
+
+ loader_load_sysclass(&class_java_lang_ClassCastException,
+ utf_new_char("java/lang/ClassCastException"));
+ loader_load_sysclass(&class_java_lang_NullPointerException,
+ utf_new_char("java/lang/NullPointerException"));
+ loader_load_sysclass(&class_java_lang_ArrayIndexOutOfBoundsException,
+ utf_new_char("java/lang/ArrayIndexOutOfBoundsException"));
+ loader_load_sysclass(&class_java_lang_NegativeArraySizeException,
+ utf_new_char("java/lang/NegativeArraySizeException"));
+ loader_load_sysclass(&class_java_lang_OutOfMemoryError,
+ utf_new_char("java/lang/OutOfMemoryError"));
+ loader_load_sysclass(&class_java_lang_ArrayStoreException,
+ utf_new_char("java/lang/ArrayStoreException"));
+ loader_load_sysclass(&class_java_lang_ArithmeticException,
+ utf_new_char("java/lang/ArithmeticException"));
+ loader_load_sysclass(&class_java_lang_ThreadDeath,
+ utf_new_char("java/lang/ThreadDeath"));
+}
+
+
+/*************** function: create_system_exception_classes *******************************
+
+ create system exception proto classes needed by default
+
+********************************************************************************/
+
+static void create_system_exception_proto_classes()
+{
+
+ if (verbose) log_text("loader_init: creating global proto_java_lang_ClassCastException");
+ proto_java_lang_ClassCastException =
+ builtin_new(class_java_lang_ClassCastException);
+
+ if (verbose) log_text("loader_init: proto_java_lang_ClassCastException has been initialized");
+
+ proto_java_lang_NullPointerException =
+ builtin_new(class_java_lang_NullPointerException);
+ if (verbose) log_text("loader_init: proto_java_lang_NullPointerException has been initialized");
+
+ proto_java_lang_ArrayIndexOutOfBoundsException =
+ builtin_new(class_java_lang_ArrayIndexOutOfBoundsException);
+
+ proto_java_lang_NegativeArraySizeException =
+ builtin_new(class_java_lang_NegativeArraySizeException);
+
+ proto_java_lang_OutOfMemoryError =
+ builtin_new(class_java_lang_OutOfMemoryError);
+
+ proto_java_lang_ArithmeticException =
+ builtin_new(class_java_lang_ArithmeticException);
+
+ proto_java_lang_ArrayStoreException =
+ builtin_new(class_java_lang_ArrayStoreException);
+
+ proto_java_lang_ThreadDeath =
+ builtin_new(class_java_lang_ThreadDeath);
+
+
+}
+
+
+
/*************** function: create_pseudo_classes *******************************
create pseudo classes used by the typechecker
utf_innerclasses = utf_new_char("InnerClasses");
utf_constantvalue = utf_new_char("ConstantValue");
utf_code = utf_new_char("Code");
+ utf_exceptions = utf_new_char("Exceptions");
+ utf_linenumbertable = utf_new_char("LineNumberTable");
+ utf_sourcefile = utf_new_char("SourceFile");
utf_finalize = utf_new_char("finalize");
utf_fidesc = utf_new_char("()V");
utf_init = utf_new_char("<init>");
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>");
+
/* create some important classes */
/* These classes have to be created now because the classinfo
* pointers are used in the loading code.
loader_load_sysclass(&class_java_lang_Throwable,
utf_new_char("java/lang/Throwable"));
- if (verbose) log_text("loader_init: loader_load: java/lang/ClassCastException");
- loader_load_sysclass(&class_java_lang_ClassCastException,
- utf_new_char ("java/lang/ClassCastException"));
- loader_load_sysclass(&class_java_lang_NullPointerException,
- utf_new_char ("java/lang/NullPointerException"));
- loader_load_sysclass(&class_java_lang_ArrayIndexOutOfBoundsException,
- utf_new_char ("java/lang/ArrayIndexOutOfBoundsException"));
- loader_load_sysclass(&class_java_lang_NegativeArraySizeException,
- utf_new_char ("java/lang/NegativeArraySizeException"));
- loader_load_sysclass(&class_java_lang_OutOfMemoryError,
- utf_new_char ("java/lang/OutOfMemoryError"));
- loader_load_sysclass(&class_java_lang_ArrayStoreException,
- utf_new_char ("java/lang/ArrayStoreException"));
- loader_load_sysclass(&class_java_lang_ArithmeticException,
- utf_new_char ("java/lang/ArithmeticException"));
- loader_load_sysclass(&class_java_lang_ThreadDeath,
- utf_new_char ("java/lang/ThreadDeath"));
-
+ create_system_exception_classes();
+
/* create classes representing primitive types */
create_primitive_classes();
/* correct vftbl-entries (retarded loading of class java/lang/String) */
stringtable_update();
-#ifdef USE_THREADS
+#if defined(USE_THREADS)
if (stackbottom!=0)
initLocks();
#endif
-
- if (verbose) log_text("loader_init: creating global proto_java_lang_ClassCastException");
- proto_java_lang_ClassCastException =
- builtin_new(class_java_lang_ClassCastException);
-
- if (verbose) log_text("loader_init: proto_java_lang_ClassCastException has been initialized");
-
- proto_java_lang_NullPointerException =
- builtin_new(class_java_lang_NullPointerException);
- if (verbose) log_text("loader_init: proto_java_lang_NullPointerException has been initialized");
-
- proto_java_lang_ArrayIndexOutOfBoundsException =
- builtin_new(class_java_lang_ArrayIndexOutOfBoundsException);
-
- proto_java_lang_NegativeArraySizeException =
- builtin_new(class_java_lang_NegativeArraySizeException);
-
- proto_java_lang_OutOfMemoryError =
- builtin_new(class_java_lang_OutOfMemoryError);
-
- proto_java_lang_ArithmeticException =
- builtin_new(class_java_lang_ArithmeticException);
-
- proto_java_lang_ArrayStoreException =
- builtin_new(class_java_lang_ArrayStoreException);
-
- proto_java_lang_ThreadDeath =
- builtin_new(class_java_lang_ThreadDeath);
+ create_system_exception_proto_classes();
loader_inited = 1;
}
}
c->vftbl->diffval = classvalue - c->vftbl->baseval;
- /*
+/*
{
int i;
for (i = 0; i < c->index; i++)
utf_display(c->name);
printf("\n");
}
- */
+*/
}
{
classinfo *c;
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
intsDisable(); /* schani */
+#endif
c = list_first(&linkedclasses);
while (c) {
cast_unlock();
#endif
+#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
intsRestore(); /* schani */
+#endif
}
while ((c = list_first(&unloadedclasses))) {
list_remove(&unloadedclasses, c);
- class_free(c);
+/* class_free(c); */
}
while ((c = list_first(&unlinkedclasses))) {
list_remove(&unlinkedclasses, c);
- class_free(c);
+/* class_free(c); */
}
while ((c = list_first(&linkedclasses))) {
list_remove(&linkedclasses, c);
- class_free(c);
+/* class_free(c); */
}
}