ClassLoader: unexpected exception during linking

Tom Tromey tromey@redhat.com
Wed Dec 4 23:42:00 GMT 2002


>>>>> "Jeff" == Jeff Sturm <jsturm@one-point.com> writes:

Jeff> Yesterday I found that isVirtualMethod fails to consider final
Jeff> methods.

The appended fixes the hang I noticed with your initial patch.  It
also fixes the original problem Per reported.  I'm checking it in.

It turned out to be more complicated than I had thought.  I discovered
we weren't handling abstract methods correctly.

Even with this patch we don't handle them extremely well.  See the
FIXME about IA-64.  In fact while doing this I noticed some other
potential IA-64 type problems: for instance the type of the `ncode'
field (and the way we set it) seems wrong to me.  I'm going to try to
get access to an IA-64 again so I can see what is going on.

I'm a bit worried that we may not implement all the required linking
checks.  However, I was unable to find another one that we don't
implement, so perhaps my fears are ungrounded.

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* java/lang/Class.h (_Jv_SetVTableEntries): Updated declaration.
	* resolve.cc: Don't include AbstractMethodError.h.
	(_Jv_abstractMethodError): Removed.
	* defineclass.cc (handleMethodsBegin): Initialize method index to
	-1.
	* java/lang/natClass.cc (_Jv_LayoutVTableMethods): Don't set
	method index for "new" final method.
	(_Jv_SetVTableEntries): Compare index against -1 instead of using
	isVirtualMethod.  Added `flags' argument.
	(_Jv_MakeVTable): Throw exception for abstract method in concrete
	class.

Index: defineclass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/defineclass.cc,v
retrieving revision 1.30
diff -u -r1.30 defineclass.cc
--- defineclass.cc 25 Sep 2002 20:57:03 -0000 1.30
+++ defineclass.cc 5 Dec 2002 07:35:48 -0000
@@ -1184,15 +1184,17 @@
 void
 _Jv_ClassReader::handleMethodsBegin (int count)
 {
-  def->methods = (_Jv_Method*)
-    _Jv_AllocBytes (sizeof (_Jv_Method)*count);
+  def->methods = (_Jv_Method *) _Jv_AllocBytes (sizeof (_Jv_Method) * count);
 
   def->interpreted_methods
     = (_Jv_MethodBase **) _Jv_AllocBytes (sizeof (_Jv_MethodBase *)
 					  * count);
 
   for (int i = 0; i < count; i++)
-    def->interpreted_methods[i] = 0;
+    {
+      def->interpreted_methods[i] = 0;
+      def->methods[i].index = (_Jv_ushort) -1;
+    }
 
   def->method_count = count;
 }
@@ -1376,12 +1378,14 @@
   throw new java::lang::InternalError (JvNewStringLatin1 (msg));
 }
 
-static void throw_incompatible_class_change_error (jstring msg)
+static void
+throw_incompatible_class_change_error (jstring msg)
 {
   throw new java::lang::IncompatibleClassChangeError (msg);
 }
 
-static void throw_class_circularity_error (jstring msg)
+static void
+throw_class_circularity_error (jstring msg)
 {
   throw new java::lang::ClassCircularityError (msg);
 }
Index: resolve.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/resolve.cc,v
retrieving revision 1.33
diff -u -r1.33 resolve.cc
--- resolve.cc 4 Nov 2002 02:45:31 -0000 1.33
+++ resolve.cc 5 Dec 2002 07:35:49 -0000
@@ -363,13 +363,6 @@
   return 0;
 }
 
-/* this is installed in place of abstract methods */
-static void
-_Jv_abstractMethodError ()
-{
-  throw new java::lang::AbstractMethodError;
-}
-
 void 
 _Jv_PrepareClass(jclass klass)
 {
Index: java/lang/Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.51
diff -u -r1.51 Class.h
--- java/lang/Class.h 3 Dec 2002 13:50:04 -0000 1.51
+++ java/lang/Class.h 5 Dec 2002 07:35:51 -0000
@@ -325,7 +325,7 @@
   friend jshort _Jv_FindIIndex (jclass *, jshort *, jshort);
   friend void _Jv_LinkOffsetTable (jclass);
   friend void _Jv_LayoutVTableMethods (jclass klass);
-  friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *);
+  friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *);
   friend void _Jv_MakeVTable (jclass);
 
   // Return array class corresponding to element type KLASS, creating it if
Index: java/lang/natClass.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClass.cc,v
retrieving revision 1.56
diff -u -r1.56 natClass.cc
--- java/lang/natClass.cc 3 Dec 2002 13:50:04 -0000 1.56
+++ java/lang/natClass.cc 5 Dec 2002 07:35:52 -0000
@@ -97,7 +97,7 @@
   java::lang::Class *klass = NULL;
   try
     {
-      for (int i=1; !klass; i++)
+      for (int i = 1; !klass; i++)
 	{
 	  klass = t->classAt (i);
 	}
@@ -1556,7 +1556,7 @@
 }
 
 // Returns true if METH should get an entry in a VTable.
