public inbox for java-patches@gcc.gnu.org
 help / color / mirror / Atom feed
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 --]

             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).