// link.cc - Code for linking and resolving classes and pool entries.
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
This file is part of libgcj.
#include <stdio.h>
+#ifdef USE_LIBFFI
+#include <ffi.h>
+#endif
+
#include <java-interp.h>
+// Set GC_DEBUG before including gc.h!
+#ifdef LIBGCJ_GC_DEBUG
+# define GC_DEBUG
+#endif
+#include <gc.h>
+
#include <jvm.h>
#include <gcj/cni.h>
#include <string.h>
#include <java/lang/NoSuchMethodError.h>
#include <java/lang/ClassFormatError.h>
#include <java/lang/IllegalAccessError.h>
+#include <java/lang/InternalError.h>
#include <java/lang/AbstractMethodError.h>
#include <java/lang/NoClassDefFoundError.h>
#include <java/lang/IncompatibleClassChangeError.h>
// superclasses and interfaces.
_Jv_Field *
_Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
- _Jv_Utf8Const *type_name,
+ _Jv_Utf8Const *type_name, jclass type,
jclass *declarer)
{
while (search)
if (! _Jv_equalUtf8Consts (field->name, name))
continue;
- if (! field->isResolved ())
- resolve_field (field, search->loader);
+ // Checks for the odd situation where we were able to retrieve the
+ // field's class from signature but the resolution of the field itself
+ // failed which means a different class was resolved.
+ if (type != NULL)
+ {
+ try
+ {
+ resolve_field (field, search->loader);
+ }
+ catch (java::lang::Throwable *exc)
+ {
+ java::lang::LinkageError *le = new java::lang::LinkageError
+ (JvNewStringLatin1
+ ("field type mismatch with different loaders"));
+
+ le->initCause(exc);
+
+ throw le;
+ }
+ }
// Note that we compare type names and not types. This is
// bizarre, but we do it because we want to find a field
// pass in the descriptor and check that way, because when
// the field is already resolved there is no easy way to
// find its descriptor again.
- if (_Jv_equalUtf8Consts (type_name, field->type->name))
+ if ((field->isResolved ()
+ ? _Jv_equalUtf8Classnames (type_name, field->type->name)
+ : _Jv_equalUtf8Classnames (type_name,
+ (_Jv_Utf8Const *) field->type)))
{
*declarer = search;
return field;
for (int i = 0; i < search->interface_count; ++i)
{
_Jv_Field *result = find_field_helper (search->interfaces[i], name,
- type_name, declarer);
+ type_name, type, declarer);
if (result)
return result;
}
{
// FIXME: this allocates a _Jv_Utf8Const each time. We should make
// it cheaper.
- jclass field_type = _Jv_FindClassFromSignature (field_type_name->chars(),
- klass->loader);
- if (field_type == NULL)
- throw new java::lang::NoClassDefFoundError(field_name->toString());
-
- _Jv_Field *the_field = find_field_helper (owner, field_name,
- field_type->name, found_class);
+ // Note: This call will resolve the primitive type names ("Z", "B", ...) to
+ // their Java counterparts ("boolean", "byte", ...) if accessed via
+ // field_type->name later. Using these variants of the type name is in turn
+ // important for the find_field_helper function. However if the class
+ // resolution failed then we can only use the already given type name.
+ jclass field_type
+ = _Jv_FindClassFromSignatureNoException (field_type_name->chars(),
+ klass->loader);
+
+ _Jv_Field *the_field
+ = find_field_helper (owner, field_name,
+ (field_type
+ ? field_type->name :
+ field_type_name ),
+ field_type, found_class);
if (the_field == 0)
{
throw new java::lang::NoSuchFieldError (sb->toString());
}
+ // Accept it when the field's class could not be resolved.
+ if (field_type == NULL)
+ // Silently ignore that we were not able to retrieve the type to make it
+ // possible to run code which does not access this field.
+ return the_field;
+
if (_Jv_CheckAccess (klass, *found_class, the_field->flags))
{
// Note that the field returned by find_field_helper is always
}
_Jv_word
-_Jv_Linker::resolve_pool_entry (jclass klass, int index)
+_Jv_Linker::resolve_pool_entry (jclass klass, int index, bool lazy)
{
using namespace java::lang::reflect;
+ if (GC_base (klass) && klass->constants.data
+ && ! GC_base (klass->constants.data))
+ {
+ jsize count = klass->constants.size;
+ if (count)
+ {
+ _Jv_word* constants
+ = (_Jv_word*) _Jv_AllocRawObj (count * sizeof (_Jv_word));
+ memcpy ((void*)constants,
+ (void*)klass->constants.data,
+ count * sizeof (_Jv_word));
+ klass->constants.data = constants;
+ }
+ }
+
_Jv_Constants *pool = &klass->constants;
if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0)
jclass found;
if (name->first() == '[')
- found = _Jv_FindClassFromSignature (name->chars(),
- klass->loader);
- else
- found = _Jv_FindClass (name, klass->loader);
-
+ found = _Jv_FindClassFromSignatureNoException (name->chars(),
+ klass->loader);
+ else
+ found = _Jv_FindClassNoException (name, klass->loader);
+
+ // If the class could not be loaded a phantom class is created. Any
+ // function that deals with such a class but cannot do something useful
+ // with it should just throw a NoClassDefFoundError with the class'
+ // name.
if (! found)
- throw new java::lang::NoClassDefFoundError (name->toString());
+ 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());
// Check accessibility, but first strip array types as
// _Jv_ClassNameSamePackage can't handle arrays.
_Jv_loadIndexes (&pool->data[index],
class_index,
name_and_type_index);
- jclass owner = (resolve_pool_entry (klass, class_index)).clazz;
+ jclass owner = (resolve_pool_entry (klass, class_index, true)).clazz;
+
+ // If a phantom class was resolved our field reference is
+ // unusable because of the missing class.
+ if (owner->state == JV_STATE_PHANTOM)
+ throw new java::lang::NoClassDefFoundError(owner->getName());
if (owner != klass)
_Jv_InitClass (owner);
throw new java::lang::NoSuchMethodError (sb->toString());
}
- int vtable_index = -1;
- if (pool->tags[index] != JV_CONSTANT_InterfaceMethodref)
- vtable_index = (jshort)the_method->index;
-
pool->data[index].rmethod
= klass->engine->resolve_method(the_method,
found_class,
((the_method->accflags
- & Modifier::STATIC) != 0),
- vtable_index);
+ & Modifier::STATIC) != 0));
pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
}
break;
#define INITIAL_IOFFSETS_LEN 4
#define INITIAL_IFACES_LEN 4
-static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} };
+static _Jv_IDispatchTable null_idt = {SHRT_MAX, 0, {}};
// Generate tables for constant-time assignment testing and interface
// method lookup. This implements the technique described by Per Bothner
// a pointer to the current class, and the rest are pointers to the
// classes ancestors, ordered from the current class down by decreasing
// depth. We do not include java.lang.Object in the table of ancestors,
- // since it is redundant.
+ // since it is redundant. Note that the classes pointed to by
+ // 'ancestors' will always be reachable by other paths.
- // FIXME: _Jv_AllocBytes
- klass->ancestors = (jclass *) _Jv_Malloc (klass->depth
+ klass->ancestors = (jclass *) _Jv_AllocBytes (klass->depth
* sizeof (jclass));
klass0 = klass;
for (int index = 0; index < klass->depth; index++)
return;
}
- // FIXME: _Jv_AllocBytes
- klass->idt =
- (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
-
_Jv_ifaces ifaces;
ifaces.count = 0;
ifaces.len = INITIAL_IFACES_LEN;
if (ifaces.count > 0)
{
- klass->idt->cls.itable =
- // FIXME: _Jv_AllocBytes
- (void **) _Jv_Malloc (itable_size * sizeof (void *));
- klass->idt->cls.itable_length = itable_size;
+ // The classes pointed to by the itable will always be reachable
+ // via other paths.
+ int idt_bytes = sizeof (_Jv_IDispatchTable) + (itable_size
+ * sizeof (void *));
+ klass->idt = (_Jv_IDispatchTable *) _Jv_AllocBytes (idt_bytes);
+ klass->idt->itable_length = itable_size;
jshort *itable_offsets =
(jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort));
for (int i = 0; i < ifaces.count; i++)
{
- ifaces.list[i]->idt->iface.ioffsets[cls_iindex] =
- itable_offsets[i];
+ ifaces.list[i]->ioffsets[cls_iindex] = itable_offsets[i];
}
- klass->idt->cls.iindex = cls_iindex;
+ klass->idt->iindex = cls_iindex;
_Jv_Free (ifaces.list);
_Jv_Free (itable_offsets);
}
else
{
- klass->idt->cls.iindex = SHRT_MAX;
+ klass->idt->iindex = SHRT_MAX;
}
}
result += get_interfaces (klass->interfaces[i], ifaces);
}
}
-
+
if (klass->isInterface())
- result += klass->method_count + 1;
+ {
+ // We want to add 1 plus the number of interface methods here.
+ // But, we take special care to skip <clinit>.
+ ++result;
+ for (int i = 0; i < klass->method_count; ++i)
+ {
+ if (klass->methods[i].name->first() != '<')
+ ++result;
+ }
+ }
else if (klass->superclass)
result += get_interfaces (klass->superclass, ifaces);
return result;
_Jv_Linker::generate_itable (jclass klass, _Jv_ifaces *ifaces,
jshort *itable_offsets)
{
- void **itable = klass->idt->cls.itable;
+ void **itable = klass->idt->itable;
jshort itable_pos = 0;
for (int i = 0; i < ifaces->count; i++)
itable_offsets[i] = itable_pos;
itable_pos = append_partial_itable (klass, iface, itable, itable_pos);
- /* Create interface dispatch table for iface */
- if (iface->idt == NULL)
+ /* Create ioffsets table for iface */
+ if (iface->ioffsets == NULL)
{
- // FIXME: _Jv_AllocBytes
- iface->idt
- = (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable));
-
// The first element of ioffsets is its length (itself included).
- // FIXME: _Jv_AllocBytes
- jshort *ioffsets = (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN
- * sizeof (jshort));
+ jshort *ioffsets = (jshort *) _Jv_AllocBytes (INITIAL_IOFFSETS_LEN
+ * sizeof (jshort));
ioffsets[0] = INITIAL_IOFFSETS_LEN;
for (int i = 1; i < INITIAL_IOFFSETS_LEN; i++)
ioffsets[i] = -1;
- iface->idt->iface.ioffsets = ioffsets;
+ iface->ioffsets = ioffsets;
}
}
}
return buf->toString();
}
-void
+void
_Jv_ThrowNoSuchMethodError ()
{
throw new java::lang::NoSuchMethodError;
}
+#ifdef USE_LIBFFI
+// 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.
+// The prepared function call is stored in a class' atable.
+void
+_Jv_ThrowNoClassDefFoundErrorTrampoline(ffi_cif *,
+ void *,
+ void **,
+ void *data)
+{
+ throw new java::lang::NoClassDefFoundError(
+ _Jv_NewStringUtf8Const((_Jv_Utf8Const *) data));
+}
+#else
+// A variant of the NoClassDefFoundError throwing method that can
+// be used without libffi.
+void
+_Jv_ThrowNoClassDefFoundError()
+{
+ throw new java::lang::NoClassDefFoundError();
+}
+#endif
+
+// Throw a NoSuchFieldError. Called by compiler-generated code when
+// an otable entry is zero. OTABLE_INDEX is the index in the caller's
+// otable that refers to the missing field. This index may be used to
+// print diagnostic information about the field.
+void
+_Jv_ThrowNoSuchFieldError (int /* otable_index */)
+{
+ throw new java::lang::NoSuchFieldError;
+}
+
// This is put in empty vtable slots.
void
_Jv_ThrowAbstractMethodError ()
// Returns the offset at which the next partial ITable should be appended.
jshort
_Jv_Linker::append_partial_itable (jclass klass, jclass iface,
- void **itable, jshort pos)
+ void **itable, jshort pos)
{
using namespace java::lang::reflect;
for (int j=0; j < iface->method_count; j++)
{
+ // Skip '<clinit>' here.
+ if (iface->methods[j].name->first() == '<')
+ continue;
+
meth = NULL;
for (jclass cl = klass; cl; cl = cl->getSuperclass())
{
break;
}
- if (meth && (meth->name->first() == '<'))
- {
- // leave a placeholder in the itable for hidden init methods.
- itable[pos] = NULL;
- }
- else if (meth)
+ if (meth)
{
if ((meth->accflags & Modifier::STATIC) != 0)
throw new java::lang::IncompatibleClassChangeError
// Interface Dispatch Table, we just compare the first element to see if it
// matches the desired interface. So how can we find the correct offset?
// Our solution is to keep a vector of candiate offsets in each interface
-// (idt->iface.ioffsets), and in each class we have an index
-// (idt->cls.iindex) used to select the correct offset from ioffsets.
+// (ioffsets), and in each class we have an index (idt->iindex) used to
+// select the correct offset from ioffsets.
//
// Calculate and return iindex for a new class.
// ifaces is a vector of num interfaces that the class implements.
{
if (j >= num)
goto found;
- if (i >= ifaces[j]->idt->iface.ioffsets[0])
+ if (i >= ifaces[j]->ioffsets[0])
continue;
- int ioffset = ifaces[j]->idt->iface.ioffsets[i];
+ int ioffset = ifaces[j]->ioffsets[i];
/* We can potentially share this position with another class. */
if (ioffset >= 0 && ioffset != offsets[j])
break; /* Nope. Try next i. */
found:
for (j = 0; j < num; j++)
{
- int len = ifaces[j]->idt->iface.ioffsets[0];
+ int len = ifaces[j]->ioffsets[0];
if (i >= len)
{
// Resize ioffsets.
int newlen = 2 * len;
if (i >= newlen)
newlen = i + 3;
- jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets;
- // FIXME: _Jv_AllocBytes
- jshort *new_ioffsets = (jshort *) _Jv_Malloc (newlen
- * sizeof(jshort));
+
+ jshort *old_ioffsets = ifaces[j]->ioffsets;
+ jshort *new_ioffsets = (jshort *) _Jv_AllocBytes (newlen
+ * sizeof(jshort));
memcpy (&new_ioffsets[1], &old_ioffsets[1],
(len - 1) * sizeof (jshort));
new_ioffsets[0] = newlen;
while (len < newlen)
new_ioffsets[len++] = -1;
- ifaces[j]->idt->iface.ioffsets = new_ioffsets;
+ ifaces[j]->ioffsets = new_ioffsets;
}
- ifaces[j]->idt->iface.ioffsets[i] = offsets[j];
+ ifaces[j]->ioffsets[i] = offsets[j];
}
_Jv_MutexUnlock (&iindex_mutex);
return i;
}
+#ifdef USE_LIBFFI
+// We use a structure of this type to store the closure that
+// represents a missing method.
+struct method_closure
+{
+ // This field must come first, since the address of this field will
+ // be the same as the address of the overall structure. This is due
+ // to disabling interior pointers in the GC.
+ ffi_closure closure;
+ ffi_cif cif;
+ ffi_type *arg_types[1];
+};
+
+void *
+_Jv_Linker::create_error_method (_Jv_Utf8Const *class_name)
+{
+ method_closure *closure
+ = (method_closure *) _Jv_AllocBytes(sizeof (method_closure));
+
+ closure->arg_types[0] = &ffi_type_void;
+
+ // Initializes the cif and the closure. If that worked the closure
+ // is returned and can be used as a function pointer in a class'
+ // atable.
+ if ( ffi_prep_cif (&closure->cif,
+ FFI_DEFAULT_ABI,
+ 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;
+ else
+ {
+ java::lang::StringBuffer *buffer = new java::lang::StringBuffer();
+ buffer->append(JvNewStringLatin1("Error setting up FFI closure"
+ " for static method of"
+ " missing class: "));
+ buffer->append (_Jv_NewStringUtf8Const(class_name));
+ throw new java::lang::InternalError(buffer->toString());
+ }
+}
+#else
+void *
+_Jv_Linker::create_error_method (_Jv_Utf8Const *)
+{
+ // 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
// Functions for indirect dispatch (symbolic virtual binding) support.
_Jv_Utf8Const *signature = sym.signature;
- {
- static char *bounce = (char *)_Jv_ThrowNoSuchMethodError;
- ptrdiff_t offset = (char *)(klass->vtable) - bounce;
- klass->otable->offsets[index] = offset;
- }
-
if (target_class == NULL)
throw new java::lang::NoClassDefFoundError
(_Jv_NewStringUTF (sym.class_name->chars()));
meth = _Jv_LookupDeclaredMethod(target_class, sym.name,
sym.signature);
- if (meth != NULL)
+ // Every class has a throwNoSuchMethodErrorIndex method that
+ // it inherits from java.lang.Object. Find its vtable
+ // offset.
+ static int throwNoSuchMethodErrorIndex;
+ if (throwNoSuchMethodErrorIndex == 0)
{
- int offset = _Jv_VTable::idx_to_offset (meth->index);
- if (offset == -1)
- JvFail ("Bad method index");
- JvAssert (meth->index < target_class->vtable_method_count);
- klass->otable->offsets[index] = offset;
+ Utf8Const* name
+ = _Jv_makeUtf8Const ("throwNoSuchMethodError",
+ strlen ("throwNoSuchMethodError"));
+ _Jv_Method* meth
+ = _Jv_LookupDeclaredMethod (&java::lang::Object::class$,
+ name, gcj::void_signature);
+ throwNoSuchMethodErrorIndex
+ = _Jv_VTable::idx_to_offset (meth->index);
}
+
+ // If we don't find a nonstatic method, insert the
+ // vtable index of Object.throwNoSuchMethodError().
+ // This defers the missing method error until an attempt
+ // is made to execute it.
+ {
+ int offset;
+
+ if (meth != NULL)
+ offset = _Jv_VTable::idx_to_offset (meth->index);
+ else
+ offset = throwNoSuchMethodErrorIndex;
+
+ if (offset == -1)
+ JvFail ("Bad method index");
+ JvAssert (meth->index < target_class->vtable_method_count);
+
+ klass->otable->offsets[index] = offset;
+ }
+
if (debug_link)
fprintf (stderr, " offsets[%d] = %d (class %s@%p : %s(%s))\n",
(int)index,
{
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);
- if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
- throw new java::lang::IncompatibleClassChangeError;
- else
- klass->otable->offsets[index] = the_field->u.boffset;
+ _Jv_Field *the_field = NULL;
+ try
+ {
+ the_field = find_field (klass, target_class, &found_class,
+ sym.name, sym.signature);
+ if ((the_field->flags & java::lang::reflect::Modifier::STATIC))
+ throw new java::lang::IncompatibleClassChangeError;
+ else
+ klass->otable->offsets[index] = the_field->u.boffset;
+ }
+ catch (java::lang::NoSuchFieldError *err)
+ {
+ klass->otable->offsets[index] = 0;
+ }
}
}
(sym = klass->atable_syms[index]).class_name != NULL;
++index)
{
- jclass target_class = _Jv_FindClass (sym.class_name, klass->loader);
+ jclass target_class =
+ _Jv_FindClassNoException (sym.class_name, klass->loader);
+
_Jv_Method *meth = NULL;
_Jv_Utf8Const *signature = sym.signature;
// ??? Setting this pointer to null will at least get us a
// NullPointerException
klass->atable->addresses[index] = NULL;
-
+
+ // 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
+ // code in classes where the missing class is part of the
+ // execution environment as long as it is never referenced.
if (target_class == NULL)
- throw new java::lang::NoClassDefFoundError
- (_Jv_NewStringUTF (sym.class_name->chars()));
-
+ klass->atable->addresses[index] = create_error_method(sym.class_name);
// We're looking for a static field or a static method, and we
// can tell which is needed by looking at the signature.
- if (signature->first() == '(' && signature->len() >= 2)
+ else if (signature->first() == '(' && signature->len() >= 2)
{
// If the target class does not have a vtable_method_count yet,
// then we can't tell the offsets for its methods, so we must lay
}
else
klass->atable->addresses[index]
- = (void *)_Jv_ThrowNoSuchMethodError;
+ = create_error_method(sym.class_name);
continue;
}
- // Try fields.
+ // Try fields only if the target class exists.
+ if (target_class != NULL)
{
wait_for_state(target_class, JV_STATE_PREPARED);
jclass found_class;
}
int instance_size;
- int static_size = 0;
+ // This is the size of the 'static' non-reference fields.
+ int non_reference_size = 0;
+ // This is the size of the 'static' reference fields. We count
+ // these separately to make it simpler for the GC to scan them.
+ int reference_size = 0;
// Although java.lang.Object is never interpreted, an interface can
// have a null superclass. Note that we have to lay out an
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 (field->u.addr == NULL)
{
// This computes an offset into a region we'll allocate
- // shortly, and then add this offset to the start
+ // shortly, and then adds this offset to the start
// address.
- static_size = ROUND (static_size, field_align);
- field->u.boffset = static_size;
- static_size += field_size;
+ if (field->isRef())
+ {
+ reference_size = ROUND (reference_size, field_align);
+ field->u.boffset = reference_size;
+ reference_size += field_size;
+ }
+ else
+ {
+ non_reference_size = ROUND (non_reference_size, field_align);
+ field->u.boffset = non_reference_size;
+ non_reference_size += field_size;
+ }
}
}
else
}
}
- if (static_size != 0)
- klass->engine->allocate_static_fields (klass, static_size);
+ if (reference_size != 0 || non_reference_size != 0)
+ klass->engine->allocate_static_fields (klass, reference_size,
+ non_reference_size);
// Set the instance size for the class. Note that first we round it
// to the alignment required for this object; this keeps us in sync
for (int index = 1; index < pool->size; ++index)
{
if (pool->tags[index] == JV_CONSTANT_Class)
- resolve_pool_entry (klass, index);
+ // Lazily resolve the entries.
+ resolve_pool_entry (klass, index, true);
}
}
-#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)
{
int mod = f->getModifiers ();
// If we have a static String field with a non-null initial
// value, we know it points to a Utf8Const.
- resolve_field(f, klass->loader);
- if (f->getClass () == &java::lang::String::class$
+
+ // Finds out whether we have to initialize a String without the
+ // need to resolve the field.
+ if ((f->isResolved()
+ ? (f->type == &java::lang::String::class$)
+ : _Jv_equalUtf8Classnames((_Jv_Utf8Const *) f->type,
+ java::lang::String::class$.name))
&& (mod & java::lang::reflect::Modifier::STATIC) != 0)
{
jstring *strp = (jstring *) f->u.addr;
// found is really unique among all superinterfaces.
int new_count = base->method_count + 1;
_Jv_Method *new_m
- = (_Jv_Method *) _Jv_AllocBytes (sizeof (_Jv_Method)
- * new_count);
+ = (_Jv_Method *) _Jv_AllocRawObj (sizeof (_Jv_Method)
+ * new_count);
memcpy (new_m, base->methods,
sizeof (_Jv_Method) * base->method_count);
void
_Jv_Linker::ensure_method_table_complete (jclass klass)
{
- if (klass->vtable != NULL || klass->isInterface())
+ if (klass->vtable != NULL)
return;
// We need our superclass to have its own Miranda methods installed.
- wait_for_state (klass->getSuperclass (), JV_STATE_LOADED);
+ if (! klass->isInterface())
+ wait_for_state (klass->getSuperclass (), JV_STATE_LOADED);
// A class might have so-called "Miranda methods". This is a method
// that is declared in an interface and not re-declared in an
if (cl1 == NULL || cl2 == NULL)
continue;
- if (! _Jv_IsAssignableFromSlow (cl2, cl1))
+ if (! _Jv_IsAssignableFromSlow (cl1, cl2))
{
jstring s = JvNewStringUTF ("Incompatible types: In class ");
s = s->concat (klass->getName());
}
}
if (codesource == NULL)
- codesource = "<no code source>";
+ codesource = (char *) "<no code source>";
- char *abi;
+ const char *abi;
if (_Jv_IsInterpretedClass (klass))
abi = "bytecode";
else if (_Jv_IsBinaryCompatibilityABI (klass))
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.