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:
Bryce McKinlay 2001-12-15 08:31:49 +00:00 committed by Bryce McKinlay
parent ed86a83d51
commit 861ef92859
13 changed files with 550 additions and 29 deletions

View File

@ -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

View File

@ -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 ()
{

View File

@ -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);

View File

@ -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,

View File

@ -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));

View File

@ -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;
}

View File

@ -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}\

View File

@ -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

View File

@ -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

View File

@ -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);
};

View File

@ -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.

View File

@ -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);
}

View File

@ -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 ();
}