/* Functions related to building classes and their related objects.
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
+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)
any later version.
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
+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.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "flags.h"
#include "toplev.h"
#include "output.h"
#include "parse.h"
+#include "function.h"
#include "ggc.h"
+#include "stdio.h"
+#include "target.h"
+
+/* DOS brain-damage */
+#ifndef O_BINARY
+#define O_BINARY 0 /* MS-DOS brain-damage */
+#endif
+
+static tree make_method_value (tree);
+static tree build_java_method_type (tree, tree, int);
+static int32 hashUtf8String (const char *, int);
+static tree make_field_value (tree);
+static tree get_dispatch_vector (tree);
+static tree get_dispatch_table (tree, tree);
+static int supers_all_compiled (tree type);
+static 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 make_method_value PARAMS ((tree));
-static tree build_java_method_type PARAMS ((tree, tree, int));
-static int32 hashUtf8String PARAMS ((const char *, int));
-static tree make_field_value PARAMS ((tree));
-static tree get_dispatch_vector PARAMS ((tree));
-static tree get_dispatch_table PARAMS ((tree, tree));
-static void add_interface_do PARAMS ((tree, tree, int));
-static tree maybe_layout_super_class PARAMS ((tree, tree));
-static int assume_compiled PARAMS ((const char *));
-static struct hash_entry *init_test_hash_newfunc PARAMS ((struct hash_entry *,
- struct hash_table *,
- hash_table_key));
-static rtx registerClass_libfunc;
-
-extern struct obstack permanent_obstack;
struct obstack temporary_obstack;
/* The compiler generates different code depending on whether or not
/* The class or package name. */
const char *ident;
- /* Non-zero if this represents an exclusion. */
+ /* Nonzero if this represents an exclusion. */
int excludep;
/* Pointers to other nodes in the tree. */
struct assume_compiled_node_struct *child;
} assume_compiled_node;
-static assume_compiled_node *find_assume_compiled_node
- PARAMS ((assume_compiled_node *, const char *));
+static assume_compiled_node *find_assume_compiled_node (assume_compiled_node *,
+ const char *);
/* This is the root of the include/exclude tree. */
static assume_compiled_node *assume_compiled_tree;
-static tree class_roots[5]
-= { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
+static GTY(()) tree class_roots[5];
#define registered_class class_roots[0]
#define fields_ident class_roots[1] /* get_identifier ("fields") */
#define info_ident class_roots[2] /* get_identifier ("info") */
appropriate node does not exist. */
static assume_compiled_node *
-find_assume_compiled_node (node, ident)
- assume_compiled_node *node;
- const char *ident;
+find_assume_compiled_node (assume_compiled_node *node, const char *ident)
{
while (node)
{
}
/* Add a new IDENT to the include/exclude tree. It's an exclusion
- if EXCLUDEP is non-zero. */
+ if EXCLUDEP is nonzero. */
void
-add_assume_compiled (ident, excludep)
- const char *ident;
- int excludep;
+add_assume_compiled (const char *ident, int excludep)
{
+ int len;
assume_compiled_node *parent;
- assume_compiled_node *node =
- (assume_compiled_node *) xmalloc (sizeof (assume_compiled_node));
+ assume_compiled_node *node = xmalloc (sizeof (assume_compiled_node));
node->ident = xstrdup (ident);
node->excludep = excludep;
if (NULL == assume_compiled_tree)
{
- assume_compiled_tree =
- (assume_compiled_node *) xmalloc (sizeof (assume_compiled_node));
+ assume_compiled_tree = xmalloc (sizeof (assume_compiled_node));
assume_compiled_tree->ident = "";
assume_compiled_tree->excludep = 0;
assume_compiled_tree->sibling = NULL;
class or a package name. Adjust PARENT accordingly. */
parent = find_assume_compiled_node (assume_compiled_tree, ident);
- if (ident[strlen (parent->ident)] != '.')
+ len = strlen (parent->ident);
+ if (parent->ident[len] && parent->ident[len] != '.')
parent = parent->parent;
/* Insert NODE into the tree. */
parent->child = node;
}
-/* Returns non-zero if IDENT is the name of a class that the compiler
- should assume has been compiled to FIXME */
+/* Returns nonzero if IDENT is the name of a class that the compiler
+ should assume has been compiled to object code. */
static int
-assume_compiled (ident)
- const char *ident;
+assume_compiled (const char *ident)
{
assume_compiled_node *i;
int result;
Also, PREFIX is prepended, and SUFFIX is appended. */
tree
-ident_subst (old_name, old_length, prefix, old_char, new_char, suffix)
- const char* old_name;
- int old_length;
- const char *prefix;
- int old_char;
- int new_char;
- const char *suffix;
+ident_subst (const char* old_name,
+ int old_length,
+ const char *prefix,
+ int old_char,
+ int new_char,
+ const char *suffix)
{
int prefix_len = strlen (prefix);
int suffix_len = strlen (suffix);
#ifdef __GNUC__
char buffer[i];
#else
- char *buffer = (char *)alloca (i);
+ char *buffer = alloca (i);
#endif
strcpy (buffer, prefix);
for (i = 0; i < old_length; i++)
Also, PREFIX is prepended, and SUFFIX is appended. */
tree
-identifier_subst (old_id, prefix, old_char, new_char, suffix)
- const tree old_id;
- const char *prefix;
- int old_char;
- int new_char;
- const char *suffix;
+identifier_subst (const tree old_id,
+ const char *prefix,
+ int old_char,
+ int new_char,
+ const char *suffix)
{
return ident_subst (IDENTIFIER_POINTER (old_id), IDENTIFIER_LENGTH (old_id),
prefix, old_char, new_char, suffix);
prefixed by PREFIX. */
tree
-mangled_classname (prefix, type)
- const char *prefix;
- tree type;
+mangled_classname (const char *prefix, tree type)
{
tree ident = TYPE_NAME (type);
if (TREE_CODE (ident) != IDENTIFIER_NODE)
}
tree
-make_class ()
+make_class (void)
{
tree type;
type = make_node (RECORD_TYPE);
-#ifdef JAVA_USE_HANDLES
- tree field1 = build_decl (FIELD_DECL, get_identifier ("obj"),
- build_pointer_type (type));
- tree field2 = build_decl (FIELD_DECL, get_identifier ("methods"),
- methodtable_ptr_type);
- tree handle_type = make_node (RECORD_TYPE);
- TREE_CHAIN (field1) = field2;
- TYPE_FIELDS (handle_type) = field1;
- TYPE_BINFO (type) = make_tree_vec (7);
- TYPE_BINFO (handle_type) = make_tree_vec (7);
- BINFO_HANDLE (TYPE_BINFO (handle_type)) = type;
- BINFO_HANDLE (TYPE_BINFO (type)) = handle_type;
-#else
- TYPE_BINFO (type) = make_tree_vec (6);
-#endif
+ TYPE_BINFO (type) = make_tree_vec (BINFO_ELTS);
MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type);
return type;
return a corresponding IDENTIFIER_NODE, except using '.' as separator. */
tree
-unmangle_classname (name, name_length)
- const char *name; int name_length;
+unmangle_classname (const char *name, int name_length)
{
tree to_return = ident_subst (name, name_length, "", '/', '.', "");
/* It's not sufficient to compare to_return and get_identifier
}
tree
-push_class (class_type, class_name)
- tree class_type, class_name;
+push_class (tree class_type, tree class_name)
{
tree decl, signature;
- const char *save_input_filename = input_filename;
- int save_lineno = lineno;
+ 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);
- lineno = 0;
+ input_line = 0;
decl = build_decl (TYPE_DECL, class_name, class_type);
- input_filename = save_input_filename;
- lineno = save_lineno;
+
+ /* dbxout needs a DECL_SIZE if in gstabs mode */
+ DECL_SIZE (decl) = integer_zero_node;
+
+ input_location = saved_loc;
signature = identifier_subst (class_name, "L", '.', '/', ";");
IDENTIFIER_SIGNATURE_TYPE (signature) = build_pointer_type (class_type);
- /* Setting DECL_ARTIFICAL forces dbxout.c to specific the type is
+ /* Setting DECL_ARTIFICIAL forces dbxout.c to specific the type is
both a typedef and in the struct name-space. We may want to re-visit
this later, but for now it reduces the changes needed for gdb. */
DECL_ARTIFICIAL (decl) = 1;
pushdecl_top_level (decl);
-#ifdef JAVA_USE_HANDLES
- {
- tree handle_name = identifier_subst (class_name,
- "Handle$", '.', '.', "");
- tree handle_decl = build_decl (TYPE_DECL, handle_name,
- CLASS_TO_HANDLE_TYPE (class_type));
- pushdecl (handle_decl);
- }
-#endif
return decl;
}
fill in field or methods, or do layout_type. */
tree
-lookup_class (name)
- tree name;
+lookup_class (tree name)
{
tree decl = IDENTIFIER_CLASS_VALUE (name);
if (decl == NULL_TREE)
}
void
-set_super_info (access_flags, this_class, super_class, interfaces_count)
- int access_flags;
- tree this_class;
- tree super_class;
- int interfaces_count;
+set_super_info (int access_flags, tree this_class,
+ tree super_class, int interfaces_count)
{
int total_supers = interfaces_count;
tree class_decl = TYPE_NAME (this_class);
TYPE_BINFO_BASETYPES (this_class) = make_tree_vec (total_supers);
if (super_class)
{
- tree super_binfo = make_tree_vec (6);
+ tree super_binfo = make_tree_vec (BINFO_ELTS);
BINFO_TYPE (super_binfo) = super_class;
BINFO_OFFSET (super_binfo) = integer_zero_node;
- TREE_VIA_PUBLIC (super_binfo) = 1;
TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (this_class)), 0)
= super_binfo;
CLASS_HAS_SUPER (this_class) = 1;
}
+ set_class_decl_access_flags (access_flags, class_decl);
+}
+
+void
+set_class_decl_access_flags (int access_flags, tree class_decl)
+{
if (access_flags & ACC_PUBLIC) CLASS_PUBLIC (class_decl) = 1;
if (access_flags & ACC_FINAL) CLASS_FINAL (class_decl) = 1;
if (access_flags & ACC_SUPER) CLASS_SUPER (class_decl) = 1;
if (access_flags & ACC_STATIC) CLASS_STATIC (class_decl) = 1;
if (access_flags & ACC_PRIVATE) CLASS_PRIVATE (class_decl) = 1;
if (access_flags & ACC_PROTECTED) CLASS_PROTECTED (class_decl) = 1;
+ if (access_flags & ACC_STRICT) CLASS_STRICTFP (class_decl) = 1;
}
/* Return length of inheritance chain of CLAS, where java.lang.Object is 0,
direct sub-classes of Object are 1, and so on. */
int
-class_depth (clas)
- tree clas;
+class_depth (tree clas)
{
int depth = 0;
if (! CLASS_LOADED_P (clas))
/* Return true iff TYPE2 is an interface that extends interface TYPE1 */
int
-interface_of_p (type1, type2)
- tree type1, type2;
+interface_of_p (tree type1, tree type2)
{
int n, i;
tree basetype_vec;
/* Return true iff TYPE1 inherits from TYPE2. */
int
-inherits_from_p (type1, type2)
- tree type1, type2;
+inherits_from_p (tree type1, tree type2)
{
while (type1 != NULL_TREE && TREE_CODE (type1) == RECORD_TYPE)
{
/* Return a 1 iff TYPE1 is an enclosing context for TYPE2 */
int
-enclosing_context_p (type1, type2)
- tree type1, type2;
+enclosing_context_p (tree type1, tree type2)
{
if (!INNER_CLASS_TYPE_P (type2))
return 0;
/* Return 1 iff there exists a common enclosing context between TYPE1
and TYPE2. */
-int common_enclosing_context_p (type1, type2)
- tree type1, type2;
+int common_enclosing_context_p (tree type1, tree type2)
{
if (!PURE_INNER_CLASS_TYPE_P (type1) || !PURE_INNER_CLASS_TYPE_P (type2))
return 0;
}
static void
-add_interface_do (basetype_vec, interface_class, i)
- tree basetype_vec, interface_class;
- int i;
+add_interface_do (tree basetype_vec, tree interface_class, int i)
{
- tree interface_binfo = make_tree_vec (6);
+ 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_VIA_PUBLIC (interface_binfo) = 1;
TREE_VEC_ELT (basetype_vec, i) = interface_binfo;
}
if attempt is made to add it twice. */
tree
-maybe_add_interface (this_class, interface_class)
- tree this_class, interface_class;
+maybe_add_interface (tree this_class, tree interface_class)
{
tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
int i;
/* Add the INTERFACE_CLASS as one of the interfaces of THIS_CLASS. */
void
-add_interface (this_class, interface_class)
- tree this_class, interface_class;
+add_interface (tree this_class, tree interface_class)
{
tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
int i;
in the list (*LIST) whose DECL_NAME is NAME. */
static tree *
-find_named_method (list, name)
- tree *list;
- tree name;
+find_named_method (tree *list, tree name)
{
while (*list && DECL_NAME (*list) != name)
list = &TREE_CHAIN (*list);
#endif
static tree
-build_java_method_type (fntype, this_class, access_flags)
- tree fntype;
- tree this_class;
- int access_flags;
+build_java_method_type (tree fntype, tree this_class, int access_flags)
{
if (access_flags & ACC_STATIC)
return fntype;
- return build_method_type (CLASS_TO_HANDLE_TYPE (this_class), fntype);
-}
-
-static struct hash_entry *
-init_test_hash_newfunc (entry, table, string)
- struct hash_entry *entry;
- struct hash_table *table;
- hash_table_key string ATTRIBUTE_UNUSED;
-{
- struct init_test_hash_entry *ret = (struct init_test_hash_entry *) entry;
- if (ret == NULL)
- {
- ret = ((struct init_test_hash_entry *)
- hash_allocate (table, sizeof (struct init_test_hash_entry)));
- if (ret == NULL)
- return NULL;
- }
- ret->init_test_decl = 0;
- return (struct hash_entry *) ret;
-}
-
-/* Hash table helpers. Also reused in find_applicable_accessible_methods_list
- (parse.y). The hash of a tree node is it's pointer value,
- comparison is direct. */
-
-unsigned long
-java_hash_hash_tree_node (k)
- hash_table_key k;
-{
- return (long) k;
-}
-
-bool
-java_hash_compare_tree_node (k1, k2)
- hash_table_key k1;
- hash_table_key k2;
-{
- return ((char*) k1 == (char*) k2);
+ return build_method_type (this_class, fntype);
}
tree
-add_method_1 (handle_class, access_flags, name, function_type)
- tree handle_class;
- int access_flags;
- tree name;
- tree function_type;
+add_method_1 (tree this_class, int access_flags, tree name, tree function_type)
{
tree method_type, fndecl;
method_type = build_java_method_type (function_type,
- handle_class, access_flags);
+ this_class, access_flags);
fndecl = build_decl (FUNCTION_DECL, name, method_type);
- DECL_CONTEXT (fndecl) = handle_class;
+ DECL_CONTEXT (fndecl) = this_class;
DECL_LANG_SPECIFIC (fndecl)
- = (struct lang_decl *) ggc_alloc_cleared (sizeof (struct lang_decl));
+ = ggc_alloc_cleared (sizeof (struct lang_decl));
+ DECL_LANG_SPECIFIC (fndecl)->desc = LANG_DECL_FUNC;
/* Initialize the static initializer test table. */
- hash_table_init (&DECL_FUNCTION_INIT_TEST_TABLE (fndecl),
- init_test_hash_newfunc, java_hash_hash_tree_node,
- java_hash_compare_tree_node);
+
+ DECL_FUNCTION_INIT_TEST_TABLE (fndecl) =
+ java_treetreehash_create (10, 1);
+
+ /* Initialize the initialized (static) class table. */
+ if (access_flags & ACC_STATIC)
+ DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl) =
+ htab_create_ggc (50, htab_hash_pointer, htab_eq_pointer, NULL);
- TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class);
- TYPE_METHODS (handle_class) = fndecl;
+ /* 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;
+
+ /* Notice that this is a finalizer and update the class type
+ accordingly. This is used to optimize instance allocation. */
+ if (name == finalize_identifier_node
+ && TREE_TYPE (function_type) == void_type_node
+ && TREE_VALUE (TYPE_ARG_TYPES (function_type)) == void_type_node)
+ HAS_FINALIZER_P (this_class) = 1;
if (access_flags & ACC_PUBLIC) METHOD_PUBLIC (fndecl) = 1;
if (access_flags & ACC_PROTECTED) METHOD_PROTECTED (fndecl) = 1;
METHOD_FINAL (fndecl) = DECL_INLINE (fndecl) = 1;
if (access_flags & ACC_SYNCHRONIZED) METHOD_SYNCHRONIZED (fndecl) = 1;
if (access_flags & ACC_ABSTRACT) METHOD_ABSTRACT (fndecl) = 1;
- if (access_flags & ACC_TRANSIENT) METHOD_TRANSIENT (fndecl) = 1;
+ if (access_flags & ACC_STRICT) METHOD_STRICTFP (fndecl) = 1;
return fndecl;
}
Its signature (mangled type) is METHOD_SIG (an IDENTIFIER_NODE). */
tree
-add_method (this_class, access_flags, name, method_sig)
- tree this_class;
- int access_flags;
- tree name;
- tree method_sig;
+add_method (tree this_class, int access_flags, tree name, tree method_sig)
{
- tree handle_class = CLASS_TO_HANDLE_TYPE (this_class);
tree function_type, fndecl;
const unsigned char *sig
= (const unsigned char *) IDENTIFIER_POINTER (method_sig);
fatal_error ("bad method signature");
function_type = get_type_from_signature (method_sig);
- fndecl = add_method_1 (handle_class, access_flags, name, function_type);
+ fndecl = add_method_1 (this_class, access_flags, name, function_type);
set_java_signature (TREE_TYPE (fndecl), method_sig);
return fndecl;
}
tree
-add_field (class, name, field_type, flags)
- tree class;
- tree name;
- tree field_type;
- int flags;
+add_field (tree class, tree name, tree field_type, int flags)
{
int is_static = (flags & ACC_STATIC) != 0;
tree field;
/* Always make field externally visible. This is required so
that native methods can always access the field. */
TREE_PUBLIC (field) = 1;
+ /* Considered external until we know what classes are being
+ compiled into this object file. */
+ DECL_EXTERNAL (field) = 1;
}
+
return field;
}
/* Associate a constant value CONSTANT with VAR_DECL FIELD. */
void
-set_constant_value (field, constant)
- tree field, constant;
+set_constant_value (tree field, tree constant)
{
if (field == NULL_TREE)
warning ("misplaced ConstantValue attribute (not in any field)");
else if (DECL_INITIAL (field) != NULL_TREE)
- warning ("duplicate ConstanValue atribute for field '%s'",
+ warning ("duplicate ConstantValue attribute for field '%s'",
IDENTIFIER_POINTER (DECL_NAME (field)));
else
{
DECL_INITIAL (field) = constant;
+ if (TREE_TYPE (constant) != TREE_TYPE (field)
+ && ! (TREE_TYPE (constant) == int_type_node
+ && INTEGRAL_TYPE_P (TREE_TYPE (field))
+ && TYPE_PRECISION (TREE_TYPE (field)) <= 32)
+ && ! (TREE_TYPE (constant) == utf8const_ptr_type
+ && TREE_TYPE (field) == string_ptr_type_node))
+ error ("ConstantValue attribute of field '%s' has wrong type",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
if (FIELD_FINAL (field))
DECL_FIELD_FINAL_IUD (field) = 1;
}
#if 0
int
-strLengthUtf8 (str, len)
- char *str;
- int len;
+strLengthUtf8 (char *str, int len)
{
register unsigned char* ptr = (unsigned char*) str;
register unsigned char *limit = ptr + len;
*/
static int32
-hashUtf8String (str, len)
- const char *str;
- int len;
+hashUtf8String (const char *str, int len)
{
register const unsigned char* ptr = (const unsigned char*) str;
register const unsigned char *limit = ptr + len;
return hash;
}
-tree utf8_decl_list = NULL_TREE;
+static GTY(()) tree utf8_decl_list = NULL_TREE;
tree
-build_utf8_ref (name)
- tree name;
+build_utf8_ref (tree name)
{
const char * name_ptr = IDENTIFIER_POINTER(name);
int name_len = IDENTIFIER_LENGTH(name);
char buf[60];
- char *buf_ptr;
tree ctype, field = NULL_TREE, str_type, cinit, string;
static int utf8_count = 0;
int name_hash;
FINISH_RECORD_CONSTRUCTOR (cinit);
TREE_CONSTANT (cinit) = 1;
- /* Build a unique identifier based on buf. */
+ /* Generate a unique-enough identifier. */
sprintf(buf, "_Utf%d", ++utf8_count);
- buf_ptr = &buf[strlen (buf)];
- if (name_len > 0 && name_ptr[0] >= '0' && name_ptr[0] <= '9')
- *buf_ptr++ = '_';
- while (--name_len >= 0)
- {
- unsigned char c = *name_ptr++;
- if (c & 0x80)
- continue;
- if (!ISALPHA(c) && !ISDIGIT(c))
- c = '_';
- *buf_ptr++ = c;
- if (buf_ptr >= buf + 50)
- break;
- }
- *buf_ptr = '\0';
decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_type);
- /* FIXME get some way to force this into .text, not .data. */
TREE_STATIC (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 1;
TREE_READONLY (decl) = 1;
TREE_THIS_VOLATILE (decl) = 0;
DECL_INITIAL (decl) = cinit;
+
+ if (HAVE_GAS_SHF_MERGE)
+ {
+ int decl_size;
+ /* Ensure decl_size is a multiple of utf8const_type's alignment. */
+ decl_size = (name_len + 5 + TYPE_ALIGN_UNIT (utf8const_type) - 1)
+ & ~(TYPE_ALIGN_UNIT (utf8const_type) - 1);
+ if (flag_merge_constants && decl_size < 256)
+ {
+ char buf[32];
+ int flags = (SECTION_OVERRIDE
+ | SECTION_MERGE | (SECTION_ENTSIZE & decl_size));
+ sprintf (buf, ".rodata.jutf8.%d", decl_size);
+ named_section_flags (buf, flags);
+ DECL_SECTION_NAME (decl) = build_string (strlen (buf), buf);
+ }
+ }
+
TREE_CHAIN (decl) = utf8_decl_list;
layout_decl (decl, 0);
pushdecl (decl);
return ref;
}
+/* Like build_class_ref, but instead of a direct reference generate a
+ pointer into the constant pool. */
+
+static tree
+build_indirect_class_ref (tree type)
+{
+ int index;
+ tree cl;
+ index = alloc_class_constant (type);
+ cl = build_ref_from_constant_pool (index);
+ TREE_TYPE (cl) = promote_type (class_ptr_type);
+ return cl;
+}
+
/* Build a reference to the class TYPE.
Also handles primitive types and array types. */
tree
-build_class_ref (type)
- tree type;
+build_class_ref (tree type)
{
int is_compiled = is_compiled_class (type);
if (is_compiled)
tree ref, decl_name, decl;
if (TREE_CODE (type) == POINTER_TYPE)
type = TREE_TYPE (type);
+
+ if (flag_indirect_dispatch
+ && type != current_class
+ && TREE_CODE (type) == RECORD_TYPE)
+ return build_indirect_class_ref (type);
+
if (TREE_CODE (type) == RECORD_TYPE)
{
if (TYPE_SIZE (type) == error_mark_node)
TREE_PUBLIC (decl) = 1;
DECL_IGNORED_P (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
- DECL_ASSEMBLER_NAME (decl) =
- java_mangle_class_field (&temporary_obstack, type);
- make_decl_rtl (decl, NULL);
- pushdecl_top_level (decl);
if (is_compiled == 1)
DECL_EXTERNAL (decl) = 1;
+ SET_DECL_ASSEMBLER_NAME (decl,
+ java_mangle_class_field
+ (&temporary_obstack, type));
+ make_decl_rtl (decl, NULL);
+ pushdecl_top_level (decl);
}
}
else
decl = build_decl (VAR_DECL, decl_name, class_type_node);
TREE_STATIC (decl) = 1;
TREE_PUBLIC (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
make_decl_rtl (decl, NULL);
pushdecl_top_level (decl);
- if (is_compiled == 1)
- DECL_EXTERNAL (decl) = 1;
}
}
return ref;
}
else
- {
- int index;
- tree cl;
- index = alloc_class_constant (type);
- cl = build_ref_from_constant_pool (index);
- TREE_TYPE (cl) = promote_type (class_ptr_type);
- return cl;
- }
+ return build_indirect_class_ref (type);
}
tree
-build_static_field_ref (fdecl)
- tree fdecl;
+build_static_field_ref (tree fdecl)
{
tree fclass = DECL_CONTEXT (fdecl);
int is_compiled = is_compiled_class (fclass);
- if (is_compiled)
+
+ /* 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))
{
}
return fdecl;
}
- else
+
+ if (flag_indirect_dispatch)
+ {
+ tree table_index
+ = build_int_2 (get_symbol_table_index (fdecl, &atable_methods), 0);
+ tree field_address
+ = build (ARRAY_REF, build_pointer_type (TREE_TYPE (fdecl)),
+ atable_decl, table_index);
+ return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl),
+ field_address));
+ }
+ else
{
/* Compile as:
* *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */
}
int
-get_access_flags_from_decl (decl)
- tree decl;
+get_access_flags_from_decl (tree decl)
{
int access_flags = 0;
if (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL)
access_flags |= ACC_PRIVATE;
if (CLASS_PROTECTED (decl))
access_flags |= ACC_PROTECTED;
+ if (CLASS_STRICTFP (decl))
+ access_flags |= ACC_STRICT;
return access_flags;
}
if (TREE_CODE (decl) == FUNCTION_DECL)
access_flags |= ACC_NATIVE;
if (METHOD_ABSTRACT (decl))
access_flags |= ACC_ABSTRACT;
- if (METHOD_TRANSIENT (decl))
- access_flags |= ACC_TRANSIENT;
+ if (METHOD_STRICTFP (decl))
+ access_flags |= ACC_STRICT;
+ if (METHOD_INVISIBLE (decl))
+ access_flags |= ACC_INVISIBLE;
return access_flags;
}
abort ();
}
static tree
-make_field_value (fdecl)
- tree fdecl;
+make_field_value (tree fdecl)
{
tree finit;
int flags;
tree type = TREE_TYPE (fdecl);
- int resolved = is_compiled_class (type);
+ int resolved = is_compiled_class (type) && ! flag_indirect_dispatch;
START_RECORD_CONSTRUCTOR (finit, field_type_node);
PUSH_FIELD_VALUE (finit, "name", build_utf8_ref (DECL_NAME (fdecl)));
PUSH_FIELD_VALUE
(finit, "info",
- build (CONSTRUCTOR, field_info_union_node, NULL_TREE,
+ build_constructor (field_info_union_node,
build_tree_list
((FIELD_STATIC (fdecl)
? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
}
static tree
-make_method_value (mdecl)
- tree mdecl;
+make_method_value (tree mdecl)
{
+ static int method_name_count = 0;
tree minit;
+ tree index;
tree code;
#define ACC_TRANSLATED 0x4000
int accflags = get_access_flags_from_decl (mdecl) | ACC_TRANSLATED;
+
+ if (!flag_indirect_dispatch && DECL_VINDEX (mdecl) != NULL_TREE)
+ index = DECL_VINDEX (mdecl);
+ else
+ index = integer_minus_one_node;
+
code = null_pointer_node;
if (DECL_RTL_SET_P (mdecl))
code = build1 (ADDR_EXPR, nativecode_ptr_type_node, mdecl);
IDENTIFIER_LENGTH(signature)))));
}
PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0));
+ PUSH_FIELD_VALUE (minit, "index", index);
PUSH_FIELD_VALUE (minit, "ncode", code);
+
+ {
+ /* Compute the `throws' information for the method. */
+ tree table = null_pointer_node;
+ if (DECL_FUNCTION_THROWS (mdecl) != NULL_TREE)
+ {
+ int length = 1 + list_length (DECL_FUNCTION_THROWS (mdecl));
+ tree iter, type, array;
+ char buf[60];
+
+ table = tree_cons (NULL_TREE, table, NULL_TREE);
+ for (iter = DECL_FUNCTION_THROWS (mdecl);
+ iter != NULL_TREE;
+ iter = TREE_CHAIN (iter))
+ {
+ tree sig = DECL_NAME (TYPE_NAME (TREE_VALUE (iter)));
+ tree utf8
+ = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (sig),
+ IDENTIFIER_LENGTH (sig)));
+ table = tree_cons (NULL_TREE, utf8, table);
+ }
+ type = build_prim_array_type (ptr_type_node, length);
+ table = build_constructor (type, table);
+ /* Compute something unique enough. */
+ sprintf (buf, "_methods%d", method_name_count++);
+ array = build_decl (VAR_DECL, get_identifier (buf), type);
+ DECL_INITIAL (array) = table;
+ TREE_STATIC (array) = 1;
+ DECL_ARTIFICIAL (array) = 1;
+ DECL_IGNORED_P (array) = 1;
+ rest_of_decl_compilation (array, (char*) 0, 1, 0);
+
+ table = build1 (ADDR_EXPR, ptr_type_node, array);
+ }
+
+ PUSH_FIELD_VALUE (minit, "throws", table);
+ }
+
FINISH_RECORD_CONSTRUCTOR (minit);
return minit;
}
static tree
-get_dispatch_vector (type)
- tree type;
+get_dispatch_vector (tree type)
{
tree vtable = TYPE_VTABLE (type);
- if (vtable == NULL)
+
+ if (vtable == NULL_TREE)
{
HOST_WIDE_INT i;
tree method;
}
static tree
-get_dispatch_table (type, this_class_addr)
- tree type, this_class_addr;
+get_dispatch_table (tree type, tree this_class_addr)
{
int abstract_p = CLASS_ABSTRACT (TYPE_NAME (type));
tree vtable = get_dispatch_vector (type);
- int i;
+ int i, j;
tree list = NULL_TREE;
int nvirtuals = TREE_VEC_LENGTH (vtable);
+ int arraysize;
+ tree gc_descr;
+
for (i = nvirtuals; --i >= 0; )
{
tree method = TREE_VEC_ELT (vtable, i);
if (METHOD_ABSTRACT (method))
{
if (! abstract_p)
- warning_with_decl (method,
- "abstract method in non-abstract class");
- method = null_pointer_node;
+ warning ("%Jabstract method in non-abstract class", method);
+
+ if (TARGET_VTABLE_USES_DESCRIPTORS)
+ for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
+ list = tree_cons (NULL_TREE, null_pointer_node, list);
+ else
+ list = tree_cons (NULL_TREE, null_pointer_node, list);
}
else
{
if (!DECL_RTL_SET_P (method))
make_decl_rtl (method, NULL);
- method = build1 (ADDR_EXPR, nativecode_ptr_type_node, method);
+
+ if (TARGET_VTABLE_USES_DESCRIPTORS)
+ for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
+ {
+ tree fdesc = build (FDESC_EXPR, nativecode_ptr_type_node,
+ method, build_int_2 (j, 0));
+ TREE_CONSTANT (fdesc) = 1;
+ list = tree_cons (NULL_TREE, fdesc, list);
+ }
+ else
+ list = tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR, nativecode_ptr_type_node,
+ method),
+ list);
}
- list = tree_cons (NULL_TREE /*DECL_VINDEX (method) + 2*/,
- method, list);
}
+
/* Dummy entry for compatibility with G++ -fvtable-thunks. When
using the Boehm GC we sometimes stash a GC type descriptor
there. We set the PURPOSE to NULL_TREE not to interfere (reset)
the emitted byte count during the output to the assembly file. */
- list = tree_cons (NULL_TREE, get_boehm_type_descriptor (type),
- list);
- list = tree_cons (integer_zero_node, this_class_addr, list);
- return build (CONSTRUCTOR, build_prim_array_type (nativecode_ptr_type_node,
- nvirtuals + 2),
- NULL_TREE, list);
+ /* With TARGET_VTABLE_USES_DESCRIPTORS, we only add one extra
+ fake "function descriptor". It's first word is the is the class
+ pointer, and subsequent words (usually one) contain the GC descriptor.
+ In all other cases, we reserve two extra vtable slots. */
+ gc_descr = get_boehm_type_descriptor (type);
+ list = tree_cons (NULL_TREE, gc_descr, list);
+ for (j = 1; j < TARGET_VTABLE_USES_DESCRIPTORS-1; ++j)
+ list = tree_cons (NULL_TREE, gc_descr, list);
+ list = tree_cons (NULL_TREE, this_class_addr, list);
+
+ /** Pointer to type_info object (to be implemented), according to g++ ABI. */
+ list = tree_cons (NULL_TREE, null_pointer_node, list);
+ /** Offset to start of whole object. Always (ptrdiff_t)0 for Java. */
+ list = tree_cons (integer_zero_node, null_pointer_node, list);
+
+ arraysize = (TARGET_VTABLE_USES_DESCRIPTORS? nvirtuals + 1 : nvirtuals + 2);
+ if (TARGET_VTABLE_USES_DESCRIPTORS)
+ arraysize *= TARGET_VTABLE_USES_DESCRIPTORS;
+ arraysize += 2;
+ return build_constructor (build_prim_array_type (nativecode_ptr_type_node,
+ arraysize), list);
+}
+
+static int
+supers_all_compiled (tree type)
+{
+ while (type != NULL_TREE)
+ {
+ if (!assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))))
+ return 0;
+ type = CLASSTYPE_SUPER (type);
+ }
+ return 1;
}
void
-make_class_data (type)
- tree type;
+make_class_data (tree type)
{
tree decl, cons, temp;
tree field, fields_decl;
tree interfaces = null_pointer_node;
int interface_len = 0;
tree type_decl = TYPE_NAME (type);
+ /** Offset from start of virtual function table declaration
+ to where objects actually point at, following new g++ ABI. */
+ tree dtable_start_offset = build_int_2 (2 * POINTER_SIZE / BITS_PER_UNIT, 0);
this_class_addr = build_class_ref (type);
decl = TREE_OPERAND (this_class_addr, 0);
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,
- NULL_TREE, static_fields);
+ DECL_INITIAL (fields_decl) = build_constructor (field_array_type,
+ static_fields);
TREE_STATIC (fields_decl) = 1;
DECL_ARTIFICIAL (fields_decl) = 1;
DECL_IGNORED_P (fields_decl) = 1;
fields_decl = NULL_TREE;
/* Build Method array. */
- for (method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (type));
+ for (method = TYPE_METHODS (type);
method != NULL_TREE; method = TREE_CHAIN (method))
{
tree init;
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,
- NULL_TREE, nreverse (methods));
+ DECL_INITIAL (methods_decl) = build_constructor (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 (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
- && ! CLASS_INTERFACE (type_decl))
+ 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);
super = CLASSTYPE_SUPER (type);
if (super == NULL_TREE)
super = null_pointer_node;
- else if (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
{
}
init = tree_cons (NULL_TREE, index, init);
}
- DECL_INITIAL (idecl) = build (CONSTRUCTOR, interface_array_type,
- NULL_TREE, init);
+ DECL_INITIAL (idecl) = build_constructor (interface_array_type, init);
TREE_STATIC (idecl) = 1;
DECL_ARTIFICIAL (idecl) = 1;
DECL_IGNORED_P (idecl) = 1;
START_RECORD_CONSTRUCTOR (temp, object_type_node);
PUSH_FIELD_VALUE (temp, "vtable",
- build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl));
+ build (PLUS_EXPR, dtable_ptr_type,
+ build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl),
+ dtable_start_offset));
if (! flag_hash_synchronization)
PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node);
FINISH_RECORD_CONSTRUCTOR (temp);
PUSH_FIELD_VALUE (cons, "methods",
build1 (ADDR_EXPR, method_ptr_type_node, methods_decl));
PUSH_FIELD_VALUE (cons, "method_count", build_int_2 (method_count, 0));
- PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
+
+ if (flag_indirect_dispatch)
+ PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node);
+ else
+ PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
+
PUSH_FIELD_VALUE (cons, "fields",
fields_decl == NULL_TREE ? null_pointer_node
: build1 (ADDR_EXPR, field_ptr_type_node, fields_decl));
PUSH_FIELD_VALUE (cons, "field_count", build_int_2 (field_count, 0));
PUSH_FIELD_VALUE (cons, "static_field_count",
build_int_2 (static_field_count, 0));
- PUSH_FIELD_VALUE (cons, "vtable",
- dtable_decl == NULL_TREE ? null_pointer_node
- : build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl));
+
+ if (flag_indirect_dispatch)
+ PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node);
+ else
+ PUSH_FIELD_VALUE (cons, "vtable",
+ dtable_decl == NULL_TREE ? null_pointer_node
+ : build (PLUS_EXPR, dtable_ptr_type,
+ build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl),
+ dtable_start_offset));
+ if (otable_methods == NULL_TREE)
+ {
+ PUSH_FIELD_VALUE (cons, "otable", null_pointer_node);
+ PUSH_FIELD_VALUE (cons, "otable_syms", null_pointer_node);
+ }
+ else
+ {
+ PUSH_FIELD_VALUE (cons, "otable",
+ build1 (ADDR_EXPR, otable_ptr_type, otable_decl));
+ PUSH_FIELD_VALUE (cons, "otable_syms",
+ build1 (ADDR_EXPR, symbols_array_ptr_type,
+ otable_syms_decl));
+ TREE_CONSTANT (otable_decl) = 1;
+ }
+ if (atable_methods == NULL_TREE)
+ {
+ PUSH_FIELD_VALUE (cons, "atable", null_pointer_node);
+ PUSH_FIELD_VALUE (cons, "atable_syms", null_pointer_node);
+ }
+ else
+ {
+ PUSH_FIELD_VALUE (cons, "atable",
+ build1 (ADDR_EXPR, atable_ptr_type, atable_decl));
+ PUSH_FIELD_VALUE (cons, "atable_syms",
+ build1 (ADDR_EXPR, symbols_array_ptr_type,
+ atable_syms_decl));
+ TREE_CONSTANT (atable_decl) = 1;
+ }
+
+ PUSH_FIELD_VALUE (cons, "catch_classes",
+ build1 (ADDR_EXPR, ptr_type_node, ctable_decl));
PUSH_FIELD_VALUE (cons, "interfaces", interfaces);
PUSH_FIELD_VALUE (cons, "loader", null_pointer_node);
PUSH_FIELD_VALUE (cons, "interface_count", build_int_2 (interface_len, 0));
PUSH_FIELD_VALUE (cons, "ancestors", null_pointer_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);
+ PUSH_FIELD_VALUE (cons, "signers", null_pointer_node);
+ PUSH_FIELD_VALUE (cons, "chain", null_pointer_node);
FINISH_RECORD_CONSTRUCTOR (cons);
DECL_INITIAL (decl) = cons;
+
+ /* Hash synchronization requires at least 64-bit alignment. */
+ if (flag_hash_synchronization && POINTER_SIZE < 64)
+ DECL_ALIGN (decl) = 64;
+
rest_of_decl_compilation (decl, (char*) 0, 1, 0);
}
void
-finish_class ()
+finish_class (void)
{
tree method;
- tree type_methods = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class));
+ tree type_methods = TYPE_METHODS (current_class);
int saw_native_method = 0;
/* Find out if we have any native methods. We use this information
{
if (! TREE_ASM_WRITTEN (method) && DECL_SAVED_INSNS (method) != 0)
{
- /* It's a deferred inline method. Decide if we need to emit it. */
- if (flag_keep_inline_functions
- || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (method))
- || ! METHOD_PRIVATE (method)
- || saw_native_method)
- {
- output_inline_function (method);
- /* Scan the list again to see if there are any earlier
- methods to emit. */
- method = type_methods;
- continue;
- }
+ output_inline_function (method);
+ /* Scan the list again to see if there are any earlier
+ methods to emit. */
+ method = type_methods;
+ continue;
}
method = TREE_CHAIN (method);
}
return 0 if we cannot assume that CLASS is compiled.
Returns 1 for primitive and 0 for array types. */
int
-is_compiled_class (class)
- tree class;
+is_compiled_class (tree class)
{
int seen_in_zip;
if (TREE_CODE (class) == POINTER_TYPE)
return 2;
seen_in_zip = (TYPE_JCF (class) && JCF_SEEN_IN_ZIP (TYPE_JCF (class)));
- if (CLASS_FROM_CURRENTLY_COMPILED_SOURCE_P (class) || seen_in_zip)
+ if (CLASS_FROM_CURRENTLY_COMPILED_P (class) || seen_in_zip)
{
/* The class was seen in the current ZIP file and will be
available as a compiled class in the future but may not have
/* Build a VAR_DECL for the dispatch table (vtable) for class TYPE. */
tree
-build_dtable_decl (type)
- tree type;
+build_dtable_decl (tree type)
{
tree dtype;
/* We need to build a new dtable type so that its size is uniquely
computed when we're dealing with the class for real and not just
faking it (like java.lang.Class during the initialization of the
- compiler.) We now we're not faking a class when CURRENT_CLASS is
+ compiler.) We know we're not faking a class when CURRENT_CLASS is
TYPE. */
if (current_class == type)
{
- tree dummy = NULL_TREE, aomt, n;
+ tree dummy = NULL_TREE;
+ int n;
dtype = make_node (RECORD_TYPE);
+
+ PUSH_FIELD (dtype, dummy, "top_offset", ptr_type_node);
+ PUSH_FIELD (dtype, dummy, "type_info", ptr_type_node);
+
PUSH_FIELD (dtype, dummy, "class", class_ptr_type);
- n = build_int_2 (TREE_VEC_LENGTH (get_dispatch_vector (type)), 0);
- aomt = build_array_type (ptr_type_node, build_index_type (n));
- PUSH_FIELD (dtype, dummy, "methods", aomt);
+ for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n)
+ {
+ tree tmp_field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node);
+ TREE_CHAIN (dummy) = tmp_field;
+ DECL_CONTEXT (tmp_field) = dtype;
+ DECL_ARTIFICIAL (tmp_field) = 1;
+ dummy = tmp_field;
+ }
+
+ PUSH_FIELD (dtype, dummy, "gc_descr", ptr_type_node);
+ for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n)
+ {
+ tree tmp_field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node);
+ TREE_CHAIN (dummy) = tmp_field;
+ DECL_CONTEXT (tmp_field) = dtype;
+ DECL_ARTIFICIAL (tmp_field) = 1;
+ dummy = tmp_field;
+ }
+
+ n = TREE_VEC_LENGTH (get_dispatch_vector (type));
+ if (TARGET_VTABLE_USES_DESCRIPTORS)
+ n *= TARGET_VTABLE_USES_DESCRIPTORS;
+
+ PUSH_FIELD (dtype, dummy, "methods",
+ build_prim_array_type (nativecode_ptr_type_node, n));
layout_type (dtype);
}
else
fields inherited from SUPER_CLASS. */
void
-push_super_field (this_class, super_class)
- tree this_class, super_class;
+push_super_field (tree this_class, tree super_class)
{
tree base_decl;
/* Don't insert the field if we're just re-laying the class out. */
/* Handle the different manners we may have to lay out a super class. */
static tree
-maybe_layout_super_class (super_class, this_class)
- tree super_class;
- tree this_class;
+maybe_layout_super_class (tree super_class, tree this_class)
{
if (TREE_CODE (super_class) == RECORD_TYPE)
{
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_class);
+ 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);
}
void
-layout_class (this_class)
- tree this_class;
+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 buffer [1024];
char *report;
tree current;
-
+
sprintf (buffer, " with `%s'",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))));
obstack_grow (&temporary_obstack, buffer, strlen (buffer));
return;
}
if (TYPE_SIZE (this_class) == NULL_TREE)
- push_super_field (this_class, super_class);
+ push_super_field (this_class, maybe_super_class);
}
for (field = TYPE_FIELDS (this_class);
if (FIELD_STATIC (field))
{
/* Set DECL_ASSEMBLER_NAME to something suitably mangled. */
- DECL_ASSEMBLER_NAME (field) =
- java_mangle_decl (&temporary_obstack, field);
+ 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. */
+ /* Also recursively load/layout any superinterfaces, but only if
+ class was loaded from bytecode. The source parser will take care
+ of this itself. */
if (!CLASS_FROM_SOURCE_P (this_class))
{
tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
}
}
- /* Convert the size back to an SI integer value */
- TYPE_SIZE_UNIT (this_class) =
+ /* Convert the size back to an SI integer value. */
+ TYPE_SIZE_UNIT (this_class) =
fold (convert (int_type_node, TYPE_SIZE_UNIT (this_class)));
CLASS_BEING_LAIDOUT (this_class) = 0;
class_list = TREE_CHAIN (class_list);
}
+static void
+add_miranda_methods (tree base_class, tree search_class)
+{
+ tree basetype_vec = TYPE_BINFO_BASETYPES (search_class);
+ int i, n = TREE_VEC_LENGTH (basetype_vec);
+ for (i = 1; i < n; ++i)
+ {
+ tree method_decl;
+ tree elt = TREE_VEC_ELT (basetype_vec, i);
+ if (elt == NULL_TREE)
+ break;
+ elt = BINFO_TYPE (elt);
+
+ /* Ensure that interface methods are seen in declared order. */
+ layout_class_methods (elt);
+
+ /* All base classes will have been laid out at this point, so the order
+ will be correct. This code must match similar layout code in the
+ runtime. */
+ for (method_decl = TYPE_METHODS (elt);
+ method_decl; method_decl = TREE_CHAIN (method_decl))
+ {
+ tree sig, override;
+
+ /* An interface can have <clinit>. */
+ if (ID_CLINIT_P (DECL_NAME (method_decl)))
+ continue;
+
+ sig = build_java_argument_signature (TREE_TYPE (method_decl));
+ override = lookup_argument_method (base_class,
+ DECL_NAME (method_decl), sig);
+ if (override == NULL_TREE)
+ {
+ /* Found a Miranda method. Add it. */
+ tree new_method;
+ sig = build_java_signature (TREE_TYPE (method_decl));
+ new_method
+ = add_method (base_class,
+ get_access_flags_from_decl (method_decl),
+ DECL_NAME (method_decl), sig);
+ METHOD_INVISIBLE (new_method) = 1;
+ }
+ }
+
+ /* Try superinterfaces. */
+ add_miranda_methods (base_class, elt);
+ }
+}
+
void
-layout_class_methods (this_class)
- tree this_class;
+layout_class_methods (tree this_class)
{
tree method_decl, dtable_count;
- tree super_class, handle_type;
+ tree super_class;
if (TYPE_NVIRTUALS (this_class))
return;
super_class = CLASSTYPE_SUPER (this_class);
- handle_type = CLASS_TO_HANDLE_TYPE (this_class);
if (super_class)
{
else
dtable_count = integer_zero_node;
- TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type));
+ if (CLASS_ABSTRACT (TYPE_NAME (this_class)))
+ {
+ /* An abstract class can have methods which are declared only in
+ an implemented interface. These are called "Miranda
+ methods". We make a dummy method entry for such methods
+ here. */
+ add_miranda_methods (this_class, this_class);
+ }
+
+ TYPE_METHODS (this_class) = nreverse (TYPE_METHODS (this_class));
- for (method_decl = TYPE_METHODS (handle_type);
+ for (method_decl = TYPE_METHODS (this_class);
method_decl; method_decl = TREE_CHAIN (method_decl))
- dtable_count = layout_class_method (this_class, super_class,
+ dtable_count = layout_class_method (this_class, super_class,
method_decl, dtable_count);
TYPE_NVIRTUALS (this_class) = dtable_count;
-
-#ifdef JAVA_USE_HANDLES
- layout_type (handle_type);
-#endif
}
-/* Return 0 if NAME is equal to STR, -1 if STR is "less" than NAME,
- and 1 if STR is "greater" than NAME. */
-
/* Lay METHOD_DECL out, returning a possibly new value of
DTABLE_COUNT. Also mangle the method's name. */
tree
-layout_class_method (this_class, super_class, method_decl, dtable_count)
- tree this_class, super_class, method_decl, dtable_count;
+layout_class_method (tree this_class, tree super_class,
+ tree method_decl, tree dtable_count)
{
tree method_name = DECL_NAME (method_decl);
TREE_PUBLIC (method_decl) = 1;
+ /* 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 */
- DECL_ASSEMBLER_NAME (method_decl) =
- java_mangle_decl (&temporary_obstack, method_decl);
+ 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)
}
else if (! METHOD_STATIC (method_decl) && !DECL_ARTIFICIAL (method_decl))
{
- tree method_sig =
+ tree method_sig =
build_java_argument_signature (TREE_TYPE (method_decl));
tree super_method = lookup_argument_method (super_class, method_name,
method_sig);
DECL_VINDEX (method_decl) = DECL_VINDEX (super_method);
if (DECL_VINDEX (method_decl) == NULL_TREE
&& !CLASS_FROM_SOURCE_P (this_class))
- error_with_decl (method_decl,
- "non-static method '%s' overrides static method");
+ error ("%Jnon-static method '%D' overrides static method",
+ method_decl, method_decl);
}
else if (! METHOD_FINAL (method_decl)
&& ! METHOD_PRIVATE (method_decl)
}
void
-register_class ()
+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,
end = current;
}
-/* Generate a function that gets called at start-up (static contructor) time,
- which calls registerClass for all the compiled classes. */
+/* 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. */
void
-emit_register_classes ()
+emit_register_classes (void)
{
- extern tree get_file_function_name PARAMS ((int));
- tree init_name = get_file_function_name ('I');
- tree init_type = build_function_type (void_type_node, end_params_node);
- tree init_decl;
- tree t;
-
- init_decl = build_decl (FUNCTION_DECL, init_name, init_type);
- DECL_ASSEMBLER_NAME (init_decl) = init_name;
- TREE_STATIC (init_decl) = 1;
- current_function_decl = init_decl;
- DECL_RESULT (init_decl) = build_decl(RESULT_DECL, NULL_TREE, void_type_node);
- /* DECL_EXTERNAL (init_decl) = 1;*/
- TREE_PUBLIC (init_decl) = 1;
- pushlevel (0);
- make_decl_rtl (init_decl, NULL);
- init_function_start (init_decl, input_filename, 0);
- expand_function_start (init_decl, 0);
-
- for ( t = registered_class; t; t = TREE_CHAIN (t))
- emit_library_call (registerClass_libfunc, 0, VOIDmode, 1,
- XEXP (DECL_RTL (t), 0), Pmode);
-
- expand_function_end (input_filename, 0, 0);
- poplevel (1, 0, 1);
- {
- /* Force generation, even with -O3 or deeper. Gross hack. FIXME */
- int saved_flag = flag_inline_functions;
- flag_inline_functions = 0;
- rest_of_compilation (init_decl);
- flag_inline_functions = saved_flag;
- }
- current_function_decl = NULL_TREE;
- assemble_constructor (IDENTIFIER_POINTER (init_name));
+ /* ??? 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)
+ {
+#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);
+#else
+ abort ();
+#endif
+ }
+ 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;
+ }
+}
+
+/* Make a symbol_type (_Jv_MethodSymbol) node for DECL. */
+
+static tree
+build_symbol_entry (tree decl)
+{
+ tree clname, name, signature, sym;
+
+ clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))));
+ name = build_utf8_ref (DECL_NAME (decl));
+ signature = build_java_signature (TREE_TYPE (decl));
+ signature = build_utf8_ref (unmangle_classname
+ (IDENTIFIER_POINTER (signature),
+ IDENTIFIER_LENGTH (signature)));
+
+ START_RECORD_CONSTRUCTOR (sym, symbol_type);
+ PUSH_FIELD_VALUE (sym, "clname", clname);
+ PUSH_FIELD_VALUE (sym, "name", name);
+ PUSH_FIELD_VALUE (sym, "signature", signature);
+ FINISH_RECORD_CONSTRUCTOR (sym);
+ TREE_CONSTANT (sym) = 1;
+
+ return sym;
+}
+
+/* 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)
+{
+ tree method_list, method, table, list, null_symbol;
+ tree table_size, the_array_type;
+ int index;
+
+ /* Only emit a table if this translation unit actually made any
+ references via it. */
+ if (decl_list == NULL_TREE)
+ return the_table;
+
+ /* Build a list of _Jv_MethodSymbols for each entry in otable_methods. */
+ index = 0;
+ method_list = decl_list;
+ list = NULL_TREE;
+ while (method_list != NULL_TREE)
+ {
+ method = TREE_VALUE (method_list);
+ list = tree_cons (NULL_TREE, build_symbol_entry (method), list);
+ method_list = TREE_CHAIN (method_list);
+ index++;
+ }
+
+ /* Terminate the list with a "null" entry. */
+ START_RECORD_CONSTRUCTOR (null_symbol, symbol_type);
+ PUSH_FIELD_VALUE (null_symbol, "clname", null_pointer_node);
+ PUSH_FIELD_VALUE (null_symbol, "name", null_pointer_node);
+ PUSH_FIELD_VALUE (null_symbol, "signature", null_pointer_node);
+ FINISH_RECORD_CONSTRUCTOR (null_symbol);
+ TREE_CONSTANT (null_symbol) = 1;
+ list = tree_cons (NULL_TREE, null_symbol, list);
+
+ /* Put the list in the right order and make it a constructor. */
+ list = nreverse (list);
+ table = build_constructor (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);
+
+ /* 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));
+ 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);
+
+ return the_table;
+}
+
+/* make an entry for the catch_classes list. */
+tree
+make_catch_class_record (tree catch_class, tree classname)
+{
+ tree entry;
+ tree type = TREE_TYPE (TREE_TYPE (ctable_decl));
+ START_RECORD_CONSTRUCTOR (entry, type);
+ PUSH_FIELD_VALUE (entry, "address", catch_class);
+ PUSH_FIELD_VALUE (entry, "classname", classname);
+ FINISH_RECORD_CONSTRUCTOR (entry);
+ return entry;
+}
+
+
+/* Generate the list of Throwable classes that are caught by exception
+ handlers in this compilation. */
+void
+emit_catch_table (void)
+{
+ tree table, table_size, array_type;
+ catch_classes
+ = tree_cons (NULL,
+ make_catch_class_record (null_pointer_node, null_pointer_node),
+ catch_classes);
+ catch_classes = nreverse (catch_classes);
+ catch_classes
+ = tree_cons (NULL,
+ make_catch_class_record (null_pointer_node, null_pointer_node),
+ catch_classes);
+ table_size = build_index_type (build_int_2 (list_length (catch_classes), 0));
+ array_type
+ = build_array_type (TREE_TYPE (TREE_TYPE (ctable_decl)), table_size);
+ table = build_decl (VAR_DECL, DECL_NAME (ctable_decl), array_type);
+ DECL_INITIAL (table) = build_constructor (array_type, catch_classes);
+ TREE_STATIC (table) = 1;
+ TREE_READONLY (table) = 1;
+ rest_of_decl_compilation (table, NULL, 1, 0);
+ ctable_decl = table;
}
+
void
-init_class_processing ()
+init_class_processing (void)
{
- registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterClass");
- ggc_add_tree_root (class_roots, sizeof (class_roots) / sizeof (tree));
+ registerClass_libfunc = gen_rtx_SYMBOL_REF (Pmode, "_Jv_RegisterClass");
fields_ident = get_identifier ("fields");
info_ident = get_identifier ("info");
- ggc_add_rtx_root (®isterClass_libfunc, 1);
gcc_obstack_init (&temporary_obstack);
}
+\f
+static hashval_t java_treetreehash_hash (const void *);
+static int java_treetreehash_compare (const void *, const void *);
+
+/* A hash table mapping trees to trees. Used generally. */
+
+#define JAVA_TREEHASHHASH_H(t) (htab_hash_pointer (t))
+
+static hashval_t
+java_treetreehash_hash (const void *k_p)
+{
+ struct treetreehash_entry *k = (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;
+ return (k1->key == k2);
+}
+
+tree
+java_treetreehash_find (htab_t ht, tree t)
+{
+ struct treetreehash_entry *e;
+ hashval_t hv = JAVA_TREEHASHHASH_H (t);
+ e = htab_find_with_hash (ht, t, hv);
+ if (e == NULL)
+ return NULL;
+ else
+ return e->value;
+}
+
+tree *
+java_treetreehash_new (htab_t ht, tree t)
+{
+ void **e;
+ struct treetreehash_entry *tthe;
+ hashval_t hv = JAVA_TREEHASHHASH_H (t);
+
+ e = htab_find_slot_with_hash (ht, t, hv, INSERT);
+ if (*e == NULL)
+ {
+ tthe = (*ht->alloc_f) (1, sizeof (*tthe));
+ tthe->key = t;
+ *e = tthe;
+ }
+ else
+ tthe = (struct treetreehash_entry *) *e;
+ return &tthe->value;
+}
+
+htab_t
+java_treetreehash_create (size_t size, int gc)
+{
+ if (gc)
+ return htab_create_ggc (size, java_treetreehash_hash,
+ java_treetreehash_compare, NULL);
+ else
+ return htab_create_alloc (size, java_treetreehash_hash,
+ java_treetreehash_compare, free, xcalloc, free);
+}
+
+#include "gt-java-class.h"