// link.cc - Code for linking and resolving classes and pool entries.
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation
This file is part of libgcj.
#include <limits.h>
#include <java-cpool.h>
#include <execution.h>
+#ifdef INTERPRETER
+#include <jvmti.h>
+#include "jvmti-int.h"
+#endif
#include <java/lang/Class.h>
#include <java/lang/String.h>
#include <java/lang/StringBuffer.h>
using namespace gcj;
-typedef unsigned int uaddr __attribute__ ((mode (pointer)));
-
template<typename T>
struct aligner
{
if (_Jv_CheckAccess (klass, *found_class, the_field->flags))
{
// Note that the field returned by find_field_helper is always
- // resolved. There's no point checking class loaders here,
- // since we already did the work to look up all the types.
- // FIXME: being lazy here would be nice.
- if (the_field->type != field_type)
- throw new java::lang::LinkageError
- (JvNewStringLatin1
- ("field type mismatch with different loaders"));
+ // resolved. However, we still use the constraint mechanism
+ // because this may affect other lookups.
+ _Jv_CheckOrCreateLoadingConstraint (field_type, (*found_class)->loader);
}
else
{
return the_field;
}
+// Check loading constraints for method.
+void
+_Jv_Linker::check_loading_constraints (_Jv_Method *method, jclass self_class,
+ jclass other_class)
+{
+ JArray<jclass> *klass_args;
+ jclass klass_return;
+
+ _Jv_GetTypesFromSignature (method, self_class, &klass_args, &klass_return);
+ jclass *klass_arg = elements (klass_args);
+ java::lang::ClassLoader *found_loader = other_class->loader;
+
+ _Jv_CheckOrCreateLoadingConstraint (klass_return, found_loader);
+ for (int i = 0; i < klass_args->length; i++)
+ _Jv_CheckOrCreateLoadingConstraint (*(klass_arg++), found_loader);
+}
+
+_Jv_Method *
+_Jv_Linker::resolve_method_entry (jclass klass, jclass &found_class,
+ int class_index, int name_and_type_index,
+ bool init, bool is_iface)
+{
+ _Jv_Constants *pool = &klass->constants;
+ jclass owner = resolve_pool_entry (klass, class_index).clazz;
+
+ if (init && owner != klass)
+ _Jv_InitClass (owner);
+
+ _Jv_ushort name_index, type_index;
+ _Jv_loadIndexes (&pool->data[name_and_type_index],
+ name_index,
+ type_index);
+
+ _Jv_Utf8Const *method_name = pool->data[name_index].utf8;
+ _Jv_Utf8Const *method_signature = pool->data[type_index].utf8;
+
+ _Jv_Method *the_method = 0;
+ found_class = 0;
+
+ // We're going to cache a pointer to the _Jv_Method object
+ // when we find it. So, to ensure this doesn't get moved from
+ // beneath us, we first put all the needed Miranda methods
+ // into the target class.
+ wait_for_state (klass, JV_STATE_LOADED);
+
+ // First search the class itself.
+ the_method = search_method_in_class (owner, klass,
+ method_name, method_signature);
+
+ if (the_method != 0)
+ {
+ found_class = owner;
+ goto end_of_method_search;
+ }
+
+ // If we are resolving an interface method, search the
+ // interface's superinterfaces (A superinterface is not an
+ // interface's superclass - a superinterface is implemented by
+ // the interface).
+ if (is_iface)
+ {
+ _Jv_ifaces ifaces;
+ ifaces.count = 0;
+ ifaces.len = 4;
+ ifaces.list = (jclass *) _Jv_Malloc (ifaces.len
+ * sizeof (jclass *));
+
+ get_interfaces (owner, &ifaces);
+
+ for (int i = 0; i < ifaces.count; i++)
+ {
+ jclass cls = ifaces.list[i];
+ the_method = search_method_in_class (cls, klass, method_name,
+ method_signature);
+ if (the_method != 0)
+ {
+ found_class = cls;
+ break;
+ }
+ }
+
+ _Jv_Free (ifaces.list);
+
+ if (the_method != 0)
+ goto end_of_method_search;
+ }
+
+ // Finally, search superclasses.
+ the_method = (search_method_in_superclasses
+ (owner->getSuperclass (), klass, method_name,
+ method_signature, &found_class));
+
+
+ end_of_method_search:
+ if (the_method == 0)
+ {
+ java::lang::StringBuffer *sb = new java::lang::StringBuffer();
+ sb->append(JvNewStringLatin1("method "));
+ sb->append(owner->getName());
+ sb->append(JvNewStringLatin1("."));
+ sb->append(_Jv_NewStringUTF(method_name->chars()));
+ sb->append(JvNewStringLatin1(" with signature "));
+ sb->append(_Jv_NewStringUTF(method_signature->chars()));
+ sb->append(JvNewStringLatin1(" was not found."));
+ throw new java::lang::NoSuchMethodError (sb->toString());
+ }
+
+ // if (found_class->loader != klass->loader), then we must actually
+ // check that the types of arguments correspond. JVMS 5.4.3.3.
+ if (found_class->loader != klass->loader)
+ check_loading_constraints (the_method, klass, found_class);
+
+ return the_method;
+}
+
+_Jv_Mutex_t _Jv_Linker::resolve_mutex;
+
+void
+_Jv_Linker::init (void)
+{
+ _Jv_MutexInit (&_Jv_Linker::resolve_mutex);
+}
+
+// Locking in resolve_pool_entry is somewhat subtle. Constant
+// resolution is idempotent, so it doesn't matter if two threads
+// resolve the same entry. However, it is important that we always
+// write the resolved flag and the data together, atomically. It is
+// also important that we read them atomically.
_Jv_word
_Jv_Linker::resolve_pool_entry (jclass klass, int index, bool lazy)
{
if (GC_base (klass) && klass->constants.data
&& ! GC_base (klass->constants.data))
+ // If a class is heap-allocated but the constant pool is not this
+ // is a "new ABI" class, i.e. one where the initial constant pool
+ // is in the read-only data section of an object file. Copy the
+ // initial constant pool from there to a new heap-allocated pool.
{
jsize count = klass->constants.size;
if (count)
_Jv_Constants *pool = &klass->constants;
- if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0)
- return pool->data[index];
+ jbyte tags;
+ _Jv_word data;
+ tags = read_cpool_entry (&data, pool, index);
+
+ if ((tags & JV_CONSTANT_ResolvedFlag) != 0)
+ return data;
- switch (pool->tags[index])
+ switch (tags & ~JV_CONSTANT_LazyFlag)
{
case JV_CONSTANT_Class:
{
- _Jv_Utf8Const *name = pool->data[index].utf8;
+ _Jv_Utf8Const *name = data.utf8;
jclass found;
if (name->first() == '[')
// with it should just throw a NoClassDefFoundError with the class'
// name.
if (! found)
- if (lazy)
- {
- found = _Jv_NewClass(name, NULL, NULL);
- found->state = JV_STATE_PHANTOM;
- pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
- pool->data[index].clazz = found;
- break;
- }
- else
- throw new java::lang::NoClassDefFoundError (name->toString());
+ {
+ if (lazy)
+ {
+ found = _Jv_NewClass(name, NULL, NULL);
+ found->state = JV_STATE_PHANTOM;
+ tags |= JV_CONSTANT_ResolvedFlag;
+ data.clazz = found;
+ break;
+ }
+ else
+ throw new java::lang::NoClassDefFoundError (name->toString());
+ }
// Check accessibility, but first strip array types as
// _Jv_ClassNameSamePackage can't handle arrays.
|| (_Jv_ClassNameSamePackage (check->name,
klass->name)))
{
- pool->data[index].clazz = found;
- pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
+ data.clazz = found;
+ tags |= JV_CONSTANT_ResolvedFlag;
}
else
{
case JV_CONSTANT_String:
{
jstring str;
- str = _Jv_NewStringUtf8Const (pool->data[index].utf8);
- pool->data[index].o = str;
- pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
+ str = _Jv_NewStringUtf8Const (data.utf8);
+ data.o = str;
+ tags |= JV_CONSTANT_ResolvedFlag;
}
break;
case JV_CONSTANT_Fieldref:
{
_Jv_ushort class_index, name_and_type_index;
- _Jv_loadIndexes (&pool->data[index],
+ _Jv_loadIndexes (&data,
class_index,
name_and_type_index);
jclass owner = (resolve_pool_entry (klass, class_index, true)).clazz;
if (owner->state == JV_STATE_PHANTOM)
throw new java::lang::NoClassDefFoundError(owner->getName());
- if (owner != klass)
- _Jv_InitClass (owner);
+ // We don't initialize 'owner', but we do make sure that its
+ // fields exist.
+ wait_for_state (owner, JV_STATE_PREPARED);
_Jv_ushort name_index, type_index;
_Jv_loadIndexes (&pool->data[name_and_type_index],
&found_class,
field_name,
field_type_name);
- if (owner != found_class)
- _Jv_InitClass (found_class);
- pool->data[index].field = the_field;
- pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
+ // Initialize the field's declaring class, not its qualifying
+ // class.
+ _Jv_InitClass (found_class);
+ data.field = the_field;
+ tags |= JV_CONSTANT_ResolvedFlag;
}
break;
case JV_CONSTANT_InterfaceMethodref:
{
_Jv_ushort class_index, name_and_type_index;
- _Jv_loadIndexes (&pool->data[index],
+ _Jv_loadIndexes (&data,
class_index,
name_and_type_index);
- jclass owner = (resolve_pool_entry (klass, class_index)).clazz;
- if (owner != klass)
- _Jv_InitClass (owner);
-
- _Jv_ushort name_index, type_index;
- _Jv_loadIndexes (&pool->data[name_and_type_index],
- name_index,
- type_index);
-
- _Jv_Utf8Const *method_name = pool->data[name_index].utf8;
- _Jv_Utf8Const *method_signature = pool->data[type_index].utf8;
-
- _Jv_Method *the_method = 0;
- jclass found_class = 0;
-
- // We're going to cache a pointer to the _Jv_Method object
- // when we find it. So, to ensure this doesn't get moved from
- // beneath us, we first put all the needed Miranda methods
- // into the target class.
- wait_for_state (klass, JV_STATE_LOADED);
-
- // First search the class itself.
- the_method = search_method_in_class (owner, klass,
- method_name, method_signature);
-
- if (the_method != 0)
- {
- found_class = owner;
- goto end_of_method_search;
- }
-
- // If we are resolving an interface method, search the
- // interface's superinterfaces (A superinterface is not an
- // interface's superclass - a superinterface is implemented by
- // the interface).
- if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref)
- {
- _Jv_ifaces ifaces;
- ifaces.count = 0;
- ifaces.len = 4;
- ifaces.list = (jclass *) _Jv_Malloc (ifaces.len
- * sizeof (jclass *));
-
- get_interfaces (owner, &ifaces);
-
- for (int i = 0; i < ifaces.count; i++)
- {
- jclass cls = ifaces.list[i];
- the_method = search_method_in_class (cls, klass, method_name,
- method_signature);
- if (the_method != 0)
- {
- found_class = cls;
- break;
- }
- }
-
- _Jv_Free (ifaces.list);
-
- if (the_method != 0)
- goto end_of_method_search;
- }
-
- // Finally, search superclasses.
- for (jclass cls = owner->getSuperclass (); cls != 0;
- cls = cls->getSuperclass ())
- {
- the_method = search_method_in_class (cls, klass, method_name,
- method_signature);
- if (the_method != 0)
- {
- found_class = cls;
- break;
- }
- }
-
- end_of_method_search:
-
- // FIXME: if (cls->loader != klass->loader), then we
- // must actually check that the types of arguments
- // correspond. That is, for each argument type, and
- // the return type, doing _Jv_FindClassFromSignature
- // with either loader should produce the same result,
- // i.e., exactly the same jclass object. JVMS 5.4.3.3
-
- if (the_method == 0)
- {
- java::lang::StringBuffer *sb = new java::lang::StringBuffer();
- sb->append(JvNewStringLatin1("method "));
- sb->append(owner->getName());
- sb->append(JvNewStringLatin1("."));
- sb->append(_Jv_NewStringUTF(method_name->chars()));
- sb->append(JvNewStringLatin1(" with signature "));
- sb->append(_Jv_NewStringUTF(method_signature->chars()));
- sb->append(JvNewStringLatin1(" was not found."));
- throw new java::lang::NoSuchMethodError (sb->toString());
- }
+ _Jv_Method *the_method;
+ jclass found_class;
+ the_method = resolve_method_entry (klass, found_class,
+ class_index, name_and_type_index,
+ true,
+ tags == JV_CONSTANT_InterfaceMethodref);
- pool->data[index].rmethod
+ data.rmethod
= klass->engine->resolve_method(the_method,
found_class,
((the_method->accflags
& Modifier::STATIC) != 0));
- pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
+ tags |= JV_CONSTANT_ResolvedFlag;
}
break;
}
- return pool->data[index];
+
+ write_cpool_entry (data, tags, pool, index);
+
+ return data;
}
// This function is used to lazily locate superclasses and
}
// Find a method declared in the cls that is referenced from klass and
-// perform access checks.
+// perform access checks if CHECK_PERMS is true.
_Jv_Method *
_Jv_Linker::search_method_in_class (jclass cls, jclass klass,
_Jv_Utf8Const *method_name,
- _Jv_Utf8Const *method_signature)
+ _Jv_Utf8Const *method_signature,
+ bool check_perms)
{
using namespace java::lang::reflect;
method_signature)))
continue;
- if (_Jv_CheckAccess (klass, cls, method->accflags))
+ if (!check_perms || _Jv_CheckAccess (klass, cls, method->accflags))
return method;
else
{
return 0;
}
+// Like search_method_in_class, but work our way up the superclass
+// chain.
+_Jv_Method *
+_Jv_Linker::search_method_in_superclasses (jclass cls, jclass klass,
+ _Jv_Utf8Const *method_name,
+ _Jv_Utf8Const *method_signature,
+ jclass *found_class, bool check_perms)
+{
+ _Jv_Method *the_method = NULL;
+
+ for ( ; cls != 0; cls = cls->getSuperclass ())
+ {
+ the_method = search_method_in_class (cls, klass, method_name,
+ method_signature, check_perms);
+ if (the_method != 0)
+ {
+ if (found_class)
+ *found_class = cls;
+ break;
+ }
+ }
+
+ return the_method;
+}
#define INITIAL_IOFFSETS_LEN 4
#define INITIAL_IFACES_LEN 4
// interfaces or primitive types.
jclass klass0 = klass;
- jboolean has_interfaces = 0;
+ jboolean has_interfaces = false;
while (klass0 != &java::lang::Object::class$)
{
- has_interfaces += klass0->interface_count;
+ if (klass0->interface_count)
+ has_interfaces = true;
klass0 = klass0->superclass;
klass->depth++;
}
throw new java::lang::NoSuchMethodError;
}
-#ifdef USE_LIBFFI
+#if defined USE_LIBFFI && FFI_CLOSURES && defined(INTERPRETER)
// A function whose invocation is prepared using libffi. It gets called
// whenever a static method of a missing class is invoked. The data argument
// holds a reference to a String denoting the missing class.
continue;
meth = NULL;
- for (jclass cl = klass; cl; cl = cl->getSuperclass())
+ jclass cl;
+ for (cl = klass; cl; cl = cl->getSuperclass())
{
meth = _Jv_GetMethodLocal (cl, iface->methods[j].name,
iface->methods[j].signature);
itable[pos] = (void *) &_Jv_ThrowAbstractMethodError;
else
itable[pos] = meth->ncode;
+
+ if (cl->loader != iface->loader)
+ check_loading_constraints (meth, cl, iface);
}
else
{
return i;
}
-#ifdef USE_LIBFFI
+#if defined USE_LIBFFI && FFI_CLOSURES && defined(INTERPRETER)
// We use a structure of this type to store the closure that
// represents a missing method.
struct method_closure
// be the same as the address of the overall structure. This is due
// to disabling interior pointers in the GC.
ffi_closure closure;
+ _Jv_ClosureList list;
ffi_cif cif;
ffi_type *arg_types[1];
};
void *
-_Jv_Linker::create_error_method (_Jv_Utf8Const *class_name)
+_Jv_Linker::create_error_method (_Jv_Utf8Const *class_name, jclass klass)
{
+ void *code;
method_closure *closure
- = (method_closure *) _Jv_AllocBytes(sizeof (method_closure));
+ = (method_closure *)ffi_closure_alloc (sizeof (method_closure), &code);
closure->arg_types[0] = &ffi_type_void;
1,
&ffi_type_void,
closure->arg_types) == FFI_OK
- && ffi_prep_closure (&closure->closure,
- &closure->cif,
- _Jv_ThrowNoClassDefFoundErrorTrampoline,
- class_name) == FFI_OK)
- return &closure->closure;
+ && ffi_prep_closure_loc (&closure->closure,
+ &closure->cif,
+ _Jv_ThrowNoClassDefFoundErrorTrampoline,
+ class_name,
+ code) == FFI_OK)
+ {
+ closure->list.registerClosure (klass, closure);
+ return code;
+ }
else
{
+ ffi_closure_free (closure);
java::lang::StringBuffer *buffer = new java::lang::StringBuffer();
buffer->append(JvNewStringLatin1("Error setting up FFI closure"
" for static method of"
}
#else
void *
-_Jv_Linker::create_error_method (_Jv_Utf8Const *)
+_Jv_Linker::create_error_method (_Jv_Utf8Const *, jclass)
{
// Codepath for platforms which do not support (or want) libffi.
// You have to accept that it is impossible to provide the name
// of the missing class then.
return (void *) _Jv_ThrowNoClassDefFoundError;
}
-#endif // USE_LIBFFI
+#endif // USE_LIBFFI && FFI_CLOSURES
// Functions for indirect dispatch (symbolic virtual binding) support.
// at the corresponding position in the virtual method offset table
// (klass->otable).
-// The same otable and atable may be shared by many classes.
-
// This must be called while holding the class lock.
void
_Jv_Method *meth = NULL;
_Jv_Utf8Const *signature = sym.signature;
+ uaddr special;
+ maybe_adjust_signature (signature, special);
if (target_class == NULL)
throw new java::lang::NoClassDefFoundError
// it out now.
wait_for_state(target_class, JV_STATE_PREPARED);
- meth = _Jv_LookupDeclaredMethod(target_class, sym.name,
- sym.signature);
+ try
+ {
+ meth = (search_method_in_superclasses
+ (target_class, klass, sym.name, signature,
+ NULL, special == 0));
+ }
+ catch (::java::lang::IllegalAccessError *e)
+ {
+ }
// Every class has a throwNoSuchMethodErrorIndex method that
// it inherits from java.lang.Object. Find its vtable
try
{
the_field = find_field (klass, target_class, &found_class,
- sym.name, sym.signature);
+ sym.name, signature);
if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
throw new java::lang::IncompatibleClassChangeError;
else
_Jv_FindClassNoException (sym.class_name, klass->loader);
_Jv_Method *meth = NULL;
+
_Jv_Utf8Const *signature = sym.signature;
+ uaddr special;
+ maybe_adjust_signature (signature, special);
// ??? Setting this pointer to null will at least get us a
// NullPointerException
klass->atable->addresses[index] = NULL;
+ bool use_error_method = false;
+
// If the target class is missing we prepare a function call
// that throws a NoClassDefFoundError and store the address of
- // that newly prepare method in the atable. The user can run
+ // that newly prepared method in the atable. The user can run
// code in classes where the missing class is part of the
// execution environment as long as it is never referenced.
if (target_class == NULL)
- klass->atable->addresses[index] = create_error_method(sym.class_name);
+ use_error_method = true;
// We're looking for a static field or a static method, and we
// can tell which is needed by looking at the signature.
else if (signature->first() == '(' && signature->len() >= 2)
throw new VerifyError(sb->toString());
}
- meth = _Jv_LookupDeclaredMethod(target_class, sym.name,
- sym.signature);
+ try
+ {
+ meth = (search_method_in_superclasses
+ (target_class, klass, sym.name, signature,
+ NULL, special == 0));
+ }
+ catch (::java::lang::IllegalAccessError *e)
+ {
+ }
if (meth != NULL)
{
}
}
else
+ use_error_method = true;
+
+ if (use_error_method)
klass->atable->addresses[index]
- = create_error_method(sym.class_name);
+ = create_error_method(sym.class_name, klass);
continue;
}
+
// Try fields only if the target class exists.
if (target_class != NULL)
{
wait_for_state(target_class, JV_STATE_PREPARED);
jclass found_class;
_Jv_Field *the_field = find_field (klass, target_class, &found_class,
- sym.name, sym.signature);
+ sym.name, signature);
if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
klass->atable->addresses[index] = the_field->u.addr;
else
++index)
{
jclass target_class = _Jv_FindClass (sym.class_name, klass->loader);
+
_Jv_Utf8Const *signature = sym.signature;
+ uaddr special;
+ maybe_adjust_signature (signature, special);
jclass cls;
int i;
wait_for_state(target_class, JV_STATE_LOADED);
bool found = _Jv_getInterfaceMethod (target_class, cls, i,
- sym.name, sym.signature);
+ sym.name, signature);
if (found)
{
sb->append(_Jv_GetMethodString(declarer, super_meth));
throw new VerifyError(sb->toString());
}
+ else if (declarer->loader != klass->loader)
+ {
+ // JVMS 5.4.2.
+ check_loading_constraints (meth, klass, declarer);
+ }
}
}
else
instance_size = java::lang::Object::class$.size();
+ klass->engine->allocate_field_initializers (klass);
+
for (int i = 0; i < klass->field_count; i++)
{
int field_size;
// It is safe to resolve the field here, since it's a
// primitive class, which does not cause loading to happen.
resolve_field (field, klass->loader);
-
field_size = field->type->size ();
field_align = get_alignment_from_class (field->type);
}
}
}
-#if 0 // Should be redundant now
- // If superclass looks like a constant pool entry,
- // resolve it now.
- if ((uaddr) klass->superclass < (uaddr) pool->size)
- klass->superclass = pool->data[(uaddr) klass->superclass].clazz;
-
- // Likewise for interfaces.
- for (int i = 0; i < klass->interface_count; i++)
- {
- if ((uaddr) klass->interfaces[i] < (uaddr) pool->size)
- klass->interfaces[i]
- = pool->data[(uaddr) klass->interfaces[i]].clazz;
- }
-#endif
-
// Resolve the remaining constant pool entries.
for (int index = 1; index < pool->size; ++index)
{
- if (pool->tags[index] == JV_CONSTANT_String)
- {
- jstring str;
+ jbyte tags;
+ _Jv_word data;
- str = _Jv_NewStringUtf8Const (pool->data[index].utf8);
- pool->data[index].o = str;
- pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
+ tags = read_cpool_entry (&data, pool, index);
+ if (tags == JV_CONSTANT_String)
+ {
+ data.o = _Jv_NewStringUtf8Const (data.utf8);
+ tags |= JV_CONSTANT_ResolvedFlag;
+ write_cpool_entry (data, tags, pool, index);
}
}
if (klass->state >= state)
return;
- JvSynchronize sync (klass);
-
- // This is similar to the strategy for class initialization. If we
- // already hold the lock, just leave.
java::lang::Thread *self = java::lang::Thread::currentThread();
- while (klass->state <= state
- && klass->thread
- && klass->thread != self)
- klass->wait ();
- java::lang::Thread *save = klass->thread;
- klass->thread = self;
+ {
+ JvSynchronize sync (klass);
- // Allocate memory for static fields and constants.
- if (GC_base (klass) && klass->fields && ! GC_base (klass->fields))
- {
- jsize count = klass->field_count;
- if (count)
- {
- _Jv_Field* fields
- = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
- memcpy ((void*)fields,
- (void*)klass->fields,
- count * sizeof (_Jv_Field));
- klass->fields = fields;
- }
- }
+ // This is similar to the strategy for class initialization. If we
+ // already hold the lock, just leave.
+ while (klass->state <= state
+ && klass->thread
+ && klass->thread != self)
+ klass->wait ();
+
+ java::lang::Thread *save = klass->thread;
+ klass->thread = self;
+
+ // Allocate memory for static fields and constants.
+ if (GC_base (klass) && klass->fields && ! GC_base (klass->fields))
+ {
+ jsize count = klass->field_count;
+ if (count)
+ {
+ _Jv_Field* fields
+ = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
+ memcpy ((void*)fields,
+ (void*)klass->fields,
+ count * sizeof (_Jv_Field));
+ klass->fields = fields;
+ }
+ }
// Print some debugging info if requested. Interpreted classes are
// handled in defineclass, so we only need to handle the two
// pre-compiled cases here.
- if (gcj::verbose_class_flag
- && (klass->state == JV_STATE_COMPILED
+ if ((klass->state == JV_STATE_COMPILED
|| klass->state == JV_STATE_PRELOADING)
&& ! _Jv_IsInterpretedClass (klass))
- print_class_loaded (klass);
-
- try
{
- if (state >= JV_STATE_LOADING && klass->state < JV_STATE_LOADING)
- {
- ensure_supers_installed (klass);
- klass->set_state(JV_STATE_LOADING);
- }
+ if (gcj::verbose_class_flag)
+ print_class_loaded (klass);
+ ++gcj::loadedClasses;
+ }
- if (state >= JV_STATE_LOADED && klass->state < JV_STATE_LOADED)
- {
- ensure_method_table_complete (klass);
- klass->set_state(JV_STATE_LOADED);
- }
+ try
+ {
+ if (state >= JV_STATE_LOADING && klass->state < JV_STATE_LOADING)
+ {
+ ensure_supers_installed (klass);
+ klass->set_state(JV_STATE_LOADING);
+ }
- if (state >= JV_STATE_PREPARED && klass->state < JV_STATE_PREPARED)
- {
- ensure_fields_laid_out (klass);
- make_vtable (klass);
- layout_interface_methods (klass);
- prepare_constant_time_tables (klass);
- klass->set_state(JV_STATE_PREPARED);
- }
+ if (state >= JV_STATE_LOADED && klass->state < JV_STATE_LOADED)
+ {
+ ensure_method_table_complete (klass);
+ klass->set_state(JV_STATE_LOADED);
+ }
- if (state >= JV_STATE_LINKED && klass->state < JV_STATE_LINKED)
- {
- if (gcj::verifyClasses)
- verify_class (klass);
+ if (state >= JV_STATE_PREPARED && klass->state < JV_STATE_PREPARED)
+ {
+ ensure_fields_laid_out (klass);
+ make_vtable (klass);
+ layout_interface_methods (klass);
+ prepare_constant_time_tables (klass);
+ klass->set_state(JV_STATE_PREPARED);
+ }
- ensure_class_linked (klass);
- link_exception_table (klass);
- link_symbol_table (klass);
- klass->set_state(JV_STATE_LINKED);
- }
- }
- catch (java::lang::Throwable *exc)
- {
- klass->thread = save;
- klass->set_state(JV_STATE_ERROR);
- throw exc;
- }
+ if (state >= JV_STATE_LINKED && klass->state < JV_STATE_LINKED)
+ {
+ if (gcj::verifyClasses)
+ verify_class (klass);
+
+ ensure_class_linked (klass);
+ link_exception_table (klass);
+ link_symbol_table (klass);
+ klass->set_state(JV_STATE_LINKED);
+ }
+ }
+ catch (java::lang::Throwable *exc)
+ {
+ klass->thread = save;
+ klass->set_state(JV_STATE_ERROR);
+ throw exc;
+ }
- klass->thread = save;
+ klass->thread = save;
- if (klass->state == JV_STATE_ERROR)
- throw new java::lang::LinkageError;
+ if (klass->state == JV_STATE_ERROR)
+ throw new java::lang::LinkageError;
+ }
+
+#ifdef INTERPRETER
+ if (__builtin_expect (klass->state == JV_STATE_LINKED, false)
+ && state >= JV_STATE_LINKED
+ && JVMTI_REQUESTED_EVENT (ClassPrepare))
+ {
+ JNIEnv *jni_env = _Jv_GetCurrentJNIEnv ();
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_CLASS_PREPARE, self, jni_env,
+ klass);
+ }
+#endif
}