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