summaryrefslogtreecommitdiff
path: root/libjava/link.cc
diff options
context:
space:
mode:
authorrschuster <rschuster@138bc75d-0d04-0410-961f-82ee72b054a4>2006-02-01 13:40:05 +0000
committerrschuster <rschuster@138bc75d-0d04-0410-961f-82ee72b054a4>2006-02-01 13:40:05 +0000
commitb07ed7feb8f9fc07ef1fd0a9e181446f0d432559 (patch)
tree331725f44321f544a0c7d62882b65627f0e43522 /libjava/link.cc
parent06d9b28a09242827b83c60e3d94ca5c2fa2db6cd (diff)
downloadgcc-b07ed7feb8f9fc07ef1fd0a9e181446f0d432559.tar.gz
2006-02-01 Robert Schuster <robertschuster@fsfe.org>
* link.cc: (_Jv_Linker::find_field_helper): Added checks. (_Jv_Linker::find_field): Use exception swallowing class resolution and added early return. (_Jv_ThrowNoClassDefFoundErrorTrampoline): New function. (_Jv_Linker::link_symbol_table): Use exception swallowing class resolution, added ffi_closure installation routine, use _Jv_ThrowNoClassDefFoundError for missing static method. (_Jv_Linker::ensure_class_linked): Added string check which does not trigger class resolution. * java/lang/natClassLoader.cc: (_Jv_FindClassNoException): New method. * java/lang/Class.h: (_Jv_FindClassNoException): New method declaration. * include/jvm.h: (_Jv_FindClassNoException): New method declaration. (_Jv_FindClassFromSignatureNoException): New method declaration. * prims.cc: (_Jv_FindClassFromSignatureNoException): New method. * gcj/javaprims.h: (_Jv_equalsUtf8Classname): New method declaration. (_Jv_isPrimitiveOrDerived): Dito. * prims.cc: (_Jv_equalsUtf8Classnames): New method. (_Jv_isPrimitiveOrDerived): New method. * verify.cc: (ref_intersection::equals): Use new classname comparison method. (type::compatible): Use new classname comparison method. Added check whether LHS' type is java.lang.Object . (type::resolve): Added new optional debug message and simplified if-expression. (type::to_array): Added codepath that generates an array type without resolving the element type. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@110474 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/link.cc')
-rw-r--r--libjava/link.cc191
1 files changed, 158 insertions, 33 deletions
diff --git a/libjava/link.cc b/libjava/link.cc
index 7070d729b4a..1118d9b8bab 100644
--- a/libjava/link.cc
+++ b/libjava/link.cc
@@ -34,6 +34,7 @@ details. */
#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>
@@ -100,7 +101,7 @@ _Jv_Linker::resolve_field (_Jv_Field *field, java::lang::ClassLoader *loader)
// 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)
@@ -112,8 +113,26 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
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
@@ -123,7 +142,10 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
// 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;
@@ -134,7 +156,7 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
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;
}
@@ -175,13 +197,21 @@ _Jv_Linker::find_field (jclass klass, jclass owner,
{
// 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)
{
@@ -194,6 +224,12 @@ _Jv_Linker::find_field (jclass klass, jclass owner,
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
@@ -221,7 +257,7 @@ _Jv_Linker::find_field (jclass klass, jclass owner,
}
_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;
@@ -238,13 +274,26 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index)
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.
@@ -286,7 +335,12 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index)
_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);
@@ -707,12 +761,31 @@ _Jv_GetMethodString (jclass klass, _Jv_Method *meth,
return buf->toString();
}
-void
+void
_Jv_ThrowNoSuchMethodError ()
{
throw new java::lang::NoSuchMethodError;
}
+// 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((jstring) data);
+}
+
+void
+_Jv_ThrowNoClassDefFoundError()
+{
+ throw new java::lang::NoClassDefFoundError();
+}
+
// 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
@@ -723,7 +796,6 @@ _Jv_ThrowNoSuchFieldError (int /* otable_index */)
throw new java::lang::NoSuchFieldError;
}
-
// This is put in empty vtable slots.
void
_Jv_ThrowAbstractMethodError ()
@@ -1030,21 +1102,65 @@ _Jv_Linker::link_symbol_table (jclass klass)
(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()));
-
+ {
+ // TODO: The following structs/objects are heap allocated are
+ // unreachable by the garbage collector:
+ // - cif, arg_types
+ // - the Java string inside the if-statement
+
+ ffi_closure *closure =
+ (ffi_closure *) _Jv_Malloc( sizeof( ffi_closure ));
+ ffi_cif *cif = (ffi_cif *) _Jv_Malloc( sizeof( ffi_cif ));
+
+ // Pretends that we want to call a void (*) (void) function via
+ // ffi_call.
+ ffi_type **arg_types = (ffi_type **) _Jv_Malloc( sizeof( ffi_type * ));
+ arg_types[0] = &ffi_type_void;
+
+ // Initializes the cif and the closure. If that worked the closure is
+ // stored as a function pointer in the atable.
+ if ( ffi_prep_cif(cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_void, arg_types) == FFI_OK
+ && (ffi_prep_closure
+ (closure, cif,
+ _Jv_ThrowNoClassDefFoundErrorTrampoline,
+ (void *) _Jv_NewStringUtf8Const(sym.class_name))
+ == FFI_OK))
+ {
+ klass->atable->addresses[index] = (void *) closure;
+ }
+ else
+ {
+ // If you land here it is possible that your architecture does
+ // not support the Closure API yet. Let's port it!
+ 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(sym.class_name));
+
+ throw new java::lang::InternalError(buffer->toString());
+ }
+ }
// 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
@@ -1082,13 +1198,16 @@ _Jv_Linker::link_symbol_table (jclass klass)
}
}
else
+ // TODO: Use _Jv_ThrowNoClassDefFoundErrorTrampoline to be able
+ // to print the class name.
klass->atable->addresses[index]
- = (void *)_Jv_ThrowNoSuchMethodError;
+ = (void *) _Jv_ThrowNoClassDefFoundError;
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;
@@ -1453,7 +1572,8 @@ _Jv_Linker::ensure_class_linked (jclass klass)
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);
}
}
@@ -1493,8 +1613,13 @@ _Jv_Linker::ensure_class_linked (jclass klass)
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;