/* 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.
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 2, or (at your option)
+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,
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 COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>.
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 get_dispatch_vector (tree);
static tree get_dispatch_table (tree, tree);
static int supers_all_compiled (tree type);
-static void add_interface_do (tree, tree, int);
static tree maybe_layout_super_class (tree, tree);
static void add_miranda_methods (tree, tree);
static int assume_compiled (const char *);
-static tree build_symbol_entry (tree);
-
-static GTY(()) rtx registerClass_libfunc;
+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);
- TYPE_BINFO (type) = make_tree_vec (BINFO_ELTS);
+ /* 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;
}
-
-/* Given a class, create the DECLs for all its associated indirect dispatch tables. */
+#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. */
void
gen_indirect_dispatch_tables (tree type)
{
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;
- tree source_name = identifier_subst (class_name, "", '.', '/', ".java");
- CLASS_P (class_type) = 1;
- input_filename = IDENTIFIER_POINTER (source_name);
+#ifndef USE_MAPPED_LOCATION
+ input_filename = "<unknown>";
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;
{
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);
- TYPE_BINFO_BASETYPES (this_class) = make_tree_vec (total_supers);
if (super_class)
{
- tree super_binfo = make_tree_vec (BINFO_ELTS);
+ tree super_binfo = make_tree_binfo (0);
BINFO_TYPE (super_binfo) = super_class;
BINFO_OFFSET (super_binfo) = integer_zero_node;
- TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (this_class)), 0)
- = super_binfo;
- CLASS_HAS_SUPER (this_class) = 1;
+ 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);
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,
while (clas != object_type_node)
{
depth++;
- clas = TYPE_BINFO_BASETYPE (clas, 0);
+ clas = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (clas), 0));
}
return depth;
}
int
interface_of_p (tree type1, tree type2)
{
- int n, i;
- tree basetype_vec;
+ int i;
+ tree binfo, base_binfo;
- if (!(basetype_vec = TYPE_BINFO_BASETYPES (type2)))
+ if (! TYPE_BINFO (type2))
return 0;
- n = TREE_VEC_LENGTH (basetype_vec);
- for (i = 0; i < n; i++)
- {
- tree vec_elt = TREE_VEC_ELT (basetype_vec, i);
- if (vec_elt && BINFO_TYPE (vec_elt) == type1)
- return 1;
- }
- for (i = 0; i < n; i++)
- {
- tree vec_elt = TREE_VEC_ELT (basetype_vec, i);
- if (vec_elt && BINFO_TYPE (vec_elt)
- && interface_of_p (type1, BINFO_TYPE (vec_elt)))
- return 1;
- }
+
+ 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;
}
{
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;
}
return 0;
}
-/* Return 1 iff there exists a common enclosing context between TYPE1
- and TYPE2. */
-int common_enclosing_context_p (tree type1, tree type2)
+/* 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;
return 0;
}
-static void
-add_interface_do (tree basetype_vec, tree interface_class, int i)
-{
- tree interface_binfo = make_tree_vec (BINFO_ELTS);
- BINFO_TYPE (interface_binfo) = interface_class;
- BINFO_OFFSET (interface_binfo) = integer_zero_node;
- BINFO_VPTR_FIELD (interface_binfo) = integer_zero_node;
- TREE_VIA_VIRTUAL (interface_binfo) = 1;
- TREE_VEC_ELT (basetype_vec, i) = interface_binfo;
-}
-
/* 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 basetype_vec = TYPE_BINFO_BASETYPES (this_class);
+ tree binfo, base_binfo;
int i;
- int n = TREE_VEC_LENGTH (basetype_vec);
- for (i = 0; ; i++)
- {
- if (i >= n)
- {
- error ("internal error - too many interface type");
- return NULL_TREE;
- }
- else if (TREE_VEC_ELT (basetype_vec, i) == NULL_TREE)
- break;
- else if (BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i)) == interface_class)
- return interface_class;
- }
- add_interface_do (basetype_vec, interface_class, 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;
}
void
add_interface (tree this_class, tree interface_class)
{
- tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
- int i;
- int n = TREE_VEC_LENGTH (basetype_vec);
- for (i = 0; ; i++)
- {
- if (i >= n)
- {
- error ("internal error - too many interface type");
- return;
- }
- else if (TREE_VEC_ELT (basetype_vec, i) == NULL_TREE)
- break;
- }
- add_interface_do (basetype_vec, interface_class, i);
-}
-
-#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;
+ 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);
}
-#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;
+}
+
+static void
+hide (tree decl ATTRIBUTE_UNUSED)
+{
+#ifdef HAVE_GAS_HIDDEN
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+#endif
}
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;
+ /* 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
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;
+ /* Hide everything that shouldn't be visible outside a DSO. */
+ if (flag_indirect_classes
+ || (FIELD_PRIVATE (field)))
+ hide (field);
+ /* 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
{
&& TREE_TYPE (field) == string_ptr_type_node))
error ("ConstantValue attribute of field '%s' has wrong type",
IDENTIFIER_POINTER (DECL_NAME (field)));
- if (FIELD_FINAL (field))
- DECL_FIELD_FINAL_IUD (field) = 1;
}
}
-/* 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_2 (name_hash, 0));
- PUSH_FIELD_VALUE (cinit, "length", build_int_2 (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);
}
}
TREE_CHAIN (decl) = utf8_decl_list;
layout_decl (decl, 0);
pushdecl (decl);
- rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
+ rest_of_decl_compilation (decl, global_bindings_p (), 0);
+ varpool_mark_needed_node (varpool_node (decl));
utf8_decl_list = decl;
- make_decl_rtl (decl, (char*) 0);
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;
+ if (CLASS_PRIVATE (TYPE_NAME (type)))
+ hide (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 (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;
+ hide (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 (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. */
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, NULL);
- 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 build (COMPONENT_REF, NULL_TREE,
- prim_class, TYPE_identifier_node);
- }
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, NULL);
+ 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)
{
int is_compiled = is_compiled_class (fclass);
/* 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, NULL);
- }
- 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
+ && (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_2 (get_symbol_table_index
- (fdecl, &TYPE_ATABLE_METHODS (output_class)), 0);
- tree field_address
- = build (ARRAY_REF, build_pointer_type (TREE_TYPE (fdecl)),
- TYPE_ATABLE_DECL (output_class), table_index);
- 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 = build (COMPONENT_REF, field_ptr_type_node, ref,
- lookup_field (&class_type_node, fields_ident));
-
- 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 (build (PLUS_EXPR, field_ptr_type_node,
- ref, build_int_2 (field_index, 0)));
- ref = build1 (INDIRECT_REF, field_type_node, ref);
- ref = build (COMPONENT_REF, field_info_union_node,
- ref, lookup_field (&field_type_node, info_ident));
- ref = build (COMPONENT_REF, ptr_type_node,
- ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)));
- 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
+ = 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
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. */
+
+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) + 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);
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, name, alias_labelno++);
+ alias = build_decl (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_INLINE (alias) = 0;
+ 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)
{
if (! resolved)
flags |= 0x8000 /* FIELD_UNRESOLVED_FLAG */;
- PUSH_FIELD_VALUE (finit, "accflags", build_int_2 (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;
}
+/** Make reflection data (_Jv_Method) for method MDECL. */
+
static tree
make_method_value (tree mdecl)
{
class_decl = DECL_CONTEXT (mdecl);
/* For interfaces, the index field contains the dispatch index. */
if (CLASS_INTERFACE (TYPE_NAME (class_decl)))
- index = build_int_2 (get_interface_method_index (mdecl, class_decl), 0);
+ 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 (DECL_RTL_SET_P (mdecl))
- code = build1 (ADDR_EXPR, nativecode_ptr_type_node, 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);
PUSH_FIELD_VALUE (minit, "name",
build_utf8_ref (DECL_CONSTRUCTOR_P (mdecl) ?
(IDENTIFIER_POINTER(signature),
IDENTIFIER_LENGTH(signature)))));
}
- PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (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);
TREE_STATIC (array) = 1;
DECL_ARTIFICIAL (array) = 1;
DECL_IGNORED_P (array) = 1;
- rest_of_decl_compilation (array, (char*) 0, 1, 0);
+ rest_of_decl_compilation (array, 1, 0);
table = build1 (ADDR_EXPR, ptr_type_node, array);
}
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, NULL);
-
if (TARGET_VTABLE_USES_DESCRIPTORS)
for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
{
- tree fdesc = build (FDESC_EXPR, nativecode_ptr_type_node,
- method, build_int_2 (j, 0));
+ tree fdesc = build2 (FDESC_EXPR, nativecode_ptr_type_node,
+ 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_2 (2 * POINTER_SIZE / BITS_PER_UNIT, 0);
+ tree dtable_start_offset = size_int (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;
+ /* The only dispatch table exported from a DSO is the dispatch
+ table for java.lang.Class. */
+ if (DECL_NAME (type_decl) != id_class)
+ hide (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);
- 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. */
if (initial != NULL_TREE
&& TREE_TYPE (initial) == string_ptr_type_node)
DECL_INITIAL (field) = NULL_TREE;
- rest_of_decl_compilation (field, (char*) 0, 1, 1);
+ 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;
- rest_of_decl_compilation (fields_decl, (char*) 0, 1, 0);
+ rest_of_decl_compilation (fields_decl, 1, 0);
}
else
fields_decl = NULL_TREE;
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)))
+ {
+ 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, (char*) 0, 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, (char*) 0, 1, 0);
- if (type == class_type_node)
- class_dtable_decl = dtable_decl;
- }
+ rest_of_decl_compilation (methods_decl, 1, 0);
if (class_dtable_decl == NULL_TREE)
{
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, (char*) 0, 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_2 (super_index, 0);
- TREE_TYPE (super) = ptr_type_node;
+ super = build_int_cst (ptr_type_node, super_index);
}
/* Build and emit the array of implemented interfaces. */
if (type != object_type_node)
- interface_len = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)) - 1;
+ interface_len = BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) - 1;
+
if (interface_len > 0)
{
tree init = NULL_TREE;
= build_prim_array_type (class_ptr_type, interface_len);
idecl = build_decl (VAR_DECL, mangled_classname ("_IF_", type),
interface_array_type);
+
for (i = interface_len; i > 0; i--)
{
- tree child = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i);
+ tree child = BINFO_BASE_BINFO (TYPE_BINFO (type), i);
tree iclass = BINFO_TYPE (child);
tree index;
if (! flag_indirect_dispatch
else
{
int int_index = alloc_class_constant (iclass);
- index = build_int_2 (int_index, 0);
- TREE_TYPE (index) = ptr_type_node;
+ 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;
interfaces = build1 (ADDR_EXPR, ptr_type_node, idecl);
- rest_of_decl_compilation (idecl, (char*) 0, 1, 0);
+ rest_of_decl_compilation (idecl, 1, 0);
}
constant_pool_constructor = build_constants_constructor ();
= 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",
- build (PLUS_EXPR, dtable_ptr_type,
- build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl),
- dtable_start_offset));
+ (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 (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_2 (get_access_flags_from_decl (type_decl), 0));
+ build_int_cst (NULL_TREE,
+ 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));
- PUSH_FIELD_VALUE (cons, "method_count", build_int_2 (method_count, 0));
+ 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));
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_2 (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_2 (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
PUSH_FIELD_VALUE (cons, "vtable",
dtable_decl == NULL_TREE ? null_pointer_node
- : build (PLUS_EXPR, dtable_ptr_type,
- build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl),
- dtable_start_offset));
+ : build2 (POINTER_PLUS_EXPR, dtable_ptr_type,
+ build1 (ADDR_EXPR, dtable_ptr_type,
+ dtable_decl),
+ dtable_start_offset));
if (TYPE_OTABLE_METHODS (type) == NULL_TREE)
{
PUSH_FIELD_VALUE (cons, "otable", 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_2 (interface_len, 0));
- PUSH_FIELD_VALUE (cons, "state", integer_zero_node);
+ PUSH_FIELD_VALUE (cons, "interface_count",
+ 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;
- rest_of_decl_compilation (decl, (char*) 0, 1, 0);
+ 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
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), (char*) 0, 1, 0);
+ rest_of_decl_compilation (TYPE_NAME (current_class), 1, 0);
}
/* Return 2 if CLASS is compiled by this compilation job;
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_LOADED_P (class))
{
- if (CLASS_FROM_SOURCE_P (class))
- safe_layout_class (class);
- 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 (!CLASS_LOADED_P (super_class))
load_class (super_class, 1);
}
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)
{
+ int i;
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
- class was loaded from bytecode. The source parser will take care
- of this itself. */
- if (!CLASS_FROM_SOURCE_P (this_class))
+ /* Also recursively load/layout any superinterfaces. */
+ if (TYPE_BINFO (this_class))
{
- tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
-
- if (basetype_vec)
+ for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (this_class)) - 1; i > 0; i--)
{
- int n = TREE_VEC_LENGTH (basetype_vec) - 1;
- int i;
- for (i = n; 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)
{
- tree vec_elt = TREE_VEC_ELT (basetype_vec, i);
- tree super_interface = BINFO_TYPE (vec_elt);
-
- tree maybe_super_interface
- = maybe_layout_super_class (super_interface, NULL_TREE);
- if (maybe_super_interface == NULL
- || TREE_CODE (TYPE_SIZE (maybe_super_interface)) == ERROR_MARK)
- {
- TYPE_SIZE (this_class) = error_mark_node;
- CLASS_BEING_LAIDOUT (this_class) = 0;
- class_list = TREE_CHAIN (class_list);
- return;
- }
+ 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 basetype_vec = TYPE_BINFO_BASETYPES (search_class);
- int i, n = TREE_VEC_LENGTH (basetype_vec);
- for (i = 1; i < n; ++i)
+ 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 = TREE_VEC_ELT (basetype_vec, i);
- if (elt == NULL_TREE)
- break;
- elt = BINFO_TYPE (elt);
+ 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, NULL);
+
+ if (flag_indirect_classes
+ || (METHOD_PRIVATE (method_decl) && METHOD_STATIC (method_decl)
+ && ! METHOD_NATIVE (method_decl)
+ && ! special_method_p (method_decl)))
+ hide (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));
- tree super_method = lookup_argument_method (super_class, method_name,
+ 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_PRIVATE (super_method))
+ 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
- && !CLASS_FROM_SOURCE_P (this_class))
- error ("%Jnon-static method '%D' overrides static method",
- method_decl, method_decl);
+ && ! flag_indirect_dispatch
+ && ! DECL_ARTIFICIAL (super_method))
+ error ("non-static method %q+D overrides static method",
+ method_decl);
}
- else if (! METHOD_FINAL (method_decl)
- && ! METHOD_PRIVATE (method_decl)
- && ! CLASS_FINAL (TYPE_NAME (this_class))
+ 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 (build (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 = 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 generate
- a `constructor' function which calls _Jv_RegisterClass for each
- class in this file. */
+ 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 (void)
+emit_register_classes (tree *list_p)
{
- /* ??? 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 (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
- 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
{
- extern tree get_file_function_name (int);
- tree init_name = get_file_function_name ('I');
- tree init_type = build_function_type (void_type_node, end_params_node);
- tree init_decl;
- tree t;
- location_t saved_loc = input_location;
-
- init_decl = build_decl (FUNCTION_DECL, init_name, init_type);
- SET_DECL_ASSEMBLER_NAME (init_decl, init_name);
- DECL_SOURCE_LINE (init_decl) = 0;
- TREE_STATIC (init_decl) = 1;
- current_function_decl = init_decl;
- DECL_RESULT (init_decl) = build_decl (RESULT_DECL, NULL_TREE,
- void_type_node);
-
- /* It can be a static function as long as collect2 does not have
- to scan the object file to find its ctor/dtor routine. */
- TREE_PUBLIC (init_decl) = ! targetm.have_ctors_dtors;
-
- /* Suppress spurious warnings. */
- TREE_USED (init_decl) = 1;
-
- pushlevel (0);
- make_decl_rtl (init_decl, NULL);
- init_function_start (init_decl);
- expand_function_start (init_decl, 0);
-
- /* Do not allow the function to be deferred. */
- current_function_cannot_inline
- = "static constructors and destructors cannot be inlined";
-
- for ( t = registered_class; t; t = TREE_CHAIN (t))
- emit_library_call (registerClass_libfunc, 0, VOIDmode, 1,
- XEXP (DECL_RTL (t), 0), Pmode);
- input_location = DECL_SOURCE_LOCATION (init_decl);
- expand_function_end ();
- poplevel (1, 0, 1);
- rest_of_compilation (init_decl);
- current_function_decl = NULL_TREE;
-
- if (targetm.have_ctors_dtors)
- (* targetm.asm_out.constructor) (XEXP (DECL_RTL (init_decl), 0),
- DEFAULT_INIT_PRIORITY);
- input_location = saved_loc;
+ 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);
+ TREE_PUBLIC (t) = 1;
+ DECL_EXTERNAL (t) = 1;
+ register_class_fn = t;
+
+ for (i = 0; VEC_iterate (tree, registered_class, i, klass); ++i)
+ {
+ t = build_fold_addr_expr (klass);
+ t = build_call_expr (register_class_fn, 1, t);
+ append_to_statement_list (t, list_p);
+ }
}
}
/* 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 (POINTER_PLUS_EXPR, TREE_TYPE (signature), signature,
+ fold_convert (sizetype, special));
+
START_RECORD_CONSTRUCTOR (sym, symbol_type);
PUSH_FIELD_VALUE (sym, "clname", clname);
PUSH_FIELD_VALUE (sym, "name", name);
/* Emit a symbol table: used by -findirect-dispatch. */
tree
-emit_symbol_table (tree name, tree the_table, tree decl_list, tree the_syms_decl,
- tree the_array_element_type)
+emit_symbol_table (tree name, tree the_table, tree decl_list,
+ 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;
DECL_ARTIFICIAL (the_syms_decl) = 1;
DECL_IGNORED_P (the_syms_decl) = 1;
- rest_of_decl_compilation (the_syms_decl, NULL, 1, 0);
+ 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_2 (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;
TREE_READONLY (the_table) = 1;
- rest_of_decl_compilation (the_table, NULL, 1, 0);
+ rest_of_decl_compilation (the_table, 1, 0);
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)
{
tree_cons (NULL,
make_catch_class_record (null_pointer_node, null_pointer_node),
TYPE_CATCH_CLASSES (this_class));
- table_size =
- build_index_type (build_int_2
- (list_length (TYPE_CATCH_CLASSES (this_class)), 0));
+ table_size = build_index_type
+ (build_int_cst (NULL_TREE,
+ 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, NULL, 1, 0);
+ 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)
{
- registerClass_libfunc = gen_rtx_SYMBOL_REF (Pmode, "_Jv_RegisterClass");
fields_ident = get_identifier ("fields");
info_ident = get_identifier ("info");
+
gcc_obstack_init (&temporary_obstack);
}
\f
static hashval_t
java_treetreehash_hash (const void *k_p)
{
- struct treetreehash_entry *k = (struct treetreehash_entry *) 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)
{
- struct treetreehash_entry * k1 = (struct treetreehash_entry *) k1_p;
- tree k2 = (tree) 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);
}
java_treetreehash_compare, free, xcalloc, free);
}
+/* 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 = 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);
+}
+
#include "gt-java-class.h"