Commit c1a9321f by Robert Schuster Committed by Robert Schuster

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.

From-SVN: r110474
parent 168b93e9
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.
2006-01-31 Mark Wielaard <mark@klomp.org> 2006-01-31 Mark Wielaard <mark@klomp.org>
* NEWS: Add 4.1 updates. * NEWS: Add 4.1 updates.
......
...@@ -566,6 +566,9 @@ class _Jv_Utf8Const ...@@ -566,6 +566,9 @@ class _Jv_Utf8Const
friend jboolean _Jv_equalUtf8Consts (const _Jv_Utf8Const*, const _Jv_Utf8Const *); friend jboolean _Jv_equalUtf8Consts (const _Jv_Utf8Const*, const _Jv_Utf8Const *);
friend jboolean _Jv_equal (_Jv_Utf8Const*, jstring, jint); friend jboolean _Jv_equal (_Jv_Utf8Const*, jstring, jint);
friend jboolean _Jv_equaln (_Jv_Utf8Const*, jstring, jint); friend jboolean _Jv_equaln (_Jv_Utf8Const*, jstring, jint);
friend jboolean _Jv_equalUtf8Classnames (const _Jv_Utf8Const*,
const _Jv_Utf8Const*);
friend jboolean _Jv_isPrimitiveOrDerived (const _Jv_Utf8Const*);
friend _Jv_Utf8Const *_Jv_makeUtf8Const (char*, int); friend _Jv_Utf8Const *_Jv_makeUtf8Const (char*, int);
friend _Jv_Utf8Const *_Jv_makeUtf8Const (jstring); friend _Jv_Utf8Const *_Jv_makeUtf8Const (jstring);
friend jstring _Jv_NewStringUtf8Const (_Jv_Utf8Const*); friend jstring _Jv_NewStringUtf8Const (_Jv_Utf8Const*);
......
...@@ -239,7 +239,7 @@ class _Jv_Linker ...@@ -239,7 +239,7 @@ class _Jv_Linker
{ {
private: private:
static _Jv_Field *find_field_helper(jclass, _Jv_Utf8Const *, _Jv_Utf8Const *, static _Jv_Field *find_field_helper(jclass, _Jv_Utf8Const *, _Jv_Utf8Const *,
jclass *); jclass, jclass *);
static _Jv_Field *find_field(jclass, jclass, jclass *, _Jv_Utf8Const *, static _Jv_Field *find_field(jclass, jclass, jclass *, _Jv_Utf8Const *,
_Jv_Utf8Const *); _Jv_Utf8Const *);
static void prepare_constant_time_tables(jclass); static void prepare_constant_time_tables(jclass);
...@@ -271,7 +271,7 @@ public: ...@@ -271,7 +271,7 @@ public:
static void print_class_loaded (jclass); static void print_class_loaded (jclass);
static void resolve_class_ref (jclass, jclass *); static void resolve_class_ref (jclass, jclass *);
static void wait_for_state(jclass, int); static void wait_for_state(jclass, int);
static _Jv_word resolve_pool_entry (jclass, int); static _Jv_word resolve_pool_entry (jclass, int, bool =false);
static void resolve_field (_Jv_Field *, java::lang::ClassLoader *); static void resolve_field (_Jv_Field *, java::lang::ClassLoader *);
static void verify_type_assertions (jclass); static void verify_type_assertions (jclass);
}; };
...@@ -463,9 +463,18 @@ extern "C" jobject _Jv_UnwrapJNIweakReference (jobject); ...@@ -463,9 +463,18 @@ extern "C" jobject _Jv_UnwrapJNIweakReference (jobject);
extern jclass _Jv_FindClass (_Jv_Utf8Const *name, extern jclass _Jv_FindClass (_Jv_Utf8Const *name,
java::lang::ClassLoader *loader); java::lang::ClassLoader *loader);
extern jclass _Jv_FindClassNoException (_Jv_Utf8Const *name,
java::lang::ClassLoader *loader);
extern jclass _Jv_FindClassFromSignature (char *, extern jclass _Jv_FindClassFromSignature (char *,
java::lang::ClassLoader *loader, java::lang::ClassLoader *loader,
char ** = NULL); char ** = NULL);
extern jclass _Jv_FindClassFromSignatureNoException (char *,
java::lang::ClassLoader *loader,
char ** = NULL);
extern void _Jv_GetTypesFromSignature (jmethodID method, extern void _Jv_GetTypesFromSignature (jmethodID method,
jclass declaringClass, jclass declaringClass,
JArray<jclass> **arg_types_out, JArray<jclass> **arg_types_out,
...@@ -643,4 +652,14 @@ _Jv_IsBinaryCompatibilityABI (jclass c) ...@@ -643,4 +652,14 @@ _Jv_IsBinaryCompatibilityABI (jclass c)
return c->otable_syms || c->atable_syms || c->itable_syms; return c->otable_syms || c->atable_syms || c->itable_syms;
} }
// Returns whether the given class does not really exists (ie. we have no
// bytecode) but still allows us to do some very conservative actions.
// E.g. throwing a NoClassDefFoundError with the name of the missing
// class.
extern inline jboolean
_Jv_IsPhantomClass (jclass c)
{
return c->state == JV_STATE_PHANTOM;
}
#endif /* __JAVA_JVM_H__ */ #endif /* __JAVA_JVM_H__ */
...@@ -69,7 +69,13 @@ enum ...@@ -69,7 +69,13 @@ enum
JV_STATE_ERROR = 12, JV_STATE_ERROR = 12,
JV_STATE_DONE = 14 // Must be last. JV_STATE_PHANTOM = 13, // Bytecode is missing. In many cases we can
// work around that. If not, throw a
// NoClassDefFoundError.
JV_STATE_DONE = 14, // Must be last.
}; };
struct _Jv_Field; struct _Jv_Field;
...@@ -240,6 +246,8 @@ void _Jv_RegisterClassHookDefault (jclass klass); ...@@ -240,6 +246,8 @@ void _Jv_RegisterClassHookDefault (jclass klass);
void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*);
void _Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*); void _Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*);
void _Jv_UnregisterClass (jclass); void _Jv_UnregisterClass (jclass);
jclass _Jv_FindClassNoException (_Jv_Utf8Const *name,
java::lang::ClassLoader *loader);
jclass _Jv_FindClass (_Jv_Utf8Const *name, jclass _Jv_FindClass (_Jv_Utf8Const *name,
java::lang::ClassLoader *loader); java::lang::ClassLoader *loader);
jclass _Jv_FindClassInCache (_Jv_Utf8Const *name); jclass _Jv_FindClassInCache (_Jv_Utf8Const *name);
...@@ -263,6 +271,8 @@ jclass _Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader); ...@@ -263,6 +271,8 @@ jclass _Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader);
jboolean _Jv_IsInterpretedClass (jclass); jboolean _Jv_IsInterpretedClass (jclass);
jboolean _Jv_IsBinaryCompatibilityABI (jclass); jboolean _Jv_IsBinaryCompatibilityABI (jclass);
jboolean _Jv_IsPhantomClass (jclass);
void _Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *); void _Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *);
#ifdef INTERPRETER #ifdef INTERPRETER
...@@ -469,6 +479,8 @@ private: ...@@ -469,6 +479,8 @@ private:
friend void ::_Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); friend void ::_Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*);
friend void ::_Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*); friend void ::_Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*);
friend void ::_Jv_UnregisterClass (jclass); friend void ::_Jv_UnregisterClass (jclass);
friend jclass (::_Jv_FindClassNoException) (_Jv_Utf8Const *name,
java::lang::ClassLoader *loader);
friend jclass (::_Jv_FindClass) (_Jv_Utf8Const *name, friend jclass (::_Jv_FindClass) (_Jv_Utf8Const *name,
java::lang::ClassLoader *loader); java::lang::ClassLoader *loader);
friend jclass (::_Jv_FindClassInCache) (_Jv_Utf8Const *name); friend jclass (::_Jv_FindClassInCache) (_Jv_Utf8Const *name);
...@@ -499,6 +511,8 @@ private: ...@@ -499,6 +511,8 @@ private:
friend jboolean (::_Jv_IsInterpretedClass) (jclass); friend jboolean (::_Jv_IsInterpretedClass) (jclass);
friend jboolean (::_Jv_IsBinaryCompatibilityABI) (jclass); friend jboolean (::_Jv_IsBinaryCompatibilityABI) (jclass);
friend jboolean (::_Jv_IsPhantomClass) (jclass);
#ifdef INTERPRETER #ifdef INTERPRETER
friend void ::_Jv_InitField (jobject, jclass, int); friend void ::_Jv_InitField (jobject, jclass, int);
......
...@@ -668,8 +668,9 @@ java::lang::Class::finalize (void) ...@@ -668,8 +668,9 @@ java::lang::Class::finalize (void)
void void
java::lang::Class::initializeClass (void) java::lang::Class::initializeClass (void)
{ {
// Short-circuit to avoid needless locking. // Short-circuit to avoid needless locking (expression includes
if (state == JV_STATE_DONE) // JV_STATE_PHANTOM and JV_STATE_DONE).
if (state >= JV_STATE_PHANTOM)
return; return;
// Step 1. We introduce a new scope so we can synchronize more // Step 1. We introduce a new scope so we can synchronize more
......
...@@ -266,6 +266,30 @@ _Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *loader) ...@@ -266,6 +266,30 @@ _Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *loader)
system_class_list = SYSTEM_LOADER_INITIALIZED; system_class_list = SYSTEM_LOADER_INITIALIZED;
} }
// An internal variant of _Jv_FindClass which simply swallows a
// NoClassDefFoundError or a ClassNotFoundException. This gives the
// caller a chance to evaluate the situation and behave accordingly.
jclass
_Jv_FindClassNoException (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
{
jclass klass;
try
{
klass = _Jv_FindClass(name, loader);
}
catch ( java::lang::NoClassDefFoundError *ncdfe )
{
return NULL;
}
catch ( java::lang::ClassNotFoundException *cnfe )
{
return NULL;
}
return klass;
}
jclass jclass
_Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
{ {
......
...@@ -34,6 +34,7 @@ details. */ ...@@ -34,6 +34,7 @@ details. */
#include <java/lang/NoSuchMethodError.h> #include <java/lang/NoSuchMethodError.h>
#include <java/lang/ClassFormatError.h> #include <java/lang/ClassFormatError.h>
#include <java/lang/IllegalAccessError.h> #include <java/lang/IllegalAccessError.h>
#include <java/lang/InternalError.h>
#include <java/lang/AbstractMethodError.h> #include <java/lang/AbstractMethodError.h>
#include <java/lang/NoClassDefFoundError.h> #include <java/lang/NoClassDefFoundError.h>
#include <java/lang/IncompatibleClassChangeError.h> #include <java/lang/IncompatibleClassChangeError.h>
...@@ -100,7 +101,7 @@ _Jv_Linker::resolve_field (_Jv_Field *field, java::lang::ClassLoader *loader) ...@@ -100,7 +101,7 @@ _Jv_Linker::resolve_field (_Jv_Field *field, java::lang::ClassLoader *loader)
// superclasses and interfaces. // superclasses and interfaces.
_Jv_Field * _Jv_Field *
_Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name, _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
_Jv_Utf8Const *type_name, _Jv_Utf8Const *type_name, jclass type,
jclass *declarer) jclass *declarer)
{ {
while (search) while (search)
...@@ -112,8 +113,26 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name, ...@@ -112,8 +113,26 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
if (! _Jv_equalUtf8Consts (field->name, name)) if (! _Jv_equalUtf8Consts (field->name, name))
continue; continue;
if (! field->isResolved ()) // Checks for the odd situation where we were able to retrieve the
resolve_field (field, search->loader); // 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 // Note that we compare type names and not types. This is
// bizarre, but we do it because we want to find a field // 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, ...@@ -123,7 +142,10 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
// pass in the descriptor and check that way, because when // pass in the descriptor and check that way, because when
// the field is already resolved there is no easy way to // the field is already resolved there is no easy way to
// find its descriptor again. // 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; *declarer = search;
return field; return field;
...@@ -134,7 +156,7 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name, ...@@ -134,7 +156,7 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
for (int i = 0; i < search->interface_count; ++i) for (int i = 0; i < search->interface_count; ++i)
{ {
_Jv_Field *result = find_field_helper (search->interfaces[i], name, _Jv_Field *result = find_field_helper (search->interfaces[i], name,
type_name, declarer); type_name, type, declarer);
if (result) if (result)
return result; return result;
} }
...@@ -175,13 +197,21 @@ _Jv_Linker::find_field (jclass klass, jclass owner, ...@@ -175,13 +197,21 @@ _Jv_Linker::find_field (jclass klass, jclass owner,
{ {
// FIXME: this allocates a _Jv_Utf8Const each time. We should make // FIXME: this allocates a _Jv_Utf8Const each time. We should make
// it cheaper. // it cheaper.
jclass field_type = _Jv_FindClassFromSignature (field_type_name->chars(), // Note: This call will resolve the primitive type names ("Z", "B", ...) to
klass->loader); // their Java counterparts ("boolean", "byte", ...) if accessed via
if (field_type == NULL) // field_type->name later. Using these variants of the type name is in turn
throw new java::lang::NoClassDefFoundError(field_name->toString()); // important for the find_field_helper function. However if the class
// resolution failed then we can only use the already given type name.
_Jv_Field *the_field = find_field_helper (owner, field_name, jclass field_type
field_type->name, found_class); = _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) if (the_field == 0)
{ {
...@@ -194,6 +224,12 @@ _Jv_Linker::find_field (jclass klass, jclass owner, ...@@ -194,6 +224,12 @@ _Jv_Linker::find_field (jclass klass, jclass owner,
throw new java::lang::NoSuchFieldError (sb->toString()); 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)) if (_Jv_CheckAccess (klass, *found_class, the_field->flags))
{ {
// Note that the field returned by find_field_helper is always // Note that the field returned by find_field_helper is always
...@@ -221,7 +257,7 @@ _Jv_Linker::find_field (jclass klass, jclass owner, ...@@ -221,7 +257,7 @@ _Jv_Linker::find_field (jclass klass, jclass owner,
} }
_Jv_word _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; using namespace java::lang::reflect;
...@@ -238,13 +274,26 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index) ...@@ -238,13 +274,26 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index)
jclass found; jclass found;
if (name->first() == '[') if (name->first() == '[')
found = _Jv_FindClassFromSignature (name->chars(), found = _Jv_FindClassFromSignatureNoException (name->chars(),
klass->loader); klass->loader);
else else
found = _Jv_FindClass (name, klass->loader); 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) 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 // Check accessibility, but first strip array types as
// _Jv_ClassNameSamePackage can't handle arrays. // _Jv_ClassNameSamePackage can't handle arrays.
...@@ -286,7 +335,12 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index) ...@@ -286,7 +335,12 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index)
_Jv_loadIndexes (&pool->data[index], _Jv_loadIndexes (&pool->data[index],
class_index, class_index,
name_and_type_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) if (owner != klass)
_Jv_InitClass (owner); _Jv_InitClass (owner);
...@@ -707,12 +761,31 @@ _Jv_GetMethodString (jclass klass, _Jv_Method *meth, ...@@ -707,12 +761,31 @@ _Jv_GetMethodString (jclass klass, _Jv_Method *meth,
return buf->toString(); return buf->toString();
} }
void void
_Jv_ThrowNoSuchMethodError () _Jv_ThrowNoSuchMethodError ()
{ {
throw new java::lang::NoSuchMethodError; 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 // Throw a NoSuchFieldError. Called by compiler-generated code when
// an otable entry is zero. OTABLE_INDEX is the index in the caller's // 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 // otable that refers to the missing field. This index may be used to
...@@ -723,7 +796,6 @@ _Jv_ThrowNoSuchFieldError (int /* otable_index */) ...@@ -723,7 +796,6 @@ _Jv_ThrowNoSuchFieldError (int /* otable_index */)
throw new java::lang::NoSuchFieldError; throw new java::lang::NoSuchFieldError;
} }
// This is put in empty vtable slots. // This is put in empty vtable slots.
void void
_Jv_ThrowAbstractMethodError () _Jv_ThrowAbstractMethodError ()
...@@ -1030,21 +1102,65 @@ _Jv_Linker::link_symbol_table (jclass klass) ...@@ -1030,21 +1102,65 @@ _Jv_Linker::link_symbol_table (jclass klass)
(sym = klass->atable_syms[index]).class_name != NULL; (sym = klass->atable_syms[index]).class_name != NULL;
++index) ++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_Method *meth = NULL;
_Jv_Utf8Const *signature = sym.signature; _Jv_Utf8Const *signature = sym.signature;
// ??? Setting this pointer to null will at least get us a // ??? Setting this pointer to null will at least get us a
// NullPointerException // NullPointerException
klass->atable->addresses[index] = NULL; 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) 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 // We're looking for a static field or a static method, and we
// can tell which is needed by looking at the signature. // 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, // 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 // 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) ...@@ -1082,13 +1198,16 @@ _Jv_Linker::link_symbol_table (jclass klass)
} }
} }
else else
// TODO: Use _Jv_ThrowNoClassDefFoundErrorTrampoline to be able
// to print the class name.
klass->atable->addresses[index] klass->atable->addresses[index]
= (void *)_Jv_ThrowNoSuchMethodError; = (void *) _Jv_ThrowNoClassDefFoundError;
continue; continue;
} }
// Try fields. // Try fields only if the target class exists.
if ( target_class != NULL )
{ {
wait_for_state(target_class, JV_STATE_PREPARED); wait_for_state(target_class, JV_STATE_PREPARED);
jclass found_class; jclass found_class;
...@@ -1453,7 +1572,8 @@ _Jv_Linker::ensure_class_linked (jclass klass) ...@@ -1453,7 +1572,8 @@ _Jv_Linker::ensure_class_linked (jclass klass)
for (int index = 1; index < pool->size; ++index) for (int index = 1; index < pool->size; ++index)
{ {
if (pool->tags[index] == JV_CONSTANT_Class) 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) ...@@ -1493,8 +1613,13 @@ _Jv_Linker::ensure_class_linked (jclass klass)
int mod = f->getModifiers (); int mod = f->getModifiers ();
// If we have a static String field with a non-null initial // If we have a static String field with a non-null initial
// value, we know it points to a Utf8Const. // 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) && (mod & java::lang::reflect::Modifier::STATIC) != 0)
{ {
jstring *strp = (jstring *) f->u.addr; jstring *strp = (jstring *) f->u.addr;
......
...@@ -49,8 +49,10 @@ details. */ ...@@ -49,8 +49,10 @@ details. */
#include <java/lang/ArrayIndexOutOfBoundsException.h> #include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/ArithmeticException.h> #include <java/lang/ArithmeticException.h>
#include <java/lang/ClassFormatError.h> #include <java/lang/ClassFormatError.h>
#include <java/lang/ClassNotFoundException.h>
#include <java/lang/InternalError.h> #include <java/lang/InternalError.h>
#include <java/lang/NegativeArraySizeException.h> #include <java/lang/NegativeArraySizeException.h>
#include <java/lang/NoClassDefFoundError.h>
#include <java/lang/NullPointerException.h> #include <java/lang/NullPointerException.h>
#include <java/lang/OutOfMemoryError.h> #include <java/lang/OutOfMemoryError.h>
#include <java/lang/System.h> #include <java/lang/System.h>
...@@ -168,7 +170,6 @@ SIGNAL_HANDLER (catch_fpe) ...@@ -168,7 +170,6 @@ SIGNAL_HANDLER (catch_fpe)
} }
#endif #endif
jboolean jboolean
_Jv_equalUtf8Consts (const Utf8Const* a, const Utf8Const *b) _Jv_equalUtf8Consts (const Utf8Const* a, const Utf8Const *b)
...@@ -236,6 +237,120 @@ _Jv_equaln (Utf8Const *a, jstring str, jint n) ...@@ -236,6 +237,120 @@ _Jv_equaln (Utf8Const *a, jstring str, jint n)
return true; return true;
} }
// Determines whether the given Utf8Const object contains
// a type which is primitive or some derived form of it, eg.
// an array or multi-dimensional array variant.
jboolean
_Jv_isPrimitiveOrDerived(const Utf8Const *a)
{
unsigned char *aptr = (unsigned char *) a->data;
unsigned char *alimit = aptr + a->length;
int ac = UTF8_GET(aptr, alimit);
// Skips any leading array marks.
while (ac == '[')
ac = UTF8_GET(aptr, alimit);
// There should not be another character. This implies that
// the type name is only one character long.
if (UTF8_GET(aptr, alimit) == -1)
switch ( ac )
{
case 'Z':
case 'B':
case 'C':
case 'S':
case 'I':
case 'J':
case 'F':
case 'D':
return true;
default:
break;
}
return false;
}
// Find out whether two _Jv_Utf8Const candidates contain the same
// classname.
// The method is written to handle the different formats of classnames.
// Eg. "Ljava/lang/Class;", "Ljava.lang.Class;", "java/lang/Class" and
// "java.lang.Class" will be seen as equal.
// Warning: This function is not smart enough to declare "Z" and "boolean"
// and similar cases as equal (and is not meant to be used this way)!
jboolean
_Jv_equalUtf8Classnames (const Utf8Const *a, const Utf8Const *b)
{
// If the class name's length differs by two characters
// it is possible that we have candidates which are given
// in the two different formats ("Lp1/p2/cn;" vs. "p1/p2/cn")
switch (a->length - b->length)
{
case -2:
case 0:
case 2:
break;
default:
return false;
}
unsigned char *aptr = (unsigned char *) a->data;
unsigned char *alimit = aptr + a->length;
unsigned char *bptr = (unsigned char *) b->data;
unsigned char *blimit = bptr + b->length;
if (alimit[-1] == ';')
alimit--;
if (blimit[-1] == ';')
blimit--;
int ac = UTF8_GET(aptr, alimit);
int bc = UTF8_GET(bptr, blimit);
// Checks whether both strings have the same amount of leading [ characters.
while (ac == '[')
{
if (bc == '[')
{
ac = UTF8_GET(aptr, alimit);
bc = UTF8_GET(bptr, blimit);
continue;
}
return false;
}
// Skips leading L character.
if (ac == 'L')
ac = UTF8_GET(aptr, alimit);
if (bc == 'L')
bc = UTF8_GET(bptr, blimit);
// Compares the remaining characters.
while (ac != -1 && bc != -1)
{
// Replaces package separating dots with slashes.
if (ac == '.')
ac = '/';
if (bc == '.')
bc = '/';
// Now classnames differ if there is at least one non-matching
// character.
if (ac != bc)
return false;
ac = UTF8_GET(aptr, alimit);
bc = UTF8_GET(bptr, blimit);
}
return (ac == bc);
}
/* Count the number of Unicode chars encoded in a given Ut8 string. */ /* Count the number of Unicode chars encoded in a given Ut8 string. */
int int
_Jv_strLengthUtf8(char* str, int len) _Jv_strLengthUtf8(char* str, int len)
...@@ -434,6 +549,9 @@ _Jv_AllocObjectNoInitNoFinalizer (jclass klass) ...@@ -434,6 +549,9 @@ _Jv_AllocObjectNoInitNoFinalizer (jclass klass)
jobject jobject
_Jv_AllocObjectNoFinalizer (jclass klass) _Jv_AllocObjectNoFinalizer (jclass klass)
{ {
if (_Jv_IsPhantomClass(klass) )
throw new java::lang::NoClassDefFoundError(klass->getName());
_Jv_InitClass (klass); _Jv_InitClass (klass);
jint size = klass->size (); jint size = klass->size ();
jobject obj = (jobject) _Jv_AllocObj (size, klass); jobject obj = (jobject) _Jv_AllocObj (size, klass);
...@@ -512,6 +630,11 @@ _Jv_AllocPtrFreeObject (jclass klass) ...@@ -512,6 +630,11 @@ _Jv_AllocPtrFreeObject (jclass klass)
jobjectArray jobjectArray
_Jv_NewObjectArray (jsize count, jclass elementClass, jobject init) _Jv_NewObjectArray (jsize count, jclass elementClass, jobject init)
{ {
// Creating an array of an unresolved type is impossible. So we throw
// the NoClassDefFoundError.
if ( _Jv_IsPhantomClass(elementClass) )
throw new java::lang::NoClassDefFoundError(elementClass->getName());
if (__builtin_expect (count < 0, false)) if (__builtin_expect (count < 0, false))
throw new java::lang::NegativeArraySizeException; throw new java::lang::NegativeArraySizeException;
...@@ -766,7 +889,28 @@ _Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader, ...@@ -766,7 +889,28 @@ _Jv_FindClassFromSignature (char *sig, java::lang::ClassLoader *loader,
return result; return result;
} }
jclass
_Jv_FindClassFromSignatureNoException (char *sig, java::lang::ClassLoader *loader,
char **endp)
{
jclass klass;
try
{
klass = _Jv_FindClassFromSignature(sig, loader, endp);
}
catch (java::lang::NoClassDefFoundError *ncdfe)
{
return NULL;
}
catch (java::lang::ClassNotFoundException *cnfe)
{
return NULL;
}
return klass;
}
JArray<jstring> * JArray<jstring> *
JvConvertArgv (int argc, const char **argv) JvConvertArgv (int argc, const char **argv)
......
...@@ -14,6 +14,8 @@ details. */ ...@@ -14,6 +14,8 @@ details. */
#include <config.h> #include <config.h>
#include <string.h>
#include <jvm.h> #include <jvm.h>
#include <gcj/cni.h> #include <gcj/cni.h>
#include <java-insns.h> #include <java-insns.h>
...@@ -324,7 +326,7 @@ private: ...@@ -324,7 +326,7 @@ private:
bool equals (ref_intersection *other, _Jv_BytecodeVerifier *verifier) bool equals (ref_intersection *other, _Jv_BytecodeVerifier *verifier)
{ {
if (! is_resolved && ! other->is_resolved if (! is_resolved && ! other->is_resolved
&& _Jv_equalUtf8Consts (data.name, other->data.name)) && _Jv_equalUtf8Classnames (data.name, other->data.name))
return true; return true;
if (! is_resolved) if (! is_resolved)
resolve (verifier); resolve (verifier);
...@@ -364,11 +366,18 @@ private: ...@@ -364,11 +366,18 @@ private:
if (is_resolved) if (is_resolved)
return; return;
// This is useful if you want to see which classes have to be resolved
// while doing the class verification.
debug_print("resolving class: %s\n", data.name->chars());
using namespace java::lang; using namespace java::lang;
java::lang::ClassLoader *loader java::lang::ClassLoader *loader
= verifier->current_class->getClassLoaderInternal(); = verifier->current_class->getClassLoaderInternal();
// We might see either kind of name. Sigh.
if (data.name->first() == 'L' && data.name->limit()[-1] == ';') // Due to special handling in to_array() array classes will always
// be of the "L ... ;" kind. The separator char ('.' or '/' may vary
// however.
if (data.name->limit()[-1] == ';')
{ {
data.klass = _Jv_FindClassFromSignature (data.name->chars(), loader); data.klass = _Jv_FindClassFromSignature (data.name->chars(), loader);
if (data.klass == NULL) if (data.klass == NULL)
...@@ -397,12 +406,21 @@ private: ...@@ -397,12 +406,21 @@ private:
// Avoid resolving if possible. // Avoid resolving if possible.
if (! self->is_resolved if (! self->is_resolved
&& ! other_iter->is_resolved && ! other_iter->is_resolved
&& _Jv_equalUtf8Consts (self->data.name, && _Jv_equalUtf8Classnames (self->data.name,
other_iter->data.name)) other_iter->data.name))
continue; continue;
if (! self->is_resolved) if (! self->is_resolved)
self->resolve(verifier); self->resolve(verifier);
// If the LHS of the expression is of type
// java.lang.Object, assignment will succeed, no matter
// what the type of the RHS is. Using this short-cut we
// don't need to resolve the class of the RHS at
// verification time.
if (self->data.klass == &java::lang::Object::class$)
continue;
if (! other_iter->is_resolved) if (! other_iter->is_resolved)
other_iter->resolve(verifier); other_iter->resolve(verifier);
...@@ -852,9 +870,70 @@ private: ...@@ -852,9 +870,70 @@ private:
if (key != reference_type) if (key != reference_type)
verifier->verify_fail ("internal error in type::to_array()"); verifier->verify_fail ("internal error in type::to_array()");
jclass k = klass->getclass (verifier); // In case the class is already resolved we can simply ask the runtime
return type (_Jv_GetArrayClass (k, k->getClassLoaderInternal()), // to give us the array version.
verifier); // If it is not resolved we prepend "[" to the classname to make the
// array usage verification more lazy. In other words: makes new Foo[300]
// pass the verifier if Foo.class is missing.
if (klass->is_resolved)
{
jclass k = klass->getclass (verifier);
return type (_Jv_GetArrayClass (k, k->getClassLoaderInternal()),
verifier);
}
else
{
int len = klass->data.name->len();
// If the classname is given in the Lp1/p2/cn; format we only need
// to add a leading '['. The same procedure has to be done for
// primitive arrays (ie. provided "[I", the result should be "[[I".
// If the classname is given as p1.p2.cn we have to embed it into
// "[L" and ';'.
if (klass->data.name->limit()[-1] == ';' ||
_Jv_isPrimitiveOrDerived(klass->data.name))
{
// Reserves space for leading '[' and trailing '\0' .
char arrayName[len + 2];
arrayName[0] = '[';
strcpy(&arrayName[1], klass->data.name->chars());
#ifdef VERIFY_DEBUG
// This is only needed when we want to print the string to the
// screen while debugging.
arrayName[len + 1] = '\0';
debug_print("len: %d - old: '%s' - new: '%s'\n", len, klass->data.name->chars(), arrayName);
#endif
return type (verifier->make_utf8_const( arrayName, len + 1 ),
verifier);
}
else
{
// Reserves space for leading "[L" and trailing ';' and '\0' .
char arrayName[len + 4];
arrayName[0] = '[';
arrayName[1] = 'L';
strcpy(&arrayName[2], klass->data.name->chars());
arrayName[len + 2] = ';';
#ifdef VERIFY_DEBUG
// This is only needed when we want to print the string to the
// screen while debugging.
arrayName[len + 3] = '\0';
debug_print("len: %d - old: '%s' - new: '%s'\n", len, klass->data.name->chars(), arrayName);
#endif
return type (verifier->make_utf8_const( arrayName, len + 3 ),
verifier);
}
}
} }
bool isreference () const bool isreference () const
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment