/* 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.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- $Id: loader.c 7692 2007-04-12 14:47:24Z twisti $
-
*/
#include "mm/memory.h"
-#if defined(ENABLE_THREADS)
-# include "threads/native/lock.h"
-#endif
+#include "native/llni.h"
+
+#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
#include "vmcore/classcache.h"
+#include "vmcore/field.h"
#include "vmcore/linker.h"
#include "vmcore/loader.h"
+#include "vmcore/method.h"
#include "vmcore/options.h"
#include "vmcore/rt-timing.h"
#endif
-/* loader_init *****************************************************************
+/* global variables ***********************************************************/
+
+static hashtable *hashtable_classloader;
+
+
+/* loader_preinit **************************************************************
- Initializes all lists and loads all classes required for the system
- or the compiler.
+ 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((java_objectheader *) lce);
+ LOCK_INIT_OBJECT_LOCK(lce);
+ }
#endif
- /* load some important classes */
+ /* initialize classloader hashtable, 10 entries should be enough */
- if (!(class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object)))
- return false;
+ hashtable_classloader = NEW(hashtable);
+ hashtable_create(hashtable_classloader, 10);
- if (!(class_java_lang_String = load_class_bootstrap(utf_java_lang_String)))
- return false;
+ /* Load the most basic classes. */
+
+ assert(vm_initializing == true);
+
+ class_java_lang_Object = load_class_bootstrap(utf_java_lang_Object);
#if defined(ENABLE_JAVASE)
- if (!(class_java_lang_Cloneable =
- load_class_bootstrap(utf_java_lang_Cloneable)))
- 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_io_Serializable =
- load_class_bootstrap(utf_java_io_Serializable)))
- return false;
+
+/* loader_init *****************************************************************
+
+ Loads all classes required in the VM.
+
+ NOTE: Exceptions thrown during VM initialization are caught in the
+ exception functions themselves.
+
+*******************************************************************************/
+
+void loader_init(void)
+{
+ TRACESUBSYSTEMINITIALIZATION("loader_init");
+
+ /* Load primitive-type wrapping classes. */
+
+ assert(vm_initializing == true);
+
+#if defined(ENABLE_JAVASE)
+ class_java_lang_Void = load_class_bootstrap(utf_java_lang_Void);
#endif
- /* load classes for wrapping primitive types */
+ 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 important system classes. */
+
+ 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_Void = load_class_bootstrap(utf_java_lang_Void)))
- return false;
+ class_java_lang_ClassLoader =
+ load_class_bootstrap(utf_java_lang_ClassLoader);
+
+ class_java_lang_SecurityManager =
+ load_class_bootstrap(utf_java_lang_SecurityManager);
#endif
- if (!(class_java_lang_Boolean =
- load_class_bootstrap(utf_java_lang_Boolean)))
- return false;
+ class_java_lang_System =
+ load_class_bootstrap(utf_new_char("java/lang/System"));
- if (!(class_java_lang_Byte = load_class_bootstrap(utf_java_lang_Byte)))
- return false;
+ class_java_lang_Thread =
+ load_class_bootstrap(utf_new_char("java/lang/Thread"));
- if (!(class_java_lang_Character =
- load_class_bootstrap(utf_java_lang_Character)))
- return false;
+#if defined(ENABLE_JAVASE)
+ class_java_lang_ThreadGroup =
+ load_class_bootstrap(utf_java_lang_ThreadGroup);
+#endif
- if (!(class_java_lang_Short = load_class_bootstrap(utf_java_lang_Short)))
- return false;
+ class_java_lang_Throwable = load_class_bootstrap(utf_java_lang_Throwable);
- if (!(class_java_lang_Integer =
- load_class_bootstrap(utf_java_lang_Integer)))
- 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_Long = load_class_bootstrap(utf_java_lang_Long)))
- return false;
+ class_java_lang_VMThread =
+ load_class_bootstrap(utf_new_char("java/lang/VMThread"));
- if (!(class_java_lang_Float = load_class_bootstrap(utf_java_lang_Float)))
- return false;
+ class_java_lang_VMThrowable =
+ load_class_bootstrap(utf_new_char("java/lang/VMThrowable"));
+#endif
- if (!(class_java_lang_Double = load_class_bootstrap(utf_java_lang_Double)))
- return false;
+ /* Important system exceptions. */
+ class_java_lang_Exception = load_class_bootstrap(utf_java_lang_Exception);
- /* load some other important classes */
+ class_java_lang_ClassNotFoundException =
+ load_class_bootstrap(utf_java_lang_ClassNotFoundException);
- if (!(class_java_lang_Class = load_class_bootstrap(utf_java_lang_Class)))
- return false;
+ class_java_lang_RuntimeException =
+ load_class_bootstrap(utf_java_lang_RuntimeException);
+
+ /* Some classes which may be used often. */
#if defined(ENABLE_JAVASE)
- if (!(class_java_lang_ClassLoader =
- load_class_bootstrap(utf_java_lang_ClassLoader)))
- return false;
+ class_java_lang_StackTraceElement = load_class_bootstrap(utf_java_lang_StackTraceElement);
+
+ 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 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
+
+ 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
+
+ arrayclass_java_lang_Object =
+ load_class_bootstrap(utf_new_char("[Ljava/lang/Object;"));
+
+# if defined(ENABLE_ANNOTATIONS)
+ /* needed by annotation support */
+ class_sun_reflect_ConstantPool =
+ load_class_bootstrap(utf_new_char("sun/reflect/ConstantPool"));
+
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+ /* needed by GNU Classpaths annotation support */
+ class_sun_reflect_annotation_AnnotationParser =
+ load_class_bootstrap(utf_new_char("sun/reflect/annotation/AnnotationParser"));
+# endif
+# endif
+#endif
+}
- if (!(class_java_lang_SecurityManager =
- load_class_bootstrap(utf_java_lang_SecurityManager)))
- return false;
+
+/* 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
- if (!(class_java_lang_System = load_class_bootstrap(utf_java_lang_System)))
- return false;
+ LLNI_CRITICAL_START;
- if (!(class_java_lang_Thread =
- load_class_bootstrap(utf_new_char("java/lang/Thread"))))
- return false;
+ cle->object = LLNI_DIRECT(cl);
-#if defined(ENABLE_JAVASE)
- if (!(class_java_lang_ThreadGroup =
- load_class_bootstrap(utf_java_lang_ThreadGroup)))
- return false;
+ 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
-#if defined(WITH_CLASSPATH_GNU)
- if (!(class_java_lang_VMSystem =
- load_class_bootstrap(utf_new_char("java/lang/VMSystem"))))
+ /* insert entry into hashtable */
- return false;
+ cle->hashlink = hashtable_classloader->ptr[slot];
+ hashtable_classloader->ptr[slot] = cle;
- if (!(class_java_lang_VMThread =
- load_class_bootstrap(utf_new_char("java/lang/VMThread"))))
- return false;
+ /* update number of entries */
+
+ hashtable_classloader->entries++;
+ }
+
+
+ LOCK_MONITOR_EXIT(hashtable_classloader->header);
+
+#if defined(ENABLE_HANDLES)
+ return cle;
+#else
+ return cl;
#endif
+}
- /* some classes which may be used more often */
+/* loader_hashtable_classloader_find *******************************************
-#if defined(ENABLE_JAVASE)
- if (!(class_java_lang_StackTraceElement =
- load_class_bootstrap(utf_java_lang_StackTraceElement)))
- return false;
+ Find an entry in the classloader hashtable.
- if (!(class_java_lang_reflect_Constructor =
- load_class_bootstrap(utf_java_lang_reflect_Constructor)))
- return false;
+*******************************************************************************/
- if (!(class_java_lang_reflect_Field =
- load_class_bootstrap(utf_java_lang_reflect_Field)))
- return false;
+classloader_t *loader_hashtable_classloader_find(java_handle_t *cl)
+{
+ hashtable_classloader_entry *cle;
+ u4 key;
+ u4 slot;
- if (!(class_java_lang_reflect_Method =
- load_class_bootstrap(utf_java_lang_reflect_Method)))
- return false;
+ if (cl == NULL)
+ return NULL;
- if (!(class_java_security_PrivilegedAction =
- load_class_bootstrap(utf_new_char("java/security/PrivilegedAction"))))
- return false;
+ LLNI_CRITICAL_START;
- if (!(class_java_util_Vector = load_class_bootstrap(utf_java_util_Vector)))
- return false;
+ /* key for entry is the hashcode of the classloader;
+ aligned to 16-byte boundaries */
- if (!(arrayclass_java_lang_Object =
- load_class_bootstrap(utf_new_char("[Ljava/lang/Object;"))))
- return false;
+ 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
- return true;
+ 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))
cptags[forward_classes->thisindex] = CONSTANT_Class;
- if (opt_eager) {
- classinfo *tc;
-
- if (!(tc = load_class_bootstrap(name)))
- return false;
-
- /* link the class later, because we cannot link the class currently
- loading */
- list_add_first(&unlinkedclasses, tc);
- }
-
/* the classref is created later */
cpinfos[forward_classes->thisindex] = name;
/* get classinfo */
- c = cb->class;
+ c = cb->clazz;
/* check remaining bytecode */
return false;
}
- /* get signature */
-
- signature_index = suck_u2(cb);
-
- if (!(*signature = class_getconstant(c, signature_index, CONSTANT_Utf8)))
- return false;
-
- return true;
-}
-#endif /* defined(ENABLE_JAVASE) */
-
-
-/* load_field ******************************************************************
-
- 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 bool load_field(classbuffer *cb, fieldinfo *f, descriptor_pool *descpool)
-{
- classinfo *c;
- u4 attrnum, i;
- u4 jtype;
- u4 pindex = field_load_NOVALUE; /* constantvalue_index */
- utf *u;
-
- c = cb->class;
-
- if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
- return false;
-
- f->flags = suck_u2(cb);
-
- if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
- return false;
-
- f->name = u;
-
- if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
- return false;
-
- f->descriptor = u;
- f->parseddesc = NULL;
-
- if (!descriptor_pool_add(descpool, u, NULL))
- return false;
-
- /* descriptor_pool_add accepts method descriptors, so we have to check */
- /* against them here before the call of descriptor_to_basic_type below. */
- if (u->text[0] == '(') {
- exceptions_throw_classformaterror(c, "Method descriptor used for field");
- return false;
- }
-
-#ifdef ENABLE_VERIFIER
- if (opt_verify) {
- /* check name */
- if (!is_valid_name_utf(f->name) || f->name->text[0] == '<') {
- exceptions_throw_classformaterror(c,
- "Illegal Field name \"%s\"",
- f->name->text);
- return false;
- }
-
- /* check flag consistency */
- i = f->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED);
-
- if ((i != 0 && i != ACC_PUBLIC && i != ACC_PRIVATE && i != ACC_PROTECTED) ||
- ((f->flags & (ACC_FINAL | ACC_VOLATILE)) == (ACC_FINAL | ACC_VOLATILE))) {
- exceptions_throw_classformaterror(c,
- "Illegal field modifiers: 0x%X",
- f->flags);
- return false;
- }
-
- if (c->flags & ACC_INTERFACE) {
- if (((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
- != (ACC_STATIC | ACC_PUBLIC | ACC_FINAL)) ||
- f->flags & ACC_TRANSIENT) {
- exceptions_throw_classformaterror(c,
- "Illegal field modifiers: 0x%X",
- f->flags);
- return false;
- }
- }
- }
-#endif /* ENABLE_VERIFIER */
-
- f->type = jtype = descriptor_to_basic_type(f->descriptor); /* data type */
- f->offset = 0; /* offset from start of object */
- f->class = c;
-
- switch (f->type) {
- case TYPE_INT:
- f->value.i = 0;
- break;
-
- case TYPE_FLT:
- f->value.f = 0.0;
- break;
-
- case TYPE_DBL:
- f->value.d = 0.0;
- break;
-
- case TYPE_ADR:
- f->value.a = NULL;
- if (!(f->flags & ACC_STATIC))
- c->flags |= ACC_CLASS_HAS_POINTERS;
- break;
-
- case TYPE_LNG:
-#if U8_AVAILABLE
- f->value.l = 0;
-#else
- f->value.l.low = 0;
- f->value.l.high = 0;
-#endif
- break;
- }
-
- /* read attributes */
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- attrnum = suck_u2(cb);
- for (i = 0; i < attrnum; i++) {
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- if (!(u = class_getconstant(c, suck_u2(cb), CONSTANT_Utf8)))
- return false;
-
- if (u == utf_ConstantValue) {
- if (!suck_check_classbuffer_size(cb, 4 + 2))
- return false;
-
- /* check attribute length */
-
- if (suck_u4(cb) != 2) {
- exceptions_throw_classformaterror(c, "Wrong size for VALUE attribute");
- return false;
- }
-
- /* constant value attribute */
-
- if (pindex != field_load_NOVALUE) {
- exceptions_throw_classformaterror(c, "Multiple ConstantValue attributes");
- return false;
- }
-
- /* index of value in constantpool */
-
- pindex = suck_u2(cb);
-
- /* initialize field with value from constantpool */
- switch (jtype) {
- case TYPE_INT: {
- constant_integer *ci;
-
- if (!(ci = class_getconstant(c, pindex, CONSTANT_Integer)))
- return false;
-
- f->value.i = ci->value;
- }
- break;
-
- case TYPE_LNG: {
- constant_long *cl;
-
- if (!(cl = class_getconstant(c, pindex, CONSTANT_Long)))
- return false;
-
- f->value.l = cl->value;
- }
- break;
-
- case TYPE_FLT: {
- constant_float *cf;
-
- if (!(cf = class_getconstant(c, pindex, CONSTANT_Float)))
- return false;
-
- f->value.f = cf->value;
- }
- break;
-
- case TYPE_DBL: {
- constant_double *cd;
-
- if (!(cd = class_getconstant(c, pindex, CONSTANT_Double)))
- return false;
-
- f->value.d = cd->value;
- }
- break;
-
- case TYPE_ADR:
- if (!(u = class_getconstant(c, pindex, CONSTANT_String)))
- return false;
-
- /* create javastring from compressed utf8-string */
- f->value.a = literalstring_new(u);
- break;
-
- default:
- log_text("Invalid Constant - Type");
- }
- }
-#if defined(ENABLE_JAVASE)
- else if (u == utf_Signature) {
- /* Signature */
-
- if (!loader_load_attribute_signature(cb, &(f->signature)))
- return false;
- }
-#endif
- else {
- /* unknown attribute */
-
- if (!loader_skip_attribute_body(cb))
- return false;
- }
- }
-
- /* everything was ok */
-
- return true;
-}
-
-
-/* loader_load_method **********************************************************
-
- 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.
-
- method_info {
- u2 access_flags;
- u2 name_index;
- u2 descriptor_index;
- u2 attributes_count;
- attribute_info attributes[attribute_count];
- }
-
- attribute_info {
- u2 attribute_name_index;
- u4 attribute_length;
- u1 info[attribute_length];
- }
-
- LineNumberTable_attribute {
- u2 attribute_name_index;
- u4 attribute_length;
- u2 line_number_table_length;
- {
- u2 start_pc;
- u2 line_number;
- } line_number_table[line_number_table_length];
- }
-
-*******************************************************************************/
-
-static bool loader_load_method(classbuffer *cb, methodinfo *m,
- descriptor_pool *descpool)
-{
- classinfo *c;
- int argcount;
- s4 i, j, k, l;
- utf *u;
- u2 name_index;
- u2 descriptor_index;
- u2 attributes_count;
- u2 attribute_name_index;
- utf *attribute_name;
- u2 code_attributes_count;
- u2 code_attribute_name_index;
- utf *code_attribute_name;
-
- /* get classinfo */
-
- c = cb->class;
-
-#if defined(ENABLE_THREADS)
- lock_init_object_lock(&m->header);
-#endif
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- count_all_methods++;
-#endif
-
- /* all fields of m have been zeroed in load_class_from_classbuffer */
-
- m->class = c;
-
- if (!suck_check_classbuffer_size(cb, 2 + 2 + 2))
- return false;
-
- /* access flags */
-
- m->flags = suck_u2(cb);
-
- /* name */
-
- name_index = suck_u2(cb);
-
- if (!(u = class_getconstant(c, name_index, CONSTANT_Utf8)))
- return false;
-
- m->name = u;
-
- /* descriptor */
-
- descriptor_index = suck_u2(cb);
-
- if (!(u = class_getconstant(c, descriptor_index, CONSTANT_Utf8)))
- return false;
-
- m->descriptor = u;
-
- if (!descriptor_pool_add(descpool, u, &argcount))
- return false;
-
-#ifdef ENABLE_VERIFIER
- if (opt_verify) {
- if (!is_valid_name_utf(m->name)) {
- exceptions_throw_classformaterror(c, "Method with invalid name");
- return false;
- }
-
- if (m->name->text[0] == '<' &&
- m->name != utf_init && m->name != utf_clinit) {
- exceptions_throw_classformaterror(c, "Method with invalid special name");
- return false;
- }
- }
-#endif /* ENABLE_VERIFIER */
-
- if (!(m->flags & ACC_STATIC))
- argcount++; /* count the 'this' argument */
-
-#ifdef ENABLE_VERIFIER
- if (opt_verify) {
- if (argcount > 255) {
- exceptions_throw_classformaterror(c, "Too many arguments in signature");
- return false;
- }
-
- /* 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) {
- exceptions_throw_classformaterror(c,
- "Illegal method modifiers: 0x%X",
- m->flags);
- return false;
- }
-
- if (m->flags & ACC_ABSTRACT) {
- if ((m->flags & (ACC_FINAL | ACC_NATIVE | ACC_PRIVATE |
- ACC_STATIC | ACC_STRICT | ACC_SYNCHRONIZED))) {
- exceptions_throw_classformaterror(c,
- "Illegal method modifiers: 0x%X",
- m->flags);
- return false;
- }
- }
-
- if (c->flags & ACC_INTERFACE) {
- if ((m->flags & (ACC_ABSTRACT | ACC_PUBLIC)) != (ACC_ABSTRACT | ACC_PUBLIC)) {
- exceptions_throw_classformaterror(c,
- "Illegal method modifiers: 0x%X",
- m->flags);
- return false;
- }
- }
-
- if (m->name == utf_init) {
- if (m->flags & (ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
- ACC_NATIVE | ACC_ABSTRACT)) {
- exceptions_throw_classformaterror(c, "Instance initialization method has invalid flags set");
- return false;
- }
- }
- }
- }
-#endif /* ENABLE_VERIFIER */
-
- /* mark the method as monomorphic until further notice */
-
- m->flags |= ACC_METHOD_MONOMORPHIC;
-
- /* non-abstract methods have an implementation in this class */
-
- if (!(m->flags & ACC_ABSTRACT))
- m->flags |= ACC_METHOD_IMPLEMENTED;
-
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- /* attributes count */
-
- attributes_count = suck_u2(cb);
-
- for (i = 0; i < attributes_count; i++) {
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- /* attribute name index */
-
- attribute_name_index = suck_u2(cb);
-
- if (!(attribute_name = class_getconstant(c, attribute_name_index, CONSTANT_Utf8)))
- return false;
-
- if (attribute_name == utf_Code) {
- /* Code */
- if (m->flags & (ACC_ABSTRACT | ACC_NATIVE)) {
- exceptions_throw_classformaterror(c, "Code attribute in native or abstract methods");
- return false;
- }
-
- if (m->jcode) {
- exceptions_throw_classformaterror(c, "Multiple Code attributes");
- return false;
- }
-
- if (!suck_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) {
- exceptions_throw_classformaterror(c, "Arguments can't fit into locals");
- return false;
- }
-
- if (!suck_check_classbuffer_size(cb, 4))
- return false;
-
- m->jcodelength = suck_u4(cb);
-
- if (m->jcodelength == 0) {
- exceptions_throw_classformaterror(c, "Code of a method has length 0");
- return false;
- }
-
- if (m->jcodelength > 65535) {
- exceptions_throw_classformaterror(c, "Code of a method longer than 65535 bytes");
- return false;
- }
-
- if (!suck_check_classbuffer_size(cb, m->jcodelength))
- return false;
-
- m->jcode = MNEW(u1, m->jcodelength);
- suck_nbytes(m->jcode, cb, m->jcodelength);
-
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- m->rawexceptiontablelength = suck_u2(cb);
- if (!suck_check_classbuffer_size(cb, (2 + 2 + 2 + 2) * m->rawexceptiontablelength))
- return false;
-
- m->rawexceptiontable = MNEW(raw_exception_entry, m->rawexceptiontablelength);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat) {
- count_vmcode_len += m->jcodelength + 18;
- count_extable_len +=
- m->rawexceptiontablelength * sizeof(raw_exception_entry);
- }
-#endif
-
- for (j = 0; j < m->rawexceptiontablelength; j++) {
- u4 idx;
- m->rawexceptiontable[j].startpc = suck_u2(cb);
- m->rawexceptiontable[j].endpc = suck_u2(cb);
- m->rawexceptiontable[j].handlerpc = suck_u2(cb);
-
- idx = suck_u2(cb);
- if (!idx) {
- m->rawexceptiontable[j].catchtype.any = NULL;
-
- } else {
- /* the classref is created later */
- if (!(m->rawexceptiontable[j].catchtype.any =
- (utf*)class_getconstant(c, idx, CONSTANT_Class)))
- return false;
- }
- }
-
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- /* code attributes count */
-
- code_attributes_count = suck_u2(cb);
-
- for (k = 0; k < code_attributes_count; k++) {
- if (!suck_check_classbuffer_size(cb, 2))
- return false;
-
- /* code attribute name index */
-
- code_attribute_name_index = suck_u2(cb);
-
- if (!(code_attribute_name = class_getconstant(c, code_attribute_name_index, CONSTANT_Utf8)))
- return false;
-
- /* check which code attribute */
-
- if (code_attribute_name == utf_LineNumberTable) {
- /* LineNumberTable */
- if (!suck_check_classbuffer_size(cb, 4 + 2))
- return false;
-
- /* attribute length */
-
- (void) suck_u4(cb);
-
- /* line number table length */
-
- m->linenumbercount = suck_u2(cb);
-
- if (!suck_check_classbuffer_size(cb,
- (2 + 2) * m->linenumbercount))
- return false;
-
- m->linenumbers = MNEW(lineinfo, m->linenumbercount);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- size_lineinfo += sizeof(lineinfo) * m->linenumbercount;
-#endif
-
- for (l = 0; l < m->linenumbercount; l++) {
- m->linenumbers[l].start_pc = suck_u2(cb);
- m->linenumbers[l].line_number = suck_u2(cb);
- }
- }
-#if defined(ENABLE_JAVASE)
- else if (code_attribute_name == utf_StackMapTable) {
- /* StackTableMap */
-
- if (!stackmap_load_attribute_stackmaptable(cb, m))
- return false;
- }
-#endif
- else {
- /* unknown code attribute */
-
- if (!loader_skip_attribute_body(cb))
- return false;
- }
- }
- }
- else if (attribute_name == utf_Exceptions) {
- /* Exceptions */
-
- if (m->thrownexceptions != NULL) {
- exceptions_throw_classformaterror(c, "Multiple Exceptions attributes");
- return false;
- }
-
- if (!suck_check_classbuffer_size(cb, 4 + 2))
- return false;
-
- /* attribute length */
-
- (void) suck_u4(cb);
-
- m->thrownexceptionscount = suck_u2(cb);
-
- if (!suck_check_classbuffer_size(cb, 2 * m->thrownexceptionscount))
- return false;
-
- m->thrownexceptions = MNEW(classref_or_classinfo, m->thrownexceptionscount);
-
- for (j = 0; j < m->thrownexceptionscount; j++) {
- /* the classref is created later */
- if (!((m->thrownexceptions)[j].any =
- (utf*) class_getconstant(c, suck_u2(cb), CONSTANT_Class)))
- return false;
- }
- }
-#if defined(ENABLE_JAVASE)
- else if (attribute_name == utf_Signature) {
- /* Signature */
-
- if (!loader_load_attribute_signature(cb, &(m->signature)))
- return false;
- }
-#endif
- else {
- /* unknown attribute */
-
- if (!loader_skip_attribute_body(cb))
- return false;
- }
- }
-
- if ((m->jcode == NULL) && !(m->flags & (ACC_ABSTRACT | ACC_NATIVE))) {
- exceptions_throw_classformaterror(c, "Missing Code attribute");
- return false;
- }
-
- /* initialize the hit countdown field */
+ /* get signature */
-#if defined(ENABLE_REPLACEMENT)
- m->hitcountdown = METHOD_INITIAL_HIT_COUNTDOWN;
-#endif
+ signature_index = suck_u2(cb);
- /* everything was ok */
+ if (!(*signature = class_getconstant(c, signature_index, CONSTANT_Utf8)))
+ return false;
return true;
}
+#endif /* defined(ENABLE_JAVASE) */
/* load_class_from_sysloader ***************************************************
classinfo *load_class_from_sysloader(utf *name)
{
- methodinfo *m;
- java_objectheader *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, java_objectheader *cl)
+classinfo *load_class_from_classloader(utf *name, classloader_t *cl)
{
- java_objectheader *o;
- classinfo *c;
- classinfo *tmpc;
- java_objectheader *string;
+ java_handle_t *o;
+ classinfo *c;
+ classinfo *tmpc;
+ java_handle_t *string;
#if defined(ENABLE_RT_TIMING)
struct timespec time_start, time_lookup, time_prepare, time_java,
time_cache;
case 'L':
/* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */
if (namelen < 4 || text[2] == '[' || text[namelen - 1] != ';') {
- exceptions_throw_noclassdeffounderror(name);
+ exceptions_throw_classnotfoundexception(name);
return false;
}
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);
- c = (classinfo *) o;
+ c = LLNI_classinfo_unwrap(o);
if (c != NULL) {
/* Store this class in the loaded class cache. If another
}
c = tmpc;
-
- } else {
- /* loadClass has thrown an exception. We must convert
- ClassNotFoundException into
- NoClassDefFoundException. */
-
- /* XXX Maybe we should have a flag that avoids this
- conversion for calling load_class_from_classloader from
- Class.forName. Currently we do a double conversion in
- these cases. */
-
- classnotfoundexception_to_noclassdeffounderror();
}
RT_TIMING_GET_TIME(time_cache);
/* lookup if this class has already been loaded */
- if ((r = classcache_lookup(NULL, name))) {
+ r = classcache_lookup(NULL, name);
+ if (r != NULL) {
RT_TIMING_GET_TIME(time_lookup);
RT_TIMING_TIME_DIFF(time_start,time_lookup,RT_TIMING_LOAD_BOOT_LOOKUP);
if (name->text[0] == '[') {
c = load_newly_created_array(c, NULL);
+
if (c == NULL)
return NULL;
+
assert(c->state & CLASS_LOADED);
RT_TIMING_GET_TIME(time_array);
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_noclassdeffounderror(name);
-
+ 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.
- The loaded class is removed from the list 'unloadedclasses' and
- added to the list 'unlinkedclasses'.
-
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);
+
+ if (index == 0) {
+ supername = NULL;
+
+ /* This is only allowed for java.lang.Object. */
- c->super.any = NULL;
+ 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);
-#if defined(ENABLE_GC_CACAO)
- c->fields = MNEW(fieldinfo, c->fieldscount);
+ c->fields = MNEW(fieldinfo, c->fieldscount);
+
MZERO(c->fields, fieldinfo, c->fieldscount);
-#else
- c->fields = GCNEW_UNCOLLECTABLE(fieldinfo, c->fieldscount);
-#endif
for (i = 0; i < c->fieldscount; i++) {
- if (!load_field(cb, &(c->fields[i]),descpool))
- goto return_exception;
+ if (!field_load(cb, &(c->fields[i]), descpool))
+ 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);
+ c->methods = MNEW(methodinfo, c->methodscount);
MZERO(c->methods, methodinfo, c->methodscount);
for (i = 0; i < c->methodscount; i++) {
- if (!loader_load_method(cb, &(c->methods[i]), descpool))
- goto return_exception;
+ if (!method_load(cb, &(c->methods[i]), descpool))
+ 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 (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;
+ }
- if (supername) {
- c->super.ref = descriptor_pool_lookup_classref(descpool, supername);
- if (!c->super.ref)
- goto return_exception;
+ /* 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;
+}
+
+
+/* load_class_from_classbuffer *************************************************
+
+ Convenience wrapper for load_class_from_classbuffer.
+
+ SYNCHRONIZATION:
+ This function is NOT synchronized!
+
+*******************************************************************************/
-return_exception:
- /* release dump area */
+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 */
- dump_release(dumpsize);
+ if (jvmti)
+ jvmti_ClassLoadPrepare(true, c);
+#endif
- /* an exception has been thrown */
+#if !defined(NDEBUG)
+ if (loadverbose)
+ log_message_class("Loading done class: ", c);
+#endif
- return NULL;
+ return c;
}
*******************************************************************************/
-classinfo *load_newly_created_array(classinfo *c, java_objectheader *loader)
+classinfo *load_newly_created_array(classinfo *c, classloader_t *loader)
{
classinfo *comp = NULL;
methodinfo *clone;
s4 namelen;
utf *u;
- text = c->name->text;
+ text = c->name->text;
namelen = c->name->blength;
/* Check array class name */
if ((namelen < 2) || (text[0] != '[')) {
- exceptions_throw_noclassdeffounderror(c->name);
+ exceptions_throw_classnotfoundexception(c->name);
return NULL;
}
/* c is an array of arrays. We have to create the component class. */
u = utf_new(text + 1, namelen - 1);
- if (!(comp = load_class_from_classloader(u, loader)))
+
+ comp = load_class_from_classloader(u, loader);
+
+ if (comp == NULL)
return NULL;
assert(comp->state & CLASS_LOADED);
- if (opt_eager)
- if (!link_class(c))
- return NULL;
-
/* the array's flags are that of the component class */
c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT;
c->classloader = comp->classloader;
/* check for cases like `[L;' or `[L[I;' or `[Ljava.lang.Object' */
if ((namelen < 4) || (text[2] == '[') || (text[namelen - 1] != ';')) {
- exceptions_throw_noclassdeffounderror(c->name);
+ exceptions_throw_classnotfoundexception(c->name);
return NULL;
}
assert(comp->state & CLASS_LOADED);
- if (opt_eager)
- if (!link_class(c))
- return NULL;
-
/* the array's flags are that of the component class */
c->flags = (comp->flags & ~ACC_INTERFACE) | ACC_FINAL | ACC_ABSTRACT;
c->classloader = comp->classloader;
default:
/* c is an array of a primitive type */
- /* check for cases like `[II' */
- if (namelen > 2) {
- exceptions_throw_noclassdeffounderror(c->name);
+ /* check for cases like `[II' and whether the character is a
+ valid primitive type */
+
+ if ((namelen > 2) || (primitive_class_get_by_char(text[1]) == NULL)) {
+ exceptions_throw_classnotfoundexception(c->name);
return NULL;
}
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);
-
- if (opt_eager) {
- classinfo *tc;
- tc = class_java_lang_Cloneable;
- assert(tc->state & CLASS_LOADED);
- list_add_first(&unlinkedclasses, tc);
- c->interfaces[0].cls = tc;
+ c->interfacescount = 2;
+ c->interfaces = MNEW(classinfo*, 2);
+ c->interfaces[0] = class_java_lang_Cloneable;
+ c->interfaces[1] = class_java_io_Serializable;
- tc = class_java_io_Serializable;
- assert(tc->state & CLASS_LOADED);
- list_add_first(&unlinkedclasses, tc);
- c->interfaces[1].cls = tc;
- }
- else {
- c->interfaces[0].cls = class_java_lang_Cloneable;
- c->interfaces[1].cls = class_java_io_Serializable;
- }
#elif defined(ENABLE_JAVAME_CLDC1_1)
+
c->interfacescount = 0;
c->interfaces = NULL;
+
#else
-#error unknow Java configuration
+# 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 */