/* Functions related to building classes and their related objects.
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
- Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
Java and all Java-based marks are trademarks or registered trademarks
of Sun Microsystems, Inc. in the United States and other countries.
#include "stdio.h"
#include "target.h"
#include "except.h"
+#include "cgraph.h"
#include "tree-iterator.h"
+#include "cgraph.h"
+#include "vecprim.h"
/* DOS brain-damage */
#ifndef O_BINARY
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);
+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
static class_flag_node *enable_assert_tree;
-static GTY(()) tree class_roots[5];
-#define registered_class class_roots[0]
-#define fields_ident class_roots[1] /* get_identifier ("fields") */
-#define info_ident class_roots[2] /* get_identifier ("info") */
-#define class_list class_roots[3]
-#define class_dtable_decl class_roots[4]
+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;
/* Return the node that most closely represents the class whose name
is IDENT. Start the search from NODE (followed by its siblings).
if (NULL == root)
{
- root = xmalloc (sizeof (class_flag_node));
+ root = XNEW (class_flag_node);
root->ident = "";
root->value = 0;
root->sibling = NULL;
else
{
/* Insert new node into the tree. */
- node = xmalloc (sizeof (class_flag_node));
+ node = XNEW (class_flag_node);
node->ident = xstrdup (ident);
node->value = value;
/* The default value returned by enable_assertions. */
-#define DEFAULT_ENABLE_ASSERT (flag_emit_class_files || optimize == 0)
+#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. */
int prefix_len = strlen (prefix);
int suffix_len = strlen (suffix);
int i = prefix_len + old_length + suffix_len + 1;
-#ifdef __GNUC__
- char buffer[i];
-#else
char *buffer = alloca (i);
-#endif
+
strcpy (buffer, prefix);
for (i = 0; i < old_length; i++)
{
{
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);
return type;
return to_return;
}
+#define GEN_TABLE(TABLE, NAME, TABLE_TYPE, TYPE) \
+do \
+{ \
+ const char *typename = IDENTIFIER_POINTER (mangled_classname ("", TYPE)); \
+ char *buf = alloca (strlen (typename) + strlen (#NAME "_syms_") + 1); \
+ tree decl; \
+ \
+ sprintf (buf, #NAME "_%s", typename); \
+ TYPE_## TABLE ##_DECL (type) = decl = \
+ build_decl (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", typename); \
+ TYPE_## TABLE ##_SYMS_DECL (TYPE) = \
+ build_decl (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. */
if (flag_indirect_dispatch)
{
- {
- char *buf = alloca (strlen (typename) + strlen ("_otable_syms_") + 1);
-
- sprintf (buf, "_otable_%s", typename);
- TYPE_OTABLE_DECL (type) =
- build_decl (VAR_DECL, get_identifier (buf), otable_type);
- DECL_EXTERNAL (TYPE_OTABLE_DECL (type)) = 1;
- TREE_STATIC (TYPE_OTABLE_DECL (type)) = 1;
- TREE_READONLY (TYPE_OTABLE_DECL (type)) = 1;
- TREE_CONSTANT (TYPE_OTABLE_DECL (type)) = 1;
- DECL_IGNORED_P (TYPE_OTABLE_DECL (type)) = 1;
- pushdecl (TYPE_OTABLE_DECL (type));
- sprintf (buf, "_otable_syms_%s", typename);
- TYPE_OTABLE_SYMS_DECL (type) =
- build_decl (VAR_DECL, get_identifier (buf), symbols_array_type);
- TREE_STATIC (TYPE_OTABLE_SYMS_DECL (type)) = 1;
- TREE_CONSTANT (TYPE_OTABLE_SYMS_DECL (type)) = 1;
- DECL_IGNORED_P(TYPE_OTABLE_SYMS_DECL (type)) = 1;
- pushdecl (TYPE_OTABLE_SYMS_DECL (type));
- }
-
- {
- char *buf = alloca (strlen (typename) + strlen ("_atable_syms_") + 1);
- tree decl;
-
- sprintf (buf, "_atable_%s", typename);
- TYPE_ATABLE_DECL (type) = decl =
- build_decl (VAR_DECL, get_identifier (buf), atable_type);
- DECL_EXTERNAL (decl) = 1;
- TREE_STATIC (decl) = 1;
- TREE_READONLY (decl) = 1;
- TREE_CONSTANT (decl) = 1;
- DECL_IGNORED_P (decl) = 1;
- /* Mark the atable as belonging to this class. */
- pushdecl (decl);
- MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
- DECL_OWNER (decl) = type;
- sprintf (buf, "_atable_syms_%s", typename);
- TYPE_ATABLE_SYMS_DECL (type) =
- build_decl (VAR_DECL, get_identifier (buf), symbols_array_type);
- TREE_STATIC (TYPE_ATABLE_SYMS_DECL (type)) = 1;
- TREE_CONSTANT (TYPE_ATABLE_SYMS_DECL (type)) = 1;
- DECL_IGNORED_P (TYPE_ATABLE_SYMS_DECL (type)) = 1;
- pushdecl (TYPE_ATABLE_SYMS_DECL (type));
- }
+ 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;
+#ifndef USE_MAPPED_LOCATION
tree source_name = identifier_subst (class_name, "", '.', '/', ".java");
- CLASS_P (class_type) = 1;
input_filename = IDENTIFIER_POINTER (source_name);
input_line = 0;
+#endif
+ CLASS_P (class_type) = 1;
decl = build_decl (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;
if (super_class)
total_supers++;
- TYPE_BINFO (this_class) = make_tree_binfo (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)
{
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,
{
if (type1 == type2)
return 1;
- type1 = CLASSTYPE_SUPER (type1);
+
+ if (! CLASS_LOADED_P (type1))
+ load_class (type1, 1);
+
+ type1 = maybe_layout_super_class (CLASSTYPE_SUPER (type1), type1);
}
return 0;
}
BINFO_BASE_APPEND (TYPE_BINFO (this_class), interface_binfo);
}
-#if 0
-/* Return the address of a pointer to the first FUNCTION_DECL
- in the list (*LIST) whose DECL_NAME is NAME. */
-
-static tree *
-find_named_method (tree *list, tree name)
-{
- while (*list && DECL_NAME (*list) != name)
- list = &TREE_CHAIN (*list);
- return list;
-}
-#endif
-
static tree
build_java_method_type (tree fntype, tree this_class, int access_flags)
{
if (access_flags & ACC_STATIC)
return fntype;
- return build_method_type (this_class, 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;
}
tree
DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl) =
htab_create_ggc (50, htab_hash_pointer, htab_eq_pointer, NULL);
- /* Initialize the static method invocation compound list */
- DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND (fndecl) = NULL_TREE;
-
TREE_CHAIN (fndecl) = TYPE_METHODS (this_class);
TYPE_METHODS (this_class) = fndecl;
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) = DECL_INLINE (fndecl) = 1;
if (access_flags & ACC_FINAL)
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;
}
TREE_CHAIN (field) = TYPE_FIELDS (class);
TYPE_FIELDS (class) = field;
DECL_CONTEXT (field) = class;
+ 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;
+ 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;
- /* Considered external until we know what classes are being
- compiled into this object file. */
- DECL_EXTERNAL (field) = 1;
+ /* Considered external unless we are compiling it into this
+ object file. */
+ DECL_EXTERNAL (field) = (is_compiled_class (class) != 2);
}
return field;
set_constant_value (tree field, tree constant)
{
if (field == NULL_TREE)
- warning ("misplaced ConstantValue attribute (not in any field)");
+ warning (OPT_Wattributes,
+ "misplaced ConstantValue attribute (not in any field)");
else if (DECL_INITIAL (field) != NULL_TREE)
- warning ("duplicate ConstantValue attribute for field '%s'",
+ warning (OPT_Wattributes,
+ "duplicate ConstantValue attribute for field '%s'",
IDENTIFIER_POINTER (DECL_NAME (field)));
else
{
}
}
-/* Count the number of Unicode chars encoded in a given Ut8 string. */
-
-#if 0
-int
-strLengthUtf8 (char *str, int len)
-{
- register unsigned char* ptr = (unsigned char*) str;
- register unsigned char *limit = ptr + len;
- int str_length = 0;
- for (; ptr < limit; str_length++) {
- if (UTF8_GET (ptr, limit) < 0)
- return -1;
- }
- return str_length;
-}
-#endif
-
-
/* Calculate a hash value for a string encoded in Utf8 format.
* This returns the same hash value as specified for java.lang.String.hashCode.
*/
FINISH_RECORD (ctype);
START_RECORD_CONSTRUCTOR (cinit, ctype);
name_hash = hashUtf8String (name_ptr, name_len) & 0xFFFF;
- PUSH_FIELD_VALUE (cinit, "hash", build_int_cst (NULL_TREE, name_hash, 0));
- PUSH_FIELD_VALUE (cinit, "length", build_int_cst (NULL_TREE, name_len, 0));
+ PUSH_FIELD_VALUE (cinit, "hash", build_int_cst (NULL_TREE, name_hash));
+ PUSH_FIELD_VALUE (cinit, "length", build_int_cst (NULL_TREE, name_len));
string = build_string (name_len, name_ptr);
TREE_TYPE (string) = str_type;
PUSH_FIELD_VALUE (cinit, "data", string);
int flags = (SECTION_OVERRIDE
| SECTION_MERGE | (SECTION_ENTSIZE & decl_size));
sprintf (buf, ".rodata.jutf8.%d", decl_size);
- named_section_flags (buf, flags);
+ switch_to_section (get_section (buf, flags, NULL));
DECL_SECTION_NAME (decl) = build_string (strlen (buf), buf);
}
}
layout_decl (decl, 0);
pushdecl (decl);
rest_of_decl_compilation (decl, global_bindings_p (), 0);
+ varpool_mark_needed_node (varpool_node (decl));
utf8_decl_list = decl;
- make_decl_rtl (decl);
ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl);
IDENTIFIER_UTF8_REF (name) = ref;
return ref;
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 (VAR_DECL, decl_name, class_type_node);
+ TREE_STATIC (decl) = 1;
+ if (! flag_indirect_classes)
+ TREE_PUBLIC (decl) = 1;
+ 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 (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_INVARIANT (decl) = 1;
+ TREE_CONSTANT (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ 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 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 (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 = build3 (CALL_EXPR, void_type_node,
+ build_address_of (soft_initclass_node),
+ build_tree_list (NULL_TREE, this_classdollar),
+ NULL_TREE);
+ 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. */
int is_compiled = is_compiled_class (type);
if (is_compiled)
{
- tree ref, decl_name, decl;
+ tree ref, decl;
if (TREE_CODE (type) == POINTER_TYPE)
type = TREE_TYPE (type);
- /* FIXME: we really want an indirect reference to our
- superclass. However, libgcj assumes that a superclass
- pointer always points directly to a class. As a workaround
- we always emit this hard superclass reference. */
- if (flag_indirect_dispatch
- && type != output_class
- && type != CLASSTYPE_SUPER (output_class)
- && TREE_CODE (type) == RECORD_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)
+ return this_classdollar;
+
if (TREE_CODE (type) == RECORD_TYPE)
- {
- 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 (VAR_DECL, decl_name, class_type_node);
- DECL_SIZE (decl) = TYPE_SIZE (class_type_node);
- DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (class_type_node);
- TREE_STATIC (decl) = 1;
- TREE_PUBLIC (decl) = 1;
- DECL_IGNORED_P (decl) = 1;
- DECL_ARTIFICIAL (decl) = 1;
- if (is_compiled == 1)
- DECL_EXTERNAL (decl) = 1;
- SET_DECL_ASSEMBLER_NAME (decl,
- java_mangle_class_field
- (&temporary_obstack, type));
- make_decl_rtl (decl);
- pushdecl_top_level (decl);
- }
- }
+ return build_static_class_ref (type);
else
{
const char *name;
+ tree decl_name;
char buffer[25];
- if (flag_emit_class_files)
- {
- const char *prim_class_name;
- tree prim_class;
- if (type == char_type_node)
- prim_class_name = "java.lang.Character";
- else if (type == boolean_type_node)
- prim_class_name = "java.lang.Boolean";
- else if (type == byte_type_node)
- prim_class_name = "java.lang.Byte";
- else if (type == short_type_node)
- prim_class_name = "java.lang.Short";
- else if (type == int_type_node)
- prim_class_name = "java.lang.Integer";
- else if (type == long_type_node)
- prim_class_name = "java.lang.Long";
- else if (type == float_type_node)
- prim_class_name = "java.lang.Float";
- else if (type == double_type_node)
- prim_class_name = "java.lang.Double";
- else if (type == void_type_node)
- prim_class_name = "java.lang.Void";
- else
- abort ();
-
- prim_class = lookup_class (get_identifier (prim_class_name));
- return build3 (COMPONENT_REF, NULL_TREE,
- prim_class, TYPE_identifier_node, NULL_TREE);
- }
decl_name = TYPE_NAME (type);
if (TREE_CODE (decl_name) == TYPE_DECL)
decl_name = DECL_NAME (decl_name);
TREE_STATIC (decl) = 1;
TREE_PUBLIC (decl) = 1;
DECL_EXTERNAL (decl) = 1;
- make_decl_rtl (decl);
+ DECL_ARTIFICIAL (decl) = 1;
pushdecl_top_level (decl);
}
}
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 = 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 (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);
+ int from_class = ! CLASS_FROM_SOURCE_P (current_class);
/* Allow static final fields to fold to a constant. When using
- -fno-assume-compiled, gcj will sometimes try to fold a field from
- an uncompiled class. This is required when the field in question
- meets the appropriate criteria for a compile-time constant.
- However, currently sometimes gcj is too eager and will end up
- returning the field itself, leading to an incorrect external
- reference being generated. */
- if ((is_compiled
- && (! flag_indirect_dispatch || current_class == fclass))
- || (FIELD_FINAL (fdecl) && DECL_INITIAL (fdecl) != NULL_TREE
- && (JSTRING_TYPE_P (TREE_TYPE (fdecl))
- || JNUMERIC_TYPE_P (TREE_TYPE (fdecl)))
- && TREE_CONSTANT (DECL_INITIAL (fdecl))))
- {
- if (!DECL_RTL_SET_P (fdecl))
- {
- if (is_compiled == 1)
- DECL_EXTERNAL (fdecl) = 1;
- make_decl_rtl (fdecl);
- }
- return fdecl;
+ -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 || !from_class)
+ && (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;
}
-
- if (flag_indirect_dispatch)
+ else
{
- tree table_index
- = build_int_cst (NULL_TREE, get_symbol_table_index
- (fdecl, &TYPE_ATABLE_METHODS (output_class)), 0);
- tree field_address
- = build4 (ARRAY_REF, build_pointer_type (TREE_TYPE (fdecl)),
- TYPE_ATABLE_DECL (output_class), table_index,
- NULL_TREE, NULL_TREE);
- return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl),
- field_address));
- }
- else
- {
- /* Compile as:
- * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */
- tree ref = build_class_ref (fclass);
- tree fld;
- int field_index = 0;
- ref = build1 (INDIRECT_REF, class_type_node, ref);
- ref = build3 (COMPONENT_REF, field_ptr_type_node, ref,
- lookup_field (&class_type_node, fields_ident),
- NULL_TREE);
-
- for (fld = TYPE_FIELDS (fclass); ; fld = TREE_CHAIN (fld))
- {
- if (fld == fdecl)
- break;
- if (fld == NULL_TREE)
- fatal_error ("field '%s' not found in class",
- IDENTIFIER_POINTER (DECL_NAME (fdecl)));
- if (FIELD_STATIC (fld))
- field_index++;
- }
- field_index *= int_size_in_bytes (field_type_node);
- ref = fold (build2 (PLUS_EXPR, field_ptr_type_node,
- ref, build_int_cst (NULL_TREE, field_index, 0)));
- ref = build1 (INDIRECT_REF, field_type_node, ref);
- ref = build3 (COMPONENT_REF, field_info_union_node,
- ref, lookup_field (&field_type_node, info_ident),
- NULL_TREE);
- ref = build3 (COMPONENT_REF, ptr_type_node,
- ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)),
- NULL_TREE);
- ref = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (fdecl)), ref);
- return fold (build1 (INDIRECT_REF, TREE_TYPE(fdecl), ref));
+ /* 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
+ = build3 (CALL_EXPR, boolean_type_node,
+ build_address_of (built_in_decls[BUILT_IN_EXPECT]),
+ tree_cons (NULL_TREE, build2 (EQ_EXPR, boolean_type_node,
+ cache_entry, null_pointer_node),
+ build_tree_list (NULL_TREE, boolean_false_node)),
+ NULL_TREE);
+ tree cpool_index_cst = build_int_cst (NULL_TREE, cpool_index);
+ tree init
+ = build3 (CALL_EXPR, ptr_type_node,
+ build_address_of (soft_resolvepoolentry_node),
+ tree_cons (NULL_TREE, build_class_ref (output_class),
+ build_tree_list (NULL_TREE, cpool_index_cst)),
+ NULL_TREE);
+ 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
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)
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)
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;
}
- abort ();
+ 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. */
+ 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 = alloca (strlen (method_name) + 1);
+ char *name = alloca (strlen (method_name) + 2);
char *buf = 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);
DECL_INITIAL (alias) = error_mark_node;
TREE_ADDRESSABLE (alias) = 1;
TREE_USED (alias) = 1;
- SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
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. */
if (! resolved)
flags |= 0x8000 /* FIELD_UNRESOLVED_FLAG */;
- PUSH_FIELD_VALUE (finit, "accflags", build_int_cst (NULL_TREE, flags, 0));
+ PUSH_FIELD_VALUE (finit, "accflags", build_int_cst (NULL_TREE, flags));
PUSH_FIELD_VALUE (finit, "bsize", TYPE_SIZE_UNIT (TREE_TYPE (fdecl)));
- PUSH_FIELD_VALUE
- (finit, "info",
- build_constructor (field_info_union_node,
- build_tree_list
- ((FIELD_STATIC (fdecl)
- ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
- : TYPE_FIELDS (field_info_union_node)),
- (FIELD_STATIC (fdecl)
- ? build_address_of (build_static_field_ref (fdecl))
- : byte_position (fdecl)))));
+ {
+ tree field_address = integer_zero_node;
+ if ((DECL_INITIAL (fdecl) || ! flag_indirect_classes)
+ && FIELD_STATIC (fdecl))
+ field_address = build_address_of (fdecl);
+
+ PUSH_FIELD_VALUE
+ (finit, "info",
+ build_constructor_from_list (field_info_union_node,
+ build_tree_list
+ ((FIELD_STATIC (fdecl)
+ ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
+ : TYPE_FIELDS (field_info_union_node)),
+ (FIELD_STATIC (fdecl)
+ ? field_address
+ : byte_position (fdecl)))));
+ }
FINISH_RECORD_CONSTRUCTOR (finit);
return finit;
/* 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), 0);
+ 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 (DECL_RTL_SET_P (mdecl))
+ 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 (minit, method_type_node);
(IDENTIFIER_POINTER(signature),
IDENTIFIER_LENGTH(signature)))));
}
- PUSH_FIELD_VALUE (minit, "accflags", build_int_cst (NULL_TREE, accflags, 0));
+ PUSH_FIELD_VALUE (minit, "accflags", build_int_cst (NULL_TREE, accflags));
PUSH_FIELD_VALUE (minit, "index", index);
PUSH_FIELD_VALUE (minit, "ncode", code);
table = tree_cons (NULL_TREE, utf8, table);
}
type = build_prim_array_type (ptr_type_node, length);
- table = build_constructor (type, table);
+ table = build_constructor_from_list (type, table);
/* Compute something unique enough. */
sprintf (buf, "_methods%d", method_name_count++);
array = build_decl (VAR_DECL, get_identifier (buf), type);
if (METHOD_ABSTRACT (method))
{
if (! abstract_p)
- warning ("%Jabstract method in non-abstract class", method);
+ warning (0, "%Jabstract method in non-abstract class", method);
if (TARGET_VTABLE_USES_DESCRIPTORS)
for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
}
else
{
- if (!DECL_RTL_SET_P (method))
- make_decl_rtl (method);
-
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, 0));
+ method, build_int_cst (NULL_TREE, j));
TREE_CONSTANT (fdesc) = 1;
TREE_INVARIANT (fdesc) = 1;
list = tree_cons (NULL_TREE, fdesc, list);
if (TARGET_VTABLE_USES_DESCRIPTORS)
arraysize *= TARGET_VTABLE_USES_DESCRIPTORS;
arraysize += 2;
- return build_constructor (build_prim_array_type (nativecode_ptr_type_node,
- arraysize), list);
+ return build_constructor_from_list
+ (build_prim_array_type (nativecode_ptr_type_node,
+ arraysize), list);
}
void
set_method_index (tree decl, tree method_index)
{
- method_index = fold (convert (sizetype, 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));
+ 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;
}
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 = build_int_cst (NULL_TREE,
- 2 * POINTER_SIZE / BITS_PER_UNIT,
- 0);
+ 2 * POINTER_SIZE / BITS_PER_UNIT);
+ VEC(int, heap) *field_indexes;
+ tree first_real_field;
- this_class_addr = build_class_ref (type);
+ 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;
+ 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);
- if (DECL_NAME (field) == NULL_TREE)
+ while (field && DECL_ARTIFICIAL (field))
+ field = TREE_CHAIN (field); /* Skip dummy fields. */
+ if (field && DECL_NAME (field) == NULL_TREE)
field = TREE_CHAIN (field); /* Skip dummy field for inherited data. */
- for ( ; field != NULL_TREE; field = TREE_CHAIN (field))
+ first_real_field = field;
+
+ /* First count static and instance fields. */
+ for ( ; field != NULL_TREE; field = TREE_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 = TREE_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++;
+ VEC_quick_push (int, field_indexes, field_index);
+ }
+ }
+ }
+
+ for (field = first_real_field; field != NULL_TREE;
+ field = TREE_CHAIN (field))
{
if (! DECL_ARTIFICIAL (field))
{
- tree init = make_field_value (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);
- static_field_count++;
static_fields = tree_cons (NULL_TREE, init, static_fields);
/* If the initial value is a string constant,
prevent output_constant from trying to assemble the value. */
rest_of_decl_compilation (field, 1, 1);
DECL_INITIAL (field) = initial;
}
- else
+ else if (uses_jv_markobj || !flag_reduced_reflection)
{
- instance_field_count++;
+ tree init = make_field_value (field);
instance_fields = tree_cons (NULL_TREE, init, instance_fields);
}
}
}
- field_count = static_field_count + instance_field_count;
+
if (field_count > 0)
{
static_fields = nreverse (static_fields);
field_array_type = build_prim_array_type (field_type_node, field_count);
fields_decl = build_decl (VAR_DECL, mangled_classname ("_FL_", type),
field_array_type);
- DECL_INITIAL (fields_decl) = build_constructor (field_array_type,
- static_fields);
+ DECL_INITIAL (fields_decl) = build_constructor_from_list
+ (field_array_type, static_fields);
TREE_STATIC (fields_decl) = 1;
DECL_ARTIFICIAL (fields_decl) = 1;
DECL_IGNORED_P (fields_decl) = 1;
tree init;
if (METHOD_PRIVATE (method)
&& ! flag_keep_inline_functions
- && (flag_inline_functions || optimize))
+ && 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;
- init = make_method_value (method);
- method_count++;
- methods = tree_cons (NULL_TREE, init, methods);
+
+ /* Generate method reflection data if:
+
+ - !flag_reduced_reflection.
+
+ - <clinit> -- 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))
+ || TYPE_DOT_CLASS (type) == method)
+ {
+ init = make_method_value (method);
+ method_count++;
+ methods = tree_cons (NULL_TREE, init, methods);
+ }
}
method_array_type = build_prim_array_type (method_type_node, method_count);
methods_decl = build_decl (VAR_DECL, mangled_classname ("_MT_", type),
method_array_type);
- DECL_INITIAL (methods_decl) = build_constructor (method_array_type,
- nreverse (methods));
+ DECL_INITIAL (methods_decl) = build_constructor_from_list
+ (method_array_type, nreverse (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 (supers_all_compiled (type) && ! CLASS_INTERFACE (type_decl)
- && !flag_indirect_dispatch)
- {
- tree dtable = get_dispatch_table (type, this_class_addr);
- dtable_decl = build_dtable_decl (type);
- DECL_INITIAL (dtable_decl) = dtable;
- TREE_STATIC (dtable_decl) = 1;
- DECL_ARTIFICIAL (dtable_decl) = 1;
- DECL_IGNORED_P (dtable_decl) = 1;
- TREE_PUBLIC (dtable_decl) = 1;
- rest_of_decl_compilation (dtable_decl, 1, 0);
- if (type == class_type_node)
- class_dtable_decl = dtable_decl;
- }
-
if (class_dtable_decl == NULL_TREE)
{
class_dtable_decl = build_dtable_decl (class_type_node);
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);
+ {
+ 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 (/* FIXME: we should also test for (!
- flag_indirect_dispatch) here, but libgcj can't cope with
- a symbolic reference a superclass in the class data. */
- assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
+ 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, 0);
+ super = build_int_cst (ptr_type_node, super_index);
}
/* Build and emit the array of implemented interfaces. */
else
{
int int_index = alloc_class_constant (iclass);
- index = build_int_cst (ptr_type_node, int_index, 0);
+ index = build_int_cst (ptr_type_node, int_index);
}
init = tree_cons (NULL_TREE, index, init);
}
- DECL_INITIAL (idecl) = build_constructor (interface_array_type, init);
+ DECL_INITIAL (idecl) = build_constructor_from_list (interface_array_type,
+ init);
TREE_STATIC (idecl) = 1;
DECL_ARTIFICIAL (idecl) = 1;
DECL_IGNORED_P (idecl) = 1;
= 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);
+ 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);
+ 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 (temp, object_type_node);
PUSH_FIELD_VALUE (temp, "vtable",
- build2 (PLUS_EXPR, dtable_ptr_type,
- build1 (ADDR_EXPR, dtable_ptr_type,
- class_dtable_decl),
- dtable_start_offset));
+ (flag_indirect_classes
+ ? null_pointer_node
+ : build2 (PLUS_EXPR, dtable_ptr_type,
+ build1 (ADDR_EXPR, dtable_ptr_type,
+ class_dtable_decl),
+ dtable_start_offset)));
if (! flag_hash_synchronization)
PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node);
FINISH_RECORD_CONSTRUCTOR (temp);
START_RECORD_CONSTRUCTOR (cons, class_type_node);
PUSH_SUPER_VALUE (cons, temp);
- PUSH_FIELD_VALUE (cons, "next", null_pointer_node);
+ PUSH_FIELD_VALUE (cons, "next_or_version", gcj_abi_version);
PUSH_FIELD_VALUE (cons, "name", build_utf8_ref (DECL_NAME (type_decl)));
PUSH_FIELD_VALUE (cons, "accflags",
build_int_cst (NULL_TREE,
- get_access_flags_from_decl (type_decl), 0));
+ get_access_flags_from_decl (type_decl)));
PUSH_FIELD_VALUE (cons, "superclass",
CLASS_INTERFACE (type_decl) ? null_pointer_node : super);
PUSH_FIELD_VALUE (cons, "constants", constant_pool_constructor);
PUSH_FIELD_VALUE (cons, "methods",
- build1 (ADDR_EXPR, method_ptr_type_node, methods_decl));
+ methods_decl == NULL_TREE ? null_pointer_node
+ : build1 (ADDR_EXPR, method_ptr_type_node, methods_decl));
PUSH_FIELD_VALUE (cons, "method_count",
- build_int_cst (NULL_TREE, method_count, 0));
+ build_int_cst (NULL_TREE, method_count));
if (flag_indirect_dispatch)
PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node);
PUSH_FIELD_VALUE (cons, "fields",
fields_decl == NULL_TREE ? null_pointer_node
: build1 (ADDR_EXPR, field_ptr_type_node, fields_decl));
- PUSH_FIELD_VALUE (cons, "size_in_bytes", size_in_bytes (type));
- PUSH_FIELD_VALUE (cons, "field_count",
- build_int_cst (NULL_TREE, field_count, 0));
+ /* If we're using the binary compatibility ABI we don't know the
+ size until load time. */
+ PUSH_FIELD_VALUE (cons, "size_in_bytes",
+ (flag_indirect_dispatch
+ ? integer_minus_one_node
+ : size_in_bytes (type)));
+ PUSH_FIELD_VALUE (cons, "field_count",
+ build_int_cst (NULL_TREE, field_count));
PUSH_FIELD_VALUE (cons, "static_field_count",
- build_int_cst (NULL_TREE, static_field_count, 0));
+ build_int_cst (NULL_TREE, static_field_count));
if (flag_indirect_dispatch)
PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node);
}
else
{
+ pushdecl_top_level (TYPE_OTABLE_SYMS_DECL (type));
PUSH_FIELD_VALUE (cons, "otable",
build1 (ADDR_EXPR, otable_ptr_type, TYPE_OTABLE_DECL (type)));
PUSH_FIELD_VALUE (cons, "otable_syms",
}
else
{
+ pushdecl_top_level (TYPE_ATABLE_SYMS_DECL (type));
PUSH_FIELD_VALUE (cons, "atable",
build1 (ADDR_EXPR, atable_ptr_type, TYPE_ATABLE_DECL (type)));
PUSH_FIELD_VALUE (cons, "atable_syms",
TREE_CONSTANT (TYPE_ATABLE_DECL (type)) = 1;
TREE_INVARIANT (TYPE_ATABLE_DECL (type)) = 1;
}
+ if (TYPE_ITABLE_METHODS(type) == NULL_TREE)
+ {
+ PUSH_FIELD_VALUE (cons, "itable", null_pointer_node);
+ PUSH_FIELD_VALUE (cons, "itable_syms", null_pointer_node);
+ }
+ else
+ {
+ pushdecl_top_level (TYPE_ITABLE_SYMS_DECL (type));
+ PUSH_FIELD_VALUE (cons, "itable",
+ build1 (ADDR_EXPR, itable_ptr_type, TYPE_ITABLE_DECL (type)));
+ PUSH_FIELD_VALUE (cons, "itable_syms",
+ build1 (ADDR_EXPR, symbols_array_ptr_type,
+ TYPE_ITABLE_SYMS_DECL (type)));
+ TREE_CONSTANT (TYPE_ITABLE_DECL (type)) = 1;
+ TREE_INVARIANT (TYPE_ITABLE_DECL (type)) = 1;
+ }
PUSH_FIELD_VALUE (cons, "catch_classes",
build1 (ADDR_EXPR, ptr_type_node, TYPE_CTABLE_DECL (type)));
PUSH_FIELD_VALUE (cons, "interfaces", interfaces);
PUSH_FIELD_VALUE (cons, "loader", null_pointer_node);
PUSH_FIELD_VALUE (cons, "interface_count",
- build_int_cst (NULL_TREE, interface_len, 0));
- PUSH_FIELD_VALUE (cons, "state", integer_zero_node);
+ build_int_cst (NULL_TREE, interface_len));
+ PUSH_FIELD_VALUE (cons, "state",
+ convert (byte_type_node,
+ build_int_cst (NULL_TREE, JV_STATE_PRELOADING)));
PUSH_FIELD_VALUE (cons, "thread", null_pointer_node);
PUSH_FIELD_VALUE (cons, "depth", integer_zero_node);
PUSH_FIELD_VALUE (cons, "idt", null_pointer_node);
PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node);
PUSH_FIELD_VALUE (cons, "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 (cons, "assertion_table", assertion_table_ref);
+ }
+
PUSH_FIELD_VALUE (cons, "hack_signers", null_pointer_node);
PUSH_FIELD_VALUE (cons, "chain", null_pointer_node);
PUSH_FIELD_VALUE (cons, "aux_info", null_pointer_node);
+ PUSH_FIELD_VALUE (cons, "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 (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);
+
+ PUSH_FIELD_VALUE (cons, "reflection_data", build_address_of (array));
+
+ free (data);
+ TYPE_REFLECTION_DATA (current_class) = NULL;
+ }
+ else
+ PUSH_FIELD_VALUE (cons, "reflection_data", null_pointer_node);
FINISH_RECORD_CONSTRUCTOR (cons);
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)
{
+ if (TYPE_VERIFY_METHOD (output_class))
+ {
+ tree verify_method = TYPE_VERIFY_METHOD (output_class);
+ DECL_SAVED_TREE (verify_method)
+ = add_stmt_to_compound (DECL_SAVED_TREE (verify_method), void_type_node,
+ build1 (RETURN_EXPR, void_type_node, NULL));
+ java_genericize (verify_method);
+ cgraph_finalize_function (verify_method, false);
+ TYPE_ASSERTIONS (current_class) = NULL;
+ }
+
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 1;
if (TYPE_ARRAY_P (class))
return 0;
- if (class == current_class)
- return 2;
seen_in_zip = (TYPE_JCF (class) && JCF_SEEN_IN_ZIP (TYPE_JCF (class)));
- if (CLASS_FROM_CURRENTLY_COMPILED_P (class) || seen_in_zip)
+ if (CLASS_FROM_CURRENTLY_COMPILED_P (class))
{
/* 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 (class))
+ if (seen_in_zip && !CLASS_LOADED_P (class) && (class != current_class))
load_class (class, 1);
/* We return 2 for class seen in ZIP and class from files
{
if (CLASS_FROM_SOURCE_P (class))
safe_layout_class (class);
- else
+ else if (class != current_class)
load_class (class, 1);
}
return 1;
tree
build_dtable_decl (tree type)
{
- tree dtype;
+ 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
else
dtype = dtable_type;
- return build_decl (VAR_DECL,
- java_mangle_vtable (&temporary_obstack, type), dtype);
+ decl = build_decl (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
/* 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)
+maybe_layout_super_class (tree super_class, tree this_class ATTRIBUTE_UNUSED)
{
- if (TREE_CODE (super_class) == RECORD_TYPE)
+ if (!super_class)
+ return NULL_TREE;
+ else if (TREE_CODE (super_class) == RECORD_TYPE)
{
if (!CLASS_LOADED_P (super_class) && CLASS_FROM_SOURCE_P (super_class))
safe_layout_class (super_class);
if (TREE_TYPE (super_class) != NULL_TREE)
super_class = TREE_TYPE (super_class);
else
- {
- /* do_resolve_class expects an EXPR_WITH_FILE_LOCATION, so
- we give it one. */
- tree this_wrap = NULL_TREE;
-
- if (this_class)
- {
- tree this_decl = TYPE_NAME (this_class);
- this_wrap = build_expr_wfl (this_class,
- DECL_SOURCE_FILE (this_decl),
- DECL_SOURCE_LINE (this_decl), 0);
- }
- super_class = do_resolve_class (NULL_TREE, /* FIXME? */
- super_class, NULL_TREE, this_wrap);
- if (!super_class)
- return NULL_TREE; /* FIXME, NULL_TREE not checked by caller. */
- super_class = TREE_TYPE (super_class);
- }
+ 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 class)
+{
+ tree save_current_class = current_class;
+ location_t save_location = input_location;
+
+ layout_class (class);
+
+ current_class = save_current_class;
+ input_location = save_location;
+}
+
void
layout_class (tree this_class)
{
tree super_class = CLASSTYPE_SUPER (this_class);
- tree field;
class_list = tree_cons (this_class, NULL_TREE, class_list);
if (CLASS_BEING_LAIDOUT (this_class))
char *report;
tree current;
- sprintf (buffer, " with `%s'",
+ sprintf (buffer, " with '%s'",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))));
obstack_grow (&temporary_obstack, buffer, strlen (buffer));
current = TREE_CHAIN (current))
{
tree decl = TYPE_NAME (TREE_PURPOSE (current));
- sprintf (buffer, "\n which inherits from `%s' (%s:%d)",
+ sprintf (buffer, "\n which inherits from '%s' (%s:%d)",
IDENTIFIER_POINTER (DECL_NAME (decl)),
DECL_SOURCE_FILE (decl),
DECL_SOURCE_LINE (decl));
push_super_field (this_class, maybe_super_class);
}
- for (field = TYPE_FIELDS (this_class);
- field != NULL_TREE; field = TREE_CHAIN (field))
- {
- if (FIELD_STATIC (field))
- {
- /* Set DECL_ASSEMBLER_NAME to something suitably mangled. */
- SET_DECL_ASSEMBLER_NAME (field,
- java_mangle_decl
- (&temporary_obstack, field));
- }
- }
-
layout_type (this_class);
/* Also recursively load/layout any superinterfaces, but only if
if (!CLASS_FROM_SOURCE_P (this_class))
{
int i;
-
- for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (this_class)) - 1; i > 0; i--)
+ if (TYPE_BINFO (this_class))
{
- 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)
+ for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (this_class)) - 1; i > 0; i--)
{
- TYPE_SIZE (this_class) = error_mark_node;
- CLASS_BEING_LAIDOUT (this_class) = 0;
- class_list = TREE_CHAIN (class_list);
- return;
+ 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;
+ }
}
}
}
static void
add_miranda_methods (tree base_class, tree search_class)
{
- tree binfo, base_binfo;
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
if (TYPE_NVIRTUALS (this_class))
return;
-
+
super_class = CLASSTYPE_SUPER (this_class);
if (super_class)
dtable_count = integer_zero_node;
type_name = TYPE_NAME (this_class);
- if (CLASS_ABSTRACT (type_name) || CLASS_INTERFACE (type_name))
+ 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
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(). */
+/* 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 = TREE_CHAIN (meth), i++)
+ for (meth = TYPE_METHODS (interface); ; meth = TREE_CHAIN (meth))
{
if (meth == method)
return i;
- if (meth == NULL_TREE)
- abort ();
+ /* We don't want to put <clinit> into the interface table. */
+ if (! ID_CLINIT_P (DECL_NAME (meth)))
+ ++i;
+ gcc_assert (meth != NULL_TREE);
}
}
tree method_name = DECL_NAME (method_decl);
TREE_PUBLIC (method_decl) = 1;
- /* Considered external until we know what classes are being
- compiled into this object file. */
- DECL_EXTERNAL (method_decl) = 1;
-
- /* This is a good occasion to mangle the method's name */
- SET_DECL_ASSEMBLER_NAME (method_decl,
- java_mangle_decl (&temporary_obstack,
- method_decl));
- /* We don't generate a RTL for the method if it's abstract, or if
- it's an interface method that isn't clinit. */
- if (! METHOD_ABSTRACT (method_decl)
- || (CLASS_INTERFACE (TYPE_NAME (this_class))
- && (DECL_CLINIT_P (method_decl))))
- make_decl_rtl (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))
{
p = ptr;
}
DECL_CONSTRUCTOR_P (method_decl) = 1;
- build_java_argument_signature (TREE_TYPE (method_decl));
+ build_java_signature (TREE_TYPE (method_decl));
}
- else if (! METHOD_STATIC (method_decl) && !DECL_ARTIFICIAL (method_decl))
+ else if (! METHOD_STATIC (method_decl))
{
tree method_sig =
- build_java_argument_signature (TREE_TYPE (method_decl));
+ build_java_signature (TREE_TYPE (method_decl));
bool method_override = false;
- tree super_method = lookup_argument_method (super_class, method_name,
+ tree super_method = lookup_java_method (super_class, method_name,
method_sig);
- if (super_method != NULL_TREE)
+ if (super_method != NULL_TREE
+ && ! METHOD_DUMMY (super_method))
{
method_override = true;
if (! METHOD_PUBLIC (super_method) &&
tree method_index = get_method_index (super_method);
set_method_index (method_decl, method_index);
if (method_index == NULL_TREE
- && !CLASS_FROM_SOURCE_P (this_class))
- error ("%Jnon-static method '%D' overrides static method",
- method_decl, method_decl);
+ && ! flag_indirect_dispatch
+ && !CLASS_FROM_SOURCE_P (this_class)
+ && ! 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_FINAL (method_decl)
- && ! METHOD_PRIVATE (method_decl)
- && ! CLASS_FINAL (TYPE_NAME (this_class))
+ 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));
+ dtable_count = fold_build2 (PLUS_EXPR, integer_type_node,
+ dtable_count, integer_one_node);
}
}
return dtable_count;
}
-void
+static void
register_class (void)
{
- /* END does not need to be registered with the garbage collector
- because it always points into the list given by REGISTERED_CLASS,
- and that variable is registered with the collector. */
- static tree end;
- tree node = TREE_OPERAND (build_class_ref (current_class), 0);
- tree current = copy_node (node);
+ tree node;
- XEXP (DECL_RTL (current), 0) = copy_rtx (XEXP (DECL_RTL(node), 0));
if (!registered_class)
- registered_class = current;
+ registered_class = VEC_alloc (tree, gc, 8);
+
+ if (flag_indirect_classes)
+ node = current_class;
else
- TREE_CHAIN (end) = current;
+ 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;
- end = current;
+ tree init = NULL_TREE;
+ int size = VEC_length (tree, registered_class) * 2 + 1;
+ tree class_array_type
+ = build_prim_array_type (ptr_type_node, size);
+ tree cdecl = build_decl (VAR_DECL, get_identifier ("_Jv_CLS"),
+ class_array_type);
+ tree reg_class_list;
+ for (i = 0; VEC_iterate (tree, registered_class, i, klass); ++i)
+ {
+ init = tree_cons (NULL_TREE,
+ fold_convert (ptr_type_node,
+ build_static_class_ref (klass)), init);
+ init = tree_cons
+ (NULL_TREE,
+ fold_convert (ptr_type_node,
+ build_address_of (build_classdollar_field (klass))),
+ init);
+ }
+ init = tree_cons (NULL_TREE, integer_zero_node, init);
+ DECL_INITIAL (cdecl) = build_constructor_from_list (class_array_type,
+ nreverse (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 (FUNCTION_DECL,
+ get_identifier ("_Jv_RegisterNewClasses"), t);
+ TREE_PUBLIC (t) = 1;
+ DECL_EXTERNAL (t) = 1;
+ register_class_fn = t;
+ t = tree_cons (NULL, reg_class_list, NULL);
+ t = build_function_call_expr (register_class_fn, t);
+ 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
if (registered_class == NULL)
return;
- /* ??? This isn't quite the correct test. We also have to know
- that the target is using gcc's crtbegin/crtend objects rather
- than the ones that come with the operating system. */
- if (SUPPORTS_WEAK && targetm.have_named_sections)
+ 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
- tree t;
- named_section_flags (JCR_SECTION_NAME, SECTION_WRITE);
- assemble_align (POINTER_SIZE);
- for (t = registered_class; t; t = TREE_CHAIN (t))
- assemble_integer (XEXP (DECL_RTL (t), 0),
- POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+ switch_to_section (get_section (JCR_SECTION_NAME, SECTION_WRITE, NULL));
#else
- abort ();
+ /* A target has defined TARGET_USE_JCR_SECTION,
+ but doesn't have a JCR_SECTION_NAME. */
+ gcc_unreachable ();
#endif
+ assemble_align (POINTER_SIZE);
+
+ for (i = 0; VEC_iterate (tree, registered_class, i, klass); ++i)
+ {
+ 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 (FUNCTION_DECL, get_identifier ("_Jv_RegisterClass"), t);
DECL_EXTERNAL (t) = 1;
register_class_fn = t;
- for (klass = registered_class; klass; klass = TREE_CHAIN (klass))
+ for (i = 0; VEC_iterate (tree, registered_class, i, klass); ++i)
{
t = build_fold_addr_expr (klass);
t = tree_cons (NULL, t, NULL);
/* Make a symbol_type (_Jv_MethodSymbol) node for DECL. */
static tree
-build_symbol_entry (tree decl)
+build_symbol_entry (tree decl, tree special)
{
tree clname, name, signature, sym;
-
clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))));
- name = build_utf8_ref (DECL_NAME (decl));
+ /* ??? Constructors are given the name foo.foo all the way through
+ the compiler, but in the method table they're all renamed
+ foo.<init>. 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 (PLUS_EXPR, TREE_TYPE (signature), signature, special);
+
START_RECORD_CONSTRUCTOR (sym, symbol_type);
PUSH_FIELD_VALUE (sym, "clname", clname);
PUSH_FIELD_VALUE (sym, "name", name);
tree
emit_symbol_table (tree name, tree the_table, tree decl_list,
- tree the_syms_decl, tree the_array_element_type)
+ tree the_syms_decl, tree the_array_element_type,
+ int element_size)
{
tree method_list, method, table, list, null_symbol;
tree table_size, the_array_type;
list = NULL_TREE;
while (method_list != NULL_TREE)
{
+ tree special = TREE_PURPOSE (method_list);
method = TREE_VALUE (method_list);
- list = tree_cons (NULL_TREE, build_symbol_entry (method), list);
+ list = tree_cons (NULL_TREE, build_symbol_entry (method, special), list);
method_list = TREE_CHAIN (method_list);
index++;
}
/* Put the list in the right order and make it a constructor. */
list = nreverse (list);
- table = build_constructor (symbols_array_type, list);
+ table = build_constructor_from_list (symbols_array_type, list);
/* Make it the initial value for otable_syms and emit the decl. */
DECL_INITIAL (the_syms_decl) = table;
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, 0));
+ 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 (VAR_DECL, name, the_array_type);
TREE_STATIC (the_table) = 1;
return the_table;
}
-/* make an entry for the catch_classes list. */
+/* Make an entry for the catch_classes list. */
tree
make_catch_class_record (tree catch_class, tree classname)
{
TYPE_CATCH_CLASSES (this_class));
table_size = build_index_type
(build_int_cst (NULL_TREE,
- list_length (TYPE_CATCH_CLASSES (this_class)), 0));
+ list_length (TYPE_CATCH_CLASSES (this_class))));
array_type
= build_array_type (TREE_TYPE (TREE_TYPE (TYPE_CTABLE_DECL (this_class))),
table_size);
table =
build_decl (VAR_DECL, DECL_NAME (TYPE_CTABLE_DECL (this_class)), array_type);
DECL_INITIAL (table) =
- build_constructor (array_type, TYPE_CATCH_CLASSES (this_class));
+ build_constructor_from_list (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;
+}
+
+/* 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;
+ tree *list = (tree *) 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);
+
+ START_RECORD_CONSTRUCTOR (entry, assertion_entry_type);
+ PUSH_FIELD_VALUE (entry, "assertion_code", code_val);
+ PUSH_FIELD_VALUE (entry, "op1", op1_utf8);
+ PUSH_FIELD_VALUE (entry, "op2", op2_utf8);
+ FINISH_RECORD_CONSTRUCTOR (entry);
+
+ *list = tree_cons (NULL_TREE, entry, *list);
+ return true;
+}
+
+/* Generate the type assertion table for CLASS, and return its DECL. */
+
+static tree
+emit_assertion_table (tree class)
+{
+ tree null_entry, ctor, table_decl;
+ tree list = NULL_TREE;
+ htab_t assertions_htab = TYPE_ASSERTIONS (class);
+
+ /* Iterate through the hash table. */
+ htab_traverse (assertions_htab, add_assertion_table_entry, &list);
+
+ /* Finish with a null entry. */
+ START_RECORD_CONSTRUCTOR (null_entry, assertion_entry_type);
+ PUSH_FIELD_VALUE (null_entry, "assertion_code", integer_zero_node);
+ PUSH_FIELD_VALUE (null_entry, "op1", null_pointer_node);
+ PUSH_FIELD_VALUE (null_entry, "op2", null_pointer_node);
+ FINISH_RECORD_CONSTRUCTOR (null_entry);
+
+ list = tree_cons (NULL_TREE, null_entry, list);
+
+ /* Put the list in the right order and make it a constructor. */
+ list = nreverse (list);
+ ctor = build_constructor_from_list (assertion_table_type, list);
+
+ table_decl = build_decl (VAR_DECL, mangled_classname ("_type_assert_", class),
+ 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)