X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fjava%2Fclass.c;h=f5c55979cd8237850e3f7deb3335961ac68725b4;hb=e6ec293d610cde9e28de78abff8a011c62241b07;hp=516ff8a38400e5c0492c33c604306435162b9c2f;hpb=7ad6876a9f0dff76e33dab6c0b59102017e3531c;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/java/class.c b/gcc/java/class.c index 516ff8a3840..f5c55979cd8 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -1,5 +1,5 @@ /* Functions related to building classes and their related objects. - Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU CC. @@ -55,11 +55,10 @@ static tree get_dispatch_table PARAMS ((tree, tree)); static void add_interface_do PARAMS ((tree, tree, int)); static tree maybe_layout_super_class PARAMS ((tree, tree)); 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 rtx registerClass_libfunc; -static rtx registerResource_libfunc; +static tree build_method_symbols_entry PARAMS ((tree)); + +static GTY(()) rtx registerClass_libfunc; +static GTY(()) rtx registerResource_libfunc; extern struct obstack permanent_obstack; struct obstack temporary_obstack; @@ -93,8 +92,7 @@ static assume_compiled_node *find_assume_compiled_node static assume_compiled_node *assume_compiled_tree; -static tree class_roots[5] -= { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }; +static GTY(()) tree class_roots[5]; #define registered_class class_roots[0] #define fields_ident class_roots[1] /* get_identifier ("fields") */ #define info_ident class_roots[2] /* get_identifier ("info") */ @@ -284,21 +282,7 @@ make_class () { tree type; type = make_node (RECORD_TYPE); -#ifdef JAVA_USE_HANDLES - tree field1 = build_decl (FIELD_DECL, get_identifier ("obj"), - build_pointer_type (type)); - tree field2 = build_decl (FIELD_DECL, get_identifier ("methods"), - methodtable_ptr_type); - tree handle_type = make_node (RECORD_TYPE); - TREE_CHAIN (field1) = field2; - TYPE_FIELDS (handle_type) = field1; - TYPE_BINFO (type) = make_tree_vec (7); - TYPE_BINFO (handle_type) = make_tree_vec (7); - BINFO_HANDLE (TYPE_BINFO (handle_type)) = type; - BINFO_HANDLE (TYPE_BINFO (type)) = handle_type; -#else TYPE_BINFO (type) = make_tree_vec (6); -#endif MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type); return type; @@ -349,21 +333,12 @@ push_class (class_type, class_name) signature = identifier_subst (class_name, "L", '.', '/', ";"); IDENTIFIER_SIGNATURE_TYPE (signature) = build_pointer_type (class_type); - /* Setting DECL_ARTIFICAL forces dbxout.c to specific the type is + /* Setting DECL_ARTIFICIAL forces dbxout.c to specific the type is both a typedef and in the struct name-space. We may want to re-visit this later, but for now it reduces the changes needed for gdb. */ DECL_ARTIFICIAL (decl) = 1; pushdecl_top_level (decl); -#ifdef JAVA_USE_HANDLES - { - tree handle_name = identifier_subst (class_name, - "Handle$", '.', '.', ""); - tree handle_decl = build_decl (TYPE_DECL, handle_name, - CLASS_TO_HANDLE_TYPE (class_type)); - pushdecl (handle_decl); - } -#endif return decl; } @@ -423,6 +398,7 @@ set_class_decl_access_flags (access_flags, class_decl) if (access_flags & ACC_STATIC) CLASS_STATIC (class_decl) = 1; if (access_flags & ACC_PRIVATE) CLASS_PRIVATE (class_decl) = 1; if (access_flags & ACC_PROTECTED) CLASS_PROTECTED (class_decl) = 1; + if (access_flags & ACC_STRICT) CLASS_STRICTFP (class_decl) = 1; } /* Return length of inheritance chain of CLAS, where java.lang.Object is 0, @@ -541,6 +517,7 @@ add_interface_do (basetype_vec, interface_class, i) tree interface_binfo = make_tree_vec (6); BINFO_TYPE (interface_binfo) = interface_class; BINFO_OFFSET (interface_binfo) = integer_zero_node; + BINFO_VPTR_FIELD (interface_binfo) = integer_zero_node; TREE_VIA_VIRTUAL (interface_binfo) = 1; TREE_VIA_PUBLIC (interface_binfo) = 1; TREE_VEC_ELT (basetype_vec, i) = interface_binfo; @@ -618,49 +595,12 @@ build_java_method_type (fntype, this_class, access_flags) { if (access_flags & ACC_STATIC) return fntype; - return build_method_type (CLASS_TO_HANDLE_TYPE (this_class), fntype); -} - -static struct hash_entry * -init_test_hash_newfunc (entry, table, string) - struct hash_entry *entry; - struct hash_table *table; - hash_table_key string ATTRIBUTE_UNUSED; -{ - struct init_test_hash_entry *ret = (struct init_test_hash_entry *) entry; - if (ret == NULL) - { - ret = ((struct init_test_hash_entry *) - hash_allocate (table, sizeof (struct init_test_hash_entry))); - if (ret == NULL) - return NULL; - } - ret->init_test_decl = 0; - return (struct hash_entry *) ret; -} - -/* Hash table helpers. Also reused in find_applicable_accessible_methods_list - (parse.y). The hash of a tree node is its pointer value, comparison - is direct. */ - -unsigned long -java_hash_hash_tree_node (k) - hash_table_key k; -{ - return (long) k; -} - -bool -java_hash_compare_tree_node (k1, k2) - hash_table_key k1; - hash_table_key k2; -{ - return ((char*) k1 == (char*) k2); + return build_method_type (this_class, fntype); } tree -add_method_1 (handle_class, access_flags, name, function_type) - tree handle_class; +add_method_1 (this_class, access_flags, name, function_type) + tree this_class; int access_flags; tree name; tree function_type; @@ -668,33 +608,37 @@ add_method_1 (handle_class, access_flags, name, function_type) tree method_type, fndecl; method_type = build_java_method_type (function_type, - handle_class, access_flags); + this_class, access_flags); fndecl = build_decl (FUNCTION_DECL, name, method_type); - DECL_CONTEXT (fndecl) = handle_class; + DECL_CONTEXT (fndecl) = this_class; DECL_LANG_SPECIFIC (fndecl) = (struct lang_decl *) ggc_alloc_cleared (sizeof (struct lang_decl)); + DECL_LANG_SPECIFIC (fndecl)->desc = LANG_DECL_FUNC; /* Initialize the static initializer test table. */ - hash_table_init (&DECL_FUNCTION_INIT_TEST_TABLE (fndecl), - init_test_hash_newfunc, java_hash_hash_tree_node, - java_hash_compare_tree_node); + + DECL_FUNCTION_INIT_TEST_TABLE (fndecl) = + java_treetreehash_create (10, 1); /* Initialize the initialized (static) class table. */ if (access_flags & ACC_STATIC) - hash_table_init (&DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl), - init_test_hash_newfunc, java_hash_hash_tree_node, - java_hash_compare_tree_node); + DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl) = + htab_create_ggc (50, htab_hash_pointer, htab_eq_pointer, NULL); + + /* Initialize the static method invocation compound list */ + DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND (fndecl) = NULL_TREE; - /* Initialize the static method invocation compound table */ - if (STATIC_CLASS_INIT_OPT_P ()) - hash_table_init (&DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND (fndecl), - init_test_hash_newfunc, java_hash_hash_tree_node, - java_hash_compare_tree_node); + TREE_CHAIN (fndecl) = TYPE_METHODS (this_class); + TYPE_METHODS (this_class) = fndecl; - TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class); - TYPE_METHODS (handle_class) = fndecl; + /* Notice that this is a finalizer and update the class type + accordingly. This is used to optimize instance allocation. */ + if (name == finalize_identifier_node + && TREE_TYPE (function_type) == void_type_node + && TREE_VALUE (TYPE_ARG_TYPES (function_type)) == void_type_node) + HAS_FINALIZER_P (this_class) = 1; if (access_flags & ACC_PUBLIC) METHOD_PUBLIC (fndecl) = 1; if (access_flags & ACC_PROTECTED) METHOD_PROTECTED (fndecl) = 1; @@ -712,6 +656,7 @@ add_method_1 (handle_class, access_flags, name, function_type) if (access_flags & ACC_SYNCHRONIZED) METHOD_SYNCHRONIZED (fndecl) = 1; if (access_flags & ACC_ABSTRACT) METHOD_ABSTRACT (fndecl) = 1; if (access_flags & ACC_TRANSIENT) METHOD_TRANSIENT (fndecl) = 1; + if (access_flags & ACC_STRICT) METHOD_STRICTFP (fndecl) = 1; return fndecl; } @@ -726,7 +671,6 @@ add_method (this_class, access_flags, name, method_sig) tree name; tree method_sig; { - tree handle_class = CLASS_TO_HANDLE_TYPE (this_class); tree function_type, fndecl; const unsigned char *sig = (const unsigned char *) IDENTIFIER_POINTER (method_sig); @@ -735,7 +679,7 @@ add_method (this_class, access_flags, name, method_sig) fatal_error ("bad method signature"); function_type = get_type_from_signature (method_sig); - fndecl = add_method_1 (handle_class, access_flags, name, function_type); + fndecl = add_method_1 (this_class, access_flags, name, function_type); set_java_signature (TREE_TYPE (fndecl), method_sig); return fndecl; } @@ -766,7 +710,11 @@ add_field (class, name, field_type, flags) /* Always make field externally visible. This is required so that native methods can always access the field. */ TREE_PUBLIC (field) = 1; + /* Considered external until we know what classes are being + compiled into this object file. */ + DECL_EXTERNAL (field) = 1; } + return field; } @@ -779,7 +727,7 @@ set_constant_value (field, constant) if (field == NULL_TREE) warning ("misplaced ConstantValue attribute (not in any field)"); else if (DECL_INITIAL (field) != NULL_TREE) - warning ("duplicate ConstanValue atribute for field '%s'", + warning ("duplicate ConstantValue attribute for field '%s'", IDENTIFIER_POINTER (DECL_NAME (field))); else { @@ -846,7 +794,7 @@ hashUtf8String (str, len) void compile_resource_file (name, filename) char *name; - char *filename; + const char *filename; { struct stat stat_buf; int fd; @@ -916,8 +864,11 @@ compile_resource_file (name, filename) current_function_decl = init_decl; DECL_RESULT (init_decl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node); - /* DECL_EXTERNAL (init_decl) = 1;*/ - TREE_PUBLIC (init_decl) = 1; + + /* It can be a static function as long as collect2 does not have + to scan the object file to find its ctor/dtor routine. */ + TREE_PUBLIC (init_decl) = ! targetm.have_ctors_dtors; + pushlevel (0); make_decl_rtl (init_decl, NULL); init_function_start (init_decl, input_filename, 0); @@ -986,6 +937,23 @@ build_utf8_ref (name) TREE_READONLY (decl) = 1; TREE_THIS_VOLATILE (decl) = 0; DECL_INITIAL (decl) = cinit; +#ifdef HAVE_GAS_SHF_MERGE + { + int decl_size; + /* Ensure decl_size is a multiple of utf8const_type's alignment. */ + decl_size = (name_len + 5 + TYPE_ALIGN_UNIT (utf8const_type) - 1) + & ~(TYPE_ALIGN_UNIT (utf8const_type) - 1); + if (flag_merge_constants && decl_size < 256) + { + char buf[32]; + int flags = (SECTION_OVERRIDE + | SECTION_MERGE | (SECTION_ENTSIZE & decl_size)); + sprintf (buf, ".rodata.jutf8.%d", decl_size); + named_section_flags (buf, flags); + DECL_SECTION_NAME (decl) = build_string (strlen (buf), buf); + } + } +#endif TREE_CHAIN (decl) = utf8_decl_list; layout_decl (decl, 0); pushdecl (decl); @@ -1026,13 +994,13 @@ build_class_ref (type) TREE_PUBLIC (decl) = 1; DECL_IGNORED_P (decl) = 1; DECL_ARTIFICIAL (decl) = 1; + if (is_compiled == 1) + DECL_EXTERNAL (decl) = 1; SET_DECL_ASSEMBLER_NAME (decl, java_mangle_class_field (&temporary_obstack, type)); make_decl_rtl (decl, NULL); pushdecl_top_level (decl); - if (is_compiled == 1) - DECL_EXTERNAL (decl) = 1; } } else @@ -1082,10 +1050,9 @@ build_class_ref (type) decl = build_decl (VAR_DECL, decl_name, class_type_node); TREE_STATIC (decl) = 1; TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = 1; make_decl_rtl (decl, NULL); pushdecl_top_level (decl); - if (is_compiled == 1) - DECL_EXTERNAL (decl) = 1; } } @@ -1193,6 +1160,8 @@ get_access_flags_from_decl (decl) access_flags |= ACC_PRIVATE; if (CLASS_PROTECTED (decl)) access_flags |= ACC_PROTECTED; + if (CLASS_STRICTFP (decl)) + access_flags |= ACC_STRICT; return access_flags; } if (TREE_CODE (decl) == FUNCTION_DECL) @@ -1215,6 +1184,8 @@ get_access_flags_from_decl (decl) access_flags |= ACC_ABSTRACT; if (METHOD_TRANSIENT (decl)) access_flags |= ACC_TRANSIENT; + if (METHOD_STRICTFP (decl)) + access_flags |= ACC_STRICT; return access_flags; } abort (); @@ -1271,9 +1242,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); @@ -1291,11 +1269,12 @@ 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); { /* Compute the `throws' information for the method. */ - tree table = integer_zero_node; + tree table = null_pointer_node; if (DECL_FUNCTION_THROWS (mdecl) != NULL_TREE) { int length = 1 + list_length (DECL_FUNCTION_THROWS (mdecl)); @@ -1372,9 +1351,12 @@ get_dispatch_table (type, this_class_addr) { int abstract_p = CLASS_ABSTRACT (TYPE_NAME (type)); tree vtable = get_dispatch_vector (type); - int i; + int i, j; tree list = NULL_TREE; int nvirtuals = TREE_VEC_LENGTH (vtable); + int arraysize; + tree gc_descr; + for (i = nvirtuals; --i >= 0; ) { tree method = TREE_VEC_ELT (vtable, i); @@ -1383,27 +1365,60 @@ get_dispatch_table (type, this_class_addr) if (! abstract_p) warning_with_decl (method, "abstract method in non-abstract class"); - method = null_pointer_node; + + if (TARGET_VTABLE_USES_DESCRIPTORS) + for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j) + list = tree_cons (NULL_TREE, null_pointer_node, list); + else + list = tree_cons (NULL_TREE, null_pointer_node, list); } else { if (!DECL_RTL_SET_P (method)) make_decl_rtl (method, NULL); - method = build1 (ADDR_EXPR, nativecode_ptr_type_node, method); + + if (TARGET_VTABLE_USES_DESCRIPTORS) + for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j) + { + tree fdesc = build (FDESC_EXPR, nativecode_ptr_type_node, + method, build_int_2 (j, 0)); + TREE_CONSTANT (fdesc) = 1; + list = tree_cons (NULL_TREE, fdesc, list); + } + else + list = tree_cons (NULL_TREE, + build1 (ADDR_EXPR, nativecode_ptr_type_node, + method), + list); } - list = tree_cons (NULL_TREE /*DECL_VINDEX (method) + 2*/, - method, list); } + /* Dummy entry for compatibility with G++ -fvtable-thunks. When using the Boehm GC we sometimes stash a GC type descriptor there. We set the PURPOSE to NULL_TREE not to interfere (reset) the emitted byte count during the output to the assembly file. */ - list = tree_cons (NULL_TREE, get_boehm_type_descriptor (type), - list); - list = tree_cons (integer_zero_node, this_class_addr, list); - return build (CONSTRUCTOR, build_prim_array_type (nativecode_ptr_type_node, - nvirtuals + 2), - NULL_TREE, list); + /* With TARGET_VTABLE_USES_DESCRIPTORS, we only add one extra + fake "function descriptor". It's first word is the is the class + pointer, and subsequent words (usually one) contain the GC descriptor. + In all other cases, we reserve two extra vtable slots. */ + gc_descr = get_boehm_type_descriptor (type); + list = tree_cons (NULL_TREE, gc_descr, list); + for (j = 1; j < TARGET_VTABLE_USES_DESCRIPTORS-1; ++j) + list = tree_cons (NULL_TREE, gc_descr, list); + list = tree_cons (NULL_TREE, this_class_addr, list); + + /** Pointer to type_info object (to be implemented), according to g++ ABI. */ + list = tree_cons (NULL_TREE, null_pointer_node, list); + /** Offset to start of whole object. Always (ptrdiff_t)0 for Java. */ + list = tree_cons (integer_zero_node, null_pointer_node, list); + + arraysize = (TARGET_VTABLE_USES_DESCRIPTORS? nvirtuals + 1 : nvirtuals + 2); + if (TARGET_VTABLE_USES_DESCRIPTORS) + arraysize *= TARGET_VTABLE_USES_DESCRIPTORS; + arraysize += 2; + return build (CONSTRUCTOR, + build_prim_array_type (nativecode_ptr_type_node, arraysize), + NULL_TREE, list); } void @@ -1430,6 +1445,9 @@ make_class_data (type) tree interfaces = null_pointer_node; int interface_len = 0; tree type_decl = TYPE_NAME (type); + /** Offset from start of virtual function table declaration + to where objects actually point at, following new g++ ABI. */ + tree dtable_start_offset = build_int_2 (2 * POINTER_SIZE / BITS_PER_UNIT, 0); this_class_addr = build_class_ref (type); decl = TREE_OPERAND (this_class_addr, 0); @@ -1483,7 +1501,7 @@ make_class_data (type) fields_decl = NULL_TREE; /* Build Method array. */ - for (method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (type)); + for (method = TYPE_METHODS (type); method != NULL_TREE; method = TREE_CHAIN (method)) { tree init; @@ -1506,7 +1524,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); @@ -1583,7 +1601,9 @@ make_class_data (type) START_RECORD_CONSTRUCTOR (temp, object_type_node); PUSH_FIELD_VALUE (temp, "vtable", - build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl)); + build (PLUS_EXPR, dtable_ptr_type, + build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl), + dtable_start_offset)); if (! flag_hash_synchronization) PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node); FINISH_RECORD_CONSTRUCTOR (temp); @@ -1600,7 +1620,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)); @@ -1608,9 +1633,29 @@ 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 + : 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); + 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)); @@ -1626,6 +1671,11 @@ make_class_data (type) FINISH_RECORD_CONSTRUCTOR (cons); DECL_INITIAL (decl) = cons; + + /* Hash synchronization requires at least 64-bit alignment. */ + if (flag_hash_synchronization && POINTER_SIZE < 64) + DECL_ALIGN (decl) = 64; + rest_of_decl_compilation (decl, (char*) 0, 1, 0); } @@ -1633,7 +1683,7 @@ void finish_class () { tree method; - tree type_methods = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class)); + tree type_methods = TYPE_METHODS (current_class); int saw_native_method = 0; /* Find out if we have any native methods. We use this information @@ -1729,17 +1779,44 @@ build_dtable_decl (type) /* We need to build a new dtable type so that its size is uniquely computed when we're dealing with the class for real and not just faking it (like java.lang.Class during the initialization of the - compiler.) We now we're not faking a class when CURRENT_CLASS is + compiler.) We know we're not faking a class when CURRENT_CLASS is TYPE. */ if (current_class == type) { - tree dummy = NULL_TREE, aomt, n; + tree dummy = NULL_TREE; + int n; dtype = make_node (RECORD_TYPE); + + PUSH_FIELD (dtype, dummy, "top_offset", ptr_type_node); + PUSH_FIELD (dtype, dummy, "type_info", ptr_type_node); + PUSH_FIELD (dtype, dummy, "class", class_ptr_type); - n = build_int_2 (TREE_VEC_LENGTH (get_dispatch_vector (type)), 0); - aomt = build_array_type (ptr_type_node, build_index_type (n)); - PUSH_FIELD (dtype, dummy, "methods", aomt); + for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n) + { + tree tmp_field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node); + TREE_CHAIN (dummy) = tmp_field; + DECL_CONTEXT (tmp_field) = dtype; + DECL_ARTIFICIAL (tmp_field) = 1; + dummy = tmp_field; + } + + PUSH_FIELD (dtype, dummy, "gc_descr", ptr_type_node); + for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n) + { + tree tmp_field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node); + TREE_CHAIN (dummy) = tmp_field; + DECL_CONTEXT (tmp_field) = dtype; + DECL_ARTIFICIAL (tmp_field) = 1; + dummy = tmp_field; + } + + n = TREE_VEC_LENGTH (get_dispatch_vector (type)); + if (TARGET_VTABLE_USES_DESCRIPTORS) + n *= TARGET_VTABLE_USES_DESCRIPTORS; + + PUSH_FIELD (dtype, dummy, "methods", + build_prim_array_type (nativecode_ptr_type_node, n)); layout_type (dtype); } else @@ -1912,13 +1989,12 @@ layout_class_methods (this_class) tree this_class; { tree method_decl, dtable_count; - tree super_class, handle_type; + tree super_class; if (TYPE_NVIRTUALS (this_class)) return; super_class = CLASSTYPE_SUPER (this_class); - handle_type = CLASS_TO_HANDLE_TYPE (this_class); if (super_class) { @@ -1930,18 +2006,14 @@ layout_class_methods (this_class) else dtable_count = integer_zero_node; - TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type)); + TYPE_METHODS (this_class) = nreverse (TYPE_METHODS (this_class)); - for (method_decl = TYPE_METHODS (handle_type); + for (method_decl = TYPE_METHODS (this_class); method_decl; method_decl = TREE_CHAIN (method_decl)) dtable_count = layout_class_method (this_class, super_class, method_decl, dtable_count); TYPE_NVIRTUALS (this_class) = dtable_count; - -#ifdef JAVA_USE_HANDLES - layout_type (handle_type); -#endif } /* Return 0 if NAME is equal to STR, -1 if STR is "less" than NAME, @@ -2101,15 +2173,169 @@ 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 () { - registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterClass"); + registerClass_libfunc = gen_rtx_SYMBOL_REF (Pmode, "_Jv_RegisterClass"); registerResource_libfunc = - gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterResource"); - ggc_add_tree_root (class_roots, sizeof (class_roots) / sizeof (tree)); + gen_rtx_SYMBOL_REF (Pmode, "_Jv_RegisterResource"); fields_ident = get_identifier ("fields"); info_ident = get_identifier ("info"); - ggc_add_rtx_root (®isterClass_libfunc, 1); gcc_obstack_init (&temporary_obstack); } + +static hashval_t java_treetreehash_hash PARAMS ((const void *)); +static int java_treetreehash_compare PARAMS ((const void *, const void *)); + +/* A hash table mapping trees to trees. Used generally. */ + +#define JAVA_TREEHASHHASH_H(t) ((hashval_t) (t)) + +static hashval_t +java_treetreehash_hash (k_p) + const void *k_p; +{ + struct treetreehash_entry *k = (struct treetreehash_entry *) k_p; + return JAVA_TREEHASHHASH_H (k->key); +} + +static int +java_treetreehash_compare (k1_p, k2_p) + const void * k1_p; + const void * k2_p; +{ + struct treetreehash_entry * k1 = (struct treetreehash_entry *) k1_p; + tree k2 = (tree) k2_p; + return (k1->key == k2); +} + +tree +java_treetreehash_find (ht, t) + htab_t ht; + tree t; +{ + struct treetreehash_entry *e; + hashval_t hv = JAVA_TREEHASHHASH_H (t); + e = (struct treetreehash_entry *) htab_find_with_hash (ht, t, hv); + if (e == NULL) + return NULL; + else + return e->value; +} + +tree * +java_treetreehash_new (ht, t) + htab_t ht; + tree t; +{ + PTR *e; + struct treetreehash_entry *tthe; + hashval_t hv = JAVA_TREEHASHHASH_H (t); + + e = htab_find_slot_with_hash (ht, t, hv, INSERT); + if (*e == NULL) + { + tthe = (*ht->alloc_f) (1, sizeof (*tthe)); + tthe->key = t; + *e = (PTR) tthe; + } + else + tthe = (struct treetreehash_entry *) *e; + return &tthe->value; +} + +htab_t +java_treetreehash_create (size, gc) + size_t size; + int gc; +{ + if (gc) + return htab_create_ggc (size, java_treetreehash_hash, + java_treetreehash_compare, NULL); + else + return htab_create_alloc (size, java_treetreehash_hash, + java_treetreehash_compare, free, xcalloc, free); +} + +#include "gt-java-class.h"