/* Functions related to building classes and their related objects.
- Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
This file is part of GNU CC.
#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 mangle_class_field PARAMS ((tree class));
static tree make_method_value PARAMS ((tree));
static tree build_java_method_type PARAMS ((tree, tree, int));
static int32 hashUtf8String PARAMS ((const char *, int));
static tree make_field_value PARAMS ((tree));
static tree get_dispatch_vector PARAMS ((tree));
static tree get_dispatch_table PARAMS ((tree, tree));
-static void append_gpp_mangled_type PARAMS ((struct obstack *, tree));
-static tree mangle_static_field PARAMS ((tree));
static void add_interface_do PARAMS ((tree, tree, int));
static tree maybe_layout_super_class PARAMS ((tree, tree));
static int assume_compiled PARAMS ((const char *));
-static struct hash_entry *init_test_hash_newfunc PARAMS ((struct hash_entry *,
- struct hash_table *,
- hash_table_key));
+static tree build_method_symbols_entry PARAMS ((tree));
-static rtx registerClass_libfunc;
+static GTY(()) rtx registerClass_libfunc;
+static GTY(()) rtx registerResource_libfunc;
extern struct obstack permanent_obstack;
-extern struct obstack temporary_obstack;
+struct obstack temporary_obstack;
/* The compiler generates different code depending on whether or not
it can assume certain classes have been compiled down to native
static assume_compiled_node *assume_compiled_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]
+
/* Return the node that most closely represents the class whose name
is IDENT. Start the search from NODE. Return NULL if an
appropriate node does not exist. */
make_class ()
{
tree type;
- push_obstacks (&permanent_obstack, &permanent_obstack);
type = make_node (RECORD_TYPE);
-#ifdef JAVA_USE_HANDLES
- tree field1 = build_decl (FIELD_DECL, get_identifier ("obj"),
- 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
MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type);
- pop_obstacks ();
return type;
}
const char *save_input_filename = input_filename;
int save_lineno = lineno;
tree source_name = identifier_subst (class_name, "", '.', '/', ".java");
- push_obstacks (&permanent_obstack, &permanent_obstack);
CLASS_P (class_type) = 1;
input_filename = IDENTIFIER_POINTER (source_name);
lineno = 0;
decl = build_decl (TYPE_DECL, class_name, class_type);
+
+ /* dbxout needs a DECL_SIZE if in gstabs mode */
+ DECL_SIZE (decl) = integer_zero_node;
+
input_filename = save_input_filename;
lineno = save_lineno;
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
- pop_obstacks ();
return decl;
}
if (super_class)
total_supers++;
- push_obstacks (&permanent_obstack, &permanent_obstack);
TYPE_BINFO_BASETYPES (this_class) = make_tree_vec (total_supers);
if (super_class)
{
= super_binfo;
CLASS_HAS_SUPER (this_class) = 1;
}
- pop_obstacks ();
+ set_class_decl_access_flags (access_flags, class_decl);
+}
+
+void
+set_class_decl_access_flags (access_flags, class_decl)
+ 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_ABSTRACT) CLASS_ABSTRACT (class_decl) = 1;
if (access_flags & ACC_STATIC) CLASS_STATIC (class_decl) = 1;
if (access_flags & ACC_PRIVATE) CLASS_PRIVATE (class_decl) = 1;
+ if (access_flags & ACC_PROTECTED) CLASS_PROTECTED (class_decl) = 1;
+ if (access_flags & ACC_STRICT) CLASS_STRICTFP (class_decl) = 1;
}
/* Return length of inheritance chain of CLAS, where java.lang.Object is 0,
int common_enclosing_context_p (type1, type2)
tree type1, type2;
{
- if (!PURE_INNER_CLASS_TYPE_P (type1) && !PURE_INNER_CLASS_TYPE_P (type2))
+ if (!PURE_INNER_CLASS_TYPE_P (type1) || !PURE_INNER_CLASS_TYPE_P (type2))
return 0;
for (type1 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1))); type1;
tree interface_binfo = make_tree_vec (6);
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 (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;
-}
-
-boolean
-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;
+add_method_1 (this_class, access_flags, name, function_type)
+ tree this_class;
int access_flags;
tree name;
tree function_type;
{
tree method_type, fndecl;
- push_obstacks (&permanent_obstack, &permanent_obstack);
method_type = build_java_method_type (function_type,
- handle_class, access_flags);
+ 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 *) permalloc (sizeof (struct lang_decl));
- bzero ((PTR) DECL_LANG_SPECIFIC (fndecl), sizeof (struct lang_decl));
+ = (struct lang_decl *) ggc_alloc_cleared (sizeof (struct lang_decl));
+ 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);
+
+ /* Initialize the static method invocation compound list */
+ DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND (fndecl) = NULL_TREE;
- TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class);
- TYPE_METHODS (handle_class) = fndecl;
- pop_obstacks ();
+ 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;
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;
}
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);
- push_obstacks (&permanent_obstack, &permanent_obstack);
+ const unsigned char *sig
+ = (const unsigned char *) IDENTIFIER_POINTER (method_sig);
+
if (sig[0] != '(')
- fatal ("bad method signature");
+ 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);
- pop_obstacks ();
return fndecl;
}
{
int is_static = (flags & ACC_STATIC) != 0;
tree field;
- /* Push the obstack of field_type ? FIXME */
- push_obstacks (&permanent_obstack, &permanent_obstack);
field = build_decl (is_static ? VAR_DECL : FIELD_DECL, name, field_type);
- pop_obstacks ();
TREE_CHAIN (field) = TYPE_FIELDS (class);
TYPE_FIELDS (class) = field;
DECL_CONTEXT (field) = class;
/* 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;
}
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;
+ {
+ 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;
+ }
}
/* Count the number of Unicode chars encoded in a given Ut8 string. */
return hash;
}
+/* Generate a byte array representing the contents of FILENAME. The
+ array is assigned a unique local symbol. The array represents a
+ compiled Java resource, which is accessed by the runtime using
+ NAME. */
+void
+compile_resource_file (name, filename)
+ char *name;
+ const char *filename;
+{
+ struct stat stat_buf;
+ int fd;
+ char *buffer;
+ char buf[60];
+ tree rtype, field = NULL_TREE, data_type, rinit, data, decl;
+ static int Jr_count = 0;
+
+ fd = open (filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ {
+ perror ("Failed to read resource file");
+ return;
+ }
+ if (fstat (fd, &stat_buf) != 0
+ || ! S_ISREG (stat_buf.st_mode))
+ {
+ perror ("Could not figure length of resource file");
+ return;
+ }
+ buffer = xmalloc (strlen (name) + stat_buf.st_size);
+ strcpy (buffer, name);
+ read (fd, buffer + strlen (name), stat_buf.st_size);
+ close (fd);
+ data_type = build_prim_array_type (unsigned_byte_type_node,
+ strlen (name) + stat_buf.st_size);
+ rtype = make_node (RECORD_TYPE);
+ PUSH_FIELD (rtype, field, "name_length", unsigned_int_type_node);
+ PUSH_FIELD (rtype, field, "resource_length", unsigned_int_type_node);
+ PUSH_FIELD (rtype, field, "data", data_type);
+ FINISH_RECORD (rtype);
+ START_RECORD_CONSTRUCTOR (rinit, rtype);
+ PUSH_FIELD_VALUE (rinit, "name_length",
+ build_int_2 (strlen (name), 0));
+ PUSH_FIELD_VALUE (rinit, "resource_length",
+ build_int_2 (stat_buf.st_size, 0));
+ data = build_string (strlen(name) + stat_buf.st_size, buffer);
+ TREE_TYPE (data) = data_type;
+ PUSH_FIELD_VALUE (rinit, "data", data);
+ FINISH_RECORD_CONSTRUCTOR (rinit);
+ TREE_CONSTANT (rinit) = 1;
+
+ /* Generate a unique-enough identifier. */
+ sprintf(buf, "_Jr%d", ++Jr_count);
+
+ decl = build_decl (VAR_DECL, get_identifier (buf), rtype);
+ 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) = rinit;
+ layout_decl (decl, 0);
+ pushdecl (decl);
+ rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
+ make_decl_rtl (decl, (char*) 0);
+ assemble_variable (decl, 1, 0, 0);
+
+ {
+ tree init_name = get_file_function_name ('I');
+ tree init_type = build_function_type (void_type_node, end_params_node);
+ tree init_decl;
+
+ init_decl = build_decl (FUNCTION_DECL, init_name, init_type);
+ SET_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);
+
+ /* 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;
+
+ pushlevel (0);
+ make_decl_rtl (init_decl, NULL);
+ init_function_start (init_decl, input_filename, 0);
+ expand_function_start (init_decl, 0);
+
+ emit_library_call (registerResource_libfunc, 0, VOIDmode, 1,
+ gen_rtx (SYMBOL_REF, Pmode, buf),
+ 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;
+ (* targetm.asm_out.constructor) (XEXP (DECL_RTL (init_decl), 0),
+ DEFAULT_INIT_PRIORITY);
+ }
+}
+
tree utf8_decl_list = NULL_TREE;
tree
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;
if (ref != NULL_TREE)
return ref;
- push_obstacks (&permanent_obstack, &permanent_obstack);
ctype = make_node (RECORD_TYPE);
str_type = build_prim_array_type (unsigned_byte_type_node,
name_len + 1); /* Allow for final '\0'. */
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;
+#ifdef 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);
+ }
+ }
+#endif
TREE_CHAIN (decl) = utf8_decl_list;
layout_decl (decl, 0);
pushdecl (decl);
rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
utf8_decl_list = decl;
- make_decl_rtl (decl, (char*) 0, 1);
+ make_decl_rtl (decl, (char*) 0);
ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl);
IDENTIFIER_UTF8_REF (name) = ref;
- pop_obstacks ();
return ref;
}
decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
if (decl == NULL_TREE)
{
- push_obstacks (&permanent_obstack, &permanent_obstack);
decl = build_decl (VAR_DECL, decl_name, class_type_node);
DECL_SIZE (decl) = TYPE_SIZE (class_type_node);
DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (class_type_node);
TREE_PUBLIC (decl) = 1;
DECL_IGNORED_P (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
- DECL_ASSEMBLER_NAME (decl) = mangle_class_field (type);
- make_decl_rtl (decl, NULL, 1);
- pushdecl_top_level (decl);
if (is_compiled == 1)
DECL_EXTERNAL (decl) = 1;
- pop_obstacks ();
+ SET_DECL_ASSEMBLER_NAME (decl,
+ java_mangle_class_field
+ (&temporary_obstack, type));
+ make_decl_rtl (decl, NULL);
+ pushdecl_top_level (decl);
}
}
else
else if (type == void_type_node)
prim_class_name = "java.lang.Void";
else
- fatal ("internal error - bad type to build_class_ref");
+ abort ();
+
prim_class = lookup_class (get_identifier (prim_class_name));
return build (COMPONENT_REF, NULL_TREE,
prim_class, TYPE_identifier_node);
decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
if (decl == NULL_TREE)
{
- push_obstacks (&permanent_obstack, &permanent_obstack);
decl = build_decl (VAR_DECL, decl_name, class_type_node);
TREE_STATIC (decl) = 1;
TREE_PUBLIC (decl) = 1;
- make_decl_rtl (decl, NULL, 1);
+ DECL_EXTERNAL (decl) = 1;
+ make_decl_rtl (decl, NULL);
pushdecl_top_level (decl);
- if (is_compiled == 1)
- DECL_EXTERNAL (decl) = 1;
- pop_obstacks ();
}
}
{
int index;
tree cl;
- push_obstacks (&permanent_obstack, &permanent_obstack);
index = alloc_class_constant (type);
cl = build_ref_from_constant_pool (index);
TREE_TYPE (cl) = promote_type (class_ptr_type);
- pop_obstacks ();
return cl;
}
}
int is_compiled = is_compiled_class (fclass);
if (is_compiled)
{
- if (DECL_RTL (fdecl) == 0)
+ if (!DECL_RTL_SET_P (fdecl))
{
- push_obstacks (&permanent_obstack, &permanent_obstack);
- make_decl_rtl (fdecl, NULL, 1);
- pop_obstacks ();
if (is_compiled == 1)
DECL_EXTERNAL (fdecl) = 1;
+ make_decl_rtl (fdecl, NULL);
}
return fdecl;
}
{
/* Compile as:
* *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */
- static tree fields_ident = NULL_TREE;
- static tree info_ident = NULL_TREE;
tree ref = build_class_ref (fclass);
tree fld;
int field_index = 0;
ref = build1 (INDIRECT_REF, class_type_node, ref);
- if (fields_ident == NULL_TREE)
- fields_ident = get_identifier ("fields");
- if (info_ident == NULL_TREE)
- info_ident = get_identifier ("info");
ref = build (COMPONENT_REF, field_ptr_type_node, ref,
lookup_field (&class_type_node, fields_ident));
if (fld == fdecl)
break;
if (fld == NULL_TREE)
- fatal ("field '%s' not found in class",
- IDENTIFIER_POINTER (DECL_NAME (fdecl)));
+ fatal_error ("field '%s' not found in class",
+ IDENTIFIER_POINTER (DECL_NAME (fdecl)));
if (FIELD_STATIC (fld))
field_index++;
}
access_flags |= ACC_ABSTRACT;
if (CLASS_STATIC (decl))
access_flags |= ACC_STATIC;
+ if (CLASS_PRIVATE (decl))
+ access_flags |= ACC_PRIVATE;
+ if (CLASS_PROTECTED (decl))
+ access_flags |= ACC_PROTECTED;
+ if (CLASS_STRICTFP (decl))
+ access_flags |= ACC_STRICT;
return access_flags;
}
if (TREE_CODE (decl) == FUNCTION_DECL)
access_flags |= ACC_ABSTRACT;
if (METHOD_TRANSIENT (decl))
access_flags |= ACC_TRANSIENT;
+ if (METHOD_STRICTFP (decl))
+ access_flags |= ACC_STRICT;
return access_flags;
}
abort ();
make_method_value (mdecl)
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 (mdecl))
+ if (DECL_RTL_SET_P (mdecl))
code = build1 (ADDR_EXPR, nativecode_ptr_type_node, mdecl);
START_RECORD_CONSTRUCTOR (minit, method_type_node);
PUSH_FIELD_VALUE (minit, "name",
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 = build_java_signature (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, NULL_TREE, 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;
}
get_dispatch_table (type, this_class_addr)
tree type, this_class_addr;
{
+ int abstract_p = CLASS_ABSTRACT (TYPE_NAME (type));
tree vtable = get_dispatch_vector (type);
- int i;
+ 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))
- warning_with_decl (method, "abstract method in non-abstract class");
- if (DECL_RTL (method) == 0)
- make_decl_rtl (method, NULL, 1);
- list = tree_cons (NULL_TREE /*DECL_VINDEX (method) + 2*/,
- build1 (ADDR_EXPR, nativecode_ptr_type_node, method),
- list);
+ {
+ if (! abstract_p)
+ warning_with_decl (method,
+ "abstract method in non-abstract class");
+
+ 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);
+
+ 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);
+ }
}
+
/* 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),
+ NULL_TREE, list);
}
void
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);
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;
rest_of_decl_compilation (methods_decl, (char*) 0, 1, 0);
if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
- && ! CLASS_ABSTRACT (type_decl) && ! CLASS_INTERFACE (type_decl))
+ && ! CLASS_INTERFACE (type_decl) && !flag_indirect_dispatch)
{
tree dtable = get_dispatch_table (type, this_class_addr);
dtable_decl = build_dtable_decl (type);
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;
+ }
+
+ if (class_dtable_decl == NULL_TREE)
+ {
+ class_dtable_decl = build_dtable_decl (class_type_node);
+ TREE_STATIC (class_dtable_decl) = 1;
+ DECL_ARTIFICIAL (class_dtable_decl) = 1;
+ DECL_IGNORED_P (class_dtable_decl) = 1;
+ if (is_compiled_class (class_type_node) != 2)
+ DECL_EXTERNAL (class_dtable_decl) = 1;
+ rest_of_decl_compilation (class_dtable_decl, (char*) 0, 1, 0);
}
super = CLASSTYPE_SUPER (type);
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, method_symbols_array_ptr_type,
+ otable_syms_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, "depth", integer_zero_node);
PUSH_FIELD_VALUE (cons, "ancestors", null_pointer_node);
PUSH_FIELD_VALUE (cons, "idt", null_pointer_node);
+ PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node);
+ PUSH_FIELD_VALUE (cons, "protectionDomain", 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);
}
finish_class ()
{
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)
- {
- temporary_allocation ();
- output_inline_function (method);
- permanent_allocation (1);
- /* Scan the list again to see if there are any earlier
- methods to emit. */
- method = type_methods;
- 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);
}
if (class == current_class)
return 2;
- seen_in_zip = (TYPE_JCF (class) && TYPE_JCF (class)->seen_in_zip);
- if (CLASS_FROM_CURRENTLY_COMPILED_SOURCE_P (class) || seen_in_zip)
+ seen_in_zip = (TYPE_JCF (class) && JCF_SEEN_IN_ZIP (TYPE_JCF (class)));
+ 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
return 0;
}
-/* Append the mangled name of TYPE onto OBSTACK. */
-
-static void
-append_gpp_mangled_type (obstack, type)
- struct obstack *obstack;
- tree type;
-{
- switch (TREE_CODE (type))
- {
- char code;
- case BOOLEAN_TYPE: code = 'b'; goto primitive;
- case CHAR_TYPE: code = 'w'; goto primitive;
- case VOID_TYPE: code = 'v'; goto primitive;
- case INTEGER_TYPE:
- /* Get the original type instead of the arguments promoted type.
- Avoid symbol name clashes. Should call a function to do that.
- FIXME. */
- if (type == promoted_short_type_node)
- type = short_type_node;
- if (type == promoted_byte_type_node)
- type = byte_type_node;
- switch (TYPE_PRECISION (type))
- {
- case 8: code = 'c'; goto primitive;
- case 16: code = 's'; goto primitive;
- case 32: code = 'i'; goto primitive;
- case 64: code = 'x'; goto primitive;
- default: goto bad_type;
- }
- primitive:
- obstack_1grow (obstack, code);
- break;
- case REAL_TYPE:
- switch (TYPE_PRECISION (type))
- {
- case 32: code = 'f'; goto primitive;
- case 64: code = 'd'; goto primitive;
- default: goto bad_type;
- }
- case POINTER_TYPE:
- type = TREE_TYPE (type);
- obstack_1grow (obstack, 'P');
- case RECORD_TYPE:
- if (TYPE_ARRAY_P (type))
- {
- obstack_grow (obstack, "t6JArray1Z", sizeof("t6JArray1Z")-1);
- append_gpp_mangled_type (obstack, TYPE_ARRAY_ELEMENT (type));
- }
- else
- {
- const char *class_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
- append_gpp_mangled_classtype (obstack, class_name);
- }
- break;
- bad_type:
- default:
- fatal ("internal error - trying to mangle unknown type");
- }
-}
-
-/* Build the mangled name of the `class' field. */
-
-static tree
-mangle_class_field (class)
- tree class;
-{
- tree name;
- obstack_grow (&temporary_obstack, "_CL_", 4);
- append_gpp_mangled_type (&temporary_obstack, class);
- obstack_1grow (&temporary_obstack, '\0');
- name = get_identifier (obstack_base (&temporary_obstack));
- obstack_free (&temporary_obstack, obstack_base (&temporary_obstack));
- return name;
-}
-
-/* Build the mangled (assembly-level) name of the static field FIELD. */
-
-static tree
-mangle_static_field (field)
- tree field;
-{
- tree class = DECL_CONTEXT (field);
- tree name = DECL_NAME (field);
- int encoded_len;
-#if ! defined (NO_DOLLAR_IN_LABEL) || ! defined (NO_DOT_IN_LABEL)
- obstack_1grow (&temporary_obstack, '_');
-#else
- obstack_grow (&temporary_obstack, "__static_", 9);
-#endif
- append_gpp_mangled_type (&temporary_obstack, class);
- encoded_len = unicode_mangling_length (IDENTIFIER_POINTER (name),
- IDENTIFIER_LENGTH (name));
- if (encoded_len > 0)
- {
- obstack_1grow (&temporary_obstack, 'U');
- }
-#ifndef NO_DOLLAR_IN_LABEL
- obstack_1grow (&temporary_obstack, '$');
-#else /* NO_DOLLAR_IN_LABEL */
-#ifndef NO_DOT_IN_LABEL
- obstack_1grow (&temporary_obstack, '.');
-#else /* NO_DOT_IN_LABEL */
- obstack_1grow (&temporary_obstack, '_');
-#endif /* NO_DOT_IN_LABEL */
-#endif /* NO_DOLLAR_IN_LABEL */
- if (encoded_len > 0)
- {
- emit_unicode_mangled_name (&temporary_obstack,
- IDENTIFIER_POINTER (name),
- IDENTIFIER_LENGTH (name));
- }
- else
- {
- obstack_grow (&temporary_obstack,
- IDENTIFIER_POINTER (name),
- IDENTIFIER_LENGTH (name));
- }
- obstack_1grow (&temporary_obstack, '\0');
- name = get_identifier (obstack_base (&temporary_obstack));
- obstack_free (&temporary_obstack, obstack_base (&temporary_obstack));
- return name;
-}
-
/* Build a VAR_DECL for the dispatch table (vtable) for class TYPE. */
tree
build_dtable_decl (type)
tree type;
{
- tree name, dtype;
+ 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, 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
dtype = dtable_type;
- obstack_grow (&temporary_obstack, "__vt_", 5);
- append_gpp_mangled_type (&temporary_obstack, type);
- obstack_1grow (&temporary_obstack, '\0');
- name = get_identifier (obstack_base (&temporary_obstack));
- obstack_free (&temporary_obstack, obstack_base (&temporary_obstack));
- return build_decl (VAR_DECL, name, dtype);
+ return build_decl (VAR_DECL,
+ java_mangle_vtable (&temporary_obstack, type), dtype);
}
/* Pre-pend the TYPE_FIELDS of THIS_CLASS with a dummy FIELD_DECL for the
/* Don't insert the field if we're just re-laying the class out. */
if (TYPE_FIELDS (this_class) && !DECL_NAME (TYPE_FIELDS (this_class)))
return;
- push_obstacks (&permanent_obstack, &permanent_obstack);
base_decl = build_decl (FIELD_DECL, NULL_TREE, super_class);
- pop_obstacks ();
DECL_IGNORED_P (base_decl) = 1;
TREE_CHAIN (base_decl) = TYPE_FIELDS (this_class);
TYPE_FIELDS (this_class) = base_decl;
{
if (TREE_CODE (super_class) == RECORD_TYPE)
{
- if (!CLASS_LOADED_P (super_class)
- && CLASS_FROM_SOURCE_P (super_class))
+ if (!CLASS_LOADED_P (super_class) && CLASS_FROM_SOURCE_P (super_class))
safe_layout_class (super_class);
if (!CLASS_LOADED_P (super_class))
load_class (super_class, 1);
layout_class (this_class)
tree this_class;
{
- static tree list = NULL_TREE;
tree super_class = CLASSTYPE_SUPER (this_class);
tree field;
- list = tree_cons (this_class, NULL_TREE, list);
+ class_list = tree_cons (this_class, NULL_TREE, class_list);
if (CLASS_BEING_LAIDOUT (this_class))
{
char buffer [1024];
+ char *report;
tree current;
sprintf (buffer, " with `%s'",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))));
obstack_grow (&temporary_obstack, buffer, strlen (buffer));
- for (current = TREE_CHAIN (list); current;
+ for (current = TREE_CHAIN (class_list); current;
current = TREE_CHAIN (current))
{
tree decl = TYPE_NAME (TREE_PURPOSE (current));
obstack_grow (&temporary_obstack, buffer, strlen (buffer));
}
obstack_1grow (&temporary_obstack, '\0');
- cyclic_inheritance_report = obstack_finish (&temporary_obstack);
+ report = obstack_finish (&temporary_obstack);
+ cyclic_inheritance_report = ggc_strdup (report);
+ obstack_free (&temporary_obstack, report);
TYPE_SIZE (this_class) = error_mark_node;
return;
}
CLASS_BEING_LAIDOUT (this_class) = 1;
- if (super_class)
+ if (super_class && !CLASS_BEING_LAIDOUT (super_class))
{
- super_class = maybe_layout_super_class (super_class, this_class);
- if (TREE_CODE (TYPE_SIZE (super_class)) == ERROR_MARK)
+ tree maybe_super_class
+ = maybe_layout_super_class (super_class, this_class);
+ if (maybe_super_class == NULL
+ || TREE_CODE (TYPE_SIZE (maybe_super_class)) == ERROR_MARK)
{
TYPE_SIZE (this_class) = error_mark_node;
CLASS_BEING_LAIDOUT (this_class) = 0;
- list = TREE_CHAIN (list);
+ class_list = TREE_CHAIN (class_list);
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) = mangle_static_field (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. */
+ if (!CLASS_FROM_SOURCE_P (this_class))
+ {
+ tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
+
+ if (basetype_vec)
+ {
+ int n = TREE_VEC_LENGTH (basetype_vec) - 1;
+ int i;
+ for (i = n; i > 0; i--)
+ {
+ tree vec_elt = TREE_VEC_ELT (basetype_vec, i);
+ tree super_interface = BINFO_TYPE (vec_elt);
+
+ tree maybe_super_interface
+ = maybe_layout_super_class (super_interface, NULL_TREE);
+ if (maybe_super_interface == NULL
+ || TREE_CODE (TYPE_SIZE (maybe_super_interface)) == ERROR_MARK)
+ {
+ TYPE_SIZE (this_class) = error_mark_node;
+ CLASS_BEING_LAIDOUT (this_class) = 0;
+ class_list = TREE_CHAIN (class_list);
+ return;
+ }
+ }
+ }
+ }
+
/* Convert the size back to an SI integer value */
TYPE_SIZE_UNIT (this_class) =
fold (convert (int_type_node, TYPE_SIZE_UNIT (this_class)));
CLASS_BEING_LAIDOUT (this_class) = 0;
- list = TREE_CHAIN (list);
+ class_list = TREE_CHAIN (class_list);
}
void
tree this_class;
{
tree method_decl, dtable_count;
- tree super_class, handle_type;
+ tree super_class;
if (TYPE_NVIRTUALS (this_class))
return;
- push_obstacks (&permanent_obstack, &permanent_obstack);
super_class = CLASSTYPE_SUPER (this_class);
- handle_type = CLASS_TO_HANDLE_TYPE (this_class);
if (super_class)
{
}
else
dtable_count = integer_zero_node;
-
- TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type));
- for (method_decl = TYPE_METHODS (handle_type);
+ TYPE_METHODS (this_class) = nreverse (TYPE_METHODS (this_class));
+
+ for (method_decl = TYPE_METHODS (this_class);
method_decl; method_decl = TREE_CHAIN (method_decl))
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
- pop_obstacks ();
}
+/* 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. */
+ 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;
{
- const char *ptr;
- char *asm_name;
- tree arg, arglist, t;
- int method_name_needs_escapes = 0;
tree method_name = DECL_NAME (method_decl);
- int method_name_is_wfl =
- (TREE_CODE (method_name) == EXPR_WITH_FILE_LOCATION);
- if (method_name_is_wfl)
- method_name = java_get_real_method_name (method_decl);
- if (!ID_INIT_P (method_name) && !ID_FINIT_P (method_name))
- {
- int encoded_len
- = unicode_mangling_length (IDENTIFIER_POINTER (method_name),
- IDENTIFIER_LENGTH (method_name));
- if (encoded_len > 0)
- {
- method_name_needs_escapes = 1;
- emit_unicode_mangled_name (&temporary_obstack,
- IDENTIFIER_POINTER (method_name),
- IDENTIFIER_LENGTH (method_name));
- }
- else
- {
- obstack_grow (&temporary_obstack,
- IDENTIFIER_POINTER (method_name),
- IDENTIFIER_LENGTH (method_name));
- }
- }
-
- obstack_grow (&temporary_obstack, "__", 2);
- if (ID_FINIT_P (method_name))
- obstack_grow (&temporary_obstack, "finit", 5);
- append_gpp_mangled_type (&temporary_obstack, this_class);
TREE_PUBLIC (method_decl) = 1;
- t = TREE_TYPE (method_decl);
- arglist = TYPE_ARG_TYPES (t);
- if (TREE_CODE (t) == METHOD_TYPE)
- arglist = TREE_CHAIN (arglist);
- for (arg = arglist; arg != end_params_node; )
- {
- tree a = arglist;
- tree argtype = TREE_VALUE (arg);
- int tindex = 1;
- if (TREE_CODE (argtype) == POINTER_TYPE)
- {
- /* This is O(N**2). Do we care? Cfr gcc/cp/method.c. */
- while (a != arg && argtype != TREE_VALUE (a))
- a = TREE_CHAIN (a), tindex++;
- }
- else
- a = arg;
- if (a != arg)
- {
- char buf[12];
- int nrepeats = 0;
- do
- {
- arg = TREE_CHAIN (arg); nrepeats++;
- }
- while (arg != end_params_node && argtype == TREE_VALUE (arg));
- if (nrepeats > 1)
- {
- obstack_1grow (&temporary_obstack, 'N');
- sprintf (buf, "%d", nrepeats);
- obstack_grow (&temporary_obstack, buf, strlen (buf));
- if (nrepeats > 9)
- obstack_1grow (&temporary_obstack, '_');
- }
- else
- obstack_1grow (&temporary_obstack, 'T');
- sprintf (buf, "%d", tindex);
- obstack_grow (&temporary_obstack, buf, strlen (buf));
- if (tindex > 9)
- obstack_1grow (&temporary_obstack, '_');
- }
- else
- {
- append_gpp_mangled_type (&temporary_obstack, argtype);
- arg = TREE_CHAIN (arg);
- }
- }
- if (method_name_needs_escapes)
- obstack_1grow (&temporary_obstack, 'U');
-
- obstack_1grow (&temporary_obstack, '\0');
- asm_name = obstack_finish (&temporary_obstack);
- DECL_ASSEMBLER_NAME (method_decl) = get_identifier (asm_name);
+ /* 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_function_rtl (method_decl);
- obstack_free (&temporary_obstack, asm_name);
+ make_decl_rtl (method_decl, NULL);
if (ID_INIT_P (method_name))
{
const char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class)));
+ const char *ptr;
for (ptr = p; *ptr; )
{
if (*ptr++ == '.')
p = ptr;
}
- if (method_name_is_wfl)
- EXPR_WFL_NODE (DECL_NAME (method_decl)) = get_identifier (p);
- else
- DECL_NAME (method_decl) = get_identifier (p);
DECL_CONSTRUCTOR_P (method_decl) = 1;
build_java_argument_signature (TREE_TYPE (method_decl));
}
&& !CLASS_FROM_SOURCE_P (this_class))
error_with_decl (method_decl,
"non-static method '%s' overrides static method");
-#if 0
- else if (TREE_TYPE (TREE_TYPE (method_decl))
- != TREE_TYPE (TREE_TYPE (super_method)))
- {
- error_with_decl (method_decl,
- "Method `%s' redefined with different return type");
- error_with_decl (super_method,
- "Overridden decl is here");
- }
-#endif
}
else if (! METHOD_FINAL (method_decl)
&& ! METHOD_PRIVATE (method_decl)
return dtable_count;
}
-static tree registered_class = NULL_TREE;
-
void
register_class ()
{
+ /* END does not need to be registered with the garbage collector
+ because it always points into the list given by REGISTERED_CLASS,
+ and that variable is registered with the collector. */
static tree end;
tree node = TREE_OPERAND (build_class_ref (current_class), 0);
tree current = copy_node (node);
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 invoction time. The fallback mechanism is to generate
+ a `constructor' function which calls _Jv_RegisterClass for each
+ class in this file. */
void
emit_register_classes ()
{
- 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_function_rtl (init_decl);
- 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 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);
+ SET_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);
+
+ /* 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, input_filename, 0);
+ 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);
+
+ expand_function_end (input_filename, 0, 0);
+ 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);
+ }
+}
+
+/* Make a method_symbol_type (_Jv_MethodSymbol) node for METHOD. */
+
+tree
+build_method_symbols_entry (tree method)
+{
+ tree clname, name, signature, method_symbol;
+
+ clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (method))));
+ name = build_utf8_ref (DECL_NAME (method));
+ signature = build_java_signature (TREE_TYPE (method));
+ signature = build_utf8_ref (unmangle_classname
+ (IDENTIFIER_POINTER (signature),
+ IDENTIFIER_LENGTH (signature)));
+
+ START_RECORD_CONSTRUCTOR (method_symbol, method_symbol_type);
+ PUSH_FIELD_VALUE (method_symbol, "clname", clname);
+ PUSH_FIELD_VALUE (method_symbol, "name", name);
+ PUSH_FIELD_VALUE (method_symbol, "signature", signature);
+ FINISH_RECORD_CONSTRUCTOR (method_symbol);
+ TREE_CONSTANT (method_symbol) = 1;
+
+ return method_symbol;
+}
+
+/* Emit the offset symbols table for indirect virtual dispatch. */
+
+void
+emit_offset_symbol_table ()
+{
+ tree method_list, method, table, list, null_symbol;
+ tree otable_bound, otable_array_type;
+ int index;
+
+ /* Only emit an offset table if this translation unit actually made virtual
+ calls. */
+ if (otable_methods == NULL_TREE)
+ return;
+
+ /* Build a list of _Jv_MethodSymbols for each entry in otable_methods. */
+ index = 0;
+ method_list = otable_methods;
+ list = NULL_TREE;
+ while (method_list != NULL_TREE)
+ {
+ method = TREE_VALUE (method_list);
+ list = tree_cons (NULL_TREE, build_method_symbols_entry (method), list);
+ method_list = TREE_CHAIN (method_list);
+ index++;
+ }
+
+ /* Terminate the list with a "null" entry. */
+ START_RECORD_CONSTRUCTOR (null_symbol, method_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, method_symbols_array_type, NULL_TREE, list);
+
+ /* Make it the initial value for otable_syms and emit the decl. */
+ DECL_INITIAL (otable_syms_decl) = table;
+ DECL_ARTIFICIAL (otable_syms_decl) = 1;
+ DECL_IGNORED_P (otable_syms_decl) = 1;
+ rest_of_decl_compilation (otable_syms_decl, NULL, 1, 0);
+
+ /* Now that its size is known, redefine otable as an uninitialized static
+ array of INDEX + 1 integers. The extra entry is used by the runtime
+ to track whether the otable has been initialized. */
+ otable_bound = build_index_type (build_int_2 (index, 0));
+ otable_array_type = build_array_type (integer_type_node, otable_bound);
+ otable_decl = build_decl (VAR_DECL, get_identifier ("otable"),
+ otable_array_type);
+ TREE_STATIC (otable_decl) = 1;
+ TREE_READONLY (otable_decl) = 1;
+ rest_of_decl_compilation (otable_decl, NULL, 1, 0);
}
void
init_class_processing ()
{
- registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterClass");
+ registerClass_libfunc = gen_rtx_SYMBOL_REF (Pmode, "_Jv_RegisterClass");
+ registerResource_libfunc =
+ gen_rtx_SYMBOL_REF (Pmode, "_Jv_RegisterResource");
+ fields_ident = get_identifier ("fields");
+ info_ident = get_identifier ("info");
+ gcc_obstack_init (&temporary_obstack);
+}
+\f
+static hashval_t java_treetreehash_hash PARAMS ((const void *));
+static int java_treetreehash_compare PARAMS ((const void *, const void *));
+
+/* A hash table mapping trees to trees. Used generally. */
+
+#define JAVA_TREEHASHHASH_H(t) ((hashval_t) (t))
+
+static hashval_t
+java_treetreehash_hash (k_p)
+ const void *k_p;
+{
+ struct treetreehash_entry *k = (struct treetreehash_entry *) k_p;
+ return JAVA_TREEHASHHASH_H (k->key);
+}
+
+static int
+java_treetreehash_compare (k1_p, k2_p)
+ 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 (ht, t)
+ htab_t ht;
+ tree t;
+{
+ struct treetreehash_entry *e;
+ hashval_t hv = JAVA_TREEHASHHASH_H (t);
+ e = (struct treetreehash_entry *) htab_find_with_hash (ht, t, hv);
+ if (e == NULL)
+ return NULL;
+ else
+ return e->value;
+}
+
+tree *
+java_treetreehash_new (ht, t)
+ htab_t ht;
+ tree t;
+{
+ PTR *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 = (PTR) tthe;
+ }
+ else
+ tthe = (struct treetreehash_entry *) *e;
+ return &tthe->value;
+}
+
+htab_t
+java_treetreehash_create (size, gc)
+ 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"