mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-15 23:11:25 +08:00
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:
parent
ed86a83d51
commit
861ef92859
@ -1,3 +1,33 @@
|
||||
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>
|
||||
|
||||
* gcj.texi: Markup for man page generation. Document missing
|
||||
|
124
gcc/java/class.c
124
gcc/java/class.c
@ -58,6 +58,8 @@ static int assume_compiled PARAMS ((const char *));
|
||||
static struct hash_entry *init_test_hash_newfunc PARAMS ((struct hash_entry *,
|
||||
struct hash_table *,
|
||||
hash_table_key));
|
||||
static tree build_method_symbols_entry PARAMS ((tree));
|
||||
|
||||
static rtx registerClass_libfunc;
|
||||
static rtx registerResource_libfunc;
|
||||
|
||||
@ -1276,9 +1278,16 @@ make_method_value (mdecl)
|
||||
{
|
||||
static int method_name_count = 0;
|
||||
tree minit;
|
||||
tree index;
|
||||
tree code;
|
||||
#define ACC_TRANSLATED 0x4000
|
||||
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;
|
||||
if (DECL_RTL_SET_P (mdecl))
|
||||
code = build1 (ADDR_EXPR, nativecode_ptr_type_node, mdecl);
|
||||
@ -1296,6 +1305,7 @@ make_method_value (mdecl)
|
||||
IDENTIFIER_LENGTH(signature)))));
|
||||
}
|
||||
PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0));
|
||||
PUSH_FIELD_VALUE (minit, "index", index);
|
||||
PUSH_FIELD_VALUE (minit, "ncode", code);
|
||||
|
||||
{
|
||||
@ -1541,7 +1551,7 @@ make_class_data (type)
|
||||
rest_of_decl_compilation (methods_decl, (char*) 0, 1, 0);
|
||||
|
||||
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);
|
||||
dtable_decl = build_dtable_decl (type);
|
||||
@ -1635,7 +1645,12 @@ make_class_data (type)
|
||||
PUSH_FIELD_VALUE (cons, "methods",
|
||||
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, "vtable_method_count", TYPE_NVIRTUALS (type));
|
||||
|
||||
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, "fields",
|
||||
fields_decl == NULL_TREE ? null_pointer_node
|
||||
: build1 (ADDR_EXPR, field_ptr_type_node, fields_decl));
|
||||
@ -1643,9 +1658,27 @@ make_class_data (type)
|
||||
PUSH_FIELD_VALUE (cons, "field_count", build_int_2 (field_count, 0));
|
||||
PUSH_FIELD_VALUE (cons, "static_field_count",
|
||||
build_int_2 (static_field_count, 0));
|
||||
PUSH_FIELD_VALUE (cons, "vtable",
|
||||
dtable_decl == NULL_TREE ? null_pointer_node
|
||||
: build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl));
|
||||
|
||||
if (flag_indirect_dispatch)
|
||||
PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node)
|
||||
else
|
||||
PUSH_FIELD_VALUE (cons, "vtable",
|
||||
dtable_decl == NULL_TREE ? null_pointer_node
|
||||
: 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, "loader", null_pointer_node);
|
||||
PUSH_FIELD_VALUE (cons, "interface_count", build_int_2 (interface_len, 0));
|
||||
@ -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
|
||||
init_class_processing ()
|
||||
{
|
||||
|
@ -614,6 +614,35 @@ java_init_decl_processing ()
|
||||
dtable_type = make_node (RECORD_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);
|
||||
/* 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
|
||||
@ -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, "static_field_count", short_type_node);
|
||||
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",
|
||||
build_pointer_type (class_ptr_type));
|
||||
PUSH_FIELD (class_type_node, field, "loader", ptr_type_node);
|
||||
@ -661,6 +693,7 @@ java_init_decl_processing ()
|
||||
for (t = TYPE_FIELDS (class_type_node); t != NULL_TREE; t = TREE_CHAIN (t))
|
||||
FIELD_PRIVATE (t) = 1;
|
||||
push_super_field (class_type_node, object_type_node);
|
||||
|
||||
FINISH_RECORD (class_type_node);
|
||||
build_decl (TYPE_DECL, get_identifier ("Class"), class_type_node);
|
||||
|
||||
@ -680,7 +713,6 @@ java_init_decl_processing ()
|
||||
FINISH_RECORD (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
|
||||
= build_array_type (nativecode_ptr_type_node, one_elt_array_domain_type);
|
||||
|
||||
@ -717,6 +749,7 @@ java_init_decl_processing ()
|
||||
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, "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, "throws", ptr_type_node);
|
||||
FINISH_RECORD (method_type_node);
|
||||
|
@ -84,6 +84,7 @@ static tree case_identity PARAMS ((tree, tree));
|
||||
static unsigned char peek_opcode_at_pc PARAMS ((struct JCF *, int, int));
|
||||
static bool emit_init_test_initialization PARAMS ((struct hash_entry *,
|
||||
PTR ptr));
|
||||
static int get_offset_table_index PARAMS ((tree));
|
||||
|
||||
static tree operand_type[59];
|
||||
extern struct obstack permanent_obstack;
|
||||
@ -1856,6 +1857,40 @@ invoke_build_dtable (is_invoke_interface, arg_list)
|
||||
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
|
||||
build_invokevirtual (dtable, method)
|
||||
tree dtable, method;
|
||||
@ -1863,20 +1898,33 @@ build_invokevirtual (dtable, method)
|
||||
tree func;
|
||||
tree nativecode_ptr_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 (TARGET_VTABLE_USES_DESCRIPTORS)
|
||||
/* Add one to skip bogus descriptor for class and GC descriptor. */
|
||||
method_index = size_binop (PLUS_EXPR, method_index, size_int (1));
|
||||
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
|
||||
/* 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 (MULT_EXPR, method_index,
|
||||
TYPE_SIZE_UNIT (nativecode_ptr_ptr_type_node));
|
||||
{
|
||||
method_index = convert (sizetype, DECL_VINDEX (method));
|
||||
|
||||
if (TARGET_VTABLE_USES_DESCRIPTORS)
|
||||
method_index = size_binop (MULT_EXPR, method_index,
|
||||
size_int (TARGET_VTABLE_USES_DESCRIPTORS));
|
||||
if (TARGET_VTABLE_USES_DESCRIPTORS)
|
||||
/* Add one to skip bogus descriptor for class and GC descriptor. */
|
||||
method_index = size_binop (PLUS_EXPR, method_index, size_int (1));
|
||||
else
|
||||
/* 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 (MULT_EXPR, method_index,
|
||||
TYPE_SIZE_UNIT (nativecode_ptr_ptr_type_node));
|
||||
|
||||
if (TARGET_VTABLE_USES_DESCRIPTORS)
|
||||
method_index = size_binop (MULT_EXPR, method_index,
|
||||
size_int (TARGET_VTABLE_USES_DESCRIPTORS));
|
||||
}
|
||||
|
||||
func = fold (build (PLUS_EXPR, nativecode_ptr_ptr_type_node, dtable,
|
||||
convert (nativecode_ptr_ptr_type_node, method_index)));
|
||||
@ -1898,6 +1946,7 @@ build_invokeinterface (dtable, method)
|
||||
tree interface;
|
||||
tree idx;
|
||||
tree meth;
|
||||
tree otable_index;
|
||||
int i;
|
||||
|
||||
/* We expand invokeinterface here. _Jv_LookupInterfaceMethod() will
|
||||
@ -1917,16 +1966,24 @@ build_invokeinterface (dtable, method)
|
||||
interface = DECL_CONTEXT (method);
|
||||
layout_class_methods (interface);
|
||||
|
||||
i = 1;
|
||||
for (meth = TYPE_METHODS (interface); ; meth = TREE_CHAIN (meth), i++)
|
||||
if (flag_indirect_dispatch)
|
||||
{
|
||||
if (meth == method)
|
||||
{
|
||||
idx = build_int_2 (i, 0);
|
||||
break;
|
||||
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;
|
||||
for (meth = TYPE_METHODS (interface); ; meth = TREE_CHAIN (meth), i++)
|
||||
{
|
||||
if (meth == method)
|
||||
{
|
||||
idx = build_int_2 (i, 0);
|
||||
break;
|
||||
}
|
||||
if (meth == NULL_TREE)
|
||||
abort ();
|
||||
}
|
||||
if (meth == NULL_TREE)
|
||||
abort ();
|
||||
}
|
||||
|
||||
lookup_arg = tree_cons (NULL_TREE, dtable,
|
||||
|
@ -141,6 +141,18 @@ extern int compiling_from_source;
|
||||
/* List of all class filenames seen so far. */
|
||||
#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_filelist_file;
|
||||
@ -196,6 +208,10 @@ extern int flag_check_references;
|
||||
initialization optimization should be performed. */
|
||||
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. */
|
||||
extern const char *current_encoding;
|
||||
|
||||
@ -331,6 +347,11 @@ enum java_tree_index
|
||||
JTI_LINENUMBERS_TYPE,
|
||||
JTI_METHOD_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,
|
||||
|
||||
@ -370,6 +391,10 @@ enum java_tree_index
|
||||
JTI_ALL_CLASS_LIST,
|
||||
JTI_ALL_CLASS_FILENAME,
|
||||
|
||||
JTI_OTABLE_METHODS,
|
||||
JTI_OTABLE_DECL,
|
||||
JTI_OTABLE_SYMS_DECL,
|
||||
|
||||
JTI_MAX
|
||||
};
|
||||
|
||||
@ -565,6 +590,16 @@ extern tree java_global_trees[JTI_MAX];
|
||||
java_global_trees[JTI_METHOD_TYPE_NODE]
|
||||
#define 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 \
|
||||
java_global_trees[JTI_END_PARAMS_NODE]
|
||||
@ -1098,6 +1133,7 @@ extern void make_class_data PARAMS ((tree));
|
||||
extern void register_class PARAMS ((void));
|
||||
extern int alloc_name_constant PARAMS ((int, tree));
|
||||
extern void emit_register_classes PARAMS ((void));
|
||||
extern void emit_offset_symbol_table PARAMS ((void));
|
||||
extern void lang_init_source PARAMS ((int));
|
||||
extern void write_classfile PARAMS ((tree));
|
||||
extern char *print_int_node PARAMS ((tree));
|
||||
|
@ -1188,7 +1188,11 @@ yyparse ()
|
||||
|
||||
java_expand_classes ();
|
||||
if (!java_report_errors () && !flag_syntax_only)
|
||||
emit_register_classes ();
|
||||
{
|
||||
emit_register_classes ();
|
||||
if (flag_indirect_dispatch)
|
||||
emit_offset_symbol_table ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@ const char jvgenmain_spec[] =
|
||||
%{<fcompile-resource*}\
|
||||
%{<femit-class-file} %{<femit-class-files} %{<fencoding*}\
|
||||
%{<fuse-boehm-gc} %{<fhash-synchronization} %{<fjni}\
|
||||
%{<findirect-dispatch} \
|
||||
%{<fclasspath*} %{<fCLASSPATH*} %{<foutput-class-dir}\
|
||||
%{<fuse-divide-subroutine} %{<fno-use-divide-subroutine}\
|
||||
%{<fcheck-references} %{<fno-check-references}\
|
||||
|
@ -153,6 +153,10 @@ int flag_force_classes_archive_check;
|
||||
be tested alone, use STATIC_CLASS_INITIALIZATION_OPTIMIZATION_P instead. */
|
||||
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. */
|
||||
static int version_flag = 0;
|
||||
|
||||
@ -174,7 +178,8 @@ lang_f_options[] =
|
||||
{"jni", &flag_jni, 1},
|
||||
{"check-references", &flag_check_references, 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
|
||||
|
@ -1,3 +1,19 @@
|
||||
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
|
||||
|
@ -57,6 +57,12 @@ struct _Jv_VTable
|
||||
#endif
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user