diff options
author | Bryce McKinlay <bryce@waitaki.otago.ac.nz> | 2001-12-15 08:31:49 +0000 |
---|---|---|
committer | Bryce McKinlay <bryce@waitaki.otago.ac.nz> | 2001-12-15 08:31:49 +0000 |
commit | 090564a63d08fbcc0358c321b21602ec4c7fd2b2 (patch) | |
tree | a15d17366ad109cb78a0bc4f4aaf8e142550387d | |
parent | 8c2bf0e36b51fe679915dfc0c248e539778e7be1 (diff) |
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.
git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@48038 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/java/ChangeLog | 30 | ||||
-rw-r--r-- | gcc/java/class.c | 124 | ||||
-rw-r--r-- | gcc/java/decl.c | 35 | ||||
-rw-r--r-- | gcc/java/expr.c | 95 | ||||
-rw-r--r-- | gcc/java/java-tree.h | 36 | ||||
-rw-r--r-- | gcc/java/jcf-parse.c | 6 | ||||
-rw-r--r-- | gcc/java/jvspec.c | 1 | ||||
-rw-r--r-- | gcc/java/lang.c | 7 | ||||
-rw-r--r-- | libjava/ChangeLog | 16 | ||||
-rw-r--r-- | libjava/include/jvm.h | 6 | ||||
-rw-r--r-- | libjava/java/lang/Class.h | 23 | ||||
-rw-r--r-- | libjava/java/lang/natClass.cc | 193 | ||||
-rw-r--r-- | libjava/java/lang/natClassLoader.cc | 7 |
13 files changed, 550 insertions, 29 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 192b6bc104d..46e3e57db6c 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -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 diff --git a/gcc/java/class.c b/gcc/java/class.c index 5695aba3e40..6b05435c11e 100644 --- a/gcc/java/class.c +++ b/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 () { diff --git a/gcc/java/decl.c b/gcc/java/decl.c index 17b3607a871..4cfa9ba7ee0 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -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); diff --git a/gcc/java/expr.c b/gcc/java/expr.c index ef1a13959e1..e5d141ea5e4 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -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, diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 9d11bf6baf1..17a06382815 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -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)); diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c index 15dcd071e5f..61d09729727 100644 --- a/gcc/java/jcf-parse.c +++ b/gcc/java/jcf-parse.c @@ -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; } diff --git a/gcc/java/jvspec.c b/gcc/java/jvspec.c index 1b53bf5a7a0..1fd4f4cc87a 100644 --- a/gcc/java/jvspec.c +++ b/gcc/java/jvspec.c @@ -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}\ diff --git a/gcc/java/lang.c b/gcc/java/lang.c index c07c5868017..11e036ca38a 100644 --- a/gcc/java/lang.c +++ b/gcc/java/lang.c @@ -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 diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 3a3294cc366..39375cf8612 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,5 +1,21 @@ 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 the bitset. (andNot): Likewise. diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 57ba44fbfad..ada8e11a2e1 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -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); }; diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index aac5f12dd26..20523912e58 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -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. diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 54289b34102..6dfe14bab71 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -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); +} diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc index 59aca071ea2..ffe5b18fbe0 100644 --- a/libjava/java/lang/natClassLoader.cc +++ b/libjava/java/lang/natClassLoader.cc @@ -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 (); } |