public inbox for java-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* RFC: lazy linker + verifier
@ 2006-01-04 16:37 Robert Schuster
  2006-01-04 16:44 ` Andrew Haley
  0 siblings, 1 reply; 3+ messages in thread
From: Robert Schuster @ 2006-01-04 16:37 UTC (permalink / raw)
  To: java-patches


[-- 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 --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: RFC: lazy linker + verifier
  2006-01-04 16:37 RFC: lazy linker + verifier Robert Schuster
@ 2006-01-04 16:44 ` Andrew Haley
  2006-01-05 12:16   ` Paperwork (Was: RFC: lazy linker + verifier) Mark Wielaard
  0 siblings, 1 reply; 3+ messages in thread
From: Andrew Haley @ 2006-01-04 16:44 UTC (permalink / raw)
  To: Robert Schuster; +Cc: java-patches

Robert Schuster writes:
 > 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.

I'm sorry I pushed you so hard for all the stuff I wanted.  In
hindisght I realize I shouldn't have been so fussy: sorry.  However,
you've risen to the challenge quite marvellously.

Thank you for this excellent work.

 > A 2nd attempt to resolve my GCC copyright assignment issue is
 > already underway. :)

Ah, yes.  My fingers are crossed.

Andrew.


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Paperwork (Was: RFC: lazy linker + verifier)
  2006-01-04 16:44 ` Andrew Haley
@ 2006-01-05 12:16   ` Mark Wielaard
  0 siblings, 0 replies; 3+ messages in thread
From: Mark Wielaard @ 2006-01-05 12:16 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Robert Schuster, java-patches

[-- Attachment #1: Type: text/plain, Size: 764 bytes --]

On Wed, 2006-01-04 at 16:45 +0000, Andrew Haley wrote:
>  > A 2nd attempt to resolve my GCC copyright assignment issue is
>  > already underway. :)
> 
> Ah, yes.  My fingers are crossed.

Apologies this took so long. There was some confusion which paper should
have been sent. For the FSF records there is only something called
CLASSPATH (GNU Classpath) and GCC (GNU Compiler Collection). There isn't
a separate category libgcj anymore (the problem actually was that the
copyright-clerk had misspelled it as libgc and then nobody could figure
out under which project that should be filed...).

In the future we should just explicitly request people to have paperwork
for both GCC and CLASSPATH then everything should go smoothly.

Cheers,

Mark

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-01-05 12:16 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-04 16:37 RFC: lazy linker + verifier Robert Schuster
2006-01-04 16:44 ` Andrew Haley
2006-01-05 12:16   ` Paperwork (Was: RFC: lazy linker + verifier) Mark Wielaard

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