java-tree.h (otable_methods, [...]): New field/global tree definitions.
gcc/java: * java-tree.h (otable_methods, otable_decl, otable_syms_decl, otable_type, otable_ptr_type, method_symbol_type, method_symbols_array_type, method_symbols_array_ptr_type): New field/global tree definitions. (flag_indirect_dispatch): New flag. * decl.c (java_init_decl_processing): Initialize new otable and otable_syms type nodes and decls. Add new field "index" to method_type_node. * class.c (build_method_symbols_entry): New function. (make_method_value): Set "index" to to method's vtable index for virtual methods when indirect-dispatch is not used. (make_class_data): For indirect-dispatch, dont emit the dtable_decl, and set vtable_method_count to -1. Set otable and otable_syms field if indirect-dispatch is used and there was something to put in them. (build_method_symbols_entry): New function. (emit_offset_symbol_table): New function. * expr.c (get_offset_table_index): New function. (build_invokevirtual): Build array reference to otable at the index returned by get_offset_table_index, and use the result as the vtable offset. (build_invokeinterface): Similar. * jcf-parse.c (yyparse): If indirect-dispatch, call emit_offset_symbol_table at the end of compilation, after all classes have been generated. * jvspec.c: Don't pass findirect-dispatch to jvgenmain. * lang.c (flag_indirect_dispatch): Define. (lang_f_options): Add indirect-dispatch flag. libjava: * include/jvm.h (_Jv_VTable::idx_to_offset): New method. * java/lang/natClassLoader.cc (_Jv_PrepareCompiledClass): Call _Jv_MakeVTable and _Jv_LinkOffsetTable if needed. * java/lang/Class.h (_Jv_Method): Add "index" field. (_Jv_MethodSymbol): New struct type. (_Jv_LinkOffsetTable, _Jv_LayoutVTableMethods, _Jv_SetVTableEntries, _Jv_MakeVTable): Friends. (otable, otable_syms): New Class fields. * java/lang/natClass.cc (_Jv_LinkOffsetTable): New function. (isVirtualMethod): New static function. (_Jv_LayoutVTableMethods): New function. (_Jv_SetVTableEntries): New function. (_Jv_MakeVTable): New function. From-SVN: r48038
This commit is contained in:
committed by
Bryce McKinlay
parent
ed86a83d51
commit
861ef92859
@@ -70,6 +70,8 @@ struct _Jv_Method
|
||||
_Jv_Utf8Const *signature;
|
||||
// Access flags.
|
||||
_Jv_ushort accflags;
|
||||
// Method's index in the vtable.
|
||||
_Jv_ushort index;
|
||||
// Pointer to underlying function.
|
||||
void *ncode;
|
||||
// NULL-terminated list of exception class names; can be NULL if
|
||||
@@ -114,6 +116,19 @@ union _Jv_Self
|
||||
jclass self;
|
||||
};
|
||||
|
||||
struct _Jv_MethodSymbol
|
||||
{
|
||||
_Jv_Utf8Const *class_name;
|
||||
_Jv_Utf8Const *name;
|
||||
_Jv_Utf8Const *signature;
|
||||
};
|
||||
|
||||
struct _Jv_OffsetTable
|
||||
{
|
||||
jint state;
|
||||
jint offsets[];
|
||||
};
|
||||
|
||||
#define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1)
|
||||
|
||||
#define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas)
|
||||
@@ -303,6 +318,10 @@ private:
|
||||
friend jstring _Jv_GetMethodString(jclass, _Jv_Utf8Const *);
|
||||
friend jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort);
|
||||
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_MakeVTable (jclass);
|
||||
|
||||
// Return array class corresponding to element type KLASS, creating it if
|
||||
// necessary.
|
||||
@@ -367,6 +386,10 @@ private:
|
||||
jshort static_field_count;
|
||||
// The vtbl for all objects of this class.
|
||||
_Jv_VTable *vtable;
|
||||
// Virtual method offset table.
|
||||
_Jv_OffsetTable *otable;
|
||||
// Offset table symbols.
|
||||
_Jv_MethodSymbol *otable_syms;
|
||||
// Interfaces implemented by this class.
|
||||
jclass *interfaces;
|
||||
// The class loader for this class.
|
||||
|
||||
@@ -692,7 +692,7 @@ java::lang::Class::initializeClass (void)
|
||||
_Jv_PrepareCompiledClass (this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (state <= JV_STATE_LINKED)
|
||||
_Jv_PrepareConstantTimeTables (this);
|
||||
|
||||
@@ -1422,3 +1422,194 @@ java::lang::Class::getProtectionDomain0 ()
|
||||
{
|
||||
return protectionDomain;
|
||||
}
|
||||
|
||||
// Functions for indirect dispatch (symbolic virtual method binding) support.
|
||||
|
||||
// Resolve entries in the virtual method offset symbol table
|
||||
// (klass->otable_syms). The vtable offset (in bytes) for each resolved method
|
||||
// is placed at the corresponding position in the virtual method offset table
|
||||
// (klass->otable). A single otable and otable_syms pair may be shared by many
|
||||
// classes.
|
||||
void
|
||||
_Jv_LinkOffsetTable(jclass klass)
|
||||
{
|
||||
//// FIXME: Need to lock the otable ////
|
||||
|
||||
if (klass->otable == NULL
|
||||
|| klass->otable->state != 0)
|
||||
return;
|
||||
|
||||
klass->otable->state = 1;
|
||||
|
||||
int index = 0;
|
||||
_Jv_MethodSymbol sym = klass->otable_syms[0];
|
||||
|
||||
while (sym.name != NULL)
|
||||
{
|
||||
jclass target_class = _Jv_FindClass (sym.class_name, NULL);
|
||||
_Jv_Method *meth = NULL;
|
||||
|
||||
if (target_class != NULL)
|
||||
if (target_class->isInterface())
|
||||
{
|
||||
// FIXME: This does not yet fully conform to binary compatibility
|
||||
// rules. It will break if a declaration is moved into a
|
||||
// superinterface.
|
||||
for (int i=0; i < target_class->method_count; i++)
|
||||
{
|
||||
meth = &target_class->methods[i];
|
||||
if (_Jv_equalUtf8Consts (sym.name, meth->name)
|
||||
&& _Jv_equalUtf8Consts (sym.signature, meth->signature))
|
||||
{
|
||||
klass->otable->offsets[index] = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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
|
||||
// it out now.
|
||||
if (target_class->vtable_method_count == -1)
|
||||
{
|
||||
JvSynchronize sync (target_class);
|
||||
_Jv_LayoutVTableMethods (target_class);
|
||||
}
|
||||
|
||||
meth = _Jv_LookupDeclaredMethod(target_class, sym.name,
|
||||
sym.signature);
|
||||
|
||||
if (meth != NULL)
|
||||
{
|
||||
klass->otable->offsets[index] =
|
||||
_Jv_VTable::idx_to_offset (meth->index);
|
||||
}
|
||||
}
|
||||
|
||||
if (meth == NULL)
|
||||
// FIXME: This should be special index for ThrowNoSuchMethod().
|
||||
klass->otable->offsets[index] = -1;
|
||||
|
||||
sym = klass->otable_syms[++index];
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if METH should get an entry in a VTable.
|
||||
static bool
|
||||
isVirtualMethod (_Jv_Method *meth)
|
||||
{
|
||||
using namespace java::lang::reflect;
|
||||
return (((meth->accflags & (Modifier::STATIC | Modifier::PRIVATE)) == 0)
|
||||
&& meth->name->data[0] != '<');
|
||||
}
|
||||
|
||||
// Prepare virtual method declarations in KLASS, and any superclasses as
|
||||
// required, by determining their vtable index, setting method->index, and
|
||||
// finally setting the class's vtable_method_count. Must be called with the
|
||||
// lock for KLASS held.
|
||||
void
|
||||
_Jv_LayoutVTableMethods (jclass klass)
|
||||
{
|
||||
if (klass->vtable != NULL || klass->isInterface()
|
||||
|| klass->vtable_method_count != -1)
|
||||
return;
|
||||
|
||||
jclass superclass = klass->superclass;
|
||||
|
||||
if (superclass != NULL && superclass->vtable_method_count == -1)
|
||||
{
|
||||
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 (superclass != NULL)
|
||||
super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name,
|
||||
meth->signature);
|
||||
|
||||
if (super_meth)
|
||||
meth->index = super_meth->index;
|
||||
else
|
||||
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.
|
||||
void
|
||||
_Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable)
|
||||
{
|
||||
using namespace java::lang::reflect;
|
||||
|
||||
jclass superclass = klass->getSuperclass();
|
||||
|
||||
if (superclass != NULL && (superclass->getModifiers() & Modifier::ABSTRACT))
|
||||
_Jv_SetVTableEntries (superclass, vtable);
|
||||
|
||||
for (int i = klass->method_count - 1; i >= 0; i--)
|
||||
{
|
||||
_Jv_Method *meth = &klass->methods[i];
|
||||
if (!isVirtualMethod(meth))
|
||||
continue;
|
||||
vtable->set_method(meth->index, meth->ncode);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate and lay out the virtual method table for KLASS. This will also
|
||||
// cause vtables to be generated for any non-abstract superclasses, and
|
||||
// virtual method layout to occur for any abstract superclasses. Must be
|
||||
// called with monitor lock for KLASS held.
|
||||
void
|
||||
_Jv_MakeVTable (jclass klass)
|
||||
{
|
||||
using namespace java::lang::reflect;
|
||||
|
||||
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);
|
||||
|
||||
// Allocate the new vtable.
|
||||
_Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count);
|
||||
klass->vtable = vtable;
|
||||
|
||||
// Copy the vtable of the closest non-abstract superclass.
|
||||
jclass superclass = klass->superclass;
|
||||
if (superclass != NULL)
|
||||
{
|
||||
while ((superclass->accflags & Modifier::ABSTRACT) != 0)
|
||||
superclass = superclass->superclass;
|
||||
|
||||
if (superclass->vtable == NULL)
|
||||
{
|
||||
JvSynchronize sync (superclass);
|
||||
_Jv_MakeVTable (superclass);
|
||||
}
|
||||
|
||||
for (int i = 0; i < superclass->vtable_method_count; ++i)
|
||||
vtable->set_method (i, superclass->vtable->get_method (i));
|
||||
}
|
||||
|
||||
// Set the class pointer and GC descriptor.
|
||||
vtable->clas = klass;
|
||||
vtable->gc_descr = _Jv_BuildGCDescr (klass);
|
||||
|
||||
// For each virtual declared in klass and any immediate abstract
|
||||
// superclasses, set new vtable entry or override an old one.
|
||||
_Jv_SetVTableEntries (klass, vtable);
|
||||
}
|
||||
|
||||
@@ -234,7 +234,6 @@ java::lang::ClassLoader::findLoadedClass (jstring name)
|
||||
return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this);
|
||||
}
|
||||
|
||||
|
||||
/** This function does class-preparation for compiled classes.
|
||||
NOTE: It contains replicated functionality from
|
||||
_Jv_ResolvePoolEntry, and this is intentional, since that function
|
||||
@@ -309,6 +308,12 @@ _Jv_PrepareCompiledClass (jclass klass)
|
||||
}
|
||||
#endif /* INTERPRETER */
|
||||
|
||||
if (klass->vtable == NULL)
|
||||
_Jv_MakeVTable(klass);
|
||||
|
||||
if (klass->otable != NULL && klass->otable->state == 0)
|
||||
_Jv_LinkOffsetTable(klass);
|
||||
|
||||
klass->notifyAll ();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user