From: Robert Schuster <theBohemian@gmx.net>
To: java-patches@gcc.gnu.org
Subject: RFC: lazy linker + verifier
Date: Wed, 04 Jan 2006 16:37:00 -0000 [thread overview]
Message-ID: <43BBF88B.3000908@gmx.net> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 2063 bytes --]
Hi,
I have applied all of Andrew's wishes regarding my last patch for the linker and
verifier and fixed merge conflicts in some files.
I excluded a regenerated aclocal.m4 and some Makefile.ins from the actual patch
file to make it easier to review the interesting bits.
A 2nd attempt to resolve my GCC copyright assignment issue is already underway. :)
The ChangeLog:
2006-01-04 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.
(_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.
* gnu/gcj/runtime/FFIBucket.java: New file.
* 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.
* sources.am: Added gnu/gcj/runtime/FFIBucket.java
* Makefile.in, testsuite/Makefile.in, gcj/Makefile.in, aclocal.m4:
Rebuilt.
cya
Robert
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: gcj-lazy-linker+verifier.diff --]
[-- Type: text/x-patch; name="gcj-lazy-linker+verifier.diff", Size: 31013 bytes --]
Index: link.cc
===================================================================
--- link.cc (Revision 109331)
+++ link.cc (Arbeitskopie)
@@ -23,6 +23,7 @@
#include <limits.h>
#include <java-cpool.h>
#include <execution.h>
+#include <gnu/gcj/runtime/FFIBucket.h>
#include <java/lang/Class.h>
#include <java/lang/String.h>
#include <java/lang/StringBuffer.h>
@@ -34,6 +35,7 @@
#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 +102,7 @@
// 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,9 +114,27 @@
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
// (and terminate the search) if it has the correct
@@ -123,7 +143,10 @@
// 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 +157,7 @@
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 +198,21 @@
{
// 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());
+ // 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->name, found_class);
+ _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 +225,12 @@
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 +258,7 @@
}
_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 +275,26 @@
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,8 +336,13 @@
_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 +762,25 @@
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);
+}
+
// 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 +791,6 @@
throw new java::lang::NoSuchFieldError;
}
-
// This is put in empty vtable slots.
void
_Jv_ThrowAbstractMethodError ()
@@ -1030,21 +1097,65 @@
(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()));
-
+ {
+ ffi_closure *closure =
+ (ffi_closure *) _Jv_Malloc( sizeof( ffi_closure ));
+ ffi_cif *cif = (ffi_cif *) jbyteArray( sizeof( ffi_cif ));
+
+ // Pretends that we want to call a void (*) (void) function via
+ // ffi_call.
+ ffi_type **arg_types = (ffi_type **) jbyteArray( 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))
+ {
+ // Make ffi structures available to the garbage collection.
+ _Jv_InitClass(&gnu::gcj::runtime::FFIBucket::class$);
+ gnu::gcj::runtime::FFIBucket::addObject ((jbyteArray) closure);
+ gnu::gcj::runtime::FFIBucket::addObject ((jbyteArray) arg_types);
+
+ 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
@@ -1088,7 +1199,8 @@
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 +1565,8 @@
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 +1606,13 @@
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;
Index: verify.cc
===================================================================
--- verify.cc (Revision 109331)
+++ verify.cc (Arbeitskopie)
@@ -14,6 +14,8 @@
#include <config.h>
+#include <string.h>
+
#include <jvm.h>
#include <gcj/cni.h>
#include <java-insns.h>
@@ -324,7 +326,7 @@
bool equals (ref_intersection *other, _Jv_BytecodeVerifier *verifier)
{
if (! is_resolved && ! other->is_resolved
- && _Jv_equalUtf8Consts (data.name, other->data.name))
+ && _Jv_equalUtf8Classnames (data.name, other->data.name))
return true;
if (! is_resolved)
resolve (verifier);
@@ -364,11 +366,18 @@
if (is_resolved)
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;
java::lang::ClassLoader *loader
= 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);
if (data.klass == NULL)
@@ -397,12 +406,21 @@
// Avoid resolving if possible.
if (! self->is_resolved
&& ! other_iter->is_resolved
- && _Jv_equalUtf8Consts (self->data.name,
- other_iter->data.name))
+ && _Jv_equalUtf8Classnames (self->data.name,
+ other_iter->data.name))
continue;
if (! self->is_resolved)
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)
other_iter->resolve(verifier);
@@ -852,9 +870,70 @@
if (key != reference_type)
verifier->verify_fail ("internal error in type::to_array()");
- jclass k = klass->getclass (verifier);
- return type (_Jv_GetArrayClass (k, k->getClassLoaderInternal()),
- verifier);
+ // In case the class is already resolved we can simply ask the runtime
+ // to give us the array version.
+ // 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
Index: gnu/gcj/runtime/FFIBucket.java
===================================================================
--- gnu/gcj/runtime/FFIBucket.java (Revision 0)
+++ gnu/gcj/runtime/FFIBucket.java (Revision 0)
@@ -0,0 +1,31 @@
+// FFIBucket.java - A GC-visible storage for libffi objects.
+
+/* Copyright (C) 2005 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package gnu.gcj.runtime;
+
+import java.util.ArrayList;
+
+/** This class is a simple bucket for libffi structures which
+ * we collect here to expose them to the garbage collection.
+ *
+ * TODO: Turn the list into a WeakHashMap or List of WeakReferences
+ * at some sane point of execution. (PR xyz)
+ */
+public final class FFIBucket
+{
+
+ private static ArrayList ffiObjects = new ArrayList();
+
+ public static synchronized void addObject(byte[] ffiObject)
+ {
+ ffiObjects.add(ffiObject);
+ }
+
+}
Index: gcj/javaprims.h
===================================================================
--- gcj/javaprims.h (Revision 109331)
+++ gcj/javaprims.h (Arbeitskopie)
@@ -566,6 +566,9 @@
friend jboolean _Jv_equalUtf8Consts (const _Jv_Utf8Const*, const _Jv_Utf8Const *);
friend jboolean _Jv_equal (_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 (jstring);
friend jstring _Jv_NewStringUtf8Const (_Jv_Utf8Const*);
Index: java/lang/natClassLoader.cc
===================================================================
--- java/lang/natClassLoader.cc (Revision 109331)
+++ java/lang/natClassLoader.cc (Arbeitskopie)
@@ -265,7 +265,31 @@
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
_Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
{
// See if the class was already loaded by this loader. This handles
Index: java/lang/natClass.cc
===================================================================
--- java/lang/natClass.cc (Revision 109331)
+++ java/lang/natClass.cc (Arbeitskopie)
@@ -668,8 +668,9 @@
void
java::lang::Class::initializeClass (void)
{
- // Short-circuit to avoid needless locking.
- if (state == JV_STATE_DONE)
+ // Short-circuit to avoid needless locking (expression includes
+ // JV_STATE_PHANTOM and JV_STATE_DONE).
+ if (state >= JV_STATE_PHANTOM)
return;
// Step 1. We introduce a new scope so we can synchronize more
Index: java/lang/Class.h
===================================================================
--- java/lang/Class.h (Revision 109331)
+++ java/lang/Class.h (Arbeitskopie)
@@ -54,7 +54,13 @@
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;
@@ -214,6 +220,8 @@
void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*);
void _Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*);
void _Jv_UnregisterClass (jclass);
+jclass _Jv_FindClassNoException (_Jv_Utf8Const *name,
+ java::lang::ClassLoader *loader);
jclass _Jv_FindClass (_Jv_Utf8Const *name,
java::lang::ClassLoader *loader);
jclass _Jv_FindClassInCache (_Jv_Utf8Const *name);
@@ -237,6 +245,8 @@
jboolean _Jv_IsInterpretedClass (jclass);
jboolean _Jv_IsBinaryCompatibilityABI (jclass);
+jboolean _Jv_IsPhantomClass (jclass);
+
void _Jv_CopyClassesToSystemLoader (java::lang::ClassLoader *);
#ifdef INTERPRETER
@@ -443,6 +453,8 @@
friend void ::_Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*);
friend void ::_Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*);
friend void ::_Jv_UnregisterClass (jclass);
+ friend jclass (::_Jv_FindClassNoException) (_Jv_Utf8Const *name,
+ java::lang::ClassLoader *loader);
friend jclass (::_Jv_FindClass) (_Jv_Utf8Const *name,
java::lang::ClassLoader *loader);
friend jclass (::_Jv_FindClassInCache) (_Jv_Utf8Const *name);
@@ -473,6 +485,8 @@
friend jboolean (::_Jv_IsInterpretedClass) (jclass);
friend jboolean (::_Jv_IsBinaryCompatibilityABI) (jclass);
+ friend jboolean (::_Jv_IsPhantomClass) (jclass);
+
#ifdef INTERPRETER
friend void ::_Jv_InitField (jobject, jclass, int);
Index: include/jvm.h
===================================================================
--- include/jvm.h (Revision 109331)
+++ include/jvm.h (Arbeitskopie)
@@ -239,7 +239,7 @@
{
private:
static _Jv_Field *find_field_helper(jclass, _Jv_Utf8Const *, _Jv_Utf8Const *,
- jclass *);
+ jclass, jclass *);
static _Jv_Field *find_field(jclass, jclass, jclass *, _Jv_Utf8Const *,
_Jv_Utf8Const *);
static void prepare_constant_time_tables(jclass);
@@ -271,7 +271,7 @@
static void print_class_loaded (jclass);
static void resolve_class_ref (jclass, jclass *);
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 verify_type_assertions (jclass);
};
@@ -463,9 +463,18 @@
extern jclass _Jv_FindClass (_Jv_Utf8Const *name,
java::lang::ClassLoader *loader);
+
+extern jclass _Jv_FindClassNoException (_Jv_Utf8Const *name,
+ java::lang::ClassLoader *loader);
+
extern jclass _Jv_FindClassFromSignature (char *,
java::lang::ClassLoader *loader,
char ** = NULL);
+
+extern jclass _Jv_FindClassFromSignatureNoException (char *,
+ java::lang::ClassLoader *loader,
+ char ** = NULL);
+
extern void _Jv_GetTypesFromSignature (jmethodID method,
jclass declaringClass,
JArray<jclass> **arg_types_out,
@@ -643,4 +652,14 @@
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__ */
Index: prims.cc
===================================================================
--- prims.cc (Revision 109331)
+++ prims.cc (Arbeitskopie)
@@ -49,8 +49,10 @@
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/ArithmeticException.h>
#include <java/lang/ClassFormatError.h>
+#include <java/lang/ClassNotFoundException.h>
#include <java/lang/InternalError.h>
#include <java/lang/NegativeArraySizeException.h>
+#include <java/lang/NoClassDefFoundError.h>
#include <java/lang/NullPointerException.h>
#include <java/lang/OutOfMemoryError.h>
#include <java/lang/System.h>
@@ -168,7 +170,6 @@
}
#endif
-\f
jboolean
_Jv_equalUtf8Consts (const Utf8Const* a, const Utf8Const *b)
@@ -236,6 +237,120 @@
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. */
int
_Jv_strLengthUtf8(char* str, int len)
@@ -434,6 +549,9 @@
jobject
_Jv_AllocObjectNoFinalizer (jclass klass)
{
+ if (_Jv_IsPhantomClass(klass) )
+ throw new java::lang::NoClassDefFoundError(klass->getName());
+
_Jv_InitClass (klass);
jint size = klass->size ();
jobject obj = (jobject) _Jv_AllocObj (size, klass);
@@ -512,6 +630,11 @@
jobjectArray
_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))
throw new java::lang::NegativeArraySizeException;
@@ -766,8 +889,29 @@
return result;
}
-\f
+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> *
JvConvertArgv (int argc, const char **argv)
{
Index: sources.am
===================================================================
--- sources.am (Revision 109331)
+++ sources.am (Arbeitskopie)
@@ -555,6 +555,7 @@
gnu_gcj_runtime_source_files = \
gnu/gcj/runtime/BootClassLoader.java \
gnu/gcj/runtime/ExtensionClassLoader.java \
+gnu/gcj/runtime/FFIBucket.java \
gnu/gcj/runtime/FileDeleter.java \
gnu/gcj/runtime/FinalizerThread.java \
gnu/gcj/runtime/HelperClassLoader.java \
[-- Attachment #1.3: gcj-lazy-linker+verifier-regenerated.tar.gz --]
[-- Type: application/x-gzip, Size: 72880 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
next reply other threads:[~2006-01-04 16:37 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-01-04 16:37 Robert Schuster [this message]
2006-01-04 16:44 ` Andrew Haley
2006-01-05 12:16 ` Paperwork (Was: RFC: lazy linker + verifier) Mark Wielaard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=43BBF88B.3000908@gmx.net \
--to=thebohemian@gmx.net \
--cc=java-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).