From 9dfc2ec225a5a8f0a5d2a9b5853d0a19d728e129 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Wed, 1 Oct 2003 16:22:13 +0000 Subject: [PATCH] jcf-parse.c (java_parse_file): Write otable and atable. 2003-10-01 Andrew Haley * jcf-parse.c (java_parse_file): Write otable and atable. * java-tree.h (atable_methods): New. (atable_decl): New. (atable_syms_decl): New. (enum java_tree_index): Add JTI_ATABLE_METHODS, JTI_ATABLE_DECL, JTI_ATABLE_SYMS_DECL. Rename JTI_METHOD_SYMBOL* to JTI_SYMBOL*. (symbol_*type): Rename method_symbol* to symbol*type. (emit_offset_symbol_table): Delete. (emit_symbol_table): New. (get_symbol_table_index): New. (atable_type): New. * expr.c (build_field_ref): Handle flag_indirect_dispatch. (build_known_method_ref): Likewise. (get_symbol_table_index): Rename from get_offset_table_index. Parameterize to allow re-use by differing types of symbol table. (build_invokevirtual): Pass table to get_offset_table_index. * decl.c (java_init_decl_processing): Push types and decls for atable and atable_syyms. * class.c (build_static_field_ref): Handle flag_indirect_dispatch. (make_class_data): Add new fields atable and atable_syms. (emit_symbol_table): Rename from emit_offset_symbol_table. Parameterize to allow re-use by different types of symbol table. (build_symbol_entry): Renamed from build_method_symbols_entry. 2003-10-01 Andrew Haley * java/lang/natClass.cc (initializeClass): Check for otable and atable. (_Jv_LinkOffsetTable): Check for existence of atable. Rewrite loops using for(). Search superinterfaces. Check for fields as well as methods. Initialize atable as well as otable: check for static methods as well as virtual methods. * java/lang/Class.h (struct _Jv_AddressTable): New. (atable): New. (atable_syms): New. * include/jvm.h (_Jv_equalUtf8Consts): constify. * prims.cc (_Jv_equalUtf8Consts): constify. From-SVN: r71979 --- gcc/java/ChangeLog | 26 +++ gcc/java/class.c | 118 +++++++++----- gcc/java/decl.c | 47 ++++-- gcc/java/expr.c | 65 ++++++-- gcc/java/java-tree.h | 62 ++++--- gcc/java/jcf-parse.c | 11 +- libjava/ChangeLog | 14 ++ libjava/include/jvm.h | 2 +- libjava/java/lang/Class.h | 10 +- libjava/java/lang/natClass.cc | 262 ++++++++++++++++++++++++------ libjava/java/util/LinkedList.java | 2 +- libjava/prims.cc | 8 +- 12 files changed, 474 insertions(+), 153 deletions(-) diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index bf5da8c9ec9..ee3a016ba7d 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,29 @@ +2003-10-01 Andrew Haley + + * jcf-parse.c (java_parse_file): Write otable and atable. + * java-tree.h (atable_methods): New. + (atable_decl): New. + (atable_syms_decl): New. + (enum java_tree_index): Add JTI_ATABLE_METHODS, JTI_ATABLE_DECL, + JTI_ATABLE_SYMS_DECL. Rename JTI_METHOD_SYMBOL* to JTI_SYMBOL*. + (symbol_*type): Rename method_symbol* to symbol*type. + (emit_offset_symbol_table): Delete. + (emit_symbol_table): New. + (get_symbol_table_index): New. + (atable_type): New. + * expr.c (build_field_ref): Handle flag_indirect_dispatch. + (build_known_method_ref): Likewise. + (get_symbol_table_index): Rename from get_offset_table_index. + Parameterize to allow re-use by differing types of symbol table. + (build_invokevirtual): Pass table to get_offset_table_index. + * decl.c (java_init_decl_processing): Push types and decls for + atable and atable_syyms. + * class.c (build_static_field_ref): Handle flag_indirect_dispatch. + (make_class_data): Add new fields atable and atable_syms. + (emit_symbol_table): Rename from emit_offset_symbol_table. + Parameterize to allow re-use by different types of symbol table. + (build_symbol_entry): Renamed from build_method_symbols_entry. + 2003-09-30 Roger Sayle * jcf-write.c (generate_bytecode_insns): Implement evaluate-once diff --git a/gcc/java/class.c b/gcc/java/class.c index 552a4f45862..d64db51fbd3 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -59,7 +59,7 @@ static void add_interface_do (tree, tree, int); static tree maybe_layout_super_class (tree, tree); static void add_miranda_methods (tree, tree); static int assume_compiled (const char *); -static tree build_method_symbols_entry (tree); +static tree build_symbol_entry (tree); static GTY(()) rtx registerClass_libfunc; @@ -925,7 +925,8 @@ build_static_field_ref (tree fdecl) However, currently sometimes gcj is too eager and will end up returning the field itself, leading to an incorrect external reference being generated. */ - if (is_compiled + if ((is_compiled + && (! flag_indirect_dispatch || current_class == fclass)) || (FIELD_FINAL (fdecl) && DECL_INITIAL (fdecl) != NULL_TREE && (JSTRING_TYPE_P (TREE_TYPE (fdecl)) || JNUMERIC_TYPE_P (TREE_TYPE (fdecl))) @@ -939,7 +940,18 @@ build_static_field_ref (tree fdecl) } return fdecl; } - else + + if (flag_indirect_dispatch) + { + tree table_index + = build_int_2 (get_symbol_table_index (fdecl, &atable_methods), 0); + tree field_address + = build (ARRAY_REF, build_pointer_type (TREE_TYPE (fdecl)), + atable_decl, table_index); + return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl), + field_address)); + } + else { /* Compile as: * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */ @@ -1500,7 +1512,6 @@ make_class_data (tree type) : build (PLUS_EXPR, dtable_ptr_type, build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl), dtable_start_offset)); - if (otable_methods == NULL_TREE) { PUSH_FIELD_VALUE (cons, "otable", null_pointer_node); @@ -1511,9 +1522,25 @@ make_class_data (tree type) 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, + build1 (ADDR_EXPR, symbols_array_ptr_type, otable_syms_decl)); + TREE_CONSTANT (otable_decl) = 1; } + if (atable_methods == NULL_TREE) + { + PUSH_FIELD_VALUE (cons, "atable", null_pointer_node); + PUSH_FIELD_VALUE (cons, "atable_syms", null_pointer_node); + } + else + { + PUSH_FIELD_VALUE (cons, "atable", + build1 (ADDR_EXPR, atable_ptr_type, atable_decl)); + PUSH_FIELD_VALUE (cons, "atable_syms", + build1 (ADDR_EXPR, symbols_array_ptr_type, + atable_syms_decl)); + TREE_CONSTANT (atable_decl) = 1; + } + 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)); @@ -2098,58 +2125,59 @@ emit_register_classes (void) } } -/* Make a method_symbol_type (_Jv_MethodSymbol) node for METHOD. */ +/* Make a symbol_type (_Jv_MethodSymbol) node for DECL. */ static tree -build_method_symbols_entry (tree method) +build_symbol_entry (tree decl) { - tree clname, name, signature, method_symbol; + tree clname, name, signature, sym; - 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)); + clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl)))); + name = build_utf8_ref (DECL_NAME (decl)); + signature = build_java_signature (TREE_TYPE (decl)); 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; + START_RECORD_CONSTRUCTOR (sym, symbol_type); + PUSH_FIELD_VALUE (sym, "clname", clname); + PUSH_FIELD_VALUE (sym, "name", name); + PUSH_FIELD_VALUE (sym, "signature", signature); + FINISH_RECORD_CONSTRUCTOR (sym); + TREE_CONSTANT (sym) = 1; - return method_symbol; + return sym; } -/* Emit the offset symbols table for indirect virtual dispatch. */ +/* Emit a symbol table: used by -findirect-dispatch. */ -void -emit_offset_symbol_table (void) +tree +emit_symbol_table (tree name, tree the_table, tree decl_list, tree the_syms_decl, + tree the_array_element_type) { tree method_list, method, table, list, null_symbol; - tree otable_bound, otable_array_type; + tree table_size, the_array_type; int index; - /* Only emit an offset table if this translation unit actually made virtual - calls. */ - if (otable_methods == NULL_TREE) - return; + /* Only emit a table if this translation unit actually made any + references via it. */ + if (decl_list == NULL_TREE) + return the_table; /* Build a list of _Jv_MethodSymbols for each entry in otable_methods. */ index = 0; - method_list = otable_methods; + method_list = decl_list; list = NULL_TREE; while (method_list != NULL_TREE) { method = TREE_VALUE (method_list); - list = tree_cons (NULL_TREE, build_method_symbols_entry (method), list); + list = tree_cons (NULL_TREE, build_symbol_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); + START_RECORD_CONSTRUCTOR (null_symbol, 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); @@ -2159,24 +2187,26 @@ emit_offset_symbol_table (void) /* Put the list in the right order and make it a constructor. */ list = nreverse (list); - table = build_constructor (method_symbols_array_type, list); + table = build_constructor (symbols_array_type, 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); + DECL_INITIAL (the_syms_decl) = table; + DECL_ARTIFICIAL (the_syms_decl) = 1; + DECL_IGNORED_P (the_syms_decl) = 1; + rest_of_decl_compilation (the_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); + /* Now that its size is known, redefine the table as an + uninitialized static array of INDEX + 1 elements. The extra entry + is used by the runtime to track whether the table has been + initialized. */ + table_size = build_index_type (build_int_2 (index, 0)); + the_array_type = build_array_type (the_array_element_type, table_size); + the_table = build_decl (VAR_DECL, name, the_array_type); + TREE_STATIC (the_table) = 1; + TREE_READONLY (the_table) = 1; + rest_of_decl_compilation (the_table, NULL, 1, 0); + + return the_table; } void diff --git a/gcc/java/decl.c b/gcc/java/decl.c index 4e413de897d..8355431be58 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -621,32 +621,46 @@ java_init_decl_processing (void) one_elt_array_domain_type); TYPE_NONALIASED_COMPONENT (otable_type) = 1; otable_ptr_type = build_pointer_type (otable_type); + atable_type = build_array_type (ptr_type_node, + one_elt_array_domain_type); + TYPE_NONALIASED_COMPONENT (atable_type) = 1; + atable_ptr_type = build_pointer_type (atable_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); + symbol_type = make_node (RECORD_TYPE); + PUSH_FIELD (symbol_type, field, "clname", utf8const_ptr_type); + PUSH_FIELD (symbol_type, field, "name", utf8const_ptr_type); + PUSH_FIELD (symbol_type, field, "signature", utf8const_ptr_type); + FINISH_RECORD (symbol_type); - 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); + symbols_array_type = build_array_type (symbol_type, + one_elt_array_domain_type); + symbols_array_ptr_type = build_pointer_type (symbols_array_type); if (flag_indirect_dispatch) { - otable_decl = build_decl (VAR_DECL, get_identifier ("otable"), - otable_type); + otable_decl = build_decl (VAR_DECL, get_identifier ("otable"), otable_type); DECL_EXTERNAL (otable_decl) = 1; TREE_STATIC (otable_decl) = 1; TREE_READONLY (otable_decl) = 1; - pushdecl (otable_decl); - + TREE_CONSTANT (otable_decl) = 1; + pushdecl (otable_decl); otable_syms_decl = build_decl (VAR_DECL, get_identifier ("otable_syms"), - method_symbols_array_type); + symbols_array_type); TREE_STATIC (otable_syms_decl) = 1; TREE_CONSTANT (otable_syms_decl) = 1; pushdecl (otable_syms_decl); + + atable_decl = build_decl (VAR_DECL, get_identifier ("atable"), atable_type); + DECL_EXTERNAL (atable_decl) = 1; + TREE_STATIC (atable_decl) = 1; + TREE_READONLY (atable_decl) = 1; + TREE_CONSTANT (atable_decl) = 1; + pushdecl (atable_decl); + atable_syms_decl = build_decl (VAR_DECL, get_identifier ("atable_syms"), + symbols_array_type); + TREE_STATIC (atable_syms_decl) = 1; + TREE_CONSTANT (atable_syms_decl) = 1; + pushdecl (atable_syms_decl); } PUSH_FIELD (object_type_node, field, "vtable", dtable_ptr_type); @@ -684,7 +698,10 @@ java_init_decl_processing (void) 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); + symbols_array_ptr_type); + PUSH_FIELD (class_type_node, field, "atable", atable_ptr_type); + PUSH_FIELD (class_type_node, field, "atable_syms", + 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); diff --git a/gcc/java/expr.c b/gcc/java/expr.c index 994a8c52ed3..2c9ac09e735 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -84,7 +84,6 @@ static tree build_java_check_indexed_type (tree, tree); static tree case_identity (tree, tree); static unsigned char peek_opcode_at_pc (struct JCF *, int, int); static int emit_init_test_initialization (void **entry, void * ptr); -static int get_offset_table_index (tree); static GTY(()) tree operand_type[59]; @@ -1510,6 +1509,25 @@ build_field_ref (tree self_value, tree self_class, tree name) tree base_type = promote_type (base_class); if (base_type != TREE_TYPE (self_value)) self_value = fold (build1 (NOP_EXPR, base_type, self_value)); + if (flag_indirect_dispatch + && current_class != self_class) + /* FIXME: current_class != self_class is not exactly the right + test. What we really want to know is whether self_class is + in the same translation unit as current_class. If it is, + we can make a direct reference. */ + { + tree otable_index + = build_int_2 + (get_symbol_table_index (field_decl, &otable_methods), 0); + tree field_offset = build (ARRAY_REF, integer_type_node, otable_decl, + otable_index); + tree address + = fold (build (PLUS_EXPR, + build_pointer_type (TREE_TYPE (field_decl)), + self_value, field_offset)); + return fold (build1 (INDIRECT_REF, TREE_TYPE (field_decl), address)); + } + self_value = build_java_indirect_ref (TREE_TYPE (TREE_TYPE (self_value)), self_value, check); return fold (build (COMPONENT_REF, TREE_TYPE (field_decl), @@ -1744,8 +1762,19 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED, tree func; if (is_compiled_class (self_type)) { - make_decl_rtl (method, NULL); - func = build1 (ADDR_EXPR, method_ptr_type_node, method); + if (!flag_indirect_dispatch + || (!TREE_PUBLIC (method) && DECL_CONTEXT (method))) + { + make_decl_rtl (method, NULL); + func = build1 (ADDR_EXPR, method_ptr_type_node, method); + } + else + { + tree table_index = build_int_2 (get_symbol_table_index + (method, &atable_methods), 0); + func = build (ARRAY_REF, method_ptr_type_node, atable_decl, + table_index); + } } else { @@ -1816,27 +1845,29 @@ invoke_build_dtable (int is_invoke_interface, tree 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. */ +/* Determine the index in SYMBOL_TABLE for a reference to the decl + T. If this decl has not been seen before, it will be added to the + otable_methods. If it has, the existing table slot will be + reused. */ -static int -get_offset_table_index (tree method) +int +get_symbol_table_index (tree t, tree *symbol_table) { int i = 1; tree method_list; - - if (otable_methods == NULL_TREE) + + if (*symbol_table == NULL_TREE) { - otable_methods = build_tree_list (method, method); + *symbol_table = build_tree_list (t, t); return 1; } - method_list = otable_methods; + method_list = *symbol_table; while (1) { - if (TREE_VALUE (method_list) == method) + tree value = TREE_VALUE (method_list); + if (value == t) return i; i++; if (TREE_CHAIN (method_list) == NULL_TREE) @@ -1845,7 +1876,7 @@ get_offset_table_index (tree method) method_list = TREE_CHAIN (method_list); } - TREE_CHAIN (method_list) = build_tree_list (method, method); + TREE_CHAIN (method_list) = build_tree_list (t, t); return i; } @@ -1860,7 +1891,8 @@ build_invokevirtual (tree dtable, tree method) if (flag_indirect_dispatch) { - otable_index = build_int_2 (get_offset_table_index (method), 0); + otable_index + = build_int_2 (get_symbol_table_index (method, &otable_methods), 0); method_index = build (ARRAY_REF, integer_type_node, otable_decl, otable_index); } @@ -1924,7 +1956,8 @@ build_invokeinterface (tree dtable, tree method) if (flag_indirect_dispatch) { - otable_index = build_int_2 (get_offset_table_index (method), 0); + otable_index + = build_int_2 (get_symbol_table_index (method, &otable_methods), 0); idx = build (ARRAY_REF, integer_type_node, otable_decl, otable_index); } else diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 8f524284c48..42f99b57e95 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -146,17 +146,26 @@ 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. */ +/* List of virtual decls referred to by this translation unit, used to + generate virtual method offset symbol table. */ #define otable_methods java_global_trees [JTI_OTABLE_METHODS] +/* List of static decls referred to by this translation unit, used to + generate virtual method offset symbol table. */ +#define atable_methods java_global_trees [JTI_ATABLE_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. */ +/* The virtual 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 static address table. */ +#define atable_decl java_global_trees [JTI_ATABLE_DECL] -/* The virtual method offset symbol table. Used by the runtime to fill out the - otable. */ +/* The virtual offset symbol table. Used by the runtime to fill out + the otable. */ #define otable_syms_decl java_global_trees [JTI_OTABLE_SYMS_DECL] +/* The static symbol table. Used by the runtime to fill out the + otable. */ +#define atable_syms_decl java_global_trees [JTI_ATABLE_SYMS_DECL] extern int flag_emit_class_files; @@ -364,9 +373,11 @@ enum java_tree_index 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_ATABLE_TYPE, + JTI_ATABLE_PTR_TYPE, + JTI_SYMBOL_TYPE, + JTI_SYMBOLS_ARRAY_TYPE, + JTI_SYMBOLS_ARRAY_PTR_TYPE, JTI_END_PARAMS_NODE, @@ -409,6 +420,10 @@ enum java_tree_index JTI_OTABLE_DECL, JTI_OTABLE_SYMS_DECL, + JTI_ATABLE_METHODS, + JTI_ATABLE_DECL, + JTI_ATABLE_SYMS_DECL, + JTI_PREDEF_FILENAMES, JTI_MAX @@ -602,14 +617,18 @@ extern GTY(()) tree java_global_trees[JTI_MAX]; java_global_trees[JTI_METHOD_PTR_TYPE_NODE] #define otable_type \ java_global_trees[JTI_OTABLE_TYPE] +#define atable_type \ + java_global_trees[JTI_ATABLE_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 atable_ptr_type \ + java_global_trees[JTI_ATABLE_PTR_TYPE] +#define symbol_type \ + java_global_trees[JTI_SYMBOL_TYPE] +#define symbols_array_type \ + java_global_trees[JTI_SYMBOLS_ARRAY_TYPE] +#define symbols_array_ptr_type \ + java_global_trees[JTI_SYMBOLS_ARRAY_PTR_TYPE] #define end_params_node \ java_global_trees[JTI_END_PARAMS_NODE] @@ -1199,7 +1218,7 @@ extern void make_class_data (tree); extern void register_class (void); extern int alloc_name_constant (int, tree); extern void emit_register_classes (void); -extern void emit_offset_symbol_table (void); +extern tree emit_symbol_table (tree, tree, tree, tree, tree); extern void lang_init_source (int); extern void write_classfile (tree); extern char *print_int_node (tree); @@ -1299,6 +1318,7 @@ extern void init_resource_processing (void); extern void start_complete_expand_method (tree); extern void java_expand_body (tree); +extern int get_symbol_table_index (tree, tree *); #define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL) @@ -1658,11 +1678,11 @@ extern tree *type_map; /* Append a field initializer to CONS for a field with the given VALUE. NAME is a char* string used for error checking; the initializer must be specified in order. */ -#define PUSH_FIELD_VALUE(CONS, NAME, VALUE) {\ - tree field = TREE_CHAIN(CONS);\ - if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), NAME) != 0) abort();\ - CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS));\ - TREE_CHAIN(CONS) = TREE_CHAIN (field); } + #define PUSH_FIELD_VALUE(CONS, NAME, VALUE) {\ + tree field = TREE_CHAIN(CONS);\ + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), NAME) != 0) abort();\ + CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS));\ + TREE_CHAIN(CONS) = TREE_CHAIN (field); } /* Finish creating a record CONSTRUCTOR CONS. */ #define FINISH_RECORD_CONSTRUCTOR(CONS) \ diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c index 4abd6ceac6e..de4b213a6c6 100644 --- a/gcc/java/jcf-parse.c +++ b/gcc/java/jcf-parse.c @@ -1127,7 +1127,16 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED) /* Emit the .jcf section. */ emit_register_classes (); if (flag_indirect_dispatch) - emit_offset_symbol_table (); + { + otable_decl + = emit_symbol_table + (get_identifier ("otable"), + otable_decl, otable_methods, otable_syms_decl, integer_type_node); + atable_decl + = emit_symbol_table + (get_identifier ("atable"), + atable_decl, atable_methods, atable_syms_decl, ptr_type_node); + } } write_resource_constructor (); diff --git a/libjava/ChangeLog b/libjava/ChangeLog index d12987a7227..a86041acd2d 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,17 @@ +2003-10-01 Andrew Haley + + * java/lang/natClass.cc (initializeClass): Check for otable and + atable. + (_Jv_LinkOffsetTable): Check for existence of atable. Rewrite + loops using for(). Search superinterfaces. Check for fields as + well as methods. Initialize atable as well as otable: check for + static methods as well as virtual methods. + * java/lang/Class.h (struct _Jv_AddressTable): New. + (atable): New. + (atable_syms): New. + * include/jvm.h (_Jv_equalUtf8Consts): constify. + * prims.cc (_Jv_equalUtf8Consts): constify. + 2003-09-29 Tom Tromey PR libgcj/10596: diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index ed6c61ec50d..b28f61a0e97 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -145,7 +145,7 @@ extern int _Jv_strLengthUtf8(char* str, int len); typedef struct _Jv_Utf8Const Utf8Const; _Jv_Utf8Const *_Jv_makeUtf8Const (char *s, int len); _Jv_Utf8Const *_Jv_makeUtf8Const (jstring string); -extern jboolean _Jv_equalUtf8Consts (_Jv_Utf8Const *, _Jv_Utf8Const *); +extern jboolean _Jv_equalUtf8Consts (const _Jv_Utf8Const *, const _Jv_Utf8Const *); extern jboolean _Jv_equal (_Jv_Utf8Const *, jstring, jint); extern jboolean _Jv_equaln (_Jv_Utf8Const *, jstring, jint); diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index 7fe96d0a01f..7572c6cfdb2 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -125,6 +125,12 @@ struct _Jv_OffsetTable jint offsets[]; }; +struct _Jv_AddressTable +{ + jint state; + void *addresses[]; +}; + #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1) #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) @@ -324,7 +330,7 @@ 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_LinkSymbolTable (jclass); friend void _Jv_LayoutVTableMethods (jclass klass); friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *); friend void _Jv_MakeVTable (jclass); @@ -404,6 +410,8 @@ private: _Jv_OffsetTable *otable; // Offset table symbols. _Jv_MethodSymbol *otable_syms; + _Jv_AddressTable *atable; + _Jv_MethodSymbol *atable_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 551a5312fe5..aa5867fc871 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -36,6 +36,7 @@ details. */ #include #include #include +#include #include #include #include @@ -790,7 +791,7 @@ java::lang::Class::initializeClass (void) so ensure internal tables are built. */ _Jv_PrepareConstantTimeTables (this); _Jv_MakeVTable(this); - _Jv_LinkOffsetTable(this); + _Jv_LinkSymbolTable(this); return; } @@ -830,8 +831,8 @@ java::lang::Class::initializeClass (void) if (vtable == NULL) _Jv_MakeVTable(this); - if (otable != NULL && otable->state == 0) - _Jv_LinkOffsetTable(this); + if (otable || atable) + _Jv_LinkSymbolTable(this); // Steps 8, 9, 10, 11. try @@ -1533,75 +1534,238 @@ java::lang::Class::getProtectionDomain0 () return protectionDomain; } -// Functions for indirect dispatch (symbolic virtual method binding) support. +// Functions for indirect dispatch (symbolic virtual binding) support. + +// There are two tables, atable and otable. atable is an array of +// addresses, and otable is an array of offsets, and these are used +// for static and virtual members respectively. + +// {a,o}table_syms is an array of _Jv_MethodSymbols. Each such symbol +// is a tuple of {classname, member name, signature}. +// _Jv_LinkSymbolTable() scans these two arrays and fills in the +// corresponding atable and otable with the addresses of static +// members and the offsets of virtual members. + +// The offset (in bytes) for each resolved method or field is placed +// at the corresponding position in the virtual method offset table +// (klass->otable). + +// The same otable and atable may be shared by many classes. -// 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) +_Jv_LinkSymbolTable(jclass klass) { - //// FIXME: Need to lock the otable //// + //// FIXME: Need to lock the tables //// + int index = 0; + _Jv_MethodSymbol sym; if (klass->otable == NULL || klass->otable->state != 0) - return; - + goto atable; + klass->otable->state = 1; - int index = 0; - _Jv_MethodSymbol sym = klass->otable_syms[0]; - - while (sym.name != NULL) + for (index = 0; sym = klass->otable_syms[index], sym.name != NULL; index++) { jclass target_class = _Jv_FindClass (sym.class_name, NULL); _Jv_Method *meth = NULL; + + const _Jv_Utf8Const *signature = sym.signature; + + // FIXME: This should be special index for ThrowNoSuchMethod(). + klass->otable->offsets[index] = -1; - if (target_class != NULL) - if (target_class->isInterface()) + if (target_class == NULL) + continue; + + 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 (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) + { + for (int i=0; i < cls->method_count; i++) + { + meth = &cls->methods[i]; + if (_Jv_equalUtf8Consts (sym.name, meth->name) + && _Jv_equalUtf8Consts (signature, meth->signature)) + { + klass->otable->offsets[index] = i + 1; + goto found; + } + } + + } + found: + continue; + } + + // We're looking for a field or a method, and we can tell + // which is needed by looking at the signature. + if (signature->length >= 2 + && signature->data[0] == '(') + { + // 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); + } + + continue; + } + + // try fields + { + _Jv_Field *the_field = NULL; + + for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) { - // 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++) + for (int i = 0; i < cls->field_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; - } + _Jv_Field *field = &cls->fields[i]; + if (! _Jv_equalUtf8Consts (field->name, sym.name)) + continue; + + // FIXME: What access checks should we perform here? +// if (_Jv_CheckAccess (klass, cls, field->flags)) +// { + + if (!field->isResolved ()) + _Jv_ResolveField (field, cls->loader); + +// if (field_type != 0 && field->type != field_type) +// throw new java::lang::LinkageError +// (JvNewStringLatin1 +// ("field type mismatch with different loaders")); + + the_field = field; + goto end_of_field_search; + } + } + end_of_field_search: + if (the_field != NULL) + { + if (the_field->flags & 0x0008 /* Modifier::STATIC */) + { + throw new java::lang::IncompatibleClassChangeError; + } + else + { + klass->otable->offsets[index] = the_field->u.boffset; } } 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); - } + throw new java::lang::NoSuchFieldError + (_Jv_NewStringUtf8Const (sym.name)); + } + } + } - meth = _Jv_LookupDeclaredMethod(target_class, sym.name, - sym.signature); + atable: + if (klass->atable == NULL + || klass->atable->state != 0) + return; - if (meth != NULL) + klass->atable->state = 1; + + for (index = 0; sym = klass->atable_syms[index], sym.name != NULL; index++) + { + jclass target_class = _Jv_FindClass (sym.class_name, NULL); + _Jv_Method *meth = NULL; + const _Jv_Utf8Const *signature = sym.signature; + + // ??? Setting this pointer to null will at least get us a + // NullPointerException + klass->atable->addresses[index] = NULL; + + if (target_class == NULL) + continue; + + // We're looking for a static field or a static method, and we + // can tell which is needed by looking at the signature. + if (signature->length >= 2 + && signature->data[0] == '(') + { + // 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->atable->addresses[index] = meth->ncode; + else + klass->atable->addresses[index] = (void *)_Jv_ThrowNoSuchMethodError; + + continue; + } + + // try fields + { + _Jv_Field *the_field = NULL; + + for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) + { + for (int i = 0; i < cls->field_count; i++) { - klass->otable->offsets[index] = - _Jv_VTable::idx_to_offset (meth->index); + _Jv_Field *field = &cls->fields[i]; + if (! _Jv_equalUtf8Consts (field->name, sym.name)) + continue; + + // FIXME: What access checks should we perform here? +// if (_Jv_CheckAccess (klass, cls, field->flags)) +// { + + if (!field->isResolved ()) + _Jv_ResolveField (field, cls->loader); + +// if (field_type != 0 && field->type != field_type) +// throw new java::lang::LinkageError +// (JvNewStringLatin1 +// ("field type mismatch with different loaders")); + + the_field = field; + goto end_of_static_field_search; } } - - if (meth == NULL) - // FIXME: This should be special index for ThrowNoSuchMethod(). - klass->otable->offsets[index] = -1; - - sym = klass->otable_syms[++index]; + end_of_static_field_search: + if (the_field != NULL) + { + if (the_field->flags & 0x0008 /* Modifier::STATIC */) + { + klass->atable->addresses[index] = the_field->u.addr; + } + else + { + throw new java::lang::IncompatibleClassChangeError; + } + } + else + { + throw new java::lang::NoSuchFieldError + (_Jv_NewStringUtf8Const (sym.name)); + } + } } } diff --git a/libjava/java/util/LinkedList.java b/libjava/java/util/LinkedList.java index c891f8230f0..2f21fb46735 100644 --- a/libjava/java/util/LinkedList.java +++ b/libjava/java/util/LinkedList.java @@ -1,4 +1,4 @@ -/* LinkedList.java -- Linked list implementation of the List interface + /* LinkedList.java -- Linked list implementation of the List interface Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Classpath. diff --git a/libjava/prims.cc b/libjava/prims.cc index 8208995460e..f15c24b7962 100644 --- a/libjava/prims.cc +++ b/libjava/prims.cc @@ -165,10 +165,10 @@ SIGNAL_HANDLER (catch_fpe) jboolean -_Jv_equalUtf8Consts (Utf8Const* a, Utf8Const *b) +_Jv_equalUtf8Consts (const Utf8Const* a, const Utf8Const *b) { int len; - _Jv_ushort *aptr, *bptr; + const _Jv_ushort *aptr, *bptr; if (a == b) return true; if (a->hash != b->hash) @@ -176,8 +176,8 @@ _Jv_equalUtf8Consts (Utf8Const* a, Utf8Const *b) len = a->length; if (b->length != len) return false; - aptr = (_Jv_ushort *)a->data; - bptr = (_Jv_ushort *)b->data; + aptr = (const _Jv_ushort *)a->data; + bptr = (const _Jv_ushort *)b->data; len = (len + 1) >> 1; while (--len >= 0) if (*aptr++ != *bptr++)