X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fjava%2Fclass.c;h=ae715f14efcac4fdf3ff67cad944aa9f3d68a299;hp=df318a010044054cef52309c1c04cb82848f63cb;hb=9007522bf97494be0eb119dc7a5daa5207755acf;hpb=a091667d93f7eca6cf206e0a710fc8122881f4c7 diff --git a/gcc/java/class.c b/gcc/java/class.c index df318a01004..ae715f14efc 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, 97-98, 1999 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of GNU CC. @@ -35,23 +35,175 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "toplev.h" #include "output.h" #include "parse.h" - -static tree mangle_class_field PROTO ((tree class)); -static tree make_method_value PROTO ((tree)); -static tree build_java_method_type PROTO ((tree, tree, int)); -static int32 hashUtf8String PROTO ((const char *, int)); -static tree make_field_value PROTO ((tree)); -static tree get_dispatch_vector PROTO ((tree)); -static tree get_dispatch_table PROTO ((tree, tree)); -static void append_gpp_mangled_type PROTO ((struct obstack *, tree)); -static tree mangle_static_field PROTO ((tree)); -static void add_interface_do PROTO ((tree, tree, int)); -static tree maybe_layout_super_class PROTO ((tree, tree)); +#include "ggc.h" + +static tree mangle_class_field PARAMS ((tree class)); +static tree make_method_value PARAMS ((tree)); +static tree build_java_method_type PARAMS ((tree, tree, int)); +static int32 hashUtf8String PARAMS ((const char *, int)); +static tree make_field_value PARAMS ((tree)); +static tree get_dispatch_vector PARAMS ((tree)); +static tree get_dispatch_table PARAMS ((tree, tree)); +static void append_gpp_mangled_type PARAMS ((struct obstack *, tree)); +static tree mangle_static_field PARAMS ((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 int utf8_cmp PARAMS ((const unsigned char *, int, const char *)); +static int cxx_keyword_p PARAMS ((const char *, int)); +static tree mangle_field PARAMS ((tree, tree)); static rtx registerClass_libfunc; extern struct obstack permanent_obstack; -extern struct obstack temporary_obstack; +struct obstack temporary_obstack; + +/* The compiler generates different code depending on whether or not + it can assume certain classes have been compiled down to native + code or not. The compiler options -fassume-compiled= and + -fno-assume-compiled= are used to create a tree of + assume_compiled_node objects. This tree is queried to determine if + a class is assume to be compiled or not. Each node in the tree + represents either a package or a specific class. */ + +typedef struct assume_compiled_node_struct +{ + /* The class or package name. */ + const char *ident; + + /* Non-zero if this represents an exclusion. */ + int excludep; + + /* Pointers to other nodes in the tree. */ + struct assume_compiled_node_struct *parent; + struct assume_compiled_node_struct *sibling; + struct assume_compiled_node_struct *child; +} assume_compiled_node; + +static assume_compiled_node *find_assume_compiled_node + PARAMS ((assume_compiled_node *, const char *)); + +/* This is the root of the include/exclude tree. */ + +static assume_compiled_node *assume_compiled_tree; + +/* Return the node that most closely represents the class whose name + is IDENT. Start the search from NODE. Return NULL if an + appropriate node does not exist. */ + +static assume_compiled_node * +find_assume_compiled_node (node, ident) + assume_compiled_node *node; + const char *ident; +{ + while (node) + { + size_t node_ident_length = strlen (node->ident); + + /* node_ident_length is zero at the root of the tree. If the + identifiers are the same length, then we have matching + classes. Otherwise check if we've matched an enclosing + package name. */ + + if (node_ident_length == 0 + || (strncmp (ident, node->ident, node_ident_length) == 0 + && (strlen (ident) == node_ident_length + || ident[node_ident_length] == '.'))) + { + /* We've found a match, however, there might be a more + specific match. */ + + assume_compiled_node *found = find_assume_compiled_node (node->child, + ident); + if (found) + return found; + else + return node; + } + + /* No match yet. Continue through the sibling list. */ + node = node->sibling; + } + + /* No match at all in this tree. */ + return NULL; +} + +/* Add a new IDENT to the include/exclude tree. It's an exclusion + if EXCLUDEP is non-zero. */ + +void +add_assume_compiled (ident, excludep) + const char *ident; + int excludep; +{ + assume_compiled_node *parent; + assume_compiled_node *node = + (assume_compiled_node *) xmalloc (sizeof (assume_compiled_node)); + + node->ident = xstrdup (ident); + node->excludep = excludep; + node->child = NULL; + + /* Create the root of the tree if it doesn't exist yet. */ + + if (NULL == assume_compiled_tree) + { + assume_compiled_tree = + (assume_compiled_node *) xmalloc (sizeof (assume_compiled_node)); + assume_compiled_tree->ident = ""; + assume_compiled_tree->excludep = 0; + assume_compiled_tree->sibling = NULL; + assume_compiled_tree->child = NULL; + assume_compiled_tree->parent = NULL; + } + + /* Calling the function with the empty string means we're setting + excludep for the root of the hierarchy. */ + + if (0 == ident[0]) + { + assume_compiled_tree->excludep = excludep; + return; + } + + /* Find the parent node for this new node. PARENT will either be a + class or a package name. Adjust PARENT accordingly. */ + + parent = find_assume_compiled_node (assume_compiled_tree, ident); + if (ident[strlen (parent->ident)] != '.') + parent = parent->parent; + + /* Insert NODE into the tree. */ + + node->parent = parent; + node->sibling = parent->child; + parent->child = node; +} + +/* Returns non-zero if IDENT is the name of a class that the compiler + should assume has been compiled to FIXME */ + +static int +assume_compiled (ident) + const char *ident; +{ + assume_compiled_node *i; + int result; + + if (NULL == assume_compiled_tree) + return 1; + + i = find_assume_compiled_node (assume_compiled_tree, + ident); + + result = ! i->excludep; + + return (result); +} /* Return an IDENTIFIER_NODE the same as (OLD_NAME, OLD_LENGTH). except that characters matching OLD_CHAR are substituted by NEW_CHAR. @@ -120,7 +272,6 @@ tree make_class () { tree type; - push_obstacks (&permanent_obstack, &permanent_obstack); type = make_node (RECORD_TYPE); #ifdef JAVA_USE_HANDLES tree field1 = build_decl (FIELD_DECL, get_identifier ("obj"), @@ -137,7 +288,7 @@ make_class () #else TYPE_BINFO (type) = make_tree_vec (6); #endif - pop_obstacks (); + MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type); return type; } @@ -171,10 +322,9 @@ push_class (class_type, class_name) tree class_type, class_name; { tree decl, signature; - char *save_input_filename = input_filename; + const char *save_input_filename = input_filename; int save_lineno = lineno; tree source_name = identifier_subst (class_name, "", '.', '/', ".java"); - push_obstacks (&permanent_obstack, &permanent_obstack); CLASS_P (class_type) = 1; input_filename = IDENTIFIER_POINTER (source_name); lineno = 0; @@ -200,7 +350,6 @@ push_class (class_type, class_name) } #endif - pop_obstacks (); return decl; } @@ -231,7 +380,6 @@ set_super_info (access_flags, this_class, super_class, interfaces_count) if (super_class) total_supers++; - push_obstacks (&permanent_obstack, &permanent_obstack); TYPE_BINFO_BASETYPES (this_class) = make_tree_vec (total_supers); if (super_class) { @@ -243,13 +391,15 @@ set_super_info (access_flags, this_class, super_class, interfaces_count) = super_binfo; CLASS_HAS_SUPER (this_class) = 1; } - pop_obstacks (); - + if (access_flags & ACC_PUBLIC) CLASS_PUBLIC (class_decl) = 1; if (access_flags & ACC_FINAL) CLASS_FINAL (class_decl) = 1; if (access_flags & ACC_SUPER) CLASS_SUPER (class_decl) = 1; if (access_flags & ACC_INTERFACE) CLASS_INTERFACE (class_decl) = 1; if (access_flags & ACC_ABSTRACT) CLASS_ABSTRACT (class_decl) = 1; + 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; } /* Return length of inheritance chain of CLAS, where java.lang.Object is 0, @@ -262,6 +412,8 @@ class_depth (clas) int depth = 0; if (! CLASS_LOADED_P (clas)) load_class (clas, 1); + if (TYPE_SIZE (clas) == error_mark_node) + return -1; while (clas != object_type_node) { depth++; @@ -313,6 +465,51 @@ inherits_from_p (type1, type2) return 0; } +/* Return a 1 iff TYPE1 is an enclosing context for TYPE2 */ + +int +enclosing_context_p (type1, type2) + tree type1, type2; +{ + if (!INNER_CLASS_TYPE_P (type2)) + return 0; + + for (type2 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type2))); + type2; + type2 = (INNER_CLASS_TYPE_P (type2) ? + TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type2))) : NULL_TREE)) + { + if (type2 == type1) + return 1; + } + + return 0; +} + +/* Return 1 iff there exists a common enclosing context between TYPE1 + and TYPE2. */ + +int common_enclosing_context_p (type1, type2) + tree type1, type2; +{ + if (!PURE_INNER_CLASS_TYPE_P (type1) || !PURE_INNER_CLASS_TYPE_P (type2)) + return 0; + + for (type1 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1))); type1; + type1 = (PURE_INNER_CLASS_TYPE_P (type1) ? + TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1))) : NULL_TREE)) + { + tree current; + for (current = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type2))); current; + current = (PURE_INNER_CLASS_TYPE_P (current) ? + TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current))) : + NULL_TREE)) + if (type1 == current) + return 1; + } + return 0; +} + static void add_interface_do (basetype_vec, interface_class, i) tree basetype_vec, interface_class; @@ -401,6 +598,43 @@ build_java_method_type (fntype, this_class, access_flags) 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 it's pointer value, + comparison is direct. */ + +unsigned long +java_hash_hash_tree_node (k) + hash_table_key k; +{ + return (long) k; +} + +boolean +java_hash_compare_tree_node (k1, k2) + hash_table_key k1; + hash_table_key k2; +{ + return ((char*) k1 == (char*) k2); +} + tree add_method_1 (handle_class, access_flags, name, function_type) tree handle_class; @@ -409,7 +643,6 @@ add_method_1 (handle_class, access_flags, name, function_type) tree function_type; { tree method_type, fndecl; - push_obstacks (&permanent_obstack, &permanent_obstack); method_type = build_java_method_type (function_type, handle_class, access_flags); @@ -418,19 +651,29 @@ add_method_1 (handle_class, access_flags, name, function_type) DECL_CONTEXT (fndecl) = handle_class; DECL_LANG_SPECIFIC (fndecl) - = (struct lang_decl *) permalloc (sizeof (struct lang_decl)); - bzero ((PTR) DECL_LANG_SPECIFIC (fndecl), sizeof (struct lang_decl)); + = (struct lang_decl *) ggc_alloc_cleared (sizeof (struct lang_decl)); + + /* 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); TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class); TYPE_METHODS (handle_class) = fndecl; - pop_obstacks (); if (access_flags & ACC_PUBLIC) METHOD_PUBLIC (fndecl) = 1; if (access_flags & ACC_PROTECTED) METHOD_PROTECTED (fndecl) = 1; - if (access_flags & ACC_PRIVATE) METHOD_PRIVATE (fndecl) = 1; - if (access_flags & ACC_NATIVE) METHOD_NATIVE (fndecl) = 1; - if (access_flags & ACC_STATIC) METHOD_STATIC (fndecl) = 1; - if (access_flags & ACC_FINAL) METHOD_FINAL (fndecl) = 1; + if (access_flags & ACC_PRIVATE) + METHOD_PRIVATE (fndecl) = DECL_INLINE (fndecl) = 1; + if (access_flags & ACC_NATIVE) + { + METHOD_NATIVE (fndecl) = 1; + DECL_EXTERNAL (fndecl) = 1; + } + if (access_flags & ACC_STATIC) + METHOD_STATIC (fndecl) = DECL_INLINE (fndecl) = 1; + if (access_flags & ACC_FINAL) + METHOD_FINAL (fndecl) = DECL_INLINE (fndecl) = 1; 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; @@ -451,13 +694,11 @@ add_method (this_class, access_flags, name, 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); - push_obstacks (&permanent_obstack, &permanent_obstack); if (sig[0] != '(') fatal ("bad method signature"); function_type = get_type_from_signature (method_sig); fndecl = add_method_1 (handle_class, access_flags, name, function_type); set_java_signature (TREE_TYPE (fndecl), method_sig); - pop_obstacks (); return fndecl; } @@ -470,10 +711,7 @@ add_field (class, name, field_type, flags) { int is_static = (flags & ACC_STATIC) != 0; tree field; - /* Push the obstack of field_type ? FIXME */ - push_obstacks (&permanent_obstack, &permanent_obstack); field = build_decl (is_static ? VAR_DECL : FIELD_DECL, name, field_type); - pop_obstacks (); TREE_CHAIN (field) = TYPE_FIELDS (class); TYPE_FIELDS (class) = field; DECL_CONTEXT (field) = class; @@ -569,7 +807,6 @@ build_utf8_ref (name) if (ref != NULL_TREE) return ref; - push_obstacks (&permanent_obstack, &permanent_obstack); ctype = make_node (RECORD_TYPE); str_type = build_prim_array_type (unsigned_byte_type_node, name_len + 1); /* Allow for final '\0'. */ @@ -621,7 +858,6 @@ build_utf8_ref (name) make_decl_rtl (decl, (char*) 0, 1); ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl); IDENTIFIER_UTF8_REF (name) = ref; - pop_obstacks (); return ref; } @@ -647,9 +883,9 @@ build_class_ref (type) decl = IDENTIFIER_GLOBAL_VALUE (decl_name); if (decl == NULL_TREE) { - push_obstacks (&permanent_obstack, &permanent_obstack); decl = build_decl (VAR_DECL, decl_name, class_type_node); DECL_SIZE (decl) = TYPE_SIZE (class_type_node); + DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (class_type_node); TREE_STATIC (decl) = 1; TREE_PUBLIC (decl) = 1; DECL_IGNORED_P (decl) = 1; @@ -659,7 +895,6 @@ build_class_ref (type) pushdecl_top_level (decl); if (is_compiled == 1) DECL_EXTERNAL (decl) = 1; - pop_obstacks (); } } else @@ -705,7 +940,6 @@ build_class_ref (type) decl = IDENTIFIER_GLOBAL_VALUE (decl_name); if (decl == NULL_TREE) { - push_obstacks (&permanent_obstack, &permanent_obstack); decl = build_decl (VAR_DECL, decl_name, class_type_node); TREE_STATIC (decl) = 1; TREE_PUBLIC (decl) = 1; @@ -713,7 +947,6 @@ build_class_ref (type) pushdecl_top_level (decl); if (is_compiled == 1) DECL_EXTERNAL (decl) = 1; - pop_obstacks (); } } @@ -724,11 +957,9 @@ build_class_ref (type) { int index; tree cl; - push_obstacks (&permanent_obstack, &permanent_obstack); index = alloc_class_constant (type); cl = build_ref_from_constant_pool (index); TREE_TYPE (cl) = promote_type (class_ptr_type); - pop_obstacks (); return cl; } } @@ -743,9 +974,7 @@ build_static_field_ref (fdecl) { if (DECL_RTL (fdecl) == 0) { - push_obstacks (&permanent_obstack, &permanent_obstack); make_decl_rtl (fdecl, NULL, 1); - pop_obstacks (); if (is_compiled == 1) DECL_EXTERNAL (fdecl) = 1; } @@ -754,8 +983,7 @@ build_static_field_ref (fdecl) else { /* Compile as: - * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr - */ + * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */ static tree fields_ident = NULL_TREE; static tree info_ident = NULL_TREE; tree ref = build_class_ref (fclass); @@ -763,9 +991,15 @@ build_static_field_ref (fdecl) int field_index = 0; ref = build1 (INDIRECT_REF, class_type_node, ref); if (fields_ident == NULL_TREE) - fields_ident = get_identifier ("fields"); + { + fields_ident = get_identifier ("fields"); + ggc_add_tree_root (&fields_ident, 1); + } if (info_ident == NULL_TREE) - info_ident = get_identifier ("info"); + { + info_ident = get_identifier ("info"); + ggc_add_tree_root (&info_ident, 1); + } ref = build (COMPONENT_REF, field_ptr_type_node, ref, lookup_field (&class_type_node, fields_ident)); @@ -826,6 +1060,12 @@ get_access_flags_from_decl (decl) access_flags |= ACC_INTERFACE; if (CLASS_ABSTRACT (decl)) access_flags |= ACC_ABSTRACT; + if (CLASS_STATIC (decl)) + access_flags |= ACC_STATIC; + if (CLASS_PRIVATE (decl)) + access_flags |= ACC_PRIVATE; + if (CLASS_PROTECTED (decl)) + access_flags |= ACC_PROTECTED; return access_flags; } if (TREE_CODE (decl) == FUNCTION_DECL) @@ -857,10 +1097,11 @@ static tree make_field_value (fdecl) tree fdecl; { - tree finit, info; - int bsize, flags; + tree finit; + int flags; tree type = TREE_TYPE (fdecl); int resolved = is_compiled_class (type); + START_RECORD_CONSTRUCTOR (finit, field_type_node); PUSH_FIELD_VALUE (finit, "name", build_utf8_ref (DECL_NAME (fdecl))); if (resolved) @@ -868,33 +1109,30 @@ make_field_value (fdecl) else { tree signature = build_java_signature (type); + type = build_utf8_ref (unmangle_classname - (IDENTIFIER_POINTER(signature), - IDENTIFIER_LENGTH(signature))); + (IDENTIFIER_POINTER (signature), + IDENTIFIER_LENGTH (signature))); } PUSH_FIELD_VALUE (finit, "type", type); + flags = get_access_flags_from_decl (fdecl); if (! resolved) flags |= 0x8000 /* FIELD_UNRESOLVED_FLAG */; + PUSH_FIELD_VALUE (finit, "accflags", build_int_2 (flags, 0)); - bsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (fdecl))) / BITS_PER_UNIT; - PUSH_FIELD_VALUE (finit, "bsize", build_int_2 (bsize, 0)); - if (FIELD_STATIC (fdecl)) - { - tree cfield = TREE_CHAIN (TYPE_FIELDS(field_info_union_node)); - tree faddr = build_address_of (build_static_field_ref (fdecl)); - info = build (CONSTRUCTOR, field_info_union_node, NULL_TREE, - build_tree_list (cfield, faddr)); - } - else - { - int boffset - = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (fdecl)) / BITS_PER_UNIT; - info = build (CONSTRUCTOR, field_info_union_node, NULL_TREE, - build_tree_list (TYPE_FIELDS(field_info_union_node), - build_int_2 (boffset, 0))); - } - PUSH_FIELD_VALUE (finit, "info", info); + PUSH_FIELD_VALUE (finit, "bsize", TYPE_SIZE_UNIT (TREE_TYPE (fdecl))); + + PUSH_FIELD_VALUE + (finit, "info", + build (CONSTRUCTOR, field_info_union_node, NULL_TREE, + build_tree_list + ((FIELD_STATIC (fdecl) + ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node)) + : TYPE_FIELDS (field_info_union_node)), + (FIELD_STATIC (fdecl) + ? build_address_of (build_static_field_ref (fdecl)) + : byte_position (fdecl))))); FINISH_RECORD_CONSTRUCTOR (finit); return finit; @@ -937,29 +1175,28 @@ get_dispatch_vector (type) tree vtable = TYPE_VTABLE (type); if (vtable == NULL) { - int i; + HOST_WIDE_INT i; tree method; tree super = CLASSTYPE_SUPER (type); - int nvirtuals = TREE_INT_CST_LOW (TYPE_NVIRTUALS (type)); + HOST_WIDE_INT nvirtuals = tree_low_cst (TYPE_NVIRTUALS (type), 0); vtable = make_tree_vec (nvirtuals); TYPE_VTABLE (type) = vtable; if (super != NULL_TREE) { tree super_vtable = get_dispatch_vector (super); - for ( i = TREE_INT_CST_LOW (TYPE_NVIRTUALS (super)); --i >= 0; ) + + for (i = tree_low_cst (TYPE_NVIRTUALS (super), 0); --i >= 0; ) TREE_VEC_ELT (vtable, i) = TREE_VEC_ELT (super_vtable, i); } + for (method = TYPE_METHODS (type); method != NULL_TREE; method = TREE_CHAIN (method)) - { - if (DECL_VINDEX (method) != NULL_TREE - && TREE_CODE (DECL_VINDEX (method)) == INTEGER_CST) - { - TREE_VEC_ELT (vtable, TREE_INT_CST_LOW (DECL_VINDEX (method))) - = method; - } - } + if (DECL_VINDEX (method) != NULL_TREE + && host_integerp (DECL_VINDEX (method), 0)) + TREE_VEC_ELT (vtable, tree_low_cst (DECL_VINDEX (method), 0)) + = method; } + return vtable; } @@ -967,6 +1204,7 @@ static tree get_dispatch_table (type, this_class_addr) tree type, this_class_addr; { + int abstract_p = CLASS_ABSTRACT (TYPE_NAME (type)); tree vtable = get_dispatch_vector (type); int i; tree list = NULL_TREE; @@ -975,15 +1213,27 @@ get_dispatch_table (type, this_class_addr) { tree method = TREE_VEC_ELT (vtable, i); if (METHOD_ABSTRACT (method)) - warning_with_decl (method, "abstract method in non-abstract class"); - if (DECL_RTL (method) == 0) - make_decl_rtl (method, NULL, 1); + { + if (! abstract_p) + warning_with_decl (method, + "abstract method in non-abstract class"); + method = null_pointer_node; + } + else + { + if (DECL_RTL (method) == 0) + make_decl_rtl (method, NULL, 1); + method = build1 (ADDR_EXPR, nativecode_ptr_type_node, method); + } list = tree_cons (NULL_TREE /*DECL_VINDEX (method) + 2*/, - build1 (ADDR_EXPR, nativecode_ptr_type_node, method), - list); + method, list); } - /* Dummy entry for compatibility with G++ -fvtable-thunks. */ - list = tree_cons (integer_zero_node, null_pointer_node, 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), @@ -1072,6 +1322,7 @@ make_class_data (type) { tree init; if (METHOD_PRIVATE (method) + && ! flag_keep_inline_functions && (flag_inline_functions || optimize)) continue; init = make_method_value (method); @@ -1088,8 +1339,8 @@ make_class_data (type) DECL_IGNORED_P (methods_decl) = 1; rest_of_decl_compilation (methods_decl, (char*) 0, 1, 0); - if (flag_assume_compiled - && ! CLASS_ABSTRACT (type_decl) && ! CLASS_INTERFACE (type_decl)) + if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl))) + && ! CLASS_INTERFACE (type_decl)) { tree dtable = get_dispatch_table (type, this_class_addr); dtable_decl = build_dtable_decl (type); @@ -1104,7 +1355,7 @@ make_class_data (type) super = CLASSTYPE_SUPER (type); if (super == NULL_TREE) super = null_pointer_node; - else if (flag_assume_compiled) + else if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))) super = build_class_ref (super); else { @@ -1130,7 +1381,7 @@ make_class_data (type) tree child = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i); tree iclass = BINFO_TYPE (child); tree index; - if (flag_assume_compiled) + if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (iclass))))) index = build_class_ref (iclass); else { @@ -1152,13 +1403,10 @@ make_class_data (type) constant_pool_constructor = build_constants_constructor (); START_RECORD_CONSTRUCTOR (temp, object_type_node); -#if 0 - PUSH_FIELD_VALUE (temp, "vtable", NULL_TREE); -#else PUSH_FIELD_VALUE (temp, "vtable", build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl)); -#endif - PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node); + if (! flag_hash_synchronization) + PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node); FINISH_RECORD_CONSTRUCTOR (temp); START_RECORD_CONSTRUCTOR (cons, class_type_node); PUSH_SUPER_VALUE (cons, temp); @@ -1190,6 +1438,10 @@ make_class_data (type) PUSH_FIELD_VALUE (cons, "state", integer_zero_node); PUSH_FIELD_VALUE (cons, "thread", null_pointer_node); + PUSH_FIELD_VALUE (cons, "depth", integer_zero_node); + PUSH_FIELD_VALUE (cons, "ancestors", null_pointer_node); + PUSH_FIELD_VALUE (cons, "idt", null_pointer_node); + PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node); FINISH_RECORD_CONSTRUCTOR (cons); @@ -1202,7 +1454,21 @@ finish_class () { tree method; tree type_methods = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class)); - + int saw_native_method = 0; + + /* Find out if we have any native methods. We use this information + later. */ + for (method = type_methods; + method != NULL_TREE; + method = TREE_CHAIN (method)) + { + if (METHOD_NATIVE (method)) + { + saw_native_method = 1; + break; + } + } + /* Emit deferred inline methods. */ for (method = type_methods; method != NULL_TREE; ) { @@ -1211,11 +1477,10 @@ finish_class () /* It's a deferred inline method. Decide if we need to emit it. */ if (flag_keep_inline_functions || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (method)) - || ! METHOD_PRIVATE (method)) + || ! METHOD_PRIVATE (method) + || saw_native_method) { - temporary_allocation (); output_inline_function (method); - permanent_allocation (1); /* Scan the list again to see if there are any earlier methods to emit. */ method = type_methods; @@ -1249,8 +1514,7 @@ is_compiled_class (class) if (class == current_class) return 2; - seen_in_zip = (TYPE_LANG_SPECIFIC (class) && TYPE_LANG_SPECIFIC (class)->jcf - && TYPE_LANG_SPECIFIC (class)->jcf->seen_in_zip); + seen_in_zip = (TYPE_JCF (class) && TYPE_JCF (class)->seen_in_zip); if (CLASS_FROM_CURRENTLY_COMPILED_SOURCE_P (class) || seen_in_zip) { /* The class was seen in the current ZIP file and will be @@ -1266,7 +1530,7 @@ is_compiled_class (class) return 2; } - if (flag_assume_compiled) + if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class))))) { if (!CLASS_LOADED_P (class)) { @@ -1341,29 +1605,13 @@ append_gpp_mangled_type (obstack, type) } } -/* Build the mangled name of the `class' field. */ - -static tree -mangle_class_field (class) - tree class; -{ - tree name; - obstack_grow (&temporary_obstack, "_CL_", 4); - append_gpp_mangled_type (&temporary_obstack, class); - obstack_1grow (&temporary_obstack, '\0'); - name = get_identifier (obstack_base (&temporary_obstack)); - obstack_free (&temporary_obstack, obstack_base (&temporary_obstack)); - return name; -} - -/* Build the mangled (assembly-level) name of the static field FIELD. */ +/* Build the mangled name of a field, given the class name and the + field name. */ static tree -mangle_static_field (field) - tree field; +mangle_field (class, name) + tree class, name; { - tree class = DECL_CONTEXT (field); - tree name = DECL_NAME (field); int encoded_len; #if ! defined (NO_DOLLAR_IN_LABEL) || ! defined (NO_DOT_IN_LABEL) obstack_1grow (&temporary_obstack, '_'); @@ -1398,25 +1646,72 @@ mangle_static_field (field) IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)); } + + /* Mangle C++ keywords by appending a `$'. */ + /* FIXME: NO_DOLLAR_IN_LABEL */ + if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name))) + obstack_grow (&temporary_obstack, "$", 1); + obstack_1grow (&temporary_obstack, '\0'); name = get_identifier (obstack_base (&temporary_obstack)); obstack_free (&temporary_obstack, obstack_base (&temporary_obstack)); return name; } +/* Build the mangled name of the `class' field. */ + +static tree +mangle_class_field (class) + tree class; +{ + /* We know that we can use `class$' to mangle the class object, + because `class' is a reserved word in Java and thus can't appear + as a field or method name. */ + return mangle_field (class, get_identifier ("class$")); +} + +/* Build the mangled (assembly-level) name of the static field FIELD. */ + +static tree +mangle_static_field (field) + tree field; +{ + return mangle_field (DECL_CONTEXT (field), DECL_NAME (field)); +} + /* Build a VAR_DECL for the dispatch table (vtable) for class TYPE. */ tree build_dtable_decl (type) tree type; { - tree name; + tree name, dtype; + + /* 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 + TYPE. */ + if (current_class == type) + { + tree dummy = NULL_TREE, aomt, n; + + dtype = make_node (RECORD_TYPE); + 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); + layout_type (dtype); + } + else + dtype = dtable_type; + obstack_grow (&temporary_obstack, "__vt_", 5); append_gpp_mangled_type (&temporary_obstack, type); obstack_1grow (&temporary_obstack, '\0'); name = get_identifier (obstack_base (&temporary_obstack)); obstack_free (&temporary_obstack, obstack_base (&temporary_obstack)); - return build_decl (VAR_DECL, name, dtable_type); + return build_decl (VAR_DECL, name, dtype); } /* Pre-pend the TYPE_FIELDS of THIS_CLASS with a dummy FIELD_DECL for the @@ -1427,13 +1722,15 @@ push_super_field (this_class, super_class) tree this_class, super_class; { tree base_decl; - push_obstacks (&permanent_obstack, &permanent_obstack); + /* Don't insert the field if we're just re-laying the class out. */ + if (TYPE_FIELDS (this_class) && !DECL_NAME (TYPE_FIELDS (this_class))) + return; base_decl = build_decl (FIELD_DECL, NULL_TREE, super_class); - pop_obstacks (); DECL_IGNORED_P (base_decl) = 1; TREE_CHAIN (base_decl) = TYPE_FIELDS (this_class); TYPE_FIELDS (this_class) = base_decl; DECL_SIZE (base_decl) = TYPE_SIZE (super_class); + DECL_SIZE_UNIT (base_decl) = TYPE_SIZE_UNIT (super_class); } /* Handle the different manners we may have to lay out a super class. */ @@ -1445,8 +1742,7 @@ maybe_layout_super_class (super_class, this_class) { if (TREE_CODE (super_class) == RECORD_TYPE) { - if (!CLASS_LOADED_P (super_class) - && CLASS_FROM_SOURCE_P (super_class)) + if (!CLASS_LOADED_P (super_class) && CLASS_FROM_SOURCE_P (super_class)) safe_layout_class (super_class); if (!CLASS_LOADED_P (super_class)) load_class (super_class, 1); @@ -1459,7 +1755,8 @@ maybe_layout_super_class (super_class, this_class) super_class = TREE_TYPE (super_class); else { - super_class = do_resolve_class (super_class, NULL_TREE, this_class); + super_class = do_resolve_class (NULL_TREE, /* FIXME? */ + super_class, NULL_TREE, this_class); if (!super_class) return NULL_TREE; /* FIXME, NULL_TREE not checked by caller. */ super_class = TREE_TYPE (super_class); @@ -1475,15 +1772,58 @@ void layout_class (this_class) tree this_class; { + static tree list = NULL_TREE; + static int initialized_p; tree super_class = CLASSTYPE_SUPER (this_class); tree field; + + /* Register LIST with the garbage collector. */ + if (!initialized_p) + { + ggc_add_tree_root (&list, 1); + initialized_p = 1; + } + + list = tree_cons (this_class, NULL_TREE, list); + if (CLASS_BEING_LAIDOUT (this_class)) + { + char buffer [1024]; + char *report; + tree current; + + sprintf (buffer, " with `%s'", + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class)))); + obstack_grow (&temporary_obstack, buffer, strlen (buffer)); + + for (current = TREE_CHAIN (list); current; + current = TREE_CHAIN (current)) + { + tree decl = TYPE_NAME (TREE_PURPOSE (current)); + sprintf (buffer, "\n which inherits from `%s' (%s:%d)", + IDENTIFIER_POINTER (DECL_NAME (decl)), + DECL_SOURCE_FILE (decl), + DECL_SOURCE_LINE (decl)); + obstack_grow (&temporary_obstack, buffer, strlen (buffer)); + } + obstack_1grow (&temporary_obstack, '\0'); + report = obstack_finish (&temporary_obstack); + cyclic_inheritance_report = ggc_strdup (report); + obstack_free (&temporary_obstack, report); + TYPE_SIZE (this_class) = error_mark_node; + return; + } + CLASS_BEING_LAIDOUT (this_class) = 1; if (super_class) { - super_class = maybe_layout_super_class (super_class, this_class); - if (TREE_CODE (TYPE_SIZE (super_class)) == ERROR_MARK) + tree maybe_super_class + = maybe_layout_super_class (super_class, this_class); + if (maybe_super_class == NULL + || TREE_CODE (TYPE_SIZE (maybe_super_class)) == ERROR_MARK) { TYPE_SIZE (this_class) = error_mark_node; + CLASS_BEING_LAIDOUT (this_class) = 0; + list = TREE_CHAIN (list); return; } if (TYPE_SIZE (this_class) == NULL_TREE) @@ -1501,6 +1841,42 @@ layout_class (this_class) } layout_type (this_class); + + /* Also recursively load/layout any superinterfaces, but only if class was + loaded from bytecode. The source parser will take care of this itself. */ + if (!CLASS_FROM_SOURCE_P (this_class)) + { + tree basetype_vec = TYPE_BINFO_BASETYPES (this_class); + + if (basetype_vec) + { + int n = TREE_VEC_LENGTH (basetype_vec) - 1; + int i; + for (i = n; i > 0; i--) + { + tree vec_elt = TREE_VEC_ELT (basetype_vec, i); + tree super_interface = BINFO_TYPE (vec_elt); + + tree maybe_super_interface + = maybe_layout_super_class (super_interface, NULL_TREE); + if (maybe_super_interface == NULL + || TREE_CODE (TYPE_SIZE (maybe_super_interface)) == ERROR_MARK) + { + TYPE_SIZE (this_class) = error_mark_node; + CLASS_BEING_LAIDOUT (this_class) = 0; + list = TREE_CHAIN (list); + return; + } + } + } + } + + /* Convert the size back to an SI integer value */ + TYPE_SIZE_UNIT (this_class) = + fold (convert (int_type_node, TYPE_SIZE_UNIT (this_class))); + + CLASS_BEING_LAIDOUT (this_class) = 0; + list = TREE_CHAIN (list); } void @@ -1513,7 +1889,6 @@ layout_class_methods (this_class) if (TYPE_NVIRTUALS (this_class)) return; - push_obstacks (&permanent_obstack, &permanent_obstack); super_class = CLASSTYPE_SUPER (this_class); handle_type = CLASS_TO_HANDLE_TYPE (this_class); @@ -1526,7 +1901,7 @@ layout_class_methods (this_class) } else dtable_count = integer_zero_node; - + TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type)); for (method_decl = TYPE_METHODS (handle_type); @@ -1539,7 +1914,105 @@ layout_class_methods (this_class) #ifdef JAVA_USE_HANDLES layout_type (handle_type); #endif - pop_obstacks (); +} + +/* A sorted list of all C++ keywords. */ + +static const char *cxx_keywords[] = +{ + "asm", + "auto", + "bool", + "const_cast", + "delete", + "dynamic_cast", + "enum", + "explicit", + "extern", + "friend", + "inline", + "mutable", + "namespace", + "overload", + "register", + "reinterpret_cast", + "signed", + "sizeof", + "static_cast", + "struct", + "template", + "typedef", + "typeid", + "typename", + "typenameopt", + "union", + "unsigned", + "using", + "virtual", + "volatile", + "wchar_t" +}; + +/* Return 0 if NAME is equal to STR, -1 if STR is "less" than NAME, + and 1 if STR is "greater" than NAME. */ + +static int +utf8_cmp (str, length, name) + const unsigned char *str; + int length; + const char *name; +{ + const unsigned char *limit = str + length; + int i; + + for (i = 0; name[i]; ++i) + { + int ch = UTF8_GET (str, limit); + if (ch != name[i]) + return ch - name[i]; + } + + return str == limit ? 0 : 1; +} + +/* Return true if NAME is a C++ keyword. */ + +static int +cxx_keyword_p (name, length) + const char *name; + int length; +{ + int last = ARRAY_SIZE (cxx_keywords); + int first = 0; + int mid = (last + first) / 2; + int old = -1; + + for (mid = (last + first) / 2; + mid != old; + old = mid, mid = (last + first) / 2) + { + int kwl = strlen (cxx_keywords[mid]); + int min_length = kwl > length ? length : kwl; + int r = utf8_cmp (name, min_length, cxx_keywords[mid]); + + if (r == 0) + { + int i; + /* We've found a match if all the remaining characters are + `$'. */ + for (i = min_length; i < length && name[i] == '$'; ++i) + ; + if (i == length) + return 1; + r = 1; + } + + if (r < 0) + last = mid; + else + first = mid; + } + return 0; } /* Lay METHOD_DECL out, returning a possibly new value of @@ -1559,8 +2032,7 @@ layout_class_method (this_class, super_class, method_decl, dtable_count) if (method_name_is_wfl) method_name = java_get_real_method_name (method_decl); - if (method_name != init_identifier_node - && method_name != finit_identifier_node) + if (!ID_INIT_P (method_name) && !ID_FINIT_P (method_name)) { int encoded_len = unicode_mangling_length (IDENTIFIER_POINTER (method_name), @@ -1578,10 +2050,16 @@ layout_class_method (this_class, super_class, method_decl, dtable_count) IDENTIFIER_POINTER (method_name), IDENTIFIER_LENGTH (method_name)); } + + /* Mangle C++ keywords by appending a `$'. */ + /* FIXME: NO_DOLLAR_IN_LABEL */ + if (cxx_keyword_p (IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name))) + obstack_grow (&temporary_obstack, "$", 1); } - + obstack_grow (&temporary_obstack, "__", 2); - if (method_name == finit_identifier_node) + if (ID_FINIT_P (method_name)) obstack_grow (&temporary_obstack, "finit", 5); append_gpp_mangled_type (&temporary_obstack, this_class); TREE_PUBLIC (method_decl) = 1; @@ -1643,11 +2121,11 @@ layout_class_method (this_class, super_class, method_decl, dtable_count) it's an interface method that isn't clinit. */ if (! METHOD_ABSTRACT (method_decl) || (CLASS_INTERFACE (TYPE_NAME (this_class)) - && (IS_CLINIT (method_decl)))) + && (DECL_CLINIT_P (method_decl)))) make_function_rtl (method_decl); obstack_free (&temporary_obstack, asm_name); - if (method_name == init_identifier_node) + if (ID_INIT_P (method_name)) { const char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); for (ptr = p; *ptr; ) @@ -1692,9 +2170,11 @@ layout_class_method (this_class, super_class, method_decl, dtable_count) && dtable_count) { DECL_VINDEX (method_decl) = dtable_count; - dtable_count = build_int_2 (1+TREE_INT_CST_LOW (dtable_count), 0); + dtable_count = fold (build (PLUS_EXPR, integer_type_node, + dtable_count, integer_one_node)); } } + return dtable_count; } @@ -1703,6 +2183,9 @@ static tree registered_class = NULL_TREE; void register_class () { + /* END does not need to be registered with the garbage collector + because it always points into the list given by REGISTERED_CLASS, + and that variable is registered with the collector. */ static tree end; tree node = TREE_OPERAND (build_class_ref (current_class), 0); tree current = copy_node (node); @@ -1722,7 +2205,7 @@ register_class () void emit_register_classes () { - extern tree get_file_function_name PROTO((int)); + extern tree get_file_function_name PARAMS ((int)); tree init_name = get_file_function_name ('I'); tree init_type = build_function_type (void_type_node, end_params_node); tree init_decl; @@ -1761,4 +2244,7 @@ void init_class_processing () { registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterClass"); + ggc_add_tree_root (®istered_class, 1); + ggc_add_rtx_root (®isterClass_libfunc, 1); + gcc_obstack_init (&temporary_obstack); }