/* vm/loader.c - class loader functions
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
- M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
- P. Tomsich, J. Wenninger
+ Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
+ R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
+ C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
+ Institut f. Computersprachen - TU Wien
This file is part of CACAO.
Edwin Steiner
Christian Thalinger
- $Id: loader.c 1673 2004-12-03 16:43:53Z twisti $
+ $Id: loader.c 1936 2005-02-10 11:04:10Z twisti $
*/
#include "vm/loader.h"
#include "vm/options.h"
#include "vm/statistics.h"
+#include "vm/stringlocal.h"
#include "vm/tables.h"
#if defined(USE_ZLIB)
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_initialize;
-static utf *utf_initializedesc;
-static utf *utf_java_lang_Object; /* java/lang/Object */
-
-utf *utf_fillInStackTrace_name;
-utf *utf_fillInStackTrace_desc;
-
-utf* clinit_desc(){
- return utf_fidesc;
-}
-utf* clinit_name(){
- return utf_clinit;
-}
-
-
-/* important system classes ***************************************************/
-
-classinfo *class_java_lang_Object;
-classinfo *class_java_lang_String;
-classinfo *class_java_lang_Cloneable;
-classinfo *class_java_io_Serializable;
-
-/* Pseudo classes for the typechecker */
-classinfo *pseudo_class_Arraystub = NULL;
-classinfo *pseudo_class_Null = NULL;
-classinfo *pseudo_class_New = NULL;
vftbl_t *pseudo_class_Arraystub_vftbl = NULL;
-utf *array_packagename = NULL;
-
/********************************************************************
list of classpath entries (either filesystem directories or
classpath_info *cpi;
classpath_info *lastcpi;
- if (!classpath)
- return;
+ /* search for last classpath entry (only if there already some) */
+
+ if ((lastcpi = classpath_entries)) {
+ while (lastcpi->next)
+ lastcpi = lastcpi->next;
+ }
for (start = classpath; (*start) != '\0';) {
unzFile uf = unzOpen(filename);
if (uf) {
- cpi = (union classpath_info *) NEW(classpath_info);
- cpi->archive.type = CLASSPATH_ARCHIVE;
- cpi->archive.uf = uf;
- cpi->archive.next = NULL;
+ cpi = NEW(classpath_info);
+ cpi->type = CLASSPATH_ARCHIVE;
+ cpi->uf = uf;
+ cpi->next = NULL;
+ cpi->pd = NULL; /* ProtectionDomain not set yet */
+ cpi->path = filename;
}
+
#else
throw_cacao_exception_exit(string_java_lang_InternalError,
"zip/jar files not supported");
#endif
} else {
- cpi = (union classpath_info *) NEW(classpath_info);
- cpi->filepath.type = CLASSPATH_PATH;
- cpi->filepath.next = NULL;
+ cpi = NEW(classpath_info);
+ cpi->type = CLASSPATH_PATH;
+ cpi->next = NULL;
+ cpi->pd = NULL; /* ProtectionDomain not set yet */
if (filename[filenamelen - 1] != '/') {/*PERHAPS THIS SHOULD BE READ FROM A GLOBAL CONFIGURATION */
filename[filenamelen] = '/';
filenamelen++;
}
- cpi->filepath.path = filename;
- cpi->filepath.pathlen = filenamelen;
+ cpi->path = filename;
+ cpi->pathlen = filenamelen;
}
/* attach current classpath entry */
if (cpi) {
- if (!classpath_entries) {
+ if (!classpath_entries)
classpath_entries = cpi;
-
- } else {
- lastcpi->filepath.next = cpi;
- }
+ else
+ lastcpi->next = cpi;
lastcpi = cpi;
}
{
classpath_info *cpi;
- for (cpi = classpath_entries; cpi != 0; cpi = cpi->filepath.next) {
+ for (cpi = classpath_entries; cpi != 0; cpi = cpi->next) {
#if defined(USE_ZLIB)
- if (cpi->filepath.type == CLASSPATH_ARCHIVE) {
+ if (cpi->type == CLASSPATH_ARCHIVE) {
cacao_entry_s *ce;
unz_s *s;
- s = (unz_s *) cpi->archive.uf;
+ s = (unz_s *) cpi->uf;
ce = s->cacao_dir_list;
while (ce) {
s4 filenamelen;
char *path;
FILE *classfile;
- int err;
+ bool found;
s4 len;
struct stat buffer;
classbuffer *cb;
-#if 0
- utf_ptr = c->name->text;
-
- while (utf_ptr < utf_end(c->name)) {
- 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 = '?';
- filename[filenamelen++] = ch;
- }
-#endif
-
/* initialize return value */
+ found = false;
cb = NULL;
filenamelen = utf_strlen(c->name) + 7; /* 7 = ".class\0" */
/* walk through all classpath entries */
- for (cpi = classpath_entries; cpi != NULL && cb == NULL; cpi = cpi->filepath.next) {
+ for (cpi = classpath_entries; cpi != NULL && cb == NULL; cpi = cpi->next) {
#if defined(USE_ZLIB)
- if (cpi->filepath.type == CLASSPATH_ARCHIVE) {
- if (cacao_locate(cpi->archive.uf, c->name) == UNZ_OK) {
+ if (cpi->type == CLASSPATH_ARCHIVE) {
+
+#if defined(USE_THREADS)
+ /* enter a monitor on zip/jar archives */
+
+ builtin_monitorenter((java_objectheader *) cpi);
+#endif
+
+ if (cacao_locate(cpi->uf, c->name) == UNZ_OK) {
unz_file_info file_info;
- if (unzGetCurrentFileInfo(cpi->archive.uf, &file_info, filename,
+ if (unzGetCurrentFileInfo(cpi->uf, &file_info, filename,
sizeof(filename), NULL, 0, NULL, 0) == UNZ_OK) {
- if (unzOpenCurrentFile(cpi->archive.uf) == UNZ_OK) {
+ if (unzOpenCurrentFile(cpi->uf) == UNZ_OK) {
cb = NEW(classbuffer);
cb->class = c;
cb->size = file_info.uncompressed_size;
cb->data = MNEW(u1, cb->size);
cb->pos = cb->data - 1;
+ /* We need this later in use_class_as_object to set a */
+ /* correct ProtectionDomain and CodeSource. */
+ c->pd = (struct java_security_ProtectionDomain *) cpi;
- len = unzReadCurrentFile(cpi->archive.uf, cb->data, cb->size);
+ len = unzReadCurrentFile(cpi->uf, cb->data, cb->size);
if (len != cb->size) {
suck_stop(cb);
log_text("Error while unzipping");
+
+ } else {
+ found = true;
}
} else {
log_text("Error while retrieving fileinfo");
}
}
- unzCloseCurrentFile(cpi->archive.uf);
+ unzCloseCurrentFile(cpi->uf);
+
+#if defined(USE_THREADS)
+ /* leave the monitor */
+
+ builtin_monitorexit((java_objectheader *) cpi);
+#endif
} else {
#endif /* USE_ZLIB */
- path = MNEW(char, cpi->filepath.pathlen + filenamelen + 1);
- strcpy(path, cpi->filepath.path);
+ path = MNEW(char, cpi->pathlen + filenamelen + 1);
+ strcpy(path, cpi->path);
strcat(path, filename);
classfile = fopen(path, "r");
if (classfile) { /* file exists */
- /* determine size of classfile */
- err = stat(path, &buffer);
-
- if (!err) { /* read classfile data */
+ if (!stat(path, &buffer)) { /* read classfile data */
cb = NEW(classbuffer);
cb->class = c;
cb->size = buffer.st_size;
cb->data = MNEW(u1, cb->size);
cb->pos = cb->data - 1;
+ /* We need this later in use_class_as_object to set a */
+ /* correct ProtectionDomain and CodeSource. */
+ c->pd = (struct java_security_ProtectionDomain *) cpi;
/* read class data */
len = fread(cb->data, 1, cb->size, classfile);
suck_stop(cb);
/* if (ferror(classfile)) { */
/* } */
+
+ } else {
+ found = true;
}
}
}
- MFREE(path, char, cpi->filepath.pathlen + filenamelen + 1);
+ MFREE(path, char, cpi->pathlen + filenamelen + 1);
#if defined(USE_ZLIB)
}
#endif
}
if (opt_verbose) {
- if (err)
+ if (!found)
dolog("Warning: Can not open class file '%s'", filename);
}
if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
return false;
- if (aname == utf_innerclasses) {
+ if (aname == utf_InnerClasses) {
/* innerclasses attribute */
if (c->innerclass) {
*exceptionptr =
info->flags = suck_u2(cb);
}
- } else if (aname == utf_sourcefile) {
+ } else if (aname == utf_SourceFile) {
if (!check_classbuffer_size(cb, 4 + 2))
return false;
if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
return false;
- if (u == utf_constantvalue) {
+ if (u == utf_ConstantValue) {
if (!check_classbuffer_size(cb, 4 + 2))
return false;
if (!(aname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
return false;
- if (aname == utf_code) {
+ if (aname == utf_Code) {
if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
*exceptionptr =
new_classformaterror(c,
if (!(caname = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
return false;
- if (caname == utf_linenumbertable) {
+ if (caname == utf_LineNumberTable) {
u2 lncid;
if (!check_classbuffer_size(cb, 4 + 2))
}
}
- } else if (aname == utf_exceptions) {
+ } else if (aname == utf_Exceptions) {
s4 j;
if (m->thrownexceptions) {
}
/* everything was ok */
- /* utf_display(m->name);
- printf("\nexceptiontablelength:%ld\n",m->exceptiontablelength);*/
return true;
}
if (opt_verify) {
/* check name */
- if (!is_valid_name_utf(cn->name))
- panic("NameAndType with invalid name");
+ if (!is_valid_name_utf(cn->name)) {
+ *exceptionptr =
+ new_exception_utfmessage(string_java_lang_InternalError,
+ cn->name);
+ return false;
+ }
+
/* disallow referencing <clinit> among others */
- if (cn->name->text[0] == '<' && cn->name != utf_init)
- panic("NameAndType with invalid special name");
+ if (cn->name->text[0] == '<' && cn->name != utf_init) {
+ *exceptionptr =
+ new_exception_utfmessage(string_java_lang_InternalError,
+ cn->name);
+ return false;
+ }
}
cptags[forward_nameandtypes->thisindex] = CONSTANT_NameAndType;
classbuffer *cb;
classinfo *r;
+#if defined(USE_THREADS)
/* enter a monitor on the class */
builtin_monitorenter((java_objectheader *) c);
+#endif
/* maybe the class is already loaded */
if (c->loaded) {
+#if defined(USE_THREADS)
builtin_monitorexit((java_objectheader *) c);
+#endif
return c;
}
new_exception_utfmessage(string_java_lang_NoClassDefFoundError,
c->name);
+#if defined(USE_THREADS)
builtin_monitorexit((java_objectheader *) c);
+#endif
return NULL;
}
if (getcompilingtime)
compilingtime_start();
+#if defined(USE_THREADS)
/* leave the monitor */
builtin_monitorexit((java_objectheader *) c);
+#endif
return r;
}
{
classinfo *r;
+#if defined(USE_THREADS)
/* enter a monitor on the class */
builtin_monitorenter((java_objectheader *) c);
+#endif
/* maybe the class is already linked */
if (c->linked) {
+#if defined(USE_THREADS)
builtin_monitorexit((java_objectheader *) c);
+#endif
return c;
}
if (getcompilingtime)
compilingtime_start();
+#if defined(USE_THREADS)
/* leave the monitor */
builtin_monitorexit((java_objectheader *) c);
+#endif
return r;
}
}
if (!tc->loaded)
- if (!class_load(tc))
+ if (!class_load(tc))
return NULL;
if (!(tc->flags & ACC_INTERFACE)) {
/* add interfaces */
- for (tc = c; tc != NULL; tc = tc->super) {
- for (i = 0; i < tc->interfacescount; i++) {
+ for (tc = c; tc != NULL; tc = tc->super)
+ for (i = 0; i < tc->interfacescount; i++)
class_addinterface(c, tc->interfaces[i]);
- }
- }
/* add finalizer method (not for java.lang.Object) */
if (super) {
methodinfo *fi;
- fi = class_findmethod(c, utf_finalize, utf_fidesc);
+ fi = class_findmethod(c, utf_finalize, utf_void__void);
- if (fi) {
- if (!(fi->flags & ACC_STATIC)) {
+ if (fi)
+ if (!(fi->flags & ACC_STATIC))
c->finalizer = fi;
- }
- }
}
/* final tasks */
if (!makeinitializations)
return c;
+#if defined(USE_THREADS)
/* enter a monitor on the class */
builtin_monitorenter((java_objectheader *) c);
+#endif
/* maybe the class is already initalized or the current thread, which can
pass the monitor, is currently initalizing this class */
+ /* JOWENN: In future we need an additinal flag: initializationfailed,
+ since further access to the class should cause a NoClassDefFound,
+ if the static initializer failed once
+ */
+
if (c->initialized || c->initializing) {
+#if defined(USE_THREADS)
builtin_monitorexit((java_objectheader *) c);
+#endif
return c;
}
/* this initalizing run is done */
c->initializing = false;
+#if defined(USE_THREADS)
/* leave the monitor */
builtin_monitorexit((java_objectheader *) c);
+#endif
return r;
}
}
}
- m = class_findmethod(c, utf_clinit, utf_fidesc);
+ m = class_findmethod(c, utf_clinit, utf_void__void);
if (!m) {
if (initverbose) {
{
/* pseudo class for Arraystubs (extends java.lang.Object) */
- pseudo_class_Arraystub = class_new_intern(utf_new_char("$ARRAYSTUB$"));
pseudo_class_Arraystub->loaded = true;
pseudo_class_Arraystub->super = class_java_lang_Object;
pseudo_class_Arraystub->interfacescount = 2;
/* pseudo class representing the null type */
- pseudo_class_Null = class_new_intern(utf_new_char("$NULL$"));
pseudo_class_Null->loaded = true;
pseudo_class_Null->super = class_java_lang_Object;
class_link(pseudo_class_Null);
/* pseudo class representing new uninitialized objects */
- pseudo_class_New = class_new_intern(utf_new_char("$NEW$"));
pseudo_class_New->loaded = true;
pseudo_class_New->linked = true;
pseudo_class_New->super = class_java_lang_Object;
-/* class_link(pseudo_class_New); */
}
*******************************************************************************/
-void loader_init(u1 *stackbottom)
+bool loader_init(u1 *stackbottom)
{
+ classpath_info *cpi;
+
+ /* reset interface index */
+
interfaceindex = 0;
- /* create utf-symbols for pointer comparison of frequently used strings */
- utf_innerclasses = utf_new_char("InnerClasses");
- utf_constantvalue = utf_new_char("ConstantValue");
- utf_code = utf_new_char("Code");
- utf_exceptions = utf_new_char("Exceptions");
- utf_linenumbertable = utf_new_char("LineNumberTable");
- utf_sourcefile = utf_new_char("SourceFile");
- utf_finalize = utf_new_char("finalize");
- utf_fidesc = utf_new_char("()V");
- utf_init = utf_new_char("<init>");
- utf_clinit = utf_new_char("<clinit>");
- utf_initsystemclass = utf_new_char("initializeSystemClass");
- utf_systemclass = utf_new_char("java/lang/System");
- utf_vmclassloader = utf_new_char("java/lang/VMClassLoader");
- utf_initialize = utf_new_char("initialize");
- utf_initializedesc = utf_new_char("(I)V");
- utf_vmclass = utf_new_char("java/lang/VMClass");
- utf_java_lang_Object= utf_new_char("java/lang/Object");
- array_packagename = utf_new_char("<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_intern(utf_java_lang_Object);
- class_load(class_java_lang_Object);
- class_link(class_java_lang_Object);
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ /* Initialize the monitor pointer for zip/jar file locking. */
- class_java_lang_String = class_new(utf_new_char("java/lang/String"));
- class_load(class_java_lang_String);
- class_link(class_java_lang_String);
+ for (cpi = classpath_entries; cpi != NULL; cpi = cpi->next) {
+ if (cpi->type == CLASSPATH_ARCHIVE)
+ initObjectLock(&cpi->header);
+ }
+#endif
+
+ /* Create some important classes. These classes have to be created now */
+ /* because the classinfo pointers are used in the loading code. */
+
+ if (!class_load(class_java_lang_Object) ||
+ !class_link(class_java_lang_Object))
+ return false;
+
+ if (!class_load(class_java_lang_String) ||
+ !class_link(class_java_lang_String))
+ return false;
- class_java_lang_Cloneable = class_new(utf_new_char("java/lang/Cloneable"));
- class_load(class_java_lang_Cloneable);
- class_link(class_java_lang_Cloneable);
+ if (!class_load(class_java_lang_Cloneable) ||
+ !class_link(class_java_lang_Cloneable))
+ return false;
- class_java_io_Serializable =
- class_new(utf_new_char("java/io/Serializable"));
- class_load(class_java_io_Serializable);
- class_link(class_java_io_Serializable);
+ if (!class_load(class_java_io_Serializable) ||
+ !class_link(class_java_io_Serializable))
+ return false;
/* create classes representing primitive types */
create_primitive_classes();
if (stackbottom != 0)
initLocks();
#endif
+
+ return true;
}