-static bool
+static jboolean
 isVirtualMethod (_Jv_Method *meth)
 {
   using namespace java::lang::reflect;
@@ -1574,7 +1574,7 @@
   if (klass->vtable != NULL || klass->isInterface() 
       || klass->vtable_method_count != -1)
     return;
-    
+
   jclass superclass = klass->superclass;
 
   if (superclass != NULL && superclass->vtable_method_count == -1)
@@ -1582,48 +1582,59 @@
       JvSynchronize sync (superclass);
       _Jv_LayoutVTableMethods (superclass);
     }
-    
+
   int index = (superclass == NULL ? 0 : superclass->vtable_method_count);
 
   for (int i = 0; i < klass->method_count; ++i)
     {
       _Jv_Method *meth = &klass->methods[i];
       _Jv_Method *super_meth = NULL;
-    
-      if (!isVirtualMethod(meth))
-        continue;
-	      
+
+      if (! isVirtualMethod (meth))
+	continue;
+
       if (superclass != NULL)
         super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name, 
 					       meth->signature);
-      
+
       if (super_meth)
         meth->index = super_meth->index;
-      else
+      else if (! (meth->accflags & java::lang::reflect::Modifier::FINAL))
         meth->index = index++;
     }
-  
+
   klass->vtable_method_count = index;
 }
 
-// Set entries in VTABLE for virtual methods declared in KLASS. If KLASS has
-// an immediate abstract parent, recursivly do its methods first.
+// Set entries in VTABLE for virtual methods declared in KLASS. If
+// KLASS has an immediate abstract parent, recursively do its methods
+// first.  FLAGS is used to determine which slots we've actually set.
 void
-_Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable)
+_Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable, jboolean *flags)
 {
   using namespace java::lang::reflect;
 
   jclass superclass = klass->getSuperclass();
 
   if (superclass != NULL && (superclass->getModifiers() & Modifier::ABSTRACT))
-    _Jv_SetVTableEntries (superclass, vtable);
-    
+    _Jv_SetVTableEntries (superclass, vtable, flags);
+
   for (int i = klass->method_count - 1; i >= 0; i--)
     {
       _Jv_Method *meth = &klass->methods[i];
-      if (!isVirtualMethod(meth))
+      if (meth->index == (_Jv_ushort) -1)
 	continue;
-      vtable->set_method(meth->index, meth->ncode);
+      if ((meth->accflags & Modifier::ABSTRACT))
+	{
+	  // FIXME: we should set abstract slots to a function that
+	  // throws AbstractMethodError.  How can we do that on IA-64?
+	  flags[meth->index] = false;
+	}
+      else
+	{
+	  vtable->set_method(meth->index, meth->ncode);
+	  flags[meth->index] = true;
+	}
     }
 }
 
@@ -1639,7 +1650,7 @@
   if (klass->vtable != NULL || klass->isInterface() 
       || (klass->accflags & Modifier::ABSTRACT))
     return;
-  
+
   //  out before we can create a vtable. 
   if (klass->vtable_method_count == -1)
     _Jv_LayoutVTableMethods (klass);
@@ -1647,7 +1658,11 @@
   // Allocate the new vtable.
   _Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count);
   klass->vtable = vtable;
-  
+
+  jboolean flags[klass->vtable_method_count];
+  for (int i = 0; i < klass->vtable_method_count; ++i)
+    flags[i] = false;
+
   // Copy the vtable of the closest non-abstract superclass.
   jclass superclass = klass->superclass;
   if (superclass != NULL)
@@ -1662,7 +1677,10 @@
 	}
 
       for (int i = 0; i < superclass->vtable_method_count; ++i)
-	vtable->set_method (i, superclass->vtable->get_method (i));
+	{
+	  vtable->set_method (i, superclass->vtable->get_method (i));
+	  flags[i] = true;
+	}
     }
 
   // Set the class pointer and GC descriptor.
@@ -1671,5 +1689,14 @@
 
   // For each virtual declared in klass and any immediate abstract 
   // superclasses, set new vtable entry or override an old one.
-  _Jv_SetVTableEntries (klass, vtable);
+  _Jv_SetVTableEntries (klass, vtable, flags);
+
+  // It is an error to have an abstract method in a concrete class.
+  if (! (klass->accflags & Modifier::ABSTRACT))
+    {
+      for (int i = 0; i < klass->vtable_method_count; ++i)
+	if (! flags[i])
+	  // FIXME: messsage.
+	  throw new java::lang::AbstractMethodError ();
+    }
 }



More information about the Java mailing list