/* src/vmcore/loader.c - class loader functions
- Copyright (C) 1996-2005, 2006, 2007 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
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include "threads/lock-common.h"
+#include "toolbox/hashtable.h"
#include "toolbox/logging.h"
#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vm/global.h"
+#include "vm/package.hpp"
#include "vm/primitive.h"
+#include "vm/resolve.h"
#include "vm/stringlocal.h"
#include "vm/vm.h"
#endif
-/* loader_init *****************************************************************
+/* global variables ***********************************************************/
+
+static hashtable *hashtable_classloader;
+
- Initializes all lists and loads all classes required for the system
- or the compiler.
+/* loader_preinit **************************************************************
+
+ Initializes the classpath list and loads classes required for the
+ primitive table.
+
+ NOTE: Exceptions thrown during VM initialization are caught in the
+ exception functions themselves.
*******************************************************************************/
-bool loader_init(void)
+void loader_preinit(void)
{
#if defined(ENABLE_THREADS)
list_classpath_entry *lce;
+#endif
+ TRACESUBSYSTEMINITIALIZATION("loader_preinit");
+
+#if defined(ENABLE_THREADS)
/* Initialize the monitor pointer for zip/jar file locking. */
for (lce = list_first(list_classpath_entries); lce != NULL;
- lce = list_next(list_classpath_entries, lce))
+ lce = list_next(list_classpath_entries, lce)) {
if (lce->type == CLASSPATH_ARCHIVE)
LOCK_INIT_OBJECT_LOCK(lce);
+ }
#endif
- /* load some important classes */
-
- if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object)))
- return false;
+ /* initialize classloader hashtable, 10 entries should be enough */
- if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String)))
- return false;
+ hashtable_classloader = NEW(hashtable);
+ hashtable_create(hashtable_classloader, 10);
-#if defined(ENABLE_JAVASE)
- if (!(class_java_lang_Cloneable =
- load_class_bootstrap(utf_java_lang_Cloneable)))
- return false;
+ /* Load the most basic classes. */
- if (!(class_java_io_Serializable =
- load_class_bootstrap(utf_java_io_Serializable)))
- return false;
-#endif
+ assert(vm_initializing == true);
- /* load classes for wrapping primitive types */
+ class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object);
#if defined(ENABLE_JAVASE)
- if (!(class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void)))
- return false;
+ class_java_lang_Cloneable = load_class_bootstrap(utf_java_lang_Cloneable);
+ class_java_io_Serializable = load_class_bootstrap(utf_java_io_Serializable);
#endif
+}
- if (!(class_java_lang_Boolean =
- load_class_bootstrap(utf_java_lang_Boolean)))
- return false;
- if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte)))
- return false;
+/* loader_init *****************************************************************
- if (!(class_java_lang_Character =
- load_class_bootstrap(utf_java_lang_Character)))
- return false;
+ Loads all classes required in the VM.
- if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short)))
- return false;
+ NOTE: Exceptions thrown during VM initialization are caught in the
+ exception functions themselves.
- if (!(class_java_lang_Integer =
- load_class_bootstrap(utf_java_lang_Integer)))
- return false;
+*******************************************************************************/
+
+void loader_init(void)
+{
+ TRACESUBSYSTEMINITIALIZATION("loader_init");
- if (!(class_java_lang_Long = load_class_bootstrap(utf_java_lang_Long)))
- return false;
+ /* Load primitive-type wrapping classes. */
- if (!(class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float)))
- return false;
+ assert(vm_initializing == true);
- if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double)))
- return false;
+#if defined(ENABLE_JAVASE)
+ class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void);
+#endif
+ class_java_lang_Boolean = load_class_bootstrap(utf_java_lang_Boolean);
+ class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte);
+ class_java_lang_Character = load_class_bootstrap(utf_java_lang_Character);
+ class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short);
+ class_java_lang_Integer = load_class_bootstrap(utf_java_lang_Integer);
+ class_java_lang_Long = load_class_bootstrap(utf_java_lang_Long);
+ class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float);
+ class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double);
- /* load some other important classes */
+ /* Load important system classes. */
- if (!(class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class)))
- return false;
+ class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class);
+ class_java_lang_String = load_class_bootstrap(utf_java_lang_String);
#if defined(ENABLE_JAVASE)
- if (!(class_java_lang_ClassLoader =
- load_class_bootstrap(utf_java_lang_ClassLoader)))
- return false;
+ class_java_lang_ClassLoader =
+ load_class_bootstrap(utf_java_lang_ClassLoader);
- if (!(class_java_lang_SecurityManager =
- load_class_bootstrap(utf_java_lang_SecurityManager)))
- return false;
+ class_java_lang_SecurityManager =
+ load_class_bootstrap(utf_java_lang_SecurityManager);
#endif
- if (!(class_java_lang_System = load_class_bootstrap(utf_java_lang_System)))
- return false;
+ class_java_lang_System =
+ load_class_bootstrap(utf_new_char("java/lang/System"));
- if (!(class_java_lang_Thread =
- load_class_bootstrap(utf_new_char("java/lang/Thread"))))
- return false;
+ class_java_lang_Thread =
+ load_class_bootstrap(utf_new_char("java/lang/Thread"));
#if defined(ENABLE_JAVASE)
- if (!(class_java_lang_ThreadGroup =
- load_class_bootstrap(utf_java_lang_ThreadGroup)))
- return false;
+ class_java_lang_ThreadGroup =
+ load_class_bootstrap(utf_java_lang_ThreadGroup);
#endif
-#if defined(WITH_CLASSPATH_GNU)
- if (!(class_java_lang_VMSystem =
- load_class_bootstrap(utf_new_char("java/lang/VMSystem"))))
+ class_java_lang_Throwable = load_class_bootstrap(utf_java_lang_Throwable);
- return false;
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+ class_java_lang_VMSystem =
+ load_class_bootstrap(utf_new_char("java/lang/VMSystem"));
- if (!(class_java_lang_VMThread =
- load_class_bootstrap(utf_new_char("java/lang/VMThread"))))
- return false;
+ class_java_lang_VMThread =
+ load_class_bootstrap(utf_new_char("java/lang/VMThread"));
+
+ class_java_lang_VMThrowable =
+ load_class_bootstrap(utf_new_char("java/lang/VMThrowable"));
#endif
+ /* Important system exceptions. */
- /* some classes which may be used more often */
+ class_java_lang_Exception = load_class_bootstrap(utf_java_lang_Exception);
-#if defined(ENABLE_JAVASE)
- if (!(class_java_lang_StackTraceElement =
- load_class_bootstrap(utf_java_lang_StackTraceElement)))
- return false;
+ class_java_lang_ClassNotFoundException =
+ load_class_bootstrap(utf_java_lang_ClassNotFoundException);
- if (!(class_java_lang_reflect_Constructor =
- load_class_bootstrap(utf_java_lang_reflect_Constructor)))
- return false;
+ class_java_lang_RuntimeException =
+ load_class_bootstrap(utf_java_lang_RuntimeException);
- if (!(class_java_lang_reflect_Field =
- load_class_bootstrap(utf_java_lang_reflect_Field)))
- return false;
+ /* Some classes which may be used often. */
- if (!(class_java_lang_reflect_Method =
- load_class_bootstrap(utf_java_lang_reflect_Method)))
- return false;
+#if defined(ENABLE_JAVASE)
+ class_java_lang_StackTraceElement = load_class_bootstrap(utf_java_lang_StackTraceElement);
- if (!(class_java_security_PrivilegedAction =
- load_class_bootstrap(utf_new_char("java/security/PrivilegedAction"))))
- return false;
+ class_java_lang_reflect_Constructor = load_class_bootstrap(utf_java_lang_reflect_Constructor);
+ class_java_lang_reflect_Field = load_class_bootstrap(utf_java_lang_reflect_Field);
+ class_java_lang_reflect_Method = load_class_bootstrap(utf_java_lang_reflect_Method);
- if (!(class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector)))
- return false;
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+ class_java_lang_reflect_VMConstructor = load_class_bootstrap(utf_java_lang_reflect_VMConstructor);
+ class_java_lang_reflect_VMField = load_class_bootstrap(utf_java_lang_reflect_VMField);
+ class_java_lang_reflect_VMMethod = load_class_bootstrap(utf_java_lang_reflect_VMMethod);
+# endif
-# if defined(WITH_CLASSPATH_SUN)
- if (!(class_sun_reflect_MagicAccessorImpl =
- load_class_bootstrap(utf_new_char("sun/reflect/MagicAccessorImpl"))))
- return false;
+ class_java_security_PrivilegedAction = load_class_bootstrap(utf_new_char("java/security/PrivilegedAction"));
+
+ class_java_util_HashMap = load_class_bootstrap(utf_new_char("java/util/HashMap"));
+ class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector);
+
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+ class_sun_reflect_MagicAccessorImpl =
+ load_class_bootstrap(utf_new_char("sun/reflect/MagicAccessorImpl"));
# endif
- if (!(arrayclass_java_lang_Object =
- load_class_bootstrap(utf_new_char("[Ljava/lang/Object;"))))
- return false;
+ arrayclass_java_lang_Object =
+ load_class_bootstrap(utf_new_char("[Ljava/lang/Object;"));
-#if defined(ENABLE_ANNOTATIONS)
+# if defined(ENABLE_ANNOTATIONS)
/* needed by annotation support */
- if (!(class_sun_reflect_ConstantPool =
- load_class_bootstrap(utf_new_char("sun/reflect/ConstantPool"))))
- return false;
+ class_sun_reflect_ConstantPool =
+ load_class_bootstrap(utf_new_char("sun/reflect/ConstantPool"));
-#if defined(WITH_CLASSPATH_GNU)
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
/* needed by GNU Classpaths annotation support */
- if (!(class_sun_reflect_annotation_AnnotationParser =
- load_class_bootstrap(utf_new_char("sun/reflect/annotation/AnnotationParser"))))
- return false;
+ class_sun_reflect_annotation_AnnotationParser =
+ load_class_bootstrap(utf_new_char("sun/reflect/annotation/AnnotationParser"));
+# endif
+# endif
#endif
+}
+
+
+/* loader_hashtable_classloader_add ********************************************
+
+ Adds an entry to the classloader hashtable.
+
+ REMEMBER: Also use this to register native loaders!
+
+*******************************************************************************/
+
+classloader_t *loader_hashtable_classloader_add(java_handle_t *cl)
+{
+ hashtable_classloader_entry *cle;
+ u4 key;
+ u4 slot;
+
+ if (cl == NULL)
+ return NULL;
+
+ LOCK_MONITOR_ENTER(hashtable_classloader->header);
+
+ LLNI_CRITICAL_START;
+
+ /* key for entry is the hashcode of the classloader;
+ aligned to 16-byte boundaries */
+
+ key = heap_hashcode(LLNI_DIRECT(cl)) >> 4;
+ slot = key & (hashtable_classloader->size - 1);
+ cle = hashtable_classloader->ptr[slot];
+
+ /* search hashchain for existing entry */
+
+ while (cle) {
+ if (cle->object == LLNI_DIRECT(cl))
+ break;
+
+ cle = cle->hashlink;
+ }
+
+ LLNI_CRITICAL_END;
+
+ /* if no classloader was found, we create a new entry here */
+
+ if (cle == NULL) {
+ cle = NEW(hashtable_classloader_entry);
+
+#if defined(ENABLE_GC_CACAO)
+ /* register the classloader object with the GC */
+
+ gc_reference_register(&(cle->object), GC_REFTYPE_CLASSLOADER);
#endif
+
+ LLNI_CRITICAL_START;
+
+ cle->object = LLNI_DIRECT(cl);
+
+ LLNI_CRITICAL_END;
+
+/*#define LOADER_DEBUG_CLASSLOADER*/
+#ifdef LOADER_DEBUG_CLASSLOADER
+ printf("CLASSLOADER: adding new classloader entry %p for %p: ", cle, cl);
+ class_print(LLNI_vftbl_direct(cl)->class);
+ printf("\n");
+ fflush(stdout);
#endif
+ /* insert entry into hashtable */
- return true;
+ cle->hashlink = hashtable_classloader->ptr[slot];
+ hashtable_classloader->ptr[slot] = cle;
+
+ /* update number of entries */
+
+ hashtable_classloader->entries++;
+ }
+
+
+ LOCK_MONITOR_EXIT(hashtable_classloader->header);
+
+#if defined(ENABLE_HANDLES)
+ return cle;
+#else
+ return cl;
+#endif
+}
+
+
+/* loader_hashtable_classloader_find *******************************************
+
+ Find an entry in the classloader hashtable.
+
+*******************************************************************************/
+
+classloader_t *loader_hashtable_classloader_find(java_handle_t *cl)
+{
+ hashtable_classloader_entry *cle;
+ u4 key;
+ u4 slot;
+
+ if (cl == NULL)
+ return NULL;
+
+ LLNI_CRITICAL_START;
+
+ /* key for entry is the hashcode of the classloader;
+ aligned to 16-byte boundaries */
+
+ key = heap_hashcode(LLNI_DIRECT(cl)) >> 4;
+ slot = key & (hashtable_classloader->size - 1);
+ cle = hashtable_classloader->ptr[slot];
+
+ /* search hashchain for existing entry */
+
+ while (cle) {
+ if (cle->object == LLNI_DIRECT(cl))
+ break;
+
+ cle = cle->hashlink;
+ }
+
+#ifdef LOADER_DEBUG_CLASSLOADER
+ if (cle == NULL) {
+ printf("CLASSLOADER: unable to find classloader entry for %p: ", cl);
+ class_print(LLNI_vftbl_direct(cl)->class);
+ printf("\n");
+ fflush(stdout);
+ }
+#endif
+
+ LLNI_CRITICAL_END;
+
+#if defined(ENABLE_HANDLES)
+ return cle;
+#else
+ return cl;
+#endif
}
u1 *cptags;
voidptr *cpinfos;
- c = cb->class;
+ c = cb->clazz;
/* number of entries in the constant_pool table plus one */
if (!suck_check_classbuffer_size(cb, 2))
/* get classinfo */
- c = cb->class;
+ c = cb->clazz;
/* check remaining bytecode */
classinfo *load_class_from_sysloader(utf *name)
{
- methodinfo *m;
- classloader *cl;
- classinfo *c;
+ methodinfo *m;
+ java_handle_t *clo;
+ classloader_t *cl;
+ classinfo *c;
assert(class_java_lang_Object);
assert(class_java_lang_ClassLoader);
if (!m)
return false;
- cl = vm_call_method(m, NULL);
+ clo = vm_call_method(m, NULL);
- if (!cl)
+ if (!clo)
return false;
+ cl = loader_hashtable_classloader_add(clo);
+
c = load_class_from_classloader(name, cl);
return c;
*******************************************************************************/
-classinfo *load_class_from_classloader(utf *name, classloader *cl)
+classinfo *load_class_from_classloader(utf *name, classloader_t *cl)
{
java_handle_t *o;
classinfo *c;
return c;
}
}
-
- assert(class_java_lang_Object);
- lc = class_resolveclassmethod(cl->vftbl->class,
+ LLNI_class_get(cl, c);
+
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+ /* OpenJDK uses this internal function because it's
+ synchronized. */
+
+ lc = class_resolveclassmethod(c,
+ utf_loadClassInternal,
+ utf_java_lang_String__java_lang_Class,
+ NULL,
+ true);
+#else
+ lc = class_resolveclassmethod(c,
utf_loadClass,
utf_java_lang_String__java_lang_Class,
- class_java_lang_Object,
+ NULL,
true);
+#endif
- if (!lc)
+ if (lc == NULL)
return false; /* exception */
/* move return value into `o' and cast it afterwards to a classinfo* */
RT_TIMING_GET_TIME(time_prepare);
- o = vm_call_method(lc, cl, string);
+ o = vm_call_method(lc, (java_handle_t *) cl, string);
RT_TIMING_GET_TIME(time_java);
cb = suck_start(c);
if (cb == NULL) {
- /* this normally means, the classpath was not set properly */
-
- if (name == utf_java_lang_Object)
- vm_abort("java/lang/NoClassDefFoundError: java/lang/Object");
-
exceptions_throw_classnotfoundexception(name);
-
return NULL;
}
RT_TIMING_GET_TIME(time_load);
- if (!r) {
+ if (r == NULL) {
/* the class could not be loaded, free the classinfo struct */
class_free(c);
-
- } else {
+ }
+ else {
/* Store this class in the loaded class cache this step also
- checks the loading constraints. If the class has been loaded
- before, the earlier loaded class is returned. */
+ checks the loading constraints. If the class has been
+ loaded before, the earlier loaded class is returned. */
classinfo *res = classcache_store(NULL, c, true);
- if (!res) {
+ if (res == NULL) {
/* exception */
class_free(c);
}
+ else {
+ /* Add the package name to the boot packages. */
+
+ Package_add(c->packagename);
+ }
r = res;
}
}
-/* load_class_from_classbuffer *************************************************
+/* load_class_from_classbuffer_intern ******************************************
- Loads everything interesting about a class from the class file. The
- 'classinfo' structure must have been allocated previously.
-
- The super class and the interfaces implemented by this class need
- not be loaded. The link is set later by the function 'class_link'.
+ Loads a class from a classbuffer into a given classinfo structure.
+ Super-classes are also loaded at this point and some verfication
+ checks are done.
SYNCHRONIZATION:
This function is NOT synchronized!
*******************************************************************************/
-classinfo *load_class_from_classbuffer(classbuffer *cb)
+static bool load_class_from_classbuffer_intern(classbuffer *cb)
{
- classinfo *c;
- utf *name;
- utf *supername;
+ classinfo *c;
+ classinfo *tc;
+ utf *name;
+ utf *supername;
+ utf **interfacesnames;
+ utf *u;
+ constant_classref *cr;
+ int16_t index;
+
u4 i,j;
u4 ma, mi;
- s4 dumpsize;
descriptor_pool *descpool;
#if defined(ENABLE_STATISTICS)
u4 classrefsize;
RT_TIMING_GET_TIME(time_start);
- /* get the classbuffer's class */
-
- c = cb->class;
-
- /* the class is already loaded */
-
- if (c->state & CLASS_LOADED)
- return c;
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- count_class_loads++;
-#endif
-
-#if !defined(NDEBUG)
- /* output for debugging purposes */
-
- if (loadverbose)
- log_message_class("Loading class: ", c);
-#endif
-
- /* mark start of dump memory area */
-
- dumpsize = dump_size();
+ /* Get the classbuffer's class. */
- /* class is currently loading */
-
- c->state |= CLASS_LOADING;
+ c = cb->clazz;
if (!suck_check_classbuffer_size(cb, 4 + 2 + 2))
- goto return_exception;
+ return false;
/* check signature */
if (suck_u4(cb) != MAGIC) {
exceptions_throw_classformaterror(c, "Bad magic number");
-
- goto return_exception;
+ return false;
}
/* check version */
if (!(ma < MAJOR_VERSION || (ma == MAJOR_VERSION && mi <= MINOR_VERSION))) {
exceptions_throw_unsupportedclassversionerror(c, ma, mi);
- goto return_exception;
+ return false;
}
RT_TIMING_GET_TIME(time_checks);
/* load the constant pool */
if (!load_constantpool(cb, descpool))
- goto return_exception;
+ return false;
RT_TIMING_GET_TIME(time_cpool);
/* ACC flags */
if (!suck_check_classbuffer_size(cb, 2))
- goto return_exception;
+ return false;
/* We OR the flags here, as we set already some flags in
class_create_classinfo. */
exceptions_throw_classformaterror(c,
"Illegal class modifiers: 0x%X",
c->flags);
- goto return_exception;
+ return false;
}
if (c->flags & ACC_SUPER) {
exceptions_throw_classformaterror(c,
"Illegal class modifiers: 0x%X",
c->flags);
- goto return_exception;
+ return false;
}
if (!suck_check_classbuffer_size(cb, 2 + 2))
- goto return_exception;
+ return false;
+
+ /* This class. */
- /* this class */
+ index = suck_u2(cb);
- i = suck_u2(cb);
+ name = (utf *) class_getconstant(c, index, CONSTANT_Class);
- if (!(name = (utf *) class_getconstant(c, i, CONSTANT_Class)))
- goto return_exception;
+ if (name == NULL)
+ return false;
if (c->name == utf_not_named_yet) {
/* we finally have a name for this class */
}
else if (name != c->name) {
exceptions_throw_noclassdeffounderror_wrong_name(c, name);
- goto return_exception;
+ return false;
}
- /* retrieve superclass */
+ /* Retrieve superclass. */
+
+ c->super = NULL;
+
+ index = suck_u2(cb);
- c->super.any = NULL;
+ if (index == 0) {
+ supername = NULL;
+
+ /* This is only allowed for java.lang.Object. */
+
+ if (c->name != utf_java_lang_Object) {
+ exceptions_throw_classformaterror(c, "Bad superclass index");
+ return false;
+ }
+ }
+ else {
+ supername = (utf *) class_getconstant(c, index, CONSTANT_Class);
- if ((i = suck_u2(cb))) {
- if (!(supername = (utf *) class_getconstant(c, i, CONSTANT_Class)))
- goto return_exception;
+ if (supername == NULL)
+ return false;
/* java.lang.Object may not have a super class. */
if (c->name == utf_java_lang_Object) {
exceptions_throw_classformaterror(NULL, "java.lang.Object with superclass");
- goto return_exception;
+ return false;
}
- /* Interfaces must have java.lang.Object as super class. */
+ /* Detect circularity. */
- if ((c->flags & ACC_INTERFACE) && (supername != utf_java_lang_Object)) {
- exceptions_throw_classformaterror(c, "Interfaces must have java.lang.Object as superclass");
- goto return_exception;
+ if (supername == c->name) {
+ exceptions_throw_classcircularityerror(c);
+ return false;
}
- } else {
- supername = NULL;
-
- /* This is only allowed for java.lang.Object. */
+ /* Interfaces must have java.lang.Object as super class. */
- if (c->name != utf_java_lang_Object) {
- exceptions_throw_classformaterror(c, "Bad superclass index");
- goto return_exception;
+ if ((c->flags & ACC_INTERFACE) && (supername != utf_java_lang_Object)) {
+ exceptions_throw_classformaterror(c, "Interfaces must have java.lang.Object as superclass");
+ return false;
}
}
- /* retrieve interfaces */
+ /* Parse the super interfaces. */
if (!suck_check_classbuffer_size(cb, 2))
- goto return_exception;
+ return false;
c->interfacescount = suck_u2(cb);
if (!suck_check_classbuffer_size(cb, 2 * c->interfacescount))
- goto return_exception;
+ return false;
+
+ c->interfaces = MNEW(classinfo*, c->interfacescount);
+
+ /* Get the names of the super interfaces. */
+
+ interfacesnames = DMNEW(utf*, c->interfacescount);
- c->interfaces = MNEW(classref_or_classinfo, c->interfacescount);
for (i = 0; i < c->interfacescount; i++) {
- /* the classrefs are created later */
- if (!(c->interfaces[i].any = (utf *) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
- goto return_exception;
+ index = suck_u2(cb);
+
+ u = (utf *) class_getconstant(c, index, CONSTANT_Class);
+
+ if (u == NULL)
+ return false;
+
+ interfacesnames[i] = u;
}
RT_TIMING_GET_TIME(time_setup);
- /* load fields */
+ /* Parse fields. */
if (!suck_check_classbuffer_size(cb, 2))
- goto return_exception;
+ return false;
c->fieldscount = suck_u2(cb);
c->fields = MNEW(fieldinfo, c->fieldscount);
for (i = 0; i < c->fieldscount; i++) {
if (!field_load(cb, &(c->fields[i]), descpool))
- goto return_exception;
+ return false;
}
RT_TIMING_GET_TIME(time_fields);
- /* load methods */
+ /* Parse methods. */
if (!suck_check_classbuffer_size(cb, 2))
- goto return_exception;
+ return false;
c->methodscount = suck_u2(cb);
c->methods = MNEW(methodinfo, c->methodscount);
for (i = 0; i < c->methodscount; i++) {
if (!method_load(cb, &(c->methods[i]), descpool))
- goto return_exception;
+ return false;
}
RT_TIMING_GET_TIME(time_methods);
RT_TIMING_GET_TIME(time_descs);
/* put the classrefs in the constant pool */
+
for (i = 0; i < c->cpcount; i++) {
if (c->cptags[i] == CONSTANT_Class) {
utf *name = (utf *) c->cpinfos[i];
}
}
- /* set the super class reference */
+ /* Resolve the super class. */
+
+ if (supername != NULL) {
+ cr = descriptor_pool_lookup_classref(descpool, supername);
+
+ if (cr == NULL)
+ return false;
+
+ /* XXX This should be done better. */
+ tc = resolve_classref_or_classinfo_eager(CLASSREF_OR_CLASSINFO(cr), false);
- if (supername) {
- c->super.ref = descriptor_pool_lookup_classref(descpool, supername);
- if (!c->super.ref)
- goto return_exception;
+ if (tc == NULL) {
+ resolve_handle_pending_exception(true);
+ return false;
+ }
+
+ /* Interfaces are not allowed as super classes. */
+
+ if (tc->flags & ACC_INTERFACE) {
+ exceptions_throw_incompatibleclasschangeerror(c, "class %s has interface %s as super class");
+ return false;
+ }
+
+ /* Don't allow extending final classes */
+
+ if (tc->flags & ACC_FINAL) {
+ exceptions_throw_verifyerror(NULL,
+ "Cannot inherit from final class");
+ return false;
+ }
+
+ /* Store the super class. */
+
+ c->super = tc;
}
- /* set the super interfaces references */
+ /* Resolve the super interfaces. */
for (i = 0; i < c->interfacescount; i++) {
- c->interfaces[i].ref =
- descriptor_pool_lookup_classref(descpool,
- (utf *) c->interfaces[i].any);
- if (!c->interfaces[i].ref)
- goto return_exception;
+ u = interfacesnames[i];
+ cr = descriptor_pool_lookup_classref(descpool, u);
+
+ if (cr == NULL)
+ return false;
+
+ /* XXX This should be done better. */
+ tc = resolve_classref_or_classinfo_eager(CLASSREF_OR_CLASSINFO(cr), false);
+
+ if (tc == NULL) {
+ resolve_handle_pending_exception(true);
+ return false;
+ }
+
+ /* Detect circularity. */
+
+ if (tc == c) {
+ exceptions_throw_classcircularityerror(c);
+ return false;
+ }
+
+ if (!(tc->flags & ACC_INTERFACE)) {
+ exceptions_throw_incompatibleclasschangeerror(tc,
+ "Implementing class");
+ return false;
+ }
+
+ /* Store the super interface. */
+
+ c->interfaces[i] = tc;
}
RT_TIMING_GET_TIME(time_setrefs);
- /* parse field descriptors */
+ /* Parse the field descriptors. */
for (i = 0; i < c->fieldscount; i++) {
c->fields[i].parseddesc =
descriptor_pool_parse_field_descriptor(descpool,
c->fields[i].descriptor);
if (!c->fields[i].parseddesc)
- goto return_exception;
+ return false;
}
RT_TIMING_GET_TIME(time_parsefds);
methodinfo *m = &c->methods[i];
m->parseddesc =
descriptor_pool_parse_method_descriptor(descpool, m->descriptor,
- m->flags, class_get_self_classref(m->class));
+ m->flags, class_get_self_classref(m->clazz));
if (!m->parseddesc)
- goto return_exception;
+ return false;
for (j = 0; j < m->rawexceptiontablelength; j++) {
if (!m->rawexceptiontable[j].catchtype.any)
continue;
+
if ((m->rawexceptiontable[j].catchtype.ref =
descriptor_pool_lookup_classref(descpool,
(utf *) m->rawexceptiontable[j].catchtype.any)) == NULL)
- goto return_exception;
+ return false;
}
for (j = 0; j < m->thrownexceptionscount; j++) {
if (!m->thrownexceptions[j].any)
continue;
+
if ((m->thrownexceptions[j].ref = descriptor_pool_lookup_classref(descpool,
(utf *) m->thrownexceptions[j].any)) == NULL)
- goto return_exception;
+ return false;
}
}
descriptor_pool_parse_field_descriptor(descpool,
fmi->descriptor);
if (!fmi->parseddesc.fd)
- goto return_exception;
+ return false;
+
index = fmi->p.index;
fmi->p.classref =
(constant_classref *) class_getconstant(c, index,
CONSTANT_Class);
if (!fmi->p.classref)
- goto return_exception;
+ return false;
break;
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
(constant_classref *) class_getconstant(c, index,
CONSTANT_Class);
if (!fmi->p.classref)
- goto return_exception;
+ return false;
fmi->parseddesc.md =
descriptor_pool_parse_method_descriptor(descpool,
fmi->descriptor,
ACC_UNDEF,
fmi->p.classref);
if (!fmi->parseddesc.md)
- goto return_exception;
+ return false;
break;
}
}
if (c->fields[old].name == fi->name &&
c->fields[old].descriptor == fi->descriptor) {
exceptions_throw_classformaterror(c, "Repetitive field name/signature");
- goto return_exception;
+ return false;
}
} while ((old = next[old]));
}
index = ((((size_t) mi->name) +
((size_t) mi->descriptor)) >> shift) % hashlen;
- /*{ JOWENN
- int dbg;
- for (dbg=0;dbg<hashlen+hashlen/5;++dbg){
- printf("Hash[%d]:%d\n",dbg,hashtab[dbg]);
- }
- }*/
-
if ((old = hashtab[index])) {
old--;
next[i] = old;
if (c->methods[old].name == mi->name &&
c->methods[old].descriptor == mi->descriptor) {
exceptions_throw_classformaterror(c, "Repetitive method name/signature");
- goto return_exception;
+ return false;
}
} while ((old = next[old]));
}
/* load attribute structures */
if (!class_load_attributes(cb))
- goto return_exception;
+ return false;
- /* Pre Java 1.5 version don't check this. This implementation is like
- Java 1.5 do it: for class file version 45.3 we don't check it, older
- versions are checked.
- */
+ /* Pre Java 1.5 version don't check this. This implementation is
+ like Java 1.5 do it: for class file version 45.3 we don't check
+ it, older versions are checked. */
if (((ma == 45) && (mi > 3)) || (ma > 45)) {
/* check if all data has been read */
if (classdata_left > 0) {
exceptions_throw_classformaterror(c, "Extra bytes at the end of class file");
- goto return_exception;
+ return false;
}
}
RT_TIMING_GET_TIME(time_attrs);
- /* release dump area */
-
- dump_release(dumpsize);
-
- /* revert loading state and class is loaded */
-
- c->state = (c->state & ~CLASS_LOADING) | CLASS_LOADED;
-
-#if defined(ENABLE_JVMTI)
- /* fire Class Prepare JVMTI event */
-
- if (jvmti)
- jvmti_ClassLoadPrepare(true, c);
-#endif
-
-#if !defined(NDEBUG)
- if (loadverbose)
- log_message_class("Loading done class: ", c);
-#endif
-
RT_TIMING_TIME_DIFF(time_start , time_checks , RT_TIMING_LOAD_CHECKS);
RT_TIMING_TIME_DIFF(time_checks , time_ndpool , RT_TIMING_LOAD_NDPOOL);
RT_TIMING_TIME_DIFF(time_ndpool , time_cpool , RT_TIMING_LOAD_CPOOL);
RT_TIMING_TIME_DIFF(time_verify , time_attrs , RT_TIMING_LOAD_ATTRS);
RT_TIMING_TIME_DIFF(time_start , time_attrs , RT_TIMING_LOAD_TOTAL);
- return c;
+ return true;
+}
-return_exception:
- /* release dump area */
- dump_release(dumpsize);
+/* load_class_from_classbuffer *************************************************
- /* an exception has been thrown */
+ Convenience wrapper for load_class_from_classbuffer.
- return NULL;
+ SYNCHRONIZATION:
+ This function is NOT synchronized!
+
+*******************************************************************************/
+
+classinfo *load_class_from_classbuffer(classbuffer *cb)
+{
+ classinfo *c;
+ bool result;
+ int32_t dumpmarker;
+
+ /* Get the classbuffer's class. */
+
+ c = cb->clazz;
+
+ /* Check if the class is already loaded. */
+
+ if (c->state & CLASS_LOADED)
+ return c;
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ count_class_loads++;
+#endif
+
+#if !defined(NDEBUG)
+ if (loadverbose)
+ log_message_class("Loading class: ", c);
+#endif
+
+ /* Mark start of dump memory area. */
+
+ DMARKER;
+
+ /* Class is currently loading. */
+
+ c->state |= CLASS_LOADING;
+
+ /* Parse the classbuffer. */
+
+ result = load_class_from_classbuffer_intern(cb);
+
+ /* Release dump area. */
+
+ DRELEASE;
+
+ /* An error occurred. */
+
+ if (result == false) {
+ /* Revert loading state. */
+
+ c->state = (c->state & ~CLASS_LOADING);
+
+ return NULL;
+ }
+
+ /* Revert loading state and set loaded. */
+
+ c->state = (c->state & ~CLASS_LOADING) | CLASS_LOADED;
+
+#if defined(ENABLE_JVMTI)
+ /* fire Class Prepare JVMTI event */
+
+ if (jvmti)
+ jvmti_ClassLoadPrepare(true, c);
+#endif
+
+#if !defined(NDEBUG)
+ if (loadverbose)
+ log_message_class("Loading done class: ", c);
+#endif
+
+ return c;
}
*******************************************************************************/
-classinfo *load_newly_created_array(classinfo *c, classloader *loader)
+classinfo *load_newly_created_array(classinfo *c, classloader_t *loader)
{
classinfo *comp = NULL;
methodinfo *clone;
assert(class_java_io_Serializable);
#endif
- /* setup the array class */
+ /* Setup the array class. */
- c->super.cls = class_java_lang_Object;
+ c->super = class_java_lang_Object;
#if defined(ENABLE_JAVASE)
- c->interfacescount = 2;
- c->interfaces = MNEW(classref_or_classinfo, 2);
- c->interfaces[0].cls = class_java_lang_Cloneable;
- c->interfaces[1].cls = class_java_io_Serializable;
+ c->interfacescount = 2;
+ c->interfaces = MNEW(classinfo*, 2);
+ c->interfaces[0] = class_java_lang_Cloneable;
+ c->interfaces[1] = class_java_io_Serializable;
#elif defined(ENABLE_JAVAME_CLDC1_1)
- c->interfacescount = 0;
- c->interfaces = NULL;
+ c->interfacescount = 0;
+ c->interfaces = NULL;
#else
# error unknow Java configuration
#endif
c->methodscount = 1;
- c->methods = MNEW(methodinfo, c->methodscount);
+ c->methods = MNEW(methodinfo, c->methodscount);
+
MZERO(c->methods, methodinfo, c->methodscount);
classrefs = MNEW(constant_classref, 2);
+
CLASSREF_INIT(classrefs[0], c, c->name);
CLASSREF_INIT(classrefs[1], c, utf_java_lang_Object);
clone->name = utf_clone;
clone->descriptor = utf_void__java_lang_Object;
clone->parseddesc = clonedesc;
- clone->class = c;
+ clone->clazz = c;
/* parse the descriptor to get the register allocation */