From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/java/class.c | 3247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3247 insertions(+) create mode 100644 gcc/java/class.c (limited to 'gcc/java/class.c') diff --git a/gcc/java/class.c b/gcc/java/class.c new file mode 100644 index 000000000..92091f9e9 --- /dev/null +++ b/gcc/java/class.c @@ -0,0 +1,3247 @@ +/* Functions related to building classes and their related objects. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007, 2008, 2010 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. + +Java and all Java-based marks are trademarks or registered trademarks +of Sun Microsystems, Inc. in the United States and other countries. +The Free Software Foundation is independent of Sun Microsystems, Inc. */ + +/* Written by Per Bothner */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "flags.h" +#include "java-tree.h" +#include "jcf.h" +#include "obstack.h" +#include "diagnostic-core.h" +#include "toplev.h" +#include "output.h" +#include "parse.h" +#include "function.h" +#include "ggc.h" +#include "cgraph.h" +#include "tree-iterator.h" +#include "vecprim.h" +#include "tm.h" /* FIXME: For gcc_obstack_init from defaults.h. */ +#include "target.h" + +static tree make_method_value (tree); +static tree build_java_method_type (tree, tree, int); +static int32 hashUtf8String (const char *, int); +static tree make_field_value (tree); +static tree get_dispatch_vector (tree); +static tree get_dispatch_table (tree, tree); +static int supers_all_compiled (tree type); +static tree maybe_layout_super_class (tree, tree); +static void add_miranda_methods (tree, tree); +static int assume_compiled (const char *); +static tree build_symbol_entry (tree, tree); +static tree emit_assertion_table (tree); +static void register_class (void); + +struct obstack temporary_obstack; + +static const char *cyclic_inheritance_report; + +/* 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 + class_flag_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 class_flag_node_struct +{ + /* The class or package name. */ + const char *ident; + + /* Nonzero if this represents an exclusion. */ + int value; + + /* Pointers to other nodes in the tree. */ + struct class_flag_node_struct *parent; + struct class_flag_node_struct *sibling; + struct class_flag_node_struct *child; +} class_flag_node; + +static class_flag_node *find_class_flag_node (class_flag_node *, const char *); +static void add_class_flag (class_flag_node **, const char *, int); + +/* This is the root of the include/exclude tree. */ + +static class_flag_node *assume_compiled_tree; + +static class_flag_node *enable_assert_tree; + +static GTY(()) tree class_roots[4]; +#define fields_ident class_roots[0] /* get_identifier ("fields") */ +#define info_ident class_roots[1] /* get_identifier ("info") */ +#define class_list class_roots[2] +#define class_dtable_decl class_roots[3] + +static GTY(()) VEC(tree,gc) *registered_class; + +/* A tree that returns the address of the class$ of the class + currently being compiled. */ +static GTY(()) tree this_classdollar; + +/* A list of static class fields. This is to emit proper debug + info for them. */ +VEC(tree,gc) *pending_static_fields; + +/* Return the node that most closely represents the class whose name + is IDENT. Start the search from NODE (followed by its siblings). + Return NULL if an appropriate node does not exist. */ + +static class_flag_node * +find_class_flag_node (class_flag_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 + && (ident[node_ident_length] == '\0' + || ident[node_ident_length] == '.'))) + { + /* We've found a match, however, there might be a more + specific match. */ + + class_flag_node *found = find_class_flag_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; +} + +void +add_class_flag (class_flag_node **rootp, const char *ident, int value) +{ + class_flag_node *root = *rootp; + class_flag_node *parent, *node; + + /* Create the root of the tree if it doesn't exist yet. */ + + if (NULL == root) + { + root = XNEW (class_flag_node); + root->ident = ""; + root->value = 0; + root->sibling = NULL; + root->child = NULL; + root->parent = NULL; + *rootp = root; + } + + /* Calling the function with the empty string means we're setting + value for the root of the hierarchy. */ + + if (0 == ident[0]) + { + root->value = value; + return; + } + + /* Find the parent node for this new node. PARENT will either be a + class or a package name. Adjust PARENT accordingly. */ + + parent = find_class_flag_node (root, ident); + if (strcmp (ident, parent->ident) == 0) + parent->value = value; + else + { + /* Insert new node into the tree. */ + node = XNEW (class_flag_node); + + node->ident = xstrdup (ident); + node->value = value; + node->child = NULL; + + node->parent = parent; + node->sibling = parent->child; + parent->child = node; + } +} + +/* Add a new IDENT to the include/exclude tree. It's an exclusion + if EXCLUDEP is nonzero. */ + +void +add_assume_compiled (const char *ident, int excludep) +{ + add_class_flag (&assume_compiled_tree, ident, excludep); +} + +/* The default value returned by enable_assertions. */ + +#define DEFAULT_ENABLE_ASSERT (optimize == 0) + +/* Enter IDENT (a class or package name) into the enable-assertions table. + VALUE is true to enable and false to disable. */ + +void +add_enable_assert (const char *ident, int value) +{ + if (enable_assert_tree == NULL) + add_class_flag (&enable_assert_tree, "", DEFAULT_ENABLE_ASSERT); + add_class_flag (&enable_assert_tree, ident, value); +} + +/* Returns nonzero if IDENT is the name of a class that the compiler + should assume has been compiled to object code. */ + +static int +assume_compiled (const char *ident) +{ + class_flag_node *i; + int result; + + if (NULL == assume_compiled_tree) + return 1; + + i = find_class_flag_node (assume_compiled_tree, ident); + + result = ! i->value; + + return (result); +} + +/* Return true if we should generate code to check assertions within KLASS. */ + +bool +enable_assertions (tree klass) +{ + /* Check if command-line specifies whether we should check assertions. */ + + if (klass != NULL_TREE && DECL_NAME (klass) && enable_assert_tree != NULL) + { + const char *ident = IDENTIFIER_POINTER (DECL_NAME (klass)); + class_flag_node *node + = find_class_flag_node (enable_assert_tree, ident); + return node->value; + } + + /* The default is to enable assertions if generating class files, + or not optimizing. */ + return DEFAULT_ENABLE_ASSERT; +} + +/* Return an IDENTIFIER_NODE the same as (OLD_NAME, OLD_LENGTH). + except that characters matching OLD_CHAR are substituted by NEW_CHAR. + Also, PREFIX is prepended, and SUFFIX is appended. */ + +tree +ident_subst (const char* old_name, + int old_length, + const char *prefix, + int old_char, + int new_char, + const char *suffix) +{ + int prefix_len = strlen (prefix); + int suffix_len = strlen (suffix); + int i = prefix_len + old_length + suffix_len + 1; + char *buffer = (char *) alloca (i); + + strcpy (buffer, prefix); + for (i = 0; i < old_length; i++) + { + char ch = old_name[i]; + if (ch == old_char) + ch = new_char; + buffer[prefix_len + i] = ch; + } + strcpy (buffer + prefix_len + old_length, suffix); + return get_identifier (buffer); +} + +/* Return an IDENTIFIER_NODE the same as OLD_ID, + except that characters matching OLD_CHAR are substituted by NEW_CHAR. + Also, PREFIX is prepended, and SUFFIX is appended. */ + +tree +identifier_subst (const tree old_id, + const char *prefix, + int old_char, + int new_char, + const char *suffix) +{ + return ident_subst (IDENTIFIER_POINTER (old_id), IDENTIFIER_LENGTH (old_id), + prefix, old_char, new_char, suffix); +} + +/* Generate a valid C identifier from the name of the class TYPE, + prefixed by PREFIX. */ + +tree +mangled_classname (const char *prefix, tree type) +{ + tree result; + tree ident = TYPE_NAME (type); + if (TREE_CODE (ident) != IDENTIFIER_NODE) + ident = DECL_NAME (ident); + result = identifier_subst (ident, prefix, '.', '_', ""); + + /* Replace any characters that aren't in the set [0-9a-zA-Z_$] with + "_0xXX". Class names containing such chracters are uncommon, but + they do sometimes occur in class files. Without this check, + these names cause assembly errors. + + There is a possibility that a real class name could conflict with + the identifier we generate, but it is unlikely and will + immediately be detected as an assembler error. At some point we + should do something more elaborate (perhaps using the full + unicode mangling scheme) in order to prevent such a conflict. */ + { + int i; + const int len = IDENTIFIER_LENGTH (result); + const char *p = IDENTIFIER_POINTER (result); + int illegal_chars = 0; + + /* Make two passes over the identifier. The first pass is merely + to count illegal characters; we need to do this in order to + allocate a buffer. */ + for (i = 0; i < len; i++) + { + char c = p[i]; + illegal_chars += (! ISALNUM (c) && c != '_' && c != '$'); + } + + /* And the second pass, which is rarely executed, does the + rewriting. */ + if (illegal_chars != 0) + { + char *buffer = (char *) alloca (illegal_chars * 4 + len + 1); + int j; + + for (i = 0, j = 0; i < len; i++) + { + char c = p[i]; + if (! ISALNUM (c) && c != '_' && c != '$') + { + buffer[j++] = '_'; + sprintf (&buffer[j], "0x%02x", c); + j += 4; + } + else + buffer[j++] = c; + } + + buffer[j] = 0; + result = get_identifier (buffer); + } + } + + return result; +} + +tree +make_class (void) +{ + tree type; + type = make_node (RECORD_TYPE); + /* Unfortunately we must create the binfo here, so that class + loading works. */ + TYPE_BINFO (type) = make_tree_binfo (0); + MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type); + TYPE_CATCH_CLASSES (type) = NULL; + /* Push a dummy entry; we can't call make_catch_class_record here + because other infrastructure may not be set up yet. We'll come + back and fill it in later once said infrastructure is + initialized. */ + CONSTRUCTOR_APPEND_ELT (TYPE_CATCH_CLASSES (type), NULL_TREE, NULL_TREE); + + return type; +} + +/* Given a fully-qualified classname in NAME (whose length is NAME_LENGTH), + and where each of the constituents is separated by '/', + return a corresponding IDENTIFIER_NODE, except using '.' as separator. */ + +tree +unmangle_classname (const char *name, int name_length) +{ + tree to_return = ident_subst (name, name_length, "", '/', '.', ""); + /* It's not sufficient to compare to_return and get_identifier + (name) to determine whether to_return is qualified. There are + cases in signature analysis where name will be stripped of a + trailing ';'. */ + name = IDENTIFIER_POINTER (to_return); + while (*name) + if (*name++ == '.') + { + QUALIFIED_P (to_return) = 1; + break; + } + + return to_return; +} + +#define GEN_TABLE(TABLE, NAME, TABLE_TYPE, TYPE) \ +do \ +{ \ + const char *type_name = IDENTIFIER_POINTER (mangled_classname ("", TYPE)); \ + char *buf = (char *) alloca (strlen (type_name) \ + + strlen (#NAME "_syms_") + 1); \ + tree decl; \ + \ + sprintf (buf, #NAME "_%s", type_name); \ + TYPE_## TABLE ##_DECL (type) = decl = \ + build_decl (input_location, VAR_DECL, get_identifier (buf), TABLE_TYPE); \ + DECL_EXTERNAL (decl) = 1; \ + TREE_STATIC (decl) = 1; \ + TREE_READONLY (decl) = 1; \ + TREE_CONSTANT (decl) = 1; \ + DECL_IGNORED_P (decl) = 1; \ + /* Mark the table as belonging to this class. */ \ + pushdecl (decl); \ + MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl); \ + DECL_OWNER (decl) = TYPE; \ + sprintf (buf, #NAME "_syms_%s", type_name); \ + TYPE_## TABLE ##_SYMS_DECL (TYPE) = \ + build_decl (input_location, VAR_DECL, get_identifier (buf), symbols_array_type); \ + TREE_STATIC (TYPE_## TABLE ##_SYMS_DECL (TYPE)) = 1; \ + TREE_CONSTANT (TYPE_## TABLE ##_SYMS_DECL (TYPE)) = 1; \ + DECL_IGNORED_P (TYPE_## TABLE ##_SYMS_DECL (TYPE)) = 1; \ +} \ +while (0) + +/* Given a class, create the DECLs for all its associated indirect + dispatch tables. */ +void +gen_indirect_dispatch_tables (tree type) +{ + const char *type_name = IDENTIFIER_POINTER (mangled_classname ("", type)); + { + tree field = NULL; + char *buf = (char *) alloca (strlen (type_name) + + strlen ("_catch_classes_") + 1); + tree catch_class_type = make_node (RECORD_TYPE); + + sprintf (buf, "_catch_classes_%s", type_name); + PUSH_FIELD (input_location, + catch_class_type, field, "address", utf8const_ptr_type); + PUSH_FIELD (input_location, + catch_class_type, field, "classname", ptr_type_node); + FINISH_RECORD (catch_class_type); + + TYPE_CTABLE_DECL (type) + = build_decl (input_location, VAR_DECL, get_identifier (buf), + build_array_type (catch_class_type, 0)); + DECL_EXTERNAL (TYPE_CTABLE_DECL (type)) = 1; + TREE_STATIC (TYPE_CTABLE_DECL (type)) = 1; + TREE_READONLY (TYPE_CTABLE_DECL (type)) = 1; + TREE_CONSTANT (TYPE_CTABLE_DECL (type)) = 1; + DECL_IGNORED_P (TYPE_CTABLE_DECL (type)) = 1; + pushdecl (TYPE_CTABLE_DECL (type)); + } + + if (flag_indirect_dispatch) + { + GEN_TABLE (ATABLE, _atable, atable_type, type); + GEN_TABLE (OTABLE, _otable, otable_type, type); + GEN_TABLE (ITABLE, _itable, itable_type, type); + } +} + +#undef GEN_TABLE + +tree +push_class (tree class_type, tree class_name) +{ + tree decl, signature; + location_t saved_loc = input_location; + CLASS_P (class_type) = 1; + decl = build_decl (input_location, TYPE_DECL, class_name, class_type); + TYPE_DECL_SUPPRESS_DEBUG (decl) = 1; + + /* dbxout needs a DECL_SIZE if in gstabs mode */ + DECL_SIZE (decl) = integer_zero_node; + + input_location = saved_loc; + signature = identifier_subst (class_name, "L", '.', '/', ";"); + IDENTIFIER_SIGNATURE_TYPE (signature) = build_pointer_type (class_type); + + /* 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); + + return decl; +} + +/* Finds the (global) class named NAME. Creates the class if not found. + Also creates associated TYPE_DECL. + Does not check if the class actually exists, load the class, + fill in field or methods, or do layout_type. */ + +tree +lookup_class (tree name) +{ + tree decl = IDENTIFIER_CLASS_VALUE (name); + if (decl == NULL_TREE) + decl = push_class (make_class (), name); + return TREE_TYPE (decl); +} + +void +set_super_info (int access_flags, tree this_class, + tree super_class, int interfaces_count) +{ + int total_supers = interfaces_count; + tree class_decl = TYPE_NAME (this_class); + + if (super_class) + total_supers++; + + if (total_supers) + TYPE_BINFO (this_class) = make_tree_binfo (total_supers); + TYPE_VFIELD (this_class) = TYPE_VFIELD (object_type_node); + if (super_class) + { + tree super_binfo = make_tree_binfo (0); + BINFO_TYPE (super_binfo) = super_class; + BINFO_OFFSET (super_binfo) = integer_zero_node; + BINFO_BASE_APPEND (TYPE_BINFO (this_class), super_binfo); + CLASS_HAS_SUPER_FLAG (TYPE_BINFO (this_class)) = 1; + } + + set_class_decl_access_flags (access_flags, class_decl); +} + +void +set_class_decl_access_flags (int access_flags, tree class_decl) +{ + 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; + if (access_flags & ACC_STRICT) CLASS_STRICTFP (class_decl) = 1; + if (access_flags & ACC_ENUM) CLASS_ENUM (class_decl) = 1; + if (access_flags & ACC_SYNTHETIC) CLASS_SYNTHETIC (class_decl) = 1; + if (access_flags & ACC_ANNOTATION) CLASS_ANNOTATION (class_decl) = 1; +} + +/* Return length of inheritance chain of CLAS, where java.lang.Object is 0, + direct sub-classes of Object are 1, and so on. */ + +int +class_depth (tree 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++; + clas = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (clas), 0)); + } + return depth; +} + +/* Return true iff TYPE2 is an interface that extends interface TYPE1 */ + +int +interface_of_p (tree type1, tree type2) +{ + int i; + tree binfo, base_binfo; + + if (! TYPE_BINFO (type2)) + return 0; + + for (binfo = TYPE_BINFO (type2), i = 0; + BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + if (BINFO_TYPE (base_binfo) == type1) + return 1; + + for (binfo = TYPE_BINFO (type2), i = 0; + BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) /* */ + if (BINFO_TYPE (base_binfo) + && interface_of_p (type1, BINFO_TYPE (base_binfo))) + return 1; + + return 0; +} + +/* Return true iff TYPE1 inherits from TYPE2. */ + +int +inherits_from_p (tree type1, tree type2) +{ + while (type1 != NULL_TREE && TREE_CODE (type1) == RECORD_TYPE) + { + if (type1 == type2) + return 1; + + if (! CLASS_LOADED_P (type1)) + load_class (type1, 1); + + type1 = maybe_layout_super_class (CLASSTYPE_SUPER (type1), type1); + } + return 0; +} + +/* Return a 1 iff TYPE1 is an enclosing context for TYPE2 */ + +int +enclosing_context_p (tree type1, tree 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 TYPE1 and TYPE2 share a common enclosing class, regardless of + nesting level. */ + +int +common_enclosing_context_p (tree type1, tree type2) +{ + while (type1) + { + tree current; + for (current = type2; current; + current = (INNER_CLASS_TYPE_P (current) ? + TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current))) : + NULL_TREE)) + if (type1 == current) + return 1; + + if (INNER_CLASS_TYPE_P (type1)) + type1 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1))); + else + break; + } + return 0; +} + +/* Return 1 iff there exists a common enclosing "this" between TYPE1 + and TYPE2, without crossing any static context. */ + +int +common_enclosing_instance_p (tree type1, tree 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; +} + +/* Add INTERFACE_CLASS to THIS_CLASS iff INTERFACE_CLASS can't be + found in THIS_CLASS. Returns NULL_TREE upon success, INTERFACE_CLASS + if attempt is made to add it twice. */ + +tree +maybe_add_interface (tree this_class, tree interface_class) +{ + tree binfo, base_binfo; + int i; + + for (binfo = TYPE_BINFO (this_class), i = 0; + BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + if (BINFO_TYPE (base_binfo) == interface_class) + return interface_class; + add_interface (this_class, interface_class); + return NULL_TREE; +} + +/* Add the INTERFACE_CLASS as one of the interfaces of THIS_CLASS. */ + +void +add_interface (tree this_class, tree interface_class) +{ + tree interface_binfo = make_tree_binfo (0); + + BINFO_TYPE (interface_binfo) = interface_class; + BINFO_OFFSET (interface_binfo) = integer_zero_node; + BINFO_VPTR_FIELD (interface_binfo) = integer_zero_node; + BINFO_VIRTUAL_P (interface_binfo) = 1; + + BINFO_BASE_APPEND (TYPE_BINFO (this_class), interface_binfo); +} + +static tree +build_java_method_type (tree fntype, tree this_class, int access_flags) +{ + if (access_flags & ACC_STATIC) + return fntype; + fntype = build_method_type (this_class, fntype); + + /* We know that arg 1 of every nonstatic method is non-null; tell + the back-end so. */ + TYPE_ATTRIBUTES (fntype) = (tree_cons + (get_identifier ("nonnull"), + tree_cons (NULL_TREE, + build_int_cst (NULL_TREE, 1), + NULL_TREE), + TYPE_ATTRIBUTES (fntype))); + return fntype; +} + +void +java_hide_decl (tree decl ATTRIBUTE_UNUSED) +{ +#ifdef HAVE_GAS_HIDDEN + DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN; + DECL_VISIBILITY_SPECIFIED (decl) = 1; +#endif +} + +tree +add_method_1 (tree this_class, int access_flags, tree name, tree function_type) +{ + tree method_type, fndecl; + + method_type = build_java_method_type (function_type, + this_class, access_flags); + + fndecl = build_decl (input_location, FUNCTION_DECL, name, method_type); + DECL_CONTEXT (fndecl) = this_class; + + DECL_LANG_SPECIFIC (fndecl) + = ggc_alloc_cleared_lang_decl(sizeof (struct lang_decl)); + DECL_LANG_SPECIFIC (fndecl)->desc = LANG_DECL_FUNC; + + /* Initialize the static initializer test table. */ + + DECL_FUNCTION_INIT_TEST_TABLE (fndecl) = java_treetreehash_create (10); + + /* Initialize the initialized (static) class table. */ + if (access_flags & ACC_STATIC) + DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl) = + htab_create_ggc (50, htab_hash_pointer, htab_eq_pointer, NULL); + + DECL_CHAIN (fndecl) = TYPE_METHODS (this_class); + TYPE_METHODS (this_class) = fndecl; + + /* If pointers to member functions use the least significant bit to + indicate whether a function is virtual, ensure a pointer + to this function will have that bit clear. */ + if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn + && !(access_flags & ACC_STATIC) + && DECL_ALIGN (fndecl) < 2 * BITS_PER_UNIT) + DECL_ALIGN (fndecl) = 2 * BITS_PER_UNIT; + + /* 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; + if (access_flags & ACC_PRIVATE) + METHOD_PRIVATE (fndecl) = 1; + if (access_flags & ACC_NATIVE) + { + METHOD_NATIVE (fndecl) = 1; + DECL_EXTERNAL (fndecl) = 1; + } + else + /* FNDECL is external unless we are compiling it into this object + file. */ + DECL_EXTERNAL (fndecl) = CLASS_FROM_CURRENTLY_COMPILED_P (this_class) == 0; + if (access_flags & ACC_STATIC) + METHOD_STATIC (fndecl) = 1; + if (access_flags & ACC_FINAL) + METHOD_FINAL (fndecl) = 1; + if (access_flags & ACC_SYNCHRONIZED) METHOD_SYNCHRONIZED (fndecl) = 1; + if (access_flags & ACC_ABSTRACT) METHOD_ABSTRACT (fndecl) = 1; + if (access_flags & ACC_STRICT) METHOD_STRICTFP (fndecl) = 1; + if (access_flags & ACC_SYNTHETIC) DECL_ARTIFICIAL (fndecl) = 1; + if (access_flags & ACC_BRIDGE) METHOD_BRIDGE (fndecl) = 1; + if (access_flags & ACC_VARARGS) METHOD_VARARGS (fndecl) = 1; + return fndecl; +} + +/* Add a method to THIS_CLASS. + The method's name is NAME. + Its signature (mangled type) is METHOD_SIG (an IDENTIFIER_NODE). */ + +tree +add_method (tree this_class, int access_flags, tree name, tree method_sig) +{ + tree function_type, fndecl; + const unsigned char *sig + = (const unsigned char *) IDENTIFIER_POINTER (method_sig); + + if (sig[0] != '(') + fatal_error ("bad method signature"); + + function_type = get_type_from_signature (method_sig); + fndecl = add_method_1 (this_class, access_flags, name, function_type); + set_java_signature (TREE_TYPE (fndecl), method_sig); + return fndecl; +} + +tree +add_field (tree klass, tree name, tree field_type, int flags) +{ + int is_static = (flags & ACC_STATIC) != 0; + tree field; + field = build_decl (input_location, + is_static ? VAR_DECL : FIELD_DECL, name, field_type); + DECL_CHAIN (field) = TYPE_FIELDS (klass); + TYPE_FIELDS (klass) = field; + DECL_CONTEXT (field) = klass; + MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (field); + + if (flags & ACC_PUBLIC) FIELD_PUBLIC (field) = 1; + if (flags & ACC_PROTECTED) FIELD_PROTECTED (field) = 1; + if (flags & ACC_PRIVATE) FIELD_PRIVATE (field) = 1; + if (flags & ACC_FINAL) FIELD_FINAL (field) = 1; + if (flags & ACC_VOLATILE) + { + FIELD_VOLATILE (field) = 1; + TREE_THIS_VOLATILE (field) = 1; + } + if (flags & ACC_TRANSIENT) FIELD_TRANSIENT (field) = 1; + if (flags & ACC_ENUM) FIELD_ENUM (field) = 1; + if (flags & ACC_SYNTHETIC) FIELD_SYNTHETIC (field) = 1; + if (is_static) + { + FIELD_STATIC (field) = 1; + /* Always make field externally visible. This is required so + that native methods can always access the field. */ + TREE_PUBLIC (field) = 1; + /* Hide everything that shouldn't be visible outside a DSO. */ + if (flag_indirect_classes + || (FIELD_PRIVATE (field))) + java_hide_decl (field); + /* Considered external unless we are compiling it into this + object file. */ + DECL_EXTERNAL (field) = (is_compiled_class (klass) != 2); + if (!DECL_EXTERNAL (field)) + VEC_safe_push (tree, gc, pending_static_fields, field); + } + + return field; +} + +/* Associate a constant value CONSTANT with VAR_DECL FIELD. */ + +void +set_constant_value (tree field, tree constant) +{ + if (field == NULL_TREE) + warning (OPT_Wattributes, + "misplaced ConstantValue attribute (not in any field)"); + else if (DECL_INITIAL (field) != NULL_TREE) + warning (OPT_Wattributes, + "duplicate ConstantValue attribute for field '%s'", + IDENTIFIER_POINTER (DECL_NAME (field))); + else + { + DECL_INITIAL (field) = constant; + if (TREE_TYPE (constant) != TREE_TYPE (field) + && ! (TREE_TYPE (constant) == int_type_node + && INTEGRAL_TYPE_P (TREE_TYPE (field)) + && TYPE_PRECISION (TREE_TYPE (field)) <= 32) + && ! (TREE_TYPE (constant) == utf8const_ptr_type + && TREE_TYPE (field) == string_ptr_type_node)) + error ("ConstantValue attribute of field '%s' has wrong type", + IDENTIFIER_POINTER (DECL_NAME (field))); + } +} + +/* Calculate a hash value for a string encoded in Utf8 format. + * This returns the same hash value as specified for java.lang.String.hashCode. + */ + +static int32 +hashUtf8String (const char *str, int len) +{ + const unsigned char* ptr = (const unsigned char*) str; + const unsigned char *limit = ptr + len; + int32 hash = 0; + for (; ptr < limit;) + { + int ch = UTF8_GET (ptr, limit); + /* Updated specification from + http://www.javasoft.com/docs/books/jls/clarify.html. */ + hash = (31 * hash) + ch; + } + return hash; +} + +tree +build_utf8_ref (tree name) +{ + const char * name_ptr = IDENTIFIER_POINTER (name); + int name_len = IDENTIFIER_LENGTH (name), name_pad; + char buf[60]; + tree ctype, field = NULL_TREE, str_type, cinit, string; + static int utf8_count = 0; + int name_hash; + tree ref = IDENTIFIER_UTF8_REF (name); + tree decl; + VEC(constructor_elt,gc) *v = NULL; + if (ref != NULL_TREE) + return ref; + + ctype = make_node (RECORD_TYPE); + /* '\0' byte plus padding to utf8const_type's alignment. */ + name_pad = TYPE_ALIGN_UNIT (utf8const_type) + - (name_len & (TYPE_ALIGN_UNIT (utf8const_type) - 1)); + str_type = build_prim_array_type (unsigned_byte_type_node, + name_len + name_pad); + PUSH_FIELD (input_location, ctype, field, "hash", unsigned_short_type_node); + PUSH_FIELD (input_location, + ctype, field, "length", unsigned_short_type_node); + PUSH_FIELD (input_location, ctype, field, "data", str_type); + FINISH_RECORD (ctype); + START_RECORD_CONSTRUCTOR (v, ctype); + name_hash = hashUtf8String (name_ptr, name_len) & 0xFFFF; + PUSH_FIELD_VALUE (v, "hash", build_int_cst (NULL_TREE, name_hash)); + PUSH_FIELD_VALUE (v, "length", build_int_cst (NULL_TREE, name_len)); + string = build_string (name_len, name_ptr); + TREE_TYPE (string) = str_type; + PUSH_FIELD_VALUE (v, "data", string); + FINISH_RECORD_CONSTRUCTOR (cinit, v, ctype); + TREE_CONSTANT (cinit) = 1; + + /* Generate a unique-enough identifier. */ + sprintf(buf, "_Utf%d", ++utf8_count); + + decl = build_decl (input_location, + VAR_DECL, get_identifier (buf), utf8const_type); + TREE_STATIC (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + TREE_READONLY (decl) = 1; + TREE_THIS_VOLATILE (decl) = 0; + DECL_INITIAL (decl) = cinit; + DECL_USER_ALIGN (decl) = 1; + + if (HAVE_GAS_SHF_MERGE) + { + int decl_size; + /* Ensure decl_size is a multiple of utf8const_type's alignment. */ + decl_size = name_len + 4 + name_pad; + 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); + switch_to_section (get_section (buf, flags, NULL)); + DECL_SECTION_NAME (decl) = build_string (strlen (buf), buf); + } + } + + layout_decl (decl, 0); + DECL_SIZE (decl) = TYPE_SIZE (ctype); + DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (ctype); + pushdecl (decl); + rest_of_decl_compilation (decl, global_bindings_p (), 0); + varpool_mark_needed_node (varpool_node (decl)); + ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl); + IDENTIFIER_UTF8_REF (name) = ref; + return ref; +} + +/* Like build_class_ref, but instead of a direct reference generate a + pointer into the constant pool. */ + +static tree +build_indirect_class_ref (tree type) +{ + int index; + tree cl; + index = alloc_class_constant (type); + cl = build_ref_from_constant_pool (index); + return convert (promote_type (class_ptr_type), cl); +} + +static tree +build_static_class_ref (tree type) +{ + tree decl_name, decl, ref; + + if (TYPE_SIZE (type) == error_mark_node) + return null_pointer_node; + decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)), + "", '/', '/', ".class$$"); + decl = IDENTIFIER_GLOBAL_VALUE (decl_name); + if (decl == NULL_TREE) + { + decl = build_decl (input_location, VAR_DECL, decl_name, class_type_node); + TREE_STATIC (decl) = 1; + if (! flag_indirect_classes) + { + TREE_PUBLIC (decl) = 1; + if (CLASS_PRIVATE (TYPE_NAME (type))) + java_hide_decl (decl); + } + DECL_IGNORED_P (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + if (is_compiled_class (type) == 1) + DECL_EXTERNAL (decl) = 1; + MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl); + DECL_CLASS_FIELD_P (decl) = 1; + DECL_CONTEXT (decl) = type; + + /* ??? We want to preserve the DECL_CONTEXT we set just above, + that that means not calling pushdecl_top_level. */ + IDENTIFIER_GLOBAL_VALUE (decl_name) = decl; + } + + ref = build1 (ADDR_EXPR, class_ptr_type, decl); + return ref; +} + +static tree +build_classdollar_field (tree type) +{ + tree decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)), + "", '/', '/', ".class$"); + tree decl = IDENTIFIER_GLOBAL_VALUE (decl_name); + + if (decl == NULL_TREE) + { + decl + = build_decl (input_location, + VAR_DECL, decl_name, + (build_type_variant + (build_pointer_type + (build_type_variant (class_type_node, + /* const */ 1, 0)), + /* const */ 1, 0))); + TREE_STATIC (decl) = 1; + TREE_CONSTANT (decl) = 1; + TREE_READONLY (decl) = 1; + TREE_PUBLIC (decl) = 1; + java_hide_decl (decl); + DECL_IGNORED_P (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl); + IDENTIFIER_GLOBAL_VALUE (decl_name) = decl; + DECL_CLASS_FIELD_P (decl) = 1; + DECL_CONTEXT (decl) = type; + } + + return decl; +} + +/* Create a local variable that holds the current class$. */ + +void +cache_this_class_ref (tree fndecl) +{ + if (optimize) + { + tree classdollar_field; + if (flag_indirect_classes) + classdollar_field = build_classdollar_field (output_class); + else + classdollar_field = build_static_class_ref (output_class); + + this_classdollar = build_decl (input_location, + VAR_DECL, NULL_TREE, + TREE_TYPE (classdollar_field)); + + java_add_local_var (this_classdollar); + java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (this_classdollar), + this_classdollar, classdollar_field)); + } + else + this_classdollar = build_classdollar_field (output_class); + + /* Prepend class initialization for static methods reachable from + other classes. */ + if (METHOD_STATIC (fndecl) + && (! METHOD_PRIVATE (fndecl) + || INNER_CLASS_P (DECL_CONTEXT (fndecl))) + && ! DECL_CLINIT_P (fndecl) + && ! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (fndecl)))) + { + tree init = build_call_expr (soft_initclass_node, 1, + this_classdollar); + java_add_stmt (init); + } +} + +/* Remove the reference to the local variable that holds the current + class$. */ + +void +uncache_this_class_ref (tree fndecl ATTRIBUTE_UNUSED) +{ + this_classdollar = build_classdollar_field (output_class); +} + +/* Build a reference to the class TYPE. + Also handles primitive types and array types. */ + +tree +build_class_ref (tree type) +{ + int is_compiled = is_compiled_class (type); + if (is_compiled) + { + tree ref, decl; + if (TREE_CODE (type) == POINTER_TYPE) + type = TREE_TYPE (type); + + if (flag_indirect_dispatch + && type != output_class + && TREE_CODE (type) == RECORD_TYPE) + return build_indirect_class_ref (type); + + if (type == output_class && flag_indirect_classes) + { + /* This can be NULL if we see a JNI stub before we see any + other method. */ + if (! this_classdollar) + this_classdollar = build_classdollar_field (output_class); + return this_classdollar; + } + + if (TREE_CODE (type) == RECORD_TYPE) + return build_static_class_ref (type); + else + { + const char *name; + tree decl_name; + char buffer[25]; + decl_name = TYPE_NAME (type); + if (TREE_CODE (decl_name) == TYPE_DECL) + decl_name = DECL_NAME (decl_name); + name = IDENTIFIER_POINTER (decl_name); + if (strncmp (name, "promoted_", 9) == 0) + name += 9; + sprintf (buffer, "_Jv_%sClass", name); + decl_name = get_identifier (buffer); + decl = IDENTIFIER_GLOBAL_VALUE (decl_name); + if (decl == NULL_TREE) + { + decl = build_decl (input_location, + VAR_DECL, decl_name, class_type_node); + TREE_STATIC (decl) = 1; + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + pushdecl_top_level (decl); + } + } + + ref = build1 (ADDR_EXPR, class_ptr_type, decl); + return ref; + } + else + return build_indirect_class_ref (type); +} + +/* Create a local statically allocated variable that will hold a + pointer to a static field. */ + +static tree +build_fieldref_cache_entry (int index, tree fdecl ATTRIBUTE_UNUSED) +{ + tree decl, decl_name; + const char *name = IDENTIFIER_POINTER (mangled_classname ("_cpool_", output_class)); + char *buf = (char *) alloca (strlen (name) + 20); + sprintf (buf, "%s_%d_ref", name, index); + decl_name = get_identifier (buf); + decl = IDENTIFIER_GLOBAL_VALUE (decl_name); + if (decl == NULL_TREE) + { + decl = build_decl (input_location, + VAR_DECL, decl_name, ptr_type_node); + TREE_STATIC (decl) = 1; + TREE_PUBLIC (decl) = 0; + DECL_EXTERNAL (decl) = 0; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + pushdecl_top_level (decl); + } + return decl; +} + +tree +build_static_field_ref (tree fdecl) +{ + tree fclass = DECL_CONTEXT (fdecl); + int is_compiled = is_compiled_class (fclass); + + /* Allow static final fields to fold to a constant. When using + -findirect-dispatch, we simply never do this folding if compiling + from .class; in the .class file constants will be referred to via + the constant pool. */ + if (!flag_indirect_dispatch + && (is_compiled + || (FIELD_FINAL (fdecl) && DECL_INITIAL (fdecl) != NULL_TREE + && (JSTRING_TYPE_P (TREE_TYPE (fdecl)) + || JNUMERIC_TYPE_P (TREE_TYPE (fdecl))) + && TREE_CONSTANT (DECL_INITIAL (fdecl))))) + { + if (is_compiled == 1) + DECL_EXTERNAL (fdecl) = 1; + } + else + { + /* Generate a CONSTANT_FieldRef for FDECL in the constant pool + and a class local static variable CACHE_ENTRY, then + + *(fdecl **)((__builtin_expect (cache_entry == null, false)) + ? cache_entry = _Jv_ResolvePoolEntry (output_class, cpool_index) + : cache_entry) + + This can mostly be optimized away, so that the usual path is a + load followed by a test and branch. _Jv_ResolvePoolEntry is + only called once for each constant pool entry. + + There is an optimization that we don't do: at the start of a + method, create a local copy of CACHE_ENTRY and use that instead. + + */ + + int cpool_index = alloc_constant_fieldref (output_class, fdecl); + tree cache_entry = build_fieldref_cache_entry (cpool_index, fdecl); + tree test + = build_call_expr (built_in_decls[BUILT_IN_EXPECT], 2, + build2 (EQ_EXPR, boolean_type_node, + cache_entry, null_pointer_node), + boolean_false_node); + tree cpool_index_cst = build_int_cst (NULL_TREE, cpool_index); + tree init + = build_call_expr (soft_resolvepoolentry_node, 2, + build_class_ref (output_class), + cpool_index_cst); + init = build2 (MODIFY_EXPR, ptr_type_node, cache_entry, init); + init = build3 (COND_EXPR, ptr_type_node, test, init, cache_entry); + init = fold_convert (build_pointer_type (TREE_TYPE (fdecl)), init); + fdecl = build1 (INDIRECT_REF, TREE_TYPE (fdecl), init); + } + return fdecl; +} + +int +get_access_flags_from_decl (tree decl) +{ + int access_flags = 0; + if (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL) + { + if (FIELD_STATIC (decl)) + access_flags |= ACC_STATIC; + if (FIELD_PUBLIC (decl)) + access_flags |= ACC_PUBLIC; + if (FIELD_PROTECTED (decl)) + access_flags |= ACC_PROTECTED; + if (FIELD_PRIVATE (decl)) + access_flags |= ACC_PRIVATE; + if (FIELD_FINAL (decl)) + access_flags |= ACC_FINAL; + if (FIELD_VOLATILE (decl)) + access_flags |= ACC_VOLATILE; + if (FIELD_TRANSIENT (decl)) + access_flags |= ACC_TRANSIENT; + if (FIELD_ENUM (decl)) + access_flags |= ACC_ENUM; + if (FIELD_SYNTHETIC (decl)) + access_flags |= ACC_SYNTHETIC; + return access_flags; + } + if (TREE_CODE (decl) == TYPE_DECL) + { + if (CLASS_PUBLIC (decl)) + access_flags |= ACC_PUBLIC; + if (CLASS_FINAL (decl)) + access_flags |= ACC_FINAL; + if (CLASS_SUPER (decl)) + access_flags |= ACC_SUPER; + if (CLASS_INTERFACE (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; + if (CLASS_STRICTFP (decl)) + access_flags |= ACC_STRICT; + if (CLASS_ENUM (decl)) + access_flags |= ACC_ENUM; + if (CLASS_SYNTHETIC (decl)) + access_flags |= ACC_SYNTHETIC; + if (CLASS_ANNOTATION (decl)) + access_flags |= ACC_ANNOTATION; + return access_flags; + } + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (METHOD_PUBLIC (decl)) + access_flags |= ACC_PUBLIC; + if (METHOD_PRIVATE (decl)) + access_flags |= ACC_PRIVATE; + if (METHOD_PROTECTED (decl)) + access_flags |= ACC_PROTECTED; + if (METHOD_STATIC (decl)) + access_flags |= ACC_STATIC; + if (METHOD_FINAL (decl)) + access_flags |= ACC_FINAL; + if (METHOD_SYNCHRONIZED (decl)) + access_flags |= ACC_SYNCHRONIZED; + if (METHOD_NATIVE (decl)) + access_flags |= ACC_NATIVE; + if (METHOD_ABSTRACT (decl)) + access_flags |= ACC_ABSTRACT; + if (METHOD_STRICTFP (decl)) + access_flags |= ACC_STRICT; + if (METHOD_INVISIBLE (decl)) + access_flags |= ACC_INVISIBLE; + if (DECL_ARTIFICIAL (decl)) + access_flags |= ACC_SYNTHETIC; + if (METHOD_BRIDGE (decl)) + access_flags |= ACC_BRIDGE; + if (METHOD_VARARGS (decl)) + access_flags |= ACC_VARARGS; + return access_flags; + } + gcc_unreachable (); +} + +static GTY (()) int alias_labelno = 0; + +/* Create a private alias for METHOD. Using this alias instead of the method + decl ensures that ncode entries in the method table point to the real function + at runtime, not a PLT entry. */ + +static tree +make_local_function_alias (tree method) +{ +#ifdef ASM_OUTPUT_DEF + tree alias; + + const char *method_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (method)); + char *name = (char *) alloca (strlen (method_name) + 2); + char *buf = (char *) alloca (strlen (method_name) + 128); + + /* Only create aliases for local functions. */ + if (DECL_EXTERNAL (method)) + return method; + + /* Prefix method_name with 'L' for the alias label. */ + *name = 'L'; + strcpy (name + 1, method_name); + + targetm.asm_out.generate_internal_label (buf, name, alias_labelno++); + alias = build_decl (input_location, + FUNCTION_DECL, get_identifier (buf), + TREE_TYPE (method)); + DECL_CONTEXT (alias) = NULL; + TREE_READONLY (alias) = TREE_READONLY (method); + TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (method); + TREE_PUBLIC (alias) = 0; + DECL_EXTERNAL (alias) = 0; + DECL_ARTIFICIAL (alias) = 1; + DECL_INITIAL (alias) = error_mark_node; + TREE_ADDRESSABLE (alias) = 1; + TREE_USED (alias) = 1; + TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; + if (!flag_syntax_only) + assemble_alias (alias, DECL_ASSEMBLER_NAME (method)); + return alias; +#else + return method; +#endif +} + +/** Make reflection data (_Jv_Field) for field FDECL. */ + +static tree +make_field_value (tree fdecl) +{ + tree finit; + int flags; + tree type = TREE_TYPE (fdecl); + int resolved = is_compiled_class (type) && ! flag_indirect_dispatch; + VEC(constructor_elt,gc) *v = NULL; + + START_RECORD_CONSTRUCTOR (v, field_type_node); + PUSH_FIELD_VALUE (v, "name", build_utf8_ref (DECL_NAME (fdecl))); + if (resolved) + type = build_class_ref (type); + else + { + tree signature = build_java_signature (type); + + type = build_utf8_ref (unmangle_classname + (IDENTIFIER_POINTER (signature), + IDENTIFIER_LENGTH (signature))); + } + PUSH_FIELD_VALUE (v, "type", type); + + flags = get_access_flags_from_decl (fdecl); + if (! resolved) + flags |= 0x8000 /* FIELD_UNRESOLVED_FLAG */; + + PUSH_FIELD_VALUE (v, "accflags", build_int_cst (NULL_TREE, flags)); + PUSH_FIELD_VALUE (v, "bsize", TYPE_SIZE_UNIT (TREE_TYPE (fdecl))); + + { + tree field_address = integer_zero_node; + tree index, value; + if ((DECL_INITIAL (fdecl) || ! flag_indirect_classes) + && FIELD_STATIC (fdecl)) + field_address = build_address_of (fdecl); + + index = (FIELD_STATIC (fdecl) + ? DECL_CHAIN (TYPE_FIELDS (field_info_union_node)) + : TYPE_FIELDS (field_info_union_node)); + value = (FIELD_STATIC (fdecl) + ? field_address + : byte_position (fdecl)); + + PUSH_FIELD_VALUE + (v, "info", + build_constructor_single (field_info_union_node, index, value)); + } + + FINISH_RECORD_CONSTRUCTOR (finit, v, field_type_node); + return finit; +} + +/** Make reflection data (_Jv_Method) for method MDECL. */ + +static tree +make_method_value (tree mdecl) +{ + static int method_name_count = 0; + tree minit; + tree index; + tree code; + tree class_decl; +#define ACC_TRANSLATED 0x4000 + int accflags = get_access_flags_from_decl (mdecl) | ACC_TRANSLATED; + VEC(constructor_elt,gc) *v = NULL; + + class_decl = DECL_CONTEXT (mdecl); + /* For interfaces, the index field contains the dispatch index. */ + if (CLASS_INTERFACE (TYPE_NAME (class_decl))) + index = build_int_cst (NULL_TREE, + get_interface_method_index (mdecl, class_decl)); + else if (!flag_indirect_dispatch && get_method_index (mdecl) != NULL_TREE) + index = get_method_index (mdecl); + else + index = integer_minus_one_node; + + code = null_pointer_node; + if (METHOD_ABSTRACT (mdecl)) + code = build1 (ADDR_EXPR, nativecode_ptr_type_node, + soft_abstractmethod_node); + else + code = build1 (ADDR_EXPR, nativecode_ptr_type_node, + make_local_function_alias (mdecl)); + START_RECORD_CONSTRUCTOR (v, method_type_node); + PUSH_FIELD_VALUE (v, "name", + build_utf8_ref (DECL_CONSTRUCTOR_P (mdecl) ? + init_identifier_node + : DECL_NAME (mdecl))); + { + tree signature = build_java_signature (TREE_TYPE (mdecl)); + PUSH_FIELD_VALUE (v, "signature", + (build_utf8_ref + (unmangle_classname + (IDENTIFIER_POINTER(signature), + IDENTIFIER_LENGTH(signature))))); + } + PUSH_FIELD_VALUE (v, "accflags", build_int_cst (NULL_TREE, accflags)); + PUSH_FIELD_VALUE (v, "index", index); + PUSH_FIELD_VALUE (v, "ncode", code); + + { + /* Compute the `throws' information for the method. */ + tree table = null_pointer_node; + + if (!VEC_empty (tree, DECL_FUNCTION_THROWS (mdecl))) + { + int length = 1 + VEC_length (tree, DECL_FUNCTION_THROWS (mdecl)); + tree t, type, array; + char buf[60]; + VEC(constructor_elt,gc) *v = NULL; + int idx = length - 1; + unsigned ix; + constructor_elt *e; + + v = VEC_alloc (constructor_elt, gc, length); + VEC_safe_grow_cleared (constructor_elt, gc, v, length); + + e = VEC_index (constructor_elt, v, idx--); + e->value = null_pointer_node; + + FOR_EACH_VEC_ELT (tree, DECL_FUNCTION_THROWS (mdecl), ix, t) + { + tree sig = DECL_NAME (TYPE_NAME (t)); + tree utf8 + = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (sig), + IDENTIFIER_LENGTH (sig))); + e = VEC_index (constructor_elt, v, idx--); + e->value = utf8; + } + gcc_assert (idx == -1); + type = build_prim_array_type (ptr_type_node, length); + table = build_constructor (type, v); + /* Compute something unique enough. */ + sprintf (buf, "_methods%d", method_name_count++); + array = build_decl (input_location, + VAR_DECL, get_identifier (buf), type); + DECL_INITIAL (array) = table; + TREE_STATIC (array) = 1; + DECL_ARTIFICIAL (array) = 1; + DECL_IGNORED_P (array) = 1; + rest_of_decl_compilation (array, 1, 0); + + table = build1 (ADDR_EXPR, ptr_type_node, array); + } + + PUSH_FIELD_VALUE (v, "throws", table); + } + + FINISH_RECORD_CONSTRUCTOR (minit, v, method_type_node); + return minit; +} + +static tree +get_dispatch_vector (tree type) +{ + tree vtable = TYPE_VTABLE (type); + + if (vtable == NULL_TREE) + { + HOST_WIDE_INT i; + tree method; + tree super = CLASSTYPE_SUPER (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_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 = DECL_CHAIN (method)) + { + tree method_index = get_method_index (method); + if (method_index != NULL_TREE + && host_integerp (method_index, 0)) + TREE_VEC_ELT (vtable, tree_low_cst (method_index, 0)) = method; + } + } + + return vtable; +} + +static tree +get_dispatch_table (tree type, tree this_class_addr) +{ + int abstract_p = CLASS_ABSTRACT (TYPE_NAME (type)); + tree vtable = get_dispatch_vector (type); + int i, j; + int nvirtuals = TREE_VEC_LENGTH (vtable); + int arraysize; + tree gc_descr; + VEC(constructor_elt,gc) *v = NULL; + constructor_elt *e; + tree arraytype; + + arraysize = (TARGET_VTABLE_USES_DESCRIPTORS? nvirtuals + 1 : nvirtuals + 2); + if (TARGET_VTABLE_USES_DESCRIPTORS) + arraysize *= TARGET_VTABLE_USES_DESCRIPTORS; + arraysize += 2; + + VEC_safe_grow_cleared (constructor_elt, gc, v, arraysize); + e = VEC_index (constructor_elt, v, arraysize - 1); + +#define CONSTRUCTOR_PREPEND_VALUE(E, V) E->value = V, E-- + for (i = nvirtuals; --i >= 0; ) + { + tree method = TREE_VEC_ELT (vtable, i); + if (METHOD_ABSTRACT (method)) + { + if (! abstract_p) + warning_at (DECL_SOURCE_LOCATION (method), 0, + "abstract method in non-abstract class"); + + if (TARGET_VTABLE_USES_DESCRIPTORS) + for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j) + CONSTRUCTOR_PREPEND_VALUE (e, null_pointer_node); + else + CONSTRUCTOR_PREPEND_VALUE (e, null_pointer_node); + } + else + { + if (TARGET_VTABLE_USES_DESCRIPTORS) + for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j) + { + tree fdesc = build2 (FDESC_EXPR, nativecode_ptr_type_node, + method, build_int_cst (NULL_TREE, j)); + TREE_CONSTANT (fdesc) = 1; + CONSTRUCTOR_PREPEND_VALUE (e, fdesc); + } + else + CONSTRUCTOR_PREPEND_VALUE (e, + build1 (ADDR_EXPR, + nativecode_ptr_type_node, + method)); + } + } + + /* 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. */ + /* 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); + CONSTRUCTOR_PREPEND_VALUE (e, gc_descr); + for (j = 1; j < TARGET_VTABLE_USES_DESCRIPTORS-1; ++j) + CONSTRUCTOR_PREPEND_VALUE (e, gc_descr); + CONSTRUCTOR_PREPEND_VALUE (e, this_class_addr); + + /** Pointer to type_info object (to be implemented), according to g++ ABI. */ + CONSTRUCTOR_PREPEND_VALUE (e, null_pointer_node); + /** Offset to start of whole object. Always (ptrdiff_t)0 for Java. */ + gcc_assert (e == VEC_address (constructor_elt, v)); + e->index = integer_zero_node; + e->value = null_pointer_node; +#undef CONSTRUCTOR_PREPEND_VALUE + + arraytype = build_prim_array_type (nativecode_ptr_type_node, arraysize); + return build_constructor (arraytype, v); +} + + +/* Set the method_index for a method decl. */ +void +set_method_index (tree decl, tree method_index) +{ + if (method_index != NULL_TREE) + { + /* method_index is null if we're using indirect dispatch. */ + method_index = fold (convert (sizetype, method_index)); + + if (TARGET_VTABLE_USES_DESCRIPTORS) + /* Add one to skip bogus descriptor for class and GC descriptor. */ + method_index = size_binop (PLUS_EXPR, method_index, size_int (1)); + else + /* Add 1 to skip "class" field of dtable, and 1 to skip GC + descriptor. */ + method_index = size_binop (PLUS_EXPR, method_index, size_int (2)); + } + + DECL_VINDEX (decl) = method_index; +} + +/* Get the method_index for a method decl. */ +tree +get_method_index (tree decl) +{ + tree method_index = DECL_VINDEX (decl); + + if (! method_index) + return NULL; + + if (TARGET_VTABLE_USES_DESCRIPTORS) + /* Sub one to skip bogus descriptor for class and GC descriptor. */ + method_index = size_binop (MINUS_EXPR, method_index, size_int (1)); + else + /* Sub 1 to skip "class" field of dtable, and 1 to skip GC descriptor. */ + method_index = size_binop (MINUS_EXPR, method_index, size_int (2)); + + return method_index; +} + +static int +supers_all_compiled (tree type) +{ + while (type != NULL_TREE) + { + if (!assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))))) + return 0; + type = CLASSTYPE_SUPER (type); + } + return 1; +} + +static void +add_table_and_syms (VEC(constructor_elt,gc) **v, + VEC(method_entry,gc) *methods, + const char *table_name, tree table_slot, tree table_type, + const char *syms_name, tree syms_slot) +{ + if (methods == NULL) + { + PUSH_FIELD_VALUE (*v, table_name, null_pointer_node); + PUSH_FIELD_VALUE (*v, syms_name, null_pointer_node); + } + else + { + pushdecl_top_level (syms_slot); + PUSH_FIELD_VALUE (*v, table_name, + build1 (ADDR_EXPR, table_type, table_slot)); + PUSH_FIELD_VALUE (*v, syms_name, + build1 (ADDR_EXPR, symbols_array_ptr_type, + syms_slot)); + TREE_CONSTANT (table_slot) = 1; + } +} + +void +make_class_data (tree type) +{ + tree decl, cons, temp; + tree field, fields_decl; + HOST_WIDE_INT static_field_count = 0; + HOST_WIDE_INT instance_field_count = 0; + HOST_WIDE_INT field_count; + tree field_array_type; + tree method; + tree dtable_decl = NULL_TREE; + HOST_WIDE_INT method_count = 0; + tree method_array_type; + tree methods_decl; + tree super; + tree this_class_addr; + tree constant_pool_constructor; + tree interfaces = null_pointer_node; + int interface_len = 0; + int uses_jv_markobj = 0; + tree type_decl = TYPE_NAME (type); + tree id_main = get_identifier("main"); + tree id_class = get_identifier("java.lang.Class"); + /** Offset from start of virtual function table declaration + to where objects actually point at, following new g++ ABI. */ + tree dtable_start_offset = size_int (2 * POINTER_SIZE / BITS_PER_UNIT); + VEC(int, heap) *field_indexes; + tree first_real_field; + VEC(constructor_elt,gc) *v1 = NULL, *v2 = NULL; + tree reflection_data; + VEC(constructor_elt,gc) *static_fields = NULL; + VEC(constructor_elt,gc) *instance_fields = NULL; + VEC(constructor_elt,gc) *methods = NULL; + + this_class_addr = build_static_class_ref (type); + decl = TREE_OPERAND (this_class_addr, 0); + + if (supers_all_compiled (type) && ! CLASS_INTERFACE (type_decl) + && !flag_indirect_dispatch) + { + tree dtable = get_dispatch_table (type, this_class_addr); + uses_jv_markobj = uses_jv_markobj_p (dtable); + if (type == class_type_node && class_dtable_decl != NULL_TREE) + { + /* We've already created some other class, and consequently + we made class_dtable_decl. Now we just want to fill it + in. */ + dtable_decl = class_dtable_decl; + } + else + { + dtable_decl = build_dtable_decl (type); + TREE_STATIC (dtable_decl) = 1; + DECL_ARTIFICIAL (dtable_decl) = 1; + DECL_IGNORED_P (dtable_decl) = 1; + } + + TREE_PUBLIC (dtable_decl) = 1; + DECL_INITIAL (dtable_decl) = dtable; + /* The only dispatch table exported from a DSO is the dispatch + table for java.lang.Class. */ + if (DECL_NAME (type_decl) != id_class) + java_hide_decl (dtable_decl); + if (! flag_indirect_classes) + rest_of_decl_compilation (dtable_decl, 1, 0); + /* Maybe we're compiling Class as the first class. If so, set + class_dtable_decl to the decl we just made. */ + if (type == class_type_node && class_dtable_decl == NULL_TREE) + class_dtable_decl = dtable_decl; + } + + /* Build Field array. */ + field = TYPE_FIELDS (type); + while (field && DECL_ARTIFICIAL (field)) + field = DECL_CHAIN (field); /* Skip dummy fields. */ + if (field && DECL_NAME (field) == NULL_TREE) + field = DECL_CHAIN (field); /* Skip dummy field for inherited data. */ + first_real_field = field; + + /* First count static and instance fields. */ + for ( ; field != NULL_TREE; field = DECL_CHAIN (field)) + { + if (! DECL_ARTIFICIAL (field)) + { + if (FIELD_STATIC (field)) + static_field_count++; + else if (uses_jv_markobj || !flag_reduced_reflection) + instance_field_count++; + } + } + field_count = static_field_count + instance_field_count; + field_indexes = VEC_alloc (int, heap, field_count); + + /* gcj sorts fields so that static fields come first, followed by + instance fields. Unfortunately, by the time this takes place we + have already generated the reflection_data for this class, and + that data contains indexes into the fields. So, we generate a + permutation that maps each original field index to its final + position. Then we pass this permutation to + rewrite_reflection_indexes(), which fixes up the reflection + data. */ + { + int i; + int static_count = 0; + int instance_count = static_field_count; + int field_index; + + for (i = 0, field = first_real_field; + field != NULL_TREE; + field = DECL_CHAIN (field), i++) + { + if (! DECL_ARTIFICIAL (field)) + { + field_index = 0; + if (FIELD_STATIC (field)) + field_index = static_count++; + else if (uses_jv_markobj || !flag_reduced_reflection) + field_index = instance_count++; + else + continue; + VEC_quick_push (int, field_indexes, field_index); + } + } + } + + for (field = first_real_field; field != NULL_TREE; + field = DECL_CHAIN (field)) + { + if (! DECL_ARTIFICIAL (field)) + { + if (FIELD_STATIC (field)) + { + /* We must always create reflection data for static fields + as it is used in the creation of the field itself. */ + tree init = make_field_value (field); + tree initial = DECL_INITIAL (field); + CONSTRUCTOR_APPEND_ELT (static_fields, NULL_TREE, init); + /* If the initial value is a string constant, + prevent output_constant from trying to assemble the value. */ + if (initial != NULL_TREE + && TREE_TYPE (initial) == string_ptr_type_node) + DECL_INITIAL (field) = NULL_TREE; + rest_of_decl_compilation (field, 1, 1); + DECL_INITIAL (field) = initial; + } + else if (uses_jv_markobj || !flag_reduced_reflection) + { + tree init = make_field_value (field); + CONSTRUCTOR_APPEND_ELT (instance_fields, NULL_TREE, init); + } + } + } + + gcc_assert (static_field_count + == (int) VEC_length (constructor_elt, static_fields)); + gcc_assert (instance_field_count + == (int) VEC_length (constructor_elt, instance_fields)); + + if (field_count > 0) + { + VEC_safe_splice (constructor_elt, gc, static_fields, instance_fields); + field_array_type = build_prim_array_type (field_type_node, field_count); + fields_decl = build_decl (input_location, + VAR_DECL, mangled_classname ("_FL_", type), + field_array_type); + DECL_INITIAL (fields_decl) + = build_constructor (field_array_type, static_fields); + TREE_STATIC (fields_decl) = 1; + DECL_ARTIFICIAL (fields_decl) = 1; + DECL_IGNORED_P (fields_decl) = 1; + rest_of_decl_compilation (fields_decl, 1, 0); + } + else + fields_decl = NULL_TREE; + + /* Build Method array. */ + for (method = TYPE_METHODS (type); + method != NULL_TREE; method = DECL_CHAIN (method)) + { + tree init; + if (METHOD_PRIVATE (method) + && ! flag_keep_inline_functions + && optimize) + continue; + /* Even if we have a decl, we don't necessarily have the code. + This can happen if we inherit a method from a superclass for + which we don't have a .class file. */ + if (METHOD_DUMMY (method)) + continue; + + /* Generate method reflection data if: + + - !flag_reduced_reflection. + + - -- The runtime uses reflection to initialize the + class. + + - Any method in class java.lang.Class -- Class.forName() and + perhaps other things require it. + + - class$ -- It does not work if reflection data missing. + + - main -- Reflection is used to find main(String[]) methods. + + - public not static -- It is potentially part of an + interface. The runtime uses reflection data to build + interface dispatch tables. */ + if (!flag_reduced_reflection + || DECL_CLINIT_P (method) + || DECL_NAME (type_decl) == id_class + || DECL_NAME (method) == id_main + || (METHOD_PUBLIC (method) && !METHOD_STATIC (method))) + { + init = make_method_value (method); + method_count++; + CONSTRUCTOR_APPEND_ELT (methods, NULL_TREE, init); + } + } + method_array_type = build_prim_array_type (method_type_node, method_count); + methods_decl = build_decl (input_location, + VAR_DECL, mangled_classname ("_MT_", type), + method_array_type); + DECL_INITIAL (methods_decl) = build_constructor (method_array_type, methods); + TREE_STATIC (methods_decl) = 1; + DECL_ARTIFICIAL (methods_decl) = 1; + DECL_IGNORED_P (methods_decl) = 1; + rest_of_decl_compilation (methods_decl, 1, 0); + + if (class_dtable_decl == NULL_TREE) + { + class_dtable_decl = build_dtable_decl (class_type_node); + TREE_STATIC (class_dtable_decl) = 1; + DECL_ARTIFICIAL (class_dtable_decl) = 1; + DECL_IGNORED_P (class_dtable_decl) = 1; + if (is_compiled_class (class_type_node) != 2) + { + DECL_EXTERNAL (class_dtable_decl) = 1; + rest_of_decl_compilation (class_dtable_decl, 1, 0); + } + } + + super = CLASSTYPE_SUPER (type); + if (super == NULL_TREE) + super = null_pointer_node; + else if (! flag_indirect_dispatch + && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl))) + && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (super))))) + super = build_class_ref (super); + else + { + int super_index = alloc_class_constant (super); + super = build_int_cst (ptr_type_node, super_index); + } + + /* Build and emit the array of implemented interfaces. */ + if (type != object_type_node) + interface_len = BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) - 1; + + if (interface_len > 0) + { + int i; + tree interface_array_type, idecl; + VEC(constructor_elt,gc) *init = VEC_alloc (constructor_elt, gc, + interface_len); + interface_array_type + = build_prim_array_type (class_ptr_type, interface_len); + idecl = build_decl (input_location, + VAR_DECL, mangled_classname ("_IF_", type), + interface_array_type); + + for (i = 1; i <= interface_len; i++) + { + tree child = BINFO_BASE_BINFO (TYPE_BINFO (type), i); + tree iclass = BINFO_TYPE (child); + tree index; + if (! flag_indirect_dispatch + && (assume_compiled + (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (iclass)))))) + index = build_class_ref (iclass); + else + { + int int_index = alloc_class_constant (iclass); + index = build_int_cst (ptr_type_node, int_index); + } + CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, index); + } + DECL_INITIAL (idecl) = build_constructor (interface_array_type, init); + TREE_STATIC (idecl) = 1; + DECL_ARTIFICIAL (idecl) = 1; + DECL_IGNORED_P (idecl) = 1; + interfaces = build1 (ADDR_EXPR, ptr_type_node, idecl); + rest_of_decl_compilation (idecl, 1, 0); + } + + constant_pool_constructor = build_constants_constructor (); + + if (flag_indirect_dispatch) + { + TYPE_OTABLE_DECL (type) + = emit_symbol_table + (DECL_NAME (TYPE_OTABLE_DECL (type)), + TYPE_OTABLE_DECL (type), TYPE_OTABLE_METHODS (type), + TYPE_OTABLE_SYMS_DECL (type), integer_type_node, 1); + + TYPE_ATABLE_DECL (type) + = emit_symbol_table + (DECL_NAME (TYPE_ATABLE_DECL (type)), + TYPE_ATABLE_DECL (type), TYPE_ATABLE_METHODS (type), + TYPE_ATABLE_SYMS_DECL (type), ptr_type_node, 1); + + TYPE_ITABLE_DECL (type) + = emit_symbol_table + (DECL_NAME (TYPE_ITABLE_DECL (type)), + TYPE_ITABLE_DECL (type), TYPE_ITABLE_METHODS (type), + TYPE_ITABLE_SYMS_DECL (type), ptr_type_node, 2); + } + + TYPE_CTABLE_DECL (type) = emit_catch_table (type); + + START_RECORD_CONSTRUCTOR (v1, object_type_node); + PUSH_FIELD_VALUE (v1, "vtable", + (flag_indirect_classes + ? null_pointer_node + : build2 (POINTER_PLUS_EXPR, dtable_ptr_type, + build1 (ADDR_EXPR, dtable_ptr_type, + class_dtable_decl), + dtable_start_offset))); + if (! flag_hash_synchronization) + PUSH_FIELD_VALUE (v1, "sync_info", null_pointer_node); + FINISH_RECORD_CONSTRUCTOR (temp, v1, object_type_node); + START_RECORD_CONSTRUCTOR (v2, class_type_node); + PUSH_SUPER_VALUE (v2, temp); + PUSH_FIELD_VALUE (v2, "next_or_version", gcj_abi_version); + PUSH_FIELD_VALUE (v2, "name", build_utf8_ref (DECL_NAME (type_decl))); + PUSH_FIELD_VALUE (v2, "accflags", + build_int_cst (NULL_TREE, + get_access_flags_from_decl (type_decl))); + + PUSH_FIELD_VALUE (v2, "superclass", + CLASS_INTERFACE (type_decl) ? null_pointer_node : super); + PUSH_FIELD_VALUE (v2, "constants", constant_pool_constructor); + PUSH_FIELD_VALUE (v2, "methods", + methods_decl == NULL_TREE ? null_pointer_node + : build1 (ADDR_EXPR, method_ptr_type_node, methods_decl)); + PUSH_FIELD_VALUE (v2, "method_count", + build_int_cst (NULL_TREE, method_count)); + + PUSH_FIELD_VALUE (v2, "vtable_method_count", + (flag_indirect_dispatch + ? integer_minus_one_node + : TYPE_NVIRTUALS (type))); + + PUSH_FIELD_VALUE (v2, "fields", + fields_decl == NULL_TREE ? null_pointer_node + : build1 (ADDR_EXPR, field_ptr_type_node, fields_decl)); + /* If we're using the binary compatibility ABI we don't know the + size until load time. */ + PUSH_FIELD_VALUE (v2, "size_in_bytes", + (flag_indirect_dispatch + ? integer_minus_one_node + : size_in_bytes (type))); + PUSH_FIELD_VALUE (v2, "field_count", + build_int_cst (NULL_TREE, field_count)); + PUSH_FIELD_VALUE (v2, "static_field_count", + build_int_cst (NULL_TREE, static_field_count)); + + PUSH_FIELD_VALUE (v2, "vtable", + (flag_indirect_dispatch || dtable_decl == NULL_TREE + ? null_pointer_node + : build2 (POINTER_PLUS_EXPR, dtable_ptr_type, + build1 (ADDR_EXPR, dtable_ptr_type, + dtable_decl), + dtable_start_offset))); + add_table_and_syms (&v2, TYPE_OTABLE_METHODS (type), + "otable", TYPE_OTABLE_DECL (type), otable_ptr_type, + "otable_syms", TYPE_OTABLE_SYMS_DECL (type)); + add_table_and_syms (&v2, TYPE_ATABLE_METHODS (type), + "atable", TYPE_ATABLE_DECL (type), atable_ptr_type, + "atable_syms", TYPE_ATABLE_SYMS_DECL (type)); + add_table_and_syms (&v2, TYPE_ITABLE_METHODS (type), + "itable", TYPE_ITABLE_DECL (type), itable_ptr_type, + "itable_syms", TYPE_ITABLE_SYMS_DECL (type)); + + PUSH_FIELD_VALUE (v2, "catch_classes", + build1 (ADDR_EXPR, ptr_type_node, TYPE_CTABLE_DECL (type))); + PUSH_FIELD_VALUE (v2, "interfaces", interfaces); + PUSH_FIELD_VALUE (v2, "loader", null_pointer_node); + PUSH_FIELD_VALUE (v2, "interface_count", + build_int_cst (NULL_TREE, interface_len)); + PUSH_FIELD_VALUE (v2, "state", + convert (byte_type_node, + build_int_cst (NULL_TREE, JV_STATE_PRELOADING))); + + PUSH_FIELD_VALUE (v2, "thread", null_pointer_node); + PUSH_FIELD_VALUE (v2, "depth", integer_zero_node); + PUSH_FIELD_VALUE (v2, "ancestors", null_pointer_node); + PUSH_FIELD_VALUE (v2, "idt", null_pointer_node); + PUSH_FIELD_VALUE (v2, "arrayclass", null_pointer_node); + PUSH_FIELD_VALUE (v2, "protectionDomain", null_pointer_node); + + { + tree assertion_table_ref; + if (TYPE_ASSERTIONS (type) == NULL) + assertion_table_ref = null_pointer_node; + else + assertion_table_ref = build1 (ADDR_EXPR, + build_pointer_type (assertion_table_type), + emit_assertion_table (type)); + + PUSH_FIELD_VALUE (v2, "assertion_table", assertion_table_ref); + } + + PUSH_FIELD_VALUE (v2, "hack_signers", null_pointer_node); + PUSH_FIELD_VALUE (v2, "chain", null_pointer_node); + PUSH_FIELD_VALUE (v2, "aux_info", null_pointer_node); + PUSH_FIELD_VALUE (v2, "engine", null_pointer_node); + + if (TYPE_REFLECTION_DATA (current_class)) + { + int i; + int count = TYPE_REFLECTION_DATASIZE (current_class); + VEC (constructor_elt, gc) *v + = VEC_alloc (constructor_elt, gc, count); + unsigned char *data = TYPE_REFLECTION_DATA (current_class); + tree max_index = build_int_cst (sizetype, count); + tree index = build_index_type (max_index); + tree type = build_array_type (unsigned_byte_type_node, index); + char buf[64]; + tree array; + static int reflection_data_count; + + sprintf (buf, "_reflection_data_%d", reflection_data_count++); + array = build_decl (input_location, + VAR_DECL, get_identifier (buf), type); + + rewrite_reflection_indexes (field_indexes); + + for (i = 0; i < count; i++) + { + constructor_elt *elt = VEC_quick_push (constructor_elt, v, NULL); + elt->index = build_int_cst (sizetype, i); + elt->value = build_int_cstu (byte_type_node, data[i]); + } + + DECL_INITIAL (array) = build_constructor (type, v); + TREE_STATIC (array) = 1; + DECL_ARTIFICIAL (array) = 1; + DECL_IGNORED_P (array) = 1; + TREE_READONLY (array) = 1; + TREE_CONSTANT (DECL_INITIAL (array)) = 1; + rest_of_decl_compilation (array, 1, 0); + + reflection_data = build_address_of (array); + + free (data); + TYPE_REFLECTION_DATA (current_class) = NULL; + } + else + reflection_data = null_pointer_node; + + PUSH_FIELD_VALUE (v2, "reflection_data", reflection_data); + FINISH_RECORD_CONSTRUCTOR (cons, v2, class_type_node); + + DECL_INITIAL (decl) = cons; + + /* Hash synchronization requires at least 64-bit alignment. */ + if (flag_hash_synchronization && POINTER_SIZE < 64) + DECL_ALIGN (decl) = 64; + + if (flag_indirect_classes) + { + TREE_READONLY (decl) = 1; + TREE_CONSTANT (DECL_INITIAL (decl)) = 1; + } + + rest_of_decl_compilation (decl, 1, 0); + + { + tree classdollar_field = build_classdollar_field (type); + if (!flag_indirect_classes) + DECL_INITIAL (classdollar_field) = build_static_class_ref (type); + rest_of_decl_compilation (classdollar_field, 1, 0); + } + + TYPE_OTABLE_DECL (type) = NULL_TREE; + TYPE_ATABLE_DECL (type) = NULL_TREE; + TYPE_CTABLE_DECL (type) = NULL_TREE; +} + +void +finish_class (void) +{ + java_expand_catch_classes (current_class); + + current_function_decl = NULL_TREE; + TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (current_class)) = 0; + make_class_data (current_class); + register_class (); + rest_of_decl_compilation (TYPE_NAME (current_class), 1, 0); +} + +/* Return 2 if KLASS is compiled by this compilation job; + return 1 if KLASS can otherwise be assumed to be compiled; + return 0 if we cannot assume that KLASS is compiled. + Returns 1 for primitive and 0 for array types. */ +int +is_compiled_class (tree klass) +{ + int seen_in_zip; + if (TREE_CODE (klass) == POINTER_TYPE) + klass = TREE_TYPE (klass); + if (TREE_CODE (klass) != RECORD_TYPE) /* Primitive types are static. */ + return 1; + if (TYPE_ARRAY_P (klass)) + return 0; + + seen_in_zip = (TYPE_JCF (klass) && JCF_SEEN_IN_ZIP (TYPE_JCF (klass))); + if (CLASS_FROM_CURRENTLY_COMPILED_P (klass)) + { + /* The class was seen in the current ZIP file and will be + available as a compiled class in the future but may not have + been loaded already. Load it if necessary. This prevent + build_class_ref () from crashing. */ + + if (seen_in_zip && !CLASS_LOADED_P (klass) && (klass != current_class)) + load_class (klass, 1); + + /* We return 2 for class seen in ZIP and class from files + belonging to the same compilation unit */ + return 2; + } + + if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (klass))))) + { + if (!CLASS_LOADED_P (klass)) + { + if (klass != current_class) + load_class (klass, 1); + } + return 1; + } + + return 0; +} + +/* Build a VAR_DECL for the dispatch table (vtable) for class TYPE. */ + +tree +build_dtable_decl (tree type) +{ + tree dtype, decl; + + /* 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 know we're not faking a class when CURRENT_CLASS is + TYPE. */ + if (current_class == type) + { + tree dummy = NULL_TREE; + int n; + + dtype = make_node (RECORD_TYPE); + + PUSH_FIELD (input_location, dtype, dummy, "top_offset", ptr_type_node); + PUSH_FIELD (input_location, dtype, dummy, "type_info", ptr_type_node); + + PUSH_FIELD (input_location, dtype, dummy, "class", class_ptr_type); + for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n) + { + tree tmp_field = build_decl (input_location, + 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 (input_location, dtype, dummy, "gc_descr", ptr_type_node); + for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n) + { + tree tmp_field = build_decl (input_location, + 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 (input_location, dtype, dummy, "methods", + build_prim_array_type (nativecode_ptr_type_node, n)); + layout_type (dtype); + } + else + dtype = dtable_type; + + decl = build_decl (input_location, + VAR_DECL, get_identifier ("vt$"), dtype); + DECL_CONTEXT (decl) = type; + MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl); + DECL_VTABLE_P (decl) = 1; + + return decl; +} + +/* Pre-pend the TYPE_FIELDS of THIS_CLASS with a dummy FIELD_DECL for the + fields inherited from SUPER_CLASS. */ + +void +push_super_field (tree this_class, tree super_class) +{ + tree base_decl; + /* 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 (input_location, + FIELD_DECL, NULL_TREE, super_class); + DECL_IGNORED_P (base_decl) = 1; + DECL_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. */ + +static tree +maybe_layout_super_class (tree super_class, tree this_class ATTRIBUTE_UNUSED) +{ + if (!super_class) + return NULL_TREE; + else if (TREE_CODE (super_class) == RECORD_TYPE) + { + if (!CLASS_LOADED_P (super_class)) + load_class (super_class, 1); + } + /* We might have to layout the class before its dependency on + the super class gets resolved by java_complete_class */ + else if (TREE_CODE (super_class) == POINTER_TYPE) + { + if (TREE_TYPE (super_class) != NULL_TREE) + super_class = TREE_TYPE (super_class); + else + gcc_unreachable (); + } + if (!TYPE_SIZE (super_class)) + safe_layout_class (super_class); + + return super_class; +} + +/* safe_layout_class just makes sure that we can load a class without + disrupting the current_class, input_file, input_line, etc, information + about the class processed currently. */ + +void +safe_layout_class (tree klass) +{ + tree save_current_class = current_class; + location_t save_location = input_location; + + layout_class (klass); + + current_class = save_current_class; + input_location = save_location; +} + +void +layout_class (tree this_class) +{ + int i; + tree super_class = CLASSTYPE_SUPER (this_class); + + class_list = tree_cons (this_class, NULL_TREE, class_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 (class_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 = XOBFINISH (&temporary_obstack, char *); + 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 && !CLASS_BEING_LAIDOUT (super_class)) + { + 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; + class_list = TREE_CHAIN (class_list); + return; + } + if (TYPE_SIZE (this_class) == NULL_TREE) + push_super_field (this_class, maybe_super_class); + } + + layout_type (this_class); + + /* Also recursively load/layout any superinterfaces. */ + if (TYPE_BINFO (this_class)) + { + for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (this_class)) - 1; i > 0; i--) + { + tree binfo = BINFO_BASE_BINFO (TYPE_BINFO (this_class), i); + tree super_interface = BINFO_TYPE (binfo); + 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; + class_list = TREE_CHAIN (class_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; + class_list = TREE_CHAIN (class_list); +} + +static void +add_miranda_methods (tree base_class, tree search_class) +{ + int i; + tree binfo, base_binfo; + + if (!CLASS_PARSED_P (search_class)) + load_class (search_class, 1); + + for (binfo = TYPE_BINFO (search_class), i = 1; + BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) + { + tree method_decl; + tree elt = BINFO_TYPE (base_binfo); + + /* FIXME: This is totally bogus. We should not be handling + Miranda methods at all if we're using the BC ABI. */ + if (TYPE_DUMMY (elt)) + continue; + + /* Ensure that interface methods are seen in declared order. */ + if (!CLASS_LOADED_P (elt)) + load_class (elt, 1); + layout_class_methods (elt); + + /* All base classes will have been laid out at this point, so the order + will be correct. This code must match similar layout code in the + runtime. */ + for (method_decl = TYPE_METHODS (elt); + method_decl; method_decl = DECL_CHAIN (method_decl)) + { + tree sig, override; + + /* An interface can have . */ + if (ID_CLINIT_P (DECL_NAME (method_decl))) + continue; + + sig = build_java_argument_signature (TREE_TYPE (method_decl)); + override = lookup_argument_method (base_class, + DECL_NAME (method_decl), sig); + if (override == NULL_TREE) + { + /* Found a Miranda method. Add it. */ + tree new_method; + sig = build_java_signature (TREE_TYPE (method_decl)); + new_method + = add_method (base_class, + get_access_flags_from_decl (method_decl), + DECL_NAME (method_decl), sig); + METHOD_INVISIBLE (new_method) = 1; + } + } + + /* Try superinterfaces. */ + add_miranda_methods (base_class, elt); + } +} + +void +layout_class_methods (tree this_class) +{ + tree method_decl, dtable_count; + tree super_class, type_name; + + if (TYPE_NVIRTUALS (this_class)) + return; + + super_class = CLASSTYPE_SUPER (this_class); + + if (super_class) + { + super_class = maybe_layout_super_class (super_class, this_class); + if (!TYPE_NVIRTUALS (super_class)) + layout_class_methods (super_class); + dtable_count = TYPE_NVIRTUALS (super_class); + } + else + dtable_count = integer_zero_node; + + type_name = TYPE_NAME (this_class); + if (!flag_indirect_dispatch + && (CLASS_ABSTRACT (type_name) || CLASS_INTERFACE (type_name))) + { + /* An abstract class can have methods which are declared only in + an implemented interface. These are called "Miranda + methods". We make a dummy method entry for such methods + here. */ + add_miranda_methods (this_class, this_class); + } + + TYPE_METHODS (this_class) = nreverse (TYPE_METHODS (this_class)); + + for (method_decl = TYPE_METHODS (this_class); + method_decl; method_decl = DECL_CHAIN (method_decl)) + dtable_count = layout_class_method (this_class, super_class, + method_decl, dtable_count); + + TYPE_NVIRTUALS (this_class) = dtable_count; +} + +/* Return the index of METHOD in INTERFACE. This index begins at 1 + and is used as an argument for _Jv_LookupInterfaceMethodIdx(). */ +int +get_interface_method_index (tree method, tree interface) +{ + tree meth; + int i = 1; + + for (meth = TYPE_METHODS (interface); ; meth = DECL_CHAIN (meth)) + { + if (meth == method) + return i; + /* We don't want to put into the interface table. */ + if (! ID_CLINIT_P (DECL_NAME (meth))) + ++i; + gcc_assert (meth != NULL_TREE); + } +} + +/* Lay METHOD_DECL out, returning a possibly new value of + DTABLE_COUNT. Also mangle the method's name. */ + +tree +layout_class_method (tree this_class, tree super_class, + tree method_decl, tree dtable_count) +{ + tree method_name = DECL_NAME (method_decl); + + TREE_PUBLIC (method_decl) = 1; + + if (flag_indirect_classes + || (METHOD_PRIVATE (method_decl) && METHOD_STATIC (method_decl) + && ! METHOD_NATIVE (method_decl) + && ! special_method_p (method_decl))) + java_hide_decl (method_decl); + + /* Considered external unless it is being compiled into this object + file, or it was already flagged as external. */ + if (!DECL_EXTERNAL (method_decl)) + DECL_EXTERNAL (method_decl) = ((is_compiled_class (this_class) != 2) + || METHOD_NATIVE (method_decl)); + + if (ID_INIT_P (method_name)) + { + const char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); + const char *ptr; + for (ptr = p; *ptr; ) + { + if (*ptr++ == '.') + p = ptr; + } + DECL_CONSTRUCTOR_P (method_decl) = 1; + build_java_signature (TREE_TYPE (method_decl)); + } + else if (! METHOD_STATIC (method_decl)) + { + tree method_sig = + build_java_signature (TREE_TYPE (method_decl)); + bool method_override = false; + tree super_method = lookup_java_method (super_class, method_name, + method_sig); + if (super_method != NULL_TREE + && ! METHOD_DUMMY (super_method)) + { + method_override = true; + if (! METHOD_PUBLIC (super_method) && + ! METHOD_PROTECTED (super_method)) + { + /* Don't override private method, or default-access method in + another package. */ + if (METHOD_PRIVATE (super_method) || + ! in_same_package (TYPE_NAME (this_class), + TYPE_NAME (super_class))) + method_override = false; + } + } + if (method_override) + { + tree method_index = get_method_index (super_method); + set_method_index (method_decl, method_index); + if (method_index == NULL_TREE + && ! flag_indirect_dispatch + && ! DECL_ARTIFICIAL (super_method)) + error ("non-static method %q+D overrides static method", + method_decl); + } + else if (this_class == object_type_node + && (METHOD_FINAL (method_decl) + || METHOD_PRIVATE (method_decl))) + { + /* We don't generate vtable entries for final Object + methods. This is simply to save space, since every + object would otherwise have to define them. */ + } + else if (! METHOD_PRIVATE (method_decl) + && dtable_count) + { + /* We generate vtable entries for final methods because they + may one day be changed to non-final. */ + set_method_index (method_decl, dtable_count); + dtable_count = fold_build2 (PLUS_EXPR, integer_type_node, + dtable_count, integer_one_node); + } + } + + return dtable_count; +} + +static void +register_class (void) +{ + tree node; + + if (!registered_class) + registered_class = VEC_alloc (tree, gc, 8); + + if (flag_indirect_classes) + node = current_class; + else + node = TREE_OPERAND (build_class_ref (current_class), 0); + VEC_safe_push (tree, gc, registered_class, node); +} + +/* Emit a function that calls _Jv_RegisterNewClasses with a list of + all the classes we have emitted. */ + +static void +emit_indirect_register_classes (tree *list_p) +{ + tree klass, t, register_class_fn; + int i; + + int size = VEC_length (tree, registered_class) * 2 + 1; + VEC(constructor_elt,gc) *init = VEC_alloc (constructor_elt, gc, size); + tree class_array_type + = build_prim_array_type (ptr_type_node, size); + tree cdecl = build_decl (input_location, + VAR_DECL, get_identifier ("_Jv_CLS"), + class_array_type); + tree reg_class_list; + FOR_EACH_VEC_ELT (tree, registered_class, i, klass) + { + t = fold_convert (ptr_type_node, build_static_class_ref (klass)); + CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, t); + t = fold_convert (ptr_type_node, + build_address_of (build_classdollar_field (klass))); + CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, t); + } + CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, integer_zero_node); + DECL_INITIAL (cdecl) = build_constructor (class_array_type, init); + TREE_CONSTANT (DECL_INITIAL (cdecl)) = 1; + TREE_STATIC (cdecl) = 1; + DECL_ARTIFICIAL (cdecl) = 1; + DECL_IGNORED_P (cdecl) = 1; + TREE_READONLY (cdecl) = 1; + TREE_CONSTANT (cdecl) = 1; + rest_of_decl_compilation (cdecl, 1, 0); + reg_class_list = fold_convert (ptr_type_node, build_address_of (cdecl)); + + t = build_function_type_list (void_type_node, + build_pointer_type (ptr_type_node), NULL); + t = build_decl (input_location, + FUNCTION_DECL, + get_identifier ("_Jv_RegisterNewClasses"), t); + TREE_PUBLIC (t) = 1; + DECL_EXTERNAL (t) = 1; + register_class_fn = t; + t = build_call_expr (register_class_fn, 1, reg_class_list); + append_to_statement_list (t, list_p); +} + + +/* Emit something to register classes at start-up time. + + The preferred mechanism is through the .jcr section, which contain + a list of pointers to classes which get registered during constructor + invocation time. + + The fallback mechanism is to add statements to *LIST_P to call + _Jv_RegisterClass for each class in this file. These statements will + be added to a static constructor function for this translation unit. */ + +void +emit_register_classes (tree *list_p) +{ + if (registered_class == NULL) + return; + + if (flag_indirect_classes) + { + emit_indirect_register_classes (list_p); + return; + } + + /* TARGET_USE_JCR_SECTION defaults to 1 if SUPPORTS_WEAK and + TARGET_ASM_NAMED_SECTION, else 0. Some targets meet those conditions + but lack suitable crtbegin/end objects or linker support. These + targets can override the default in tm.h to use the fallback mechanism. */ + if (TARGET_USE_JCR_SECTION) + { + tree klass, t; + int i; + +#ifdef JCR_SECTION_NAME + switch_to_section (get_section (JCR_SECTION_NAME, SECTION_WRITE, NULL)); +#else + /* A target has defined TARGET_USE_JCR_SECTION, + but doesn't have a JCR_SECTION_NAME. */ + gcc_unreachable (); +#endif + assemble_align (POINTER_SIZE); + + FOR_EACH_VEC_ELT (tree, registered_class, i, klass) + { + t = build_fold_addr_expr (klass); + output_constant (t, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE); + } + } + else + { + tree klass, t, register_class_fn; + int i; + + t = build_function_type_list (void_type_node, class_ptr_type, NULL); + t = build_decl (input_location, + FUNCTION_DECL, get_identifier ("_Jv_RegisterClass"), t); + TREE_PUBLIC (t) = 1; + DECL_EXTERNAL (t) = 1; + register_class_fn = t; + + FOR_EACH_VEC_ELT (tree, registered_class, i, klass) + { + t = build_fold_addr_expr (klass); + t = build_call_expr (register_class_fn, 1, t); + append_to_statement_list (t, list_p); + } + } +} + +/* Build a constructor for an entry in the symbol table. */ + +static tree +build_symbol_table_entry (tree clname, tree name, tree signature) +{ + tree symbol; + VEC(constructor_elt,gc) *v = NULL; + + START_RECORD_CONSTRUCTOR (v, symbol_type); + PUSH_FIELD_VALUE (v, "clname", clname); + PUSH_FIELD_VALUE (v, "name", name); + PUSH_FIELD_VALUE (v, "signature", signature); + FINISH_RECORD_CONSTRUCTOR (symbol, v, symbol_type); + TREE_CONSTANT (symbol) = 1; + + return symbol; +} + +/* Make a symbol_type (_Jv_MethodSymbol) node for DECL. */ + +static tree +build_symbol_entry (tree decl, tree special) +{ + tree clname, name, signature; + clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl)))); + /* ??? Constructors are given the name foo.foo all the way through + the compiler, but in the method table they're all renamed + foo.. So, we have to do the same here unless we want an + unresolved reference at runtime. */ + name = build_utf8_ref ((TREE_CODE (decl) == FUNCTION_DECL + && DECL_CONSTRUCTOR_P (decl)) + ? init_identifier_node + : DECL_NAME (decl)); + signature = build_java_signature (TREE_TYPE (decl)); + signature = build_utf8_ref (unmangle_classname + (IDENTIFIER_POINTER (signature), + IDENTIFIER_LENGTH (signature))); + /* SPECIAL is either NULL_TREE or integer_one_node. We emit + signature addr+1 if SPECIAL, and this indicates to the runtime + system that this is a "special" symbol, i.e. one that should + bypass access controls. */ + if (special != NULL_TREE) + signature = build2 (POINTER_PLUS_EXPR, TREE_TYPE (signature), signature, + fold_convert (sizetype, special)); + + return build_symbol_table_entry (clname, name, signature); +} + +/* Emit a symbol table: used by -findirect-dispatch. */ + +tree +emit_symbol_table (tree name, tree the_table, + VEC(method_entry,gc) *decl_table, + tree the_syms_decl, tree the_array_element_type, + int element_size) +{ + tree table, null_symbol, table_size, the_array_type; + unsigned index; + method_entry *e; + VEC(constructor_elt,gc) *v = NULL; + + /* Only emit a table if this translation unit actually made any + references via it. */ + if (decl_table == NULL) + return the_table; + + /* Build a list of _Jv_MethodSymbols for each entry in otable_methods. */ + FOR_EACH_VEC_ELT (method_entry, decl_table, index, e) + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, + build_symbol_entry (e->method, e->special)); + + /* Terminate the list with a "null" entry. */ + null_symbol = build_symbol_table_entry (null_pointer_node, + null_pointer_node, + null_pointer_node); + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, null_symbol); + + table = build_constructor (symbols_array_type, v); + + /* Make it the initial value for otable_syms and emit the decl. */ + 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, 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_cst (NULL_TREE, index * element_size + 1)); + the_array_type = build_array_type (the_array_element_type, table_size); + the_table = build_decl (input_location, + VAR_DECL, name, the_array_type); + TREE_STATIC (the_table) = 1; + TREE_READONLY (the_table) = 1; + rest_of_decl_compilation (the_table, 1, 0); + + return the_table; +} + +/* Make an entry for the catch_classes list. */ +tree +make_catch_class_record (tree catch_class, tree classname) +{ + tree entry; + tree type = TREE_TYPE (TREE_TYPE (TYPE_CTABLE_DECL (output_class))); + VEC(constructor_elt,gc) *v = NULL; + START_RECORD_CONSTRUCTOR (v, type); + PUSH_FIELD_VALUE (v, "address", catch_class); + PUSH_FIELD_VALUE (v, "classname", classname); + FINISH_RECORD_CONSTRUCTOR (entry, v, type); + return entry; +} + + +/* Generate the list of Throwable classes that are caught by exception + handlers in this class. */ +tree +emit_catch_table (tree this_class) +{ + tree table, table_size, array_type; + int n_catch_classes; + constructor_elt *e; + /* Fill in the dummy entry that make_class created. */ + e = VEC_index (constructor_elt, TYPE_CATCH_CLASSES (this_class), 0); + e->value = make_catch_class_record (null_pointer_node, null_pointer_node); + CONSTRUCTOR_APPEND_ELT (TYPE_CATCH_CLASSES (this_class), NULL_TREE, + make_catch_class_record (null_pointer_node, + null_pointer_node)); + n_catch_classes = VEC_length (constructor_elt, + TYPE_CATCH_CLASSES (this_class)); + table_size = build_index_type (build_int_cst (NULL_TREE, n_catch_classes)); + array_type + = build_array_type (TREE_TYPE (TREE_TYPE (TYPE_CTABLE_DECL (this_class))), + table_size); + table = + build_decl (input_location, + VAR_DECL, DECL_NAME (TYPE_CTABLE_DECL (this_class)), array_type); + DECL_INITIAL (table) = + build_constructor (array_type, TYPE_CATCH_CLASSES (this_class)); + TREE_STATIC (table) = 1; + TREE_READONLY (table) = 1; + DECL_IGNORED_P (table) = 1; + rest_of_decl_compilation (table, 1, 0); + return table; +} + +/* Given a type, return the signature used by + _Jv_FindClassFromSignature() in libgcj. This isn't exactly the + same as build_java_signature() because we want the canonical array + type. */ + +static tree +build_signature_for_libgcj (tree type) +{ + tree sig, ref; + + sig = build_java_signature (type); + ref = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (sig), + IDENTIFIER_LENGTH (sig))); + return ref; +} + +/* Build an entry in the type assertion table. */ + +static tree +build_assertion_table_entry (tree code, tree op1, tree op2) +{ + VEC(constructor_elt,gc) *v = NULL; + tree entry; + + START_RECORD_CONSTRUCTOR (v, assertion_entry_type); + PUSH_FIELD_VALUE (v, "assertion_code", code); + PUSH_FIELD_VALUE (v, "op1", op1); + PUSH_FIELD_VALUE (v, "op2", op2); + FINISH_RECORD_CONSTRUCTOR (entry, v, assertion_entry_type); + + return entry; +} + +/* Add an entry to the type assertion table. Callback used during hashtable + traversal. */ + +static int +add_assertion_table_entry (void **htab_entry, void *ptr) +{ + tree entry; + tree code_val, op1_utf8, op2_utf8; + VEC(constructor_elt,gc) **v = (VEC(constructor_elt,gc) **) ptr; + type_assertion *as = (type_assertion *) *htab_entry; + + code_val = build_int_cst (NULL_TREE, as->assertion_code); + + if (as->op1 == NULL_TREE) + op1_utf8 = null_pointer_node; + else + op1_utf8 = build_signature_for_libgcj (as->op1); + + if (as->op2 == NULL_TREE) + op2_utf8 = null_pointer_node; + else + op2_utf8 = build_signature_for_libgcj (as->op2); + + entry = build_assertion_table_entry (code_val, op1_utf8, op2_utf8); + + CONSTRUCTOR_APPEND_ELT (*v, NULL_TREE, entry); + return true; +} + +/* Generate the type assertion table for KLASS, and return its DECL. */ + +static tree +emit_assertion_table (tree klass) +{ + tree null_entry, ctor, table_decl; + htab_t assertions_htab = TYPE_ASSERTIONS (klass); + VEC(constructor_elt,gc) *v = NULL; + + /* Iterate through the hash table. */ + htab_traverse (assertions_htab, add_assertion_table_entry, &v); + + /* Finish with a null entry. */ + null_entry = build_assertion_table_entry (integer_zero_node, + null_pointer_node, + null_pointer_node); + + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, null_entry); + + ctor = build_constructor (assertion_table_type, v); + + table_decl = build_decl (input_location, + VAR_DECL, mangled_classname ("_type_assert_", klass), + assertion_table_type); + + TREE_STATIC (table_decl) = 1; + TREE_READONLY (table_decl) = 1; + TREE_CONSTANT (table_decl) = 1; + DECL_IGNORED_P (table_decl) = 1; + + DECL_INITIAL (table_decl) = ctor; + DECL_ARTIFICIAL (table_decl) = 1; + rest_of_decl_compilation (table_decl, 1, 0); + + return table_decl; +} + +void +init_class_processing (void) +{ + fields_ident = get_identifier ("fields"); + info_ident = get_identifier ("info"); + + gcc_obstack_init (&temporary_obstack); +} + +static hashval_t java_treetreehash_hash (const void *); +static int java_treetreehash_compare (const void *, const void *); + +/* A hash table mapping trees to trees. Used generally. */ + +#define JAVA_TREEHASHHASH_H(t) ((hashval_t)TYPE_UID (t)) + +static hashval_t +java_treetreehash_hash (const void *k_p) +{ + const struct treetreehash_entry *const k + = (const struct treetreehash_entry *) k_p; + return JAVA_TREEHASHHASH_H (k->key); +} + +static int +java_treetreehash_compare (const void * k1_p, const void * k2_p) +{ + const struct treetreehash_entry *const k1 + = (const struct treetreehash_entry *) k1_p; + const_tree const k2 = (const_tree) k2_p; + return (k1->key == k2); +} + +tree +java_treetreehash_find (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 (htab_t ht, tree t) +{ + void **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 = ggc_alloc_cleared_treetreehash_entry (); + tthe->key = t; + *e = tthe; + } + else + tthe = (struct treetreehash_entry *) *e; + return &tthe->value; +} + +htab_t +java_treetreehash_create (size_t size) +{ + return htab_create_ggc (size, java_treetreehash_hash, + java_treetreehash_compare, NULL); +} + +/* Break down qualified IDENTIFIER into package and class-name components. + For example, given SOURCE "pkg.foo.Bar", LEFT will be set to + "pkg.foo", and RIGHT to "Bar". */ + +int +split_qualified_name (tree *left, tree *right, tree source) +{ + char *p, *base; + int l = IDENTIFIER_LENGTH (source); + + base = (char *) alloca (l + 1); + memcpy (base, IDENTIFIER_POINTER (source), l + 1); + + /* Breakdown NAME into REMAINDER . IDENTIFIER. */ + p = base + l - 1; + while (*p != '.' && p != base) + p--; + + /* We didn't find a '.'. Return an error. */ + if (p == base) + return 1; + + *p = '\0'; + if (right) + *right = get_identifier (p+1); + *left = get_identifier (base); + + return 0; +} + +/* Given two classes (TYPE_DECL) or class names (IDENTIFIER), return TRUE + if the classes are from the same package. */ + +int +in_same_package (tree name1, tree name2) +{ + tree tmp; + tree pkg1; + tree pkg2; + + if (TREE_CODE (name1) == TYPE_DECL) + name1 = DECL_NAME (name1); + if (TREE_CODE (name2) == TYPE_DECL) + name2 = DECL_NAME (name2); + + if (QUALIFIED_P (name1) != QUALIFIED_P (name2)) + /* One in empty package. */ + return 0; + + if (QUALIFIED_P (name1) == 0 && QUALIFIED_P (name2) == 0) + /* Both in empty package. */ + return 1; + + split_qualified_name (&pkg1, &tmp, name1); + split_qualified_name (&pkg2, &tmp, name2); + + return (pkg1 == pkg2); +} + +/* lang_hooks.decls.final_write_globals: perform final processing on + global variables. */ + +void +java_write_globals (void) +{ + tree *vec = VEC_address (tree, pending_static_fields); + int len = VEC_length (tree, pending_static_fields); + write_global_declarations (); + emit_debug_global_declarations (vec, len); + VEC_free (tree, gc, pending_static_fields); +} + +#include "gt-java-class.h" -- cgit v1.2.3