This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: make linking BC-compiled classes more lazy - part one


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,
this patch fixes half of the problems I mentioned in bug 24616[0]. For further
details about the approach taken see the bug report. Another patch which fixes
the remaining bits is already prepared.

This patch makes a lot more sense with my previous fixes for the verifier[1]. :)

2005-11-23  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.
        * jvm.h:
        (_Jv_FindClassNoException): New method declaration.
        (_Jv_FindClassFromSignatureNoException): New method declaration.
        * prims.cc:
        (_Jv_FindClassFromSignatureNoException): New method.

cya
Robert

[0] - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24616
[1] - http://gcc.gnu.org/ml/java-patches/2005-q4/msg00213.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFDhHBVG9cfwmwwEtoRAnDTAJwNITGv/VvpU4VrFy4JrRBn+75AHwCfW1Oy
76UB97O/WitB1jnvTUoQGG4=
=129U
-----END PGP SIGNATURE-----
Index: link.cc
===================================================================
--- link.cc	(Revision 106248)
+++ link.cc	(Arbeitskopie)
@@ -34,6 +34,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 +101,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 +113,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 +142,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 +156,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 +197,19 @@
 {
   // 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);
+                                            (field_type ?
+                                              field_type->name :
+                                              field_type_name ),
+                                            field_type, found_class);
 
   if (the_field == 0)
     {
@@ -194,6 +222,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
@@ -707,12 +741,26 @@
   return buf->toString();
 }
 
-void 
+void
 _Jv_ThrowNoSuchMethodError ()
 {
   throw new java::lang::NoSuchMethodError;
 }
 
+// A function that 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);
+}
+
+
 // This is put in empty vtable slots.
 void
 _Jv_ThrowAbstractMethodError ()
@@ -990,21 +1038,55 @@
        (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 to a function
+      // that simply throws a NoClassDefFoundError and store the address in the
+      // atable. The effect is that the user can run code of classes where the
+      // missing class is part of the execution environment but gets 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 *) _Jv_Malloc( sizeof( ffi_cif ));
+
+          // Pretends that we want to call a void (*) (void) function via
+          // ffi_call.
+          ffi_type **arg_types = (ffi_type **) _Jv_Malloc( sizeof( ffi_type * ));
+          arg_types[0] = &ffi_type_void;
+
+          // Initializes the cif and the closure. If that worked the closure is
+          // stored as a function pointer in the atable.
+          if ( ( ffi_prep_cif(cif, FFI_DEFAULT_ABI, 1,
+                  &ffi_type_void, arg_types) == FFI_OK) &&
+                ( ffi_prep_closure(closure, cif,
+                   _Jv_ThrowNoClassDefFoundErrorTrampoline,
+                   (void *) _Jv_NewStringUtf8Const(sym.class_name)) == FFI_OK ) )
+            klass->atable->addresses[index] = (void *) closure;
+          else
+            {
+              // If you land here it is possible that your architecture does
+              // not support the Closure API yet. Let's port it!
+              java::lang::StringBuffer *buffer = new java::lang::StringBuffer();
+              buffer->append(JvNewStringLatin1(
+                "Error setting up FFI closure for static method of missing class: "));
+              buffer->append(_Jv_NewStringUtf8Const(sym.class_name));
+
+              throw new java::lang::InternalError(buffer->toString());
+            }
+        }
       // We're looking for a static field or a static method, and we
       // can tell which is needed by looking at the signature.
-      if (signature->first() == '(' && signature->len() >= 2)
+      else if (signature->first() == '(' && signature->len() >= 2)
 	{
  	  // If the target class does not have a vtable_method_count yet, 
 	  // then we can't tell the offsets for its methods, so we must lay 
@@ -1048,7 +1130,8 @@
 	  continue;
 	}
 
-      // Try fields.
+      // Tries fields only if the target class exists.
+      if ( target_class != NULL )
       {
 	wait_for_state(target_class, JV_STATE_PREPARED);
 	jclass found_class;
@@ -1453,9 +1536,14 @@
 	      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$
-		  && (mod & java::lang::reflect::Modifier::STATIC) != 0)
+
+              // 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;
 		  if (*strp)
Index: java/lang/natClassLoader.cc
===================================================================
--- java/lang/natClassLoader.cc	(Revision 106248)
+++ 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/Class.h
===================================================================
--- java/lang/Class.h	(Revision 106248)
+++ java/lang/Class.h	(Arbeitskopie)
@@ -214,6 +214,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);
@@ -443,6 +445,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);
Index: include/jvm.h
===================================================================
--- include/jvm.h	(Revision 106248)
+++ include/jvm.h	(Arbeitskopie)
@@ -240,7 +240,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);
@@ -452,11 +452,16 @@
 extern "C" void _Jv_RegisterResource (void *vptr);
 extern void _Jv_UnregisterClass (_Jv_Utf8Const*, java::lang::ClassLoader*);
 
+extern jclass _Jv_FindClassNoException (_Jv_Utf8Const *name,
+			     java::lang::ClassLoader *loader);
 extern jclass _Jv_FindClass (_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,
Index: prims.cc
===================================================================
--- prims.cc	(Revision 106248)
+++ 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>
@@ -766,8 +886,28 @@
   return result;
 }
 
-
+jclass
+_Jv_FindClassFromSignatureNoException (char *sig, java::lang::ClassLoader *loader,
+			    char **endp)
+{
+  jclass klass;
 
+  try
+    {
+      klass = _Jv_FindClassFromSignature(sig, loader, endp);
+    }
+  catch ( java::lang::NoClassDefFoundError *ncdfe )
+    {
+      return NULL;
+    }
+  catch ( java::lang::ClassNotFoundException *cnfe )
+    {
+      return NULL;
+    }
+
+  return klass;
+}
+
 JArray<jstring> *
 JvConvertArgv (int argc, const char **argv)
 {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]