diff options
Diffstat (limited to 'gcc')
-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 |
8 files changed, 307 insertions, 27 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 |