Commit 861ef928 by Bryce McKinlay Committed by Bryce McKinlay

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
parent ed86a83d
2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
* 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.
2001-12-14 Matthias Klose <doko@debian.org> 2001-12-14 Matthias Klose <doko@debian.org>
* gcj.texi: Markup for man page generation. Document missing * gcj.texi: Markup for man page generation. Document missing
......
...@@ -58,6 +58,8 @@ static int assume_compiled PARAMS ((const char *)); ...@@ -58,6 +58,8 @@ static int assume_compiled PARAMS ((const char *));
static struct hash_entry *init_test_hash_newfunc PARAMS ((struct hash_entry *, static struct hash_entry *init_test_hash_newfunc PARAMS ((struct hash_entry *,
struct hash_table *, struct hash_table *,
hash_table_key)); hash_table_key));
static tree build_method_symbols_entry PARAMS ((tree));
static rtx registerClass_libfunc; static rtx registerClass_libfunc;
static rtx registerResource_libfunc; static rtx registerResource_libfunc;
...@@ -1276,9 +1278,16 @@ make_method_value (mdecl) ...@@ -1276,9 +1278,16 @@ make_method_value (mdecl)
{ {
static int method_name_count = 0; static int method_name_count = 0;
tree minit; tree minit;
tree index;
tree code; tree code;
#define ACC_TRANSLATED 0x4000 #define ACC_TRANSLATED 0x4000
int accflags = get_access_flags_from_decl (mdecl) | ACC_TRANSLATED; int accflags = get_access_flags_from_decl (mdecl) | ACC_TRANSLATED;
if (!flag_indirect_dispatch && DECL_VINDEX (mdecl) != NULL_TREE)
index = DECL_VINDEX (mdecl);
else
index = integer_minus_one_node;
code = null_pointer_node; code = null_pointer_node;
if (DECL_RTL_SET_P (mdecl)) if (DECL_RTL_SET_P (mdecl))
code = build1 (ADDR_EXPR, nativecode_ptr_type_node, mdecl); code = build1 (ADDR_EXPR, nativecode_ptr_type_node, mdecl);
...@@ -1296,6 +1305,7 @@ make_method_value (mdecl) ...@@ -1296,6 +1305,7 @@ make_method_value (mdecl)
IDENTIFIER_LENGTH(signature))))); IDENTIFIER_LENGTH(signature)))));
} }
PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0)); PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0));
PUSH_FIELD_VALUE (minit, "index", index);
PUSH_FIELD_VALUE (minit, "ncode", code); PUSH_FIELD_VALUE (minit, "ncode", code);
{ {
...@@ -1541,7 +1551,7 @@ make_class_data (type) ...@@ -1541,7 +1551,7 @@ make_class_data (type)
rest_of_decl_compilation (methods_decl, (char*) 0, 1, 0); rest_of_decl_compilation (methods_decl, (char*) 0, 1, 0);
if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl))) if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
&& ! CLASS_INTERFACE (type_decl)) && ! CLASS_INTERFACE (type_decl) && !flag_indirect_dispatch)
{ {
tree dtable = get_dispatch_table (type, this_class_addr); tree dtable = get_dispatch_table (type, this_class_addr);
dtable_decl = build_dtable_decl (type); dtable_decl = build_dtable_decl (type);
...@@ -1635,7 +1645,12 @@ make_class_data (type) ...@@ -1635,7 +1645,12 @@ make_class_data (type)
PUSH_FIELD_VALUE (cons, "methods", PUSH_FIELD_VALUE (cons, "methods",
build1 (ADDR_EXPR, method_ptr_type_node, methods_decl)); build1 (ADDR_EXPR, method_ptr_type_node, methods_decl));
PUSH_FIELD_VALUE (cons, "method_count", build_int_2 (method_count, 0)); PUSH_FIELD_VALUE (cons, "method_count", build_int_2 (method_count, 0));
if (flag_indirect_dispatch)
PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node)
else
PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type)); PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
PUSH_FIELD_VALUE (cons, "fields", PUSH_FIELD_VALUE (cons, "fields",
fields_decl == NULL_TREE ? null_pointer_node fields_decl == NULL_TREE ? null_pointer_node
: build1 (ADDR_EXPR, field_ptr_type_node, fields_decl)); : build1 (ADDR_EXPR, field_ptr_type_node, fields_decl));
...@@ -1643,9 +1658,27 @@ make_class_data (type) ...@@ -1643,9 +1658,27 @@ make_class_data (type)
PUSH_FIELD_VALUE (cons, "field_count", build_int_2 (field_count, 0)); PUSH_FIELD_VALUE (cons, "field_count", build_int_2 (field_count, 0));
PUSH_FIELD_VALUE (cons, "static_field_count", PUSH_FIELD_VALUE (cons, "static_field_count",
build_int_2 (static_field_count, 0)); build_int_2 (static_field_count, 0));
if (flag_indirect_dispatch)
PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node)
else
PUSH_FIELD_VALUE (cons, "vtable", PUSH_FIELD_VALUE (cons, "vtable",
dtable_decl == NULL_TREE ? null_pointer_node dtable_decl == NULL_TREE ? null_pointer_node
: build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl)); : build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl));
if (otable_methods == NULL_TREE)
{
PUSH_FIELD_VALUE (cons, "otable", null_pointer_node);
PUSH_FIELD_VALUE (cons, "otable_syms", null_pointer_node);
}
else
{
PUSH_FIELD_VALUE (cons, "otable",
build1 (ADDR_EXPR, otable_ptr_type, otable_decl));
PUSH_FIELD_VALUE (cons, "otable_syms",
build1 (ADDR_EXPR, method_symbols_array_ptr_type,
otable_syms_decl));
}
PUSH_FIELD_VALUE (cons, "interfaces", interfaces); PUSH_FIELD_VALUE (cons, "interfaces", interfaces);
PUSH_FIELD_VALUE (cons, "loader", null_pointer_node); PUSH_FIELD_VALUE (cons, "loader", null_pointer_node);
PUSH_FIELD_VALUE (cons, "interface_count", build_int_2 (interface_len, 0)); PUSH_FIELD_VALUE (cons, "interface_count", build_int_2 (interface_len, 0));
...@@ -2160,6 +2193,87 @@ emit_register_classes () ...@@ -2160,6 +2193,87 @@ emit_register_classes ()
} }
} }
/* Make a method_symbol_type (_Jv_MethodSymbol) node for METHOD. */
tree
build_method_symbols_entry (tree method)
{
tree clname, name, signature, method_symbol;
clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (method))));
name = build_utf8_ref (DECL_NAME (method));
signature = build_java_signature (TREE_TYPE (method));
signature = build_utf8_ref (unmangle_classname
(IDENTIFIER_POINTER (signature),
IDENTIFIER_LENGTH (signature)));
START_RECORD_CONSTRUCTOR (method_symbol, method_symbol_type);
PUSH_FIELD_VALUE (method_symbol, "clname", clname);
PUSH_FIELD_VALUE (method_symbol, "name", name);
PUSH_FIELD_VALUE (method_symbol, "signature", signature);
FINISH_RECORD_CONSTRUCTOR (method_symbol);
TREE_CONSTANT (method_symbol) = 1;
return method_symbol;
}
/* Emit the offset symbols table for indirect virtual dispatch. */
void
emit_offset_symbol_table ()
{
tree method_list, method, table, list, null_symbol;
tree otable_bound, otable_array_type;
int index;
/* Only emit an offset table if this translation unit actually made virtual
calls. */
if (otable_methods == NULL_TREE)
return;
/* Build a list of _Jv_MethodSymbols for each entry in otable_methods. */
index = 0;
method_list = otable_methods;
list = NULL_TREE;
while (method_list != NULL_TREE)
{
method = TREE_VALUE (method_list);
list = tree_cons (NULL_TREE, build_method_symbols_entry (method), list);
method_list = TREE_CHAIN (method_list);
index++;
}
/* Terminate the list with a "null" entry. */
START_RECORD_CONSTRUCTOR (null_symbol, method_symbol_type);
PUSH_FIELD_VALUE (null_symbol, "clname", null_pointer_node);
PUSH_FIELD_VALUE (null_symbol, "name", null_pointer_node);
PUSH_FIELD_VALUE (null_symbol, "signature", null_pointer_node);
FINISH_RECORD_CONSTRUCTOR (null_symbol);
TREE_CONSTANT (null_symbol) = 1;
list = tree_cons (NULL_TREE, null_symbol, list);
/* Put the list in the right order and make it a constructor. */
list = nreverse (list);
table = build (CONSTRUCTOR, method_symbols_array_type, NULL_TREE, list);
/* Make it the initial value for otable_syms and emit the decl. */
DECL_INITIAL (otable_syms_decl) = table;
DECL_ARTIFICIAL (otable_syms_decl) = 1;
DECL_IGNORED_P (otable_syms_decl) = 1;
rest_of_decl_compilation (otable_syms_decl, NULL, 1, 0);
/* Now that its size is known, redefine otable as an uninitialized static
array of INDEX + 1 integers. The extra entry is used by the runtime
to track whether the otable has been initialized. */
otable_bound = build_index_type (build_int_2 (index, 0));
otable_array_type = build_array_type (integer_type_node, otable_bound);
otable_decl = build_decl (VAR_DECL, get_identifier ("otable"),
otable_array_type);
TREE_STATIC (otable_decl) = 1;
TREE_READONLY (otable_decl) = 1;
rest_of_decl_compilation (otable_decl, NULL, 1, 0);
}
void void
init_class_processing () init_class_processing ()
{ {
......
...@@ -614,6 +614,35 @@ java_init_decl_processing () ...@@ -614,6 +614,35 @@ java_init_decl_processing ()
dtable_type = make_node (RECORD_TYPE); dtable_type = make_node (RECORD_TYPE);
dtable_ptr_type = build_pointer_type (dtable_type); dtable_ptr_type = build_pointer_type (dtable_type);
otable_type = make_node (RECORD_TYPE);
otable_ptr_type = build_pointer_type (otable_type);
method_symbol_type = make_node (RECORD_TYPE);
PUSH_FIELD (method_symbol_type, field, "clname", utf8const_ptr_type);
PUSH_FIELD (method_symbol_type, field, "name", utf8const_ptr_type);
PUSH_FIELD (method_symbol_type, field, "signature", utf8const_ptr_type);
FINISH_RECORD (method_symbol_type);
one_elt_array_domain_type = build_index_type (integer_one_node);
method_symbols_array_type = build_array_type (method_symbol_type,
one_elt_array_domain_type);
method_symbols_array_ptr_type = build_pointer_type
(method_symbols_array_type);
otable_decl = build_decl (VAR_DECL, get_identifier ("otable"),
build_array_type (integer_type_node,
one_elt_array_domain_type));
DECL_EXTERNAL (otable_decl) = 1;
TREE_STATIC (otable_decl) = 1;
TREE_READONLY (otable_decl) = 1;
pushdecl (otable_decl);
otable_syms_decl = build_decl (VAR_DECL, get_identifier ("otable_syms"),
method_symbols_array_type);
TREE_STATIC (otable_syms_decl) = 1;
TREE_CONSTANT (otable_syms_decl) = 1;
pushdecl (otable_syms_decl);
PUSH_FIELD (object_type_node, field, "vtable", dtable_ptr_type); PUSH_FIELD (object_type_node, field, "vtable", dtable_ptr_type);
/* This isn't exactly true, but it is what we have in the source. /* This isn't exactly true, but it is what we have in the source.
There is an unresolved issue here, which is whether the vtable There is an unresolved issue here, which is whether the vtable
...@@ -647,6 +676,9 @@ java_init_decl_processing () ...@@ -647,6 +676,9 @@ java_init_decl_processing ()
PUSH_FIELD (class_type_node, field, "field_count", short_type_node); PUSH_FIELD (class_type_node, field, "field_count", short_type_node);
PUSH_FIELD (class_type_node, field, "static_field_count", short_type_node); PUSH_FIELD (class_type_node, field, "static_field_count", short_type_node);
PUSH_FIELD (class_type_node, field, "vtable", dtable_ptr_type); PUSH_FIELD (class_type_node, field, "vtable", dtable_ptr_type);
PUSH_FIELD (class_type_node, field, "otable", otable_ptr_type);
PUSH_FIELD (class_type_node, field, "otable_syms",
method_symbols_array_ptr_type);
PUSH_FIELD (class_type_node, field, "interfaces", PUSH_FIELD (class_type_node, field, "interfaces",
build_pointer_type (class_ptr_type)); build_pointer_type (class_ptr_type));
PUSH_FIELD (class_type_node, field, "loader", ptr_type_node); PUSH_FIELD (class_type_node, field, "loader", ptr_type_node);
...@@ -661,6 +693,7 @@ java_init_decl_processing () ...@@ -661,6 +693,7 @@ java_init_decl_processing ()
for (t = TYPE_FIELDS (class_type_node); t != NULL_TREE; t = TREE_CHAIN (t)) for (t = TYPE_FIELDS (class_type_node); t != NULL_TREE; t = TREE_CHAIN (t))
FIELD_PRIVATE (t) = 1; FIELD_PRIVATE (t) = 1;
push_super_field (class_type_node, object_type_node); push_super_field (class_type_node, object_type_node);
FINISH_RECORD (class_type_node); FINISH_RECORD (class_type_node);
build_decl (TYPE_DECL, get_identifier ("Class"), class_type_node); build_decl (TYPE_DECL, get_identifier ("Class"), class_type_node);
...@@ -680,7 +713,6 @@ java_init_decl_processing () ...@@ -680,7 +713,6 @@ java_init_decl_processing ()
FINISH_RECORD (field_type_node); FINISH_RECORD (field_type_node);
build_decl (TYPE_DECL, get_identifier ("Field"), field_type_node); build_decl (TYPE_DECL, get_identifier ("Field"), field_type_node);
one_elt_array_domain_type = build_index_type (integer_one_node);
nativecode_ptr_array_type_node nativecode_ptr_array_type_node
= build_array_type (nativecode_ptr_type_node, one_elt_array_domain_type); = build_array_type (nativecode_ptr_type_node, one_elt_array_domain_type);
...@@ -717,6 +749,7 @@ java_init_decl_processing () ...@@ -717,6 +749,7 @@ java_init_decl_processing ()
PUSH_FIELD (method_type_node, field, "name", utf8const_ptr_type); PUSH_FIELD (method_type_node, field, "name", utf8const_ptr_type);
PUSH_FIELD (method_type_node, field, "signature", utf8const_ptr_type); PUSH_FIELD (method_type_node, field, "signature", utf8const_ptr_type);
PUSH_FIELD (method_type_node, field, "accflags", access_flags_type_node); PUSH_FIELD (method_type_node, field, "accflags", access_flags_type_node);
PUSH_FIELD (method_type_node, field, "index", unsigned_short_type_node);
PUSH_FIELD (method_type_node, field, "ncode", nativecode_ptr_type_node); PUSH_FIELD (method_type_node, field, "ncode", nativecode_ptr_type_node);
PUSH_FIELD (method_type_node, field, "throws", ptr_type_node); PUSH_FIELD (method_type_node, field, "throws", ptr_type_node);
FINISH_RECORD (method_type_node); FINISH_RECORD (method_type_node);
......
...@@ -84,6 +84,7 @@ static tree case_identity PARAMS ((tree, tree)); ...@@ -84,6 +84,7 @@ static tree case_identity PARAMS ((tree, tree));
static unsigned char peek_opcode_at_pc PARAMS ((struct JCF *, int, int)); static unsigned char peek_opcode_at_pc PARAMS ((struct JCF *, int, int));
static bool emit_init_test_initialization PARAMS ((struct hash_entry *, static bool emit_init_test_initialization PARAMS ((struct hash_entry *,
PTR ptr)); PTR ptr));
static int get_offset_table_index PARAMS ((tree));
static tree operand_type[59]; static tree operand_type[59];
extern struct obstack permanent_obstack; extern struct obstack permanent_obstack;
...@@ -1856,6 +1857,40 @@ invoke_build_dtable (is_invoke_interface, arg_list) ...@@ -1856,6 +1857,40 @@ invoke_build_dtable (is_invoke_interface, arg_list)
return dtable; return dtable;
} }
/* Determine the index in the virtual offset table (otable) for a call to
METHOD. If this method has not been seen before, it will be added to the
otable_methods. If it has, the existing otable slot will be reused. */
int
get_offset_table_index (method)
tree method;
{
int i = 1;
tree method_list;
if (otable_methods == NULL_TREE)
{
otable_methods = build_tree_list (method, method);
return 1;
}
method_list = otable_methods;
while (1)
{
if (TREE_VALUE (method_list) == method)
return i;
i++;
if (TREE_CHAIN (method_list) == NULL_TREE)
break;
else
method_list = TREE_CHAIN (method_list);
}
TREE_CHAIN (method_list) = build_tree_list (method, method);
return i;
}
tree tree
build_invokevirtual (dtable, method) build_invokevirtual (dtable, method)
tree dtable, method; tree dtable, method;
...@@ -1863,7 +1898,18 @@ build_invokevirtual (dtable, method) ...@@ -1863,7 +1898,18 @@ build_invokevirtual (dtable, method)
tree func; tree func;
tree nativecode_ptr_ptr_type_node tree nativecode_ptr_ptr_type_node
= build_pointer_type (nativecode_ptr_type_node); = build_pointer_type (nativecode_ptr_type_node);
tree method_index = convert (sizetype, DECL_VINDEX (method)); tree method_index;
tree otable_index;
if (flag_indirect_dispatch)
{
otable_index = build_int_2 (get_offset_table_index (method), 0);
method_index = build (ARRAY_REF, integer_type_node, otable_decl,
otable_index);
}
else
{
method_index = convert (sizetype, DECL_VINDEX (method));
if (TARGET_VTABLE_USES_DESCRIPTORS) if (TARGET_VTABLE_USES_DESCRIPTORS)
/* Add one to skip bogus descriptor for class and GC descriptor. */ /* Add one to skip bogus descriptor for class and GC descriptor. */
...@@ -1871,12 +1917,14 @@ build_invokevirtual (dtable, method) ...@@ -1871,12 +1917,14 @@ build_invokevirtual (dtable, method)
else else
/* Add 1 to skip "class" field of dtable, and 1 to skip GC descriptor. */ /* Add 1 to skip "class" field of dtable, and 1 to skip GC descriptor. */
method_index = size_binop (PLUS_EXPR, method_index, size_int (2)); method_index = size_binop (PLUS_EXPR, method_index, size_int (2));
method_index = size_binop (MULT_EXPR, method_index, method_index = size_binop (MULT_EXPR, method_index,
TYPE_SIZE_UNIT (nativecode_ptr_ptr_type_node)); TYPE_SIZE_UNIT (nativecode_ptr_ptr_type_node));
if (TARGET_VTABLE_USES_DESCRIPTORS) if (TARGET_VTABLE_USES_DESCRIPTORS)
method_index = size_binop (MULT_EXPR, method_index, method_index = size_binop (MULT_EXPR, method_index,
size_int (TARGET_VTABLE_USES_DESCRIPTORS)); size_int (TARGET_VTABLE_USES_DESCRIPTORS));
}
func = fold (build (PLUS_EXPR, nativecode_ptr_ptr_type_node, dtable, func = fold (build (PLUS_EXPR, nativecode_ptr_ptr_type_node, dtable,
convert (nativecode_ptr_ptr_type_node, method_index))); convert (nativecode_ptr_ptr_type_node, method_index)));
...@@ -1898,6 +1946,7 @@ build_invokeinterface (dtable, method) ...@@ -1898,6 +1946,7 @@ build_invokeinterface (dtable, method)
tree interface; tree interface;
tree idx; tree idx;
tree meth; tree meth;
tree otable_index;
int i; int i;
/* We expand invokeinterface here. _Jv_LookupInterfaceMethod() will /* We expand invokeinterface here. _Jv_LookupInterfaceMethod() will
...@@ -1917,6 +1966,13 @@ build_invokeinterface (dtable, method) ...@@ -1917,6 +1966,13 @@ build_invokeinterface (dtable, method)
interface = DECL_CONTEXT (method); interface = DECL_CONTEXT (method);
layout_class_methods (interface); layout_class_methods (interface);
if (flag_indirect_dispatch)
{
otable_index = build_int_2 (get_offset_table_index (method), 0);
idx = build (ARRAY_REF, integer_type_node, otable_decl, otable_index);
}
else
{
i = 1; i = 1;
for (meth = TYPE_METHODS (interface); ; meth = TREE_CHAIN (meth), i++) for (meth = TYPE_METHODS (interface); ; meth = TREE_CHAIN (meth), i++)
{ {
...@@ -1928,6 +1984,7 @@ build_invokeinterface (dtable, method) ...@@ -1928,6 +1984,7 @@ build_invokeinterface (dtable, method)
if (meth == NULL_TREE) if (meth == NULL_TREE)
abort (); abort ();
} }
}
lookup_arg = tree_cons (NULL_TREE, dtable, lookup_arg = tree_cons (NULL_TREE, dtable,
tree_cons (NULL_TREE, build_class_ref (interface), tree_cons (NULL_TREE, build_class_ref (interface),
......
...@@ -141,6 +141,18 @@ extern int compiling_from_source; ...@@ -141,6 +141,18 @@ extern int compiling_from_source;
/* List of all class filenames seen so far. */ /* List of all class filenames seen so far. */
#define all_class_filename java_global_trees [JTI_ALL_CLASS_FILENAME] #define all_class_filename java_global_trees [JTI_ALL_CLASS_FILENAME]
/* List of virtual method decls called in this translation unit, used to
generate virtual method offset symbol table. */
#define otable_methods java_global_trees [JTI_OTABLE_METHODS]
/* The virtual method offset table. This is emitted as uninitialized data of
the required length, and filled out at run time during class linking. */
#define otable_decl java_global_trees [JTI_OTABLE_DECL]
/* The virtual method offset symbol table. Used by the runtime to fill out the
otable. */
#define otable_syms_decl java_global_trees [JTI_OTABLE_SYMS_DECL]
extern int flag_emit_class_files; extern int flag_emit_class_files;
extern int flag_filelist_file; extern int flag_filelist_file;
...@@ -196,6 +208,10 @@ extern int flag_check_references; ...@@ -196,6 +208,10 @@ extern int flag_check_references;
initialization optimization should be performed. */ initialization optimization should be performed. */
extern int flag_optimize_sci; extern int flag_optimize_sci;
/* When non zero, use offset tables for virtual method calls
in order to improve binary compatibility. */
extern int flag_indirect_dispatch;
/* Encoding used for source files. */ /* Encoding used for source files. */
extern const char *current_encoding; extern const char *current_encoding;
...@@ -331,6 +347,11 @@ enum java_tree_index ...@@ -331,6 +347,11 @@ enum java_tree_index
JTI_LINENUMBERS_TYPE, JTI_LINENUMBERS_TYPE,
JTI_METHOD_TYPE_NODE, JTI_METHOD_TYPE_NODE,
JTI_METHOD_PTR_TYPE_NODE, JTI_METHOD_PTR_TYPE_NODE,
JTI_OTABLE_TYPE,
JTI_OTABLE_PTR_TYPE,
JTI_METHOD_SYMBOL_TYPE,
JTI_METHOD_SYMBOLS_ARRAY_TYPE,
JTI_METHOD_SYMBOLS_ARRAY_PTR_TYPE,
JTI_END_PARAMS_NODE, JTI_END_PARAMS_NODE,
...@@ -370,6 +391,10 @@ enum java_tree_index ...@@ -370,6 +391,10 @@ enum java_tree_index
JTI_ALL_CLASS_LIST, JTI_ALL_CLASS_LIST,
JTI_ALL_CLASS_FILENAME, JTI_ALL_CLASS_FILENAME,
JTI_OTABLE_METHODS,
JTI_OTABLE_DECL,
JTI_OTABLE_SYMS_DECL,
JTI_MAX JTI_MAX
}; };
...@@ -565,6 +590,16 @@ extern tree java_global_trees[JTI_MAX]; ...@@ -565,6 +590,16 @@ extern tree java_global_trees[JTI_MAX];
java_global_trees[JTI_METHOD_TYPE_NODE] java_global_trees[JTI_METHOD_TYPE_NODE]
#define method_ptr_type_node \ #define method_ptr_type_node \
java_global_trees[JTI_METHOD_PTR_TYPE_NODE] java_global_trees[JTI_METHOD_PTR_TYPE_NODE]
#define otable_type \
java_global_trees[JTI_OTABLE_TYPE]
#define otable_ptr_type \
java_global_trees[JTI_OTABLE_PTR_TYPE]
#define method_symbol_type \
java_global_trees[JTI_METHOD_SYMBOL_TYPE]
#define method_symbols_array_type \
java_global_trees[JTI_METHOD_SYMBOLS_ARRAY_TYPE]
#define method_symbols_array_ptr_type \
java_global_trees[JTI_METHOD_SYMBOLS_ARRAY_PTR_TYPE]
#define end_params_node \ #define end_params_node \
java_global_trees[JTI_END_PARAMS_NODE] java_global_trees[JTI_END_PARAMS_NODE]
...@@ -1098,6 +1133,7 @@ extern void make_class_data PARAMS ((tree)); ...@@ -1098,6 +1133,7 @@ extern void make_class_data PARAMS ((tree));
extern void register_class PARAMS ((void)); extern void register_class PARAMS ((void));
extern int alloc_name_constant PARAMS ((int, tree)); extern int alloc_name_constant PARAMS ((int, tree));
extern void emit_register_classes PARAMS ((void)); extern void emit_register_classes PARAMS ((void));
extern void emit_offset_symbol_table PARAMS ((void));
extern void lang_init_source PARAMS ((int)); extern void lang_init_source PARAMS ((int));
extern void write_classfile PARAMS ((tree)); extern void write_classfile PARAMS ((tree));
extern char *print_int_node PARAMS ((tree)); extern char *print_int_node PARAMS ((tree));
......
...@@ -1188,7 +1188,11 @@ yyparse () ...@@ -1188,7 +1188,11 @@ yyparse ()
java_expand_classes (); java_expand_classes ();
if (!java_report_errors () && !flag_syntax_only) if (!java_report_errors () && !flag_syntax_only)
{
emit_register_classes (); emit_register_classes ();
if (flag_indirect_dispatch)
emit_offset_symbol_table ();
}
return 0; return 0;
} }
......
...@@ -64,6 +64,7 @@ const char jvgenmain_spec[] = ...@@ -64,6 +64,7 @@ const char jvgenmain_spec[] =
%{<fcompile-resource*}\ %{<fcompile-resource*}\
%{<femit-class-file} %{<femit-class-files} %{<fencoding*}\ %{<femit-class-file} %{<femit-class-files} %{<fencoding*}\
%{<fuse-boehm-gc} %{<fhash-synchronization} %{<fjni}\ %{<fuse-boehm-gc} %{<fhash-synchronization} %{<fjni}\
%{<findirect-dispatch} \
%{<fclasspath*} %{<fCLASSPATH*} %{<foutput-class-dir}\ %{<fclasspath*} %{<fCLASSPATH*} %{<foutput-class-dir}\
%{<fuse-divide-subroutine} %{<fno-use-divide-subroutine}\ %{<fuse-divide-subroutine} %{<fno-use-divide-subroutine}\
%{<fcheck-references} %{<fno-check-references}\ %{<fcheck-references} %{<fno-check-references}\
......
...@@ -153,6 +153,10 @@ int flag_force_classes_archive_check; ...@@ -153,6 +153,10 @@ int flag_force_classes_archive_check;
be tested alone, use STATIC_CLASS_INITIALIZATION_OPTIMIZATION_P instead. */ be tested alone, use STATIC_CLASS_INITIALIZATION_OPTIMIZATION_P instead. */
int flag_optimize_sci = 1; int flag_optimize_sci = 1;
/* When non zero, use offset tables for virtual method calls
in order to improve binary compatibility. */
int flag_indirect_dispatch = 0;
/* When non zero, print extra version information. */ /* When non zero, print extra version information. */
static int version_flag = 0; static int version_flag = 0;
...@@ -174,7 +178,8 @@ lang_f_options[] = ...@@ -174,7 +178,8 @@ lang_f_options[] =
{"jni", &flag_jni, 1}, {"jni", &flag_jni, 1},
{"check-references", &flag_check_references, 1}, {"check-references", &flag_check_references, 1},
{"force-classes-archive-check", &flag_force_classes_archive_check, 1}, {"force-classes-archive-check", &flag_force_classes_archive_check, 1},
{"optimize-static-class-initialization", &flag_optimize_sci, 1 } {"optimize-static-class-initialization", &flag_optimize_sci, 1 },
{"indirect-dispatch", &flag_indirect_dispatch, 1}
}; };
static struct string_option static struct string_option
......
2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz> 2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
* 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.
2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
* java/util/BitSet.java (and): Fix off-by-one bug, don't skip part of * java/util/BitSet.java (and): Fix off-by-one bug, don't skip part of
the bitset. the bitset.
(andNot): Likewise. (andNot): Likewise.
......
...@@ -57,6 +57,12 @@ struct _Jv_VTable ...@@ -57,6 +57,12 @@ struct _Jv_VTable
#endif #endif
static size_t vtable_elt_size() { return sizeof(vtable_elt); } static size_t vtable_elt_size() { return sizeof(vtable_elt); }
// Given a method index, return byte offset from the vtable pointer.
static jint idx_to_offset (int index)
{
return (2 * sizeof (void *)) + (index * vtable_elt_size ());
}
static _Jv_VTable *new_vtable (int count); static _Jv_VTable *new_vtable (int count);
}; };
......
...@@ -70,6 +70,8 @@ struct _Jv_Method ...@@ -70,6 +70,8 @@ struct _Jv_Method
_Jv_Utf8Const *signature; _Jv_Utf8Const *signature;
// Access flags. // Access flags.
_Jv_ushort accflags; _Jv_ushort accflags;
// Method's index in the vtable.
_Jv_ushort index;
// Pointer to underlying function. // Pointer to underlying function.
void *ncode; void *ncode;
// NULL-terminated list of exception class names; can be NULL if // NULL-terminated list of exception class names; can be NULL if
...@@ -114,6 +116,19 @@ union _Jv_Self ...@@ -114,6 +116,19 @@ union _Jv_Self
jclass 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_PRIMITIVE_VTABLE ((_Jv_VTable *) -1)
#define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas)
...@@ -303,6 +318,10 @@ private: ...@@ -303,6 +318,10 @@ private:
friend jstring _Jv_GetMethodString(jclass, _Jv_Utf8Const *); friend jstring _Jv_GetMethodString(jclass, _Jv_Utf8Const *);
friend jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort); friend jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort);
friend jshort _Jv_FindIIndex (jclass *, jshort *, 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 // Return array class corresponding to element type KLASS, creating it if
// necessary. // necessary.
...@@ -367,6 +386,10 @@ private: ...@@ -367,6 +386,10 @@ private:
jshort static_field_count; jshort static_field_count;
// The vtbl for all objects of this class. // The vtbl for all objects of this class.
_Jv_VTable *vtable; _Jv_VTable *vtable;
// Virtual method offset table.
_Jv_OffsetTable *otable;
// Offset table symbols.
_Jv_MethodSymbol *otable_syms;
// Interfaces implemented by this class. // Interfaces implemented by this class.
jclass *interfaces; jclass *interfaces;
// The class loader for this class. // The class loader for this class.
......
...@@ -1422,3 +1422,194 @@ java::lang::Class::getProtectionDomain0 () ...@@ -1422,3 +1422,194 @@ java::lang::Class::getProtectionDomain0 ()
{ {
return protectionDomain; 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) ...@@ -234,7 +234,6 @@ java::lang::ClassLoader::findLoadedClass (jstring name)
return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this); return _Jv_FindClassInCache (_Jv_makeUtf8Const (name), this);
} }
/** This function does class-preparation for compiled classes. /** This function does class-preparation for compiled classes.
NOTE: It contains replicated functionality from NOTE: It contains replicated functionality from
_Jv_ResolvePoolEntry, and this is intentional, since that function _Jv_ResolvePoolEntry, and this is intentional, since that function
...@@ -309,6 +308,12 @@ _Jv_PrepareCompiledClass (jclass klass) ...@@ -309,6 +308,12 @@ _Jv_PrepareCompiledClass (jclass klass)
} }
#endif /* INTERPRETER */ #endif /* INTERPRETER */
if (klass->vtable == NULL)
_Jv_MakeVTable(klass);
if (klass->otable != NULL && klass->otable->state == 0)
_Jv_LinkOffsetTable(klass);
klass->notifyAll (); klass->notifyAll ();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment