/* Functions related to building classes and their related objects.
- Copyright (C) 1996, 97-99, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "toplev.h"
#include "output.h"
#include "parse.h"
+#include "ggc.h"
static tree mangle_class_field PARAMS ((tree class));
static tree make_method_value 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 int utf8_cmp PARAMS ((const unsigned char *, int, const char *));
+static int cxx_keyword_p PARAMS ((const char *, int));
+static tree mangle_field PARAMS ((tree, tree));
static rtx registerClass_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
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"),
#else
TYPE_BINFO (type) = make_tree_vec (6);
#endif
- pop_obstacks ();
+ MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type);
return type;
}
tree class_type, class_name;
{
tree decl, signature;
- char *save_input_filename = input_filename;
+ 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;
}
#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 ();
-
+
if (access_flags & ACC_PUBLIC) CLASS_PUBLIC (class_decl) = 1;
if (access_flags & ACC_FINAL) CLASS_FINAL (class_decl) = 1;
if (access_flags & ACC_SUPER) CLASS_SUPER (class_decl) = 1;
if (access_flags & ACC_INTERFACE) CLASS_INTERFACE (class_decl) = 1;
if (access_flags & ACC_ABSTRACT) CLASS_ABSTRACT (class_decl) = 1;
+ if (access_flags & ACC_STATIC) CLASS_STATIC (class_decl) = 1;
+ if (access_flags & ACC_PRIVATE) CLASS_PRIVATE (class_decl) = 1;
+ if (access_flags & ACC_PROTECTED) CLASS_PROTECTED (class_decl) = 1;
}
/* Return length of inheritance chain of CLAS, where java.lang.Object is 0,
return 0;
}
+/* Return a 1 iff TYPE1 is an enclosing context for TYPE2 */
+
+int
+enclosing_context_p (type1, type2)
+ tree type1, type2;
+{
+ if (!INNER_CLASS_TYPE_P (type2))
+ return 0;
+
+ for (type2 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type2)));
+ type2;
+ type2 = (INNER_CLASS_TYPE_P (type2) ?
+ TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type2))) : NULL_TREE))
+ {
+ if (type2 == type1)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return 1 iff there exists a common enclosing context between TYPE1
+ and TYPE2. */
+
+int common_enclosing_context_p (type1, type2)
+ tree type1, type2;
+{
+ if (!PURE_INNER_CLASS_TYPE_P (type1) || !PURE_INNER_CLASS_TYPE_P (type2))
+ return 0;
+
+ for (type1 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1))); type1;
+ type1 = (PURE_INNER_CLASS_TYPE_P (type1) ?
+ TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1))) : NULL_TREE))
+ {
+ tree current;
+ for (current = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type2))); current;
+ current = (PURE_INNER_CLASS_TYPE_P (current) ?
+ TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current))) :
+ NULL_TREE))
+ if (type1 == current)
+ return 1;
+ }
+ return 0;
+}
+
static void
add_interface_do (basetype_vec, interface_class, i)
tree basetype_vec, interface_class;
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);
+}
+
tree
add_method_1 (handle_class, access_flags, name, function_type)
tree handle_class;
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);
DECL_CONTEXT (fndecl) = handle_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));
+
+ /* 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);
TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class);
TYPE_METHODS (handle_class) = fndecl;
- pop_obstacks ();
if (access_flags & ACC_PUBLIC) METHOD_PUBLIC (fndecl) = 1;
if (access_flags & ACC_PROTECTED) METHOD_PROTECTED (fndecl) = 1;
if (access_flags & ACC_PRIVATE)
METHOD_PRIVATE (fndecl) = DECL_INLINE (fndecl) = 1;
- if (access_flags & ACC_NATIVE) METHOD_NATIVE (fndecl) = 1;
+ if (access_flags & ACC_NATIVE)
+ {
+ METHOD_NATIVE (fndecl) = 1;
+ DECL_EXTERNAL (fndecl) = 1;
+ }
if (access_flags & ACC_STATIC)
METHOD_STATIC (fndecl) = DECL_INLINE (fndecl) = 1;
if (access_flags & ACC_FINAL)
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);
if (sig[0] != '(')
fatal ("bad method signature");
function_type = get_type_from_signature (method_sig);
fndecl = add_method_1 (handle_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;
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'. */
make_decl_rtl (decl, (char*) 0, 1);
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_STATIC (decl) = 1;
TREE_PUBLIC (decl) = 1;
DECL_IGNORED_P (decl) = 1;
pushdecl_top_level (decl);
if (is_compiled == 1)
DECL_EXTERNAL (decl) = 1;
- pop_obstacks ();
}
}
else
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;
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;
}
}
{
if (DECL_RTL (fdecl) == 0)
{
- push_obstacks (&permanent_obstack, &permanent_obstack);
make_decl_rtl (fdecl, NULL, 1);
- pop_obstacks ();
if (is_compiled == 1)
DECL_EXTERNAL (fdecl) = 1;
}
else
{
/* Compile as:
- * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr
- */
+ * *(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);
int field_index = 0;
ref = build1 (INDIRECT_REF, class_type_node, ref);
if (fields_ident == NULL_TREE)
- fields_ident = get_identifier ("fields");
+ {
+ fields_ident = get_identifier ("fields");
+ ggc_add_tree_root (&fields_ident, 1);
+ }
if (info_ident == NULL_TREE)
- info_ident = get_identifier ("info");
+ {
+ info_ident = get_identifier ("info");
+ ggc_add_tree_root (&info_ident, 1);
+ }
ref = build (COMPONENT_REF, field_ptr_type_node, ref,
lookup_field (&class_type_node, fields_ident));
access_flags |= ACC_INTERFACE;
if (CLASS_ABSTRACT (decl))
access_flags |= ACC_ABSTRACT;
+ if (CLASS_STATIC (decl))
+ access_flags |= ACC_STATIC;
+ if (CLASS_PRIVATE (decl))
+ access_flags |= ACC_PRIVATE;
+ if (CLASS_PROTECTED (decl))
+ access_flags |= ACC_PROTECTED;
return access_flags;
}
if (TREE_CODE (decl) == FUNCTION_DECL)
make_field_value (fdecl)
tree fdecl;
{
- tree finit, info;
- int bsize, flags;
+ tree finit;
+ int flags;
tree type = TREE_TYPE (fdecl);
int resolved = is_compiled_class (type);
+
START_RECORD_CONSTRUCTOR (finit, field_type_node);
PUSH_FIELD_VALUE (finit, "name", build_utf8_ref (DECL_NAME (fdecl)));
if (resolved)
else
{
tree signature = build_java_signature (type);
+
type = build_utf8_ref (unmangle_classname
- (IDENTIFIER_POINTER(signature),
- IDENTIFIER_LENGTH(signature)));
+ (IDENTIFIER_POINTER (signature),
+ IDENTIFIER_LENGTH (signature)));
}
PUSH_FIELD_VALUE (finit, "type", type);
+
flags = get_access_flags_from_decl (fdecl);
if (! resolved)
flags |= 0x8000 /* FIELD_UNRESOLVED_FLAG */;
+
PUSH_FIELD_VALUE (finit, "accflags", build_int_2 (flags, 0));
- bsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (fdecl))) / BITS_PER_UNIT;
- PUSH_FIELD_VALUE (finit, "bsize", build_int_2 (bsize, 0));
- if (FIELD_STATIC (fdecl))
- {
- tree cfield = TREE_CHAIN (TYPE_FIELDS(field_info_union_node));
- tree faddr = build_address_of (build_static_field_ref (fdecl));
- info = build (CONSTRUCTOR, field_info_union_node, NULL_TREE,
- build_tree_list (cfield, faddr));
- }
- else
- {
- int boffset
- = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (fdecl)) / BITS_PER_UNIT;
- info = build (CONSTRUCTOR, field_info_union_node, NULL_TREE,
- build_tree_list (TYPE_FIELDS(field_info_union_node),
- build_int_2 (boffset, 0)));
- }
- PUSH_FIELD_VALUE (finit, "info", info);
+ PUSH_FIELD_VALUE (finit, "bsize", TYPE_SIZE_UNIT (TREE_TYPE (fdecl)));
+
+ PUSH_FIELD_VALUE
+ (finit, "info",
+ build (CONSTRUCTOR, field_info_union_node, NULL_TREE,
+ build_tree_list
+ ((FIELD_STATIC (fdecl)
+ ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
+ : TYPE_FIELDS (field_info_union_node)),
+ (FIELD_STATIC (fdecl)
+ ? build_address_of (build_static_field_ref (fdecl))
+ : byte_position (fdecl)))));
FINISH_RECORD_CONSTRUCTOR (finit);
return finit;
tree vtable = TYPE_VTABLE (type);
if (vtable == NULL)
{
- int i;
+ HOST_WIDE_INT i;
tree method;
tree super = CLASSTYPE_SUPER (type);
- int nvirtuals = TREE_INT_CST_LOW (TYPE_NVIRTUALS (type));
+ HOST_WIDE_INT nvirtuals = tree_low_cst (TYPE_NVIRTUALS (type), 0);
vtable = make_tree_vec (nvirtuals);
TYPE_VTABLE (type) = vtable;
if (super != NULL_TREE)
{
tree super_vtable = get_dispatch_vector (super);
- for ( i = TREE_INT_CST_LOW (TYPE_NVIRTUALS (super)); --i >= 0; )
+
+ for (i = tree_low_cst (TYPE_NVIRTUALS (super), 0); --i >= 0; )
TREE_VEC_ELT (vtable, i) = TREE_VEC_ELT (super_vtable, i);
}
+
for (method = TYPE_METHODS (type); method != NULL_TREE;
method = TREE_CHAIN (method))
- {
- if (DECL_VINDEX (method) != NULL_TREE
- && TREE_CODE (DECL_VINDEX (method)) == INTEGER_CST)
- {
- TREE_VEC_ELT (vtable, TREE_INT_CST_LOW (DECL_VINDEX (method)))
- = method;
- }
- }
+ if (DECL_VINDEX (method) != NULL_TREE
+ && host_integerp (DECL_VINDEX (method), 0))
+ TREE_VEC_ELT (vtable, tree_low_cst (DECL_VINDEX (method), 0))
+ = method;
}
+
return vtable;
}
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;
tree list = NULL_TREE;
{
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);
+ {
+ if (! abstract_p)
+ warning_with_decl (method,
+ "abstract method in non-abstract class");
+ method = null_pointer_node;
+ }
+ else
+ {
+ if (DECL_RTL (method) == 0)
+ make_decl_rtl (method, NULL, 1);
+ method = build1 (ADDR_EXPR, nativecode_ptr_type_node, method);
+ }
list = tree_cons (NULL_TREE /*DECL_VINDEX (method) + 2*/,
- build1 (ADDR_EXPR, nativecode_ptr_type_node, method),
- list);
+ method, list);
}
- /* Dummy entry for compatibility with G++ -fvtable-thunks. */
- list = tree_cons (integer_zero_node, null_pointer_node, 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),
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))
{
tree dtable = get_dispatch_table (type, this_class_addr);
dtable_decl = build_dtable_decl (type);
constant_pool_constructor = build_constants_constructor ();
START_RECORD_CONSTRUCTOR (temp, object_type_node);
-#if 0
- PUSH_FIELD_VALUE (temp, "vtable", NULL_TREE);
-#else
PUSH_FIELD_VALUE (temp, "vtable",
build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl));
-#endif
- PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node);
+ if (! flag_hash_synchronization)
+ PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node);
FINISH_RECORD_CONSTRUCTOR (temp);
START_RECORD_CONSTRUCTOR (cons, class_type_node);
PUSH_SUPER_VALUE (cons, temp);
PUSH_FIELD_VALUE (cons, "state", integer_zero_node);
PUSH_FIELD_VALUE (cons, "thread", null_pointer_node);
+ 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);
FINISH_RECORD_CONSTRUCTOR (cons);
|| ! 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;
if (class == current_class)
return 2;
- seen_in_zip = (TYPE_LANG_SPECIFIC (class) && TYPE_LANG_SPECIFIC (class)->jcf
- && TYPE_LANG_SPECIFIC (class)->jcf->seen_in_zip);
+ seen_in_zip = (TYPE_JCF (class) && TYPE_JCF (class)->seen_in_zip);
if (CLASS_FROM_CURRENTLY_COMPILED_SOURCE_P (class) || seen_in_zip)
{
/* The class was seen in the current ZIP file and will be
}
}
-/* Build the mangled name of the `class' field. */
+/* Build the mangled name of a field, given the class name and the
+ field name. */
static tree
-mangle_class_field (class)
- tree class;
+mangle_field (class, name)
+ tree class, name;
{
- 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, '_');
IDENTIFIER_POINTER (name),
IDENTIFIER_LENGTH (name));
}
+
+ /* Mangle C++ keywords by appending a `$'. */
+ /* FIXME: NO_DOLLAR_IN_LABEL */
+ if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
+ obstack_grow (&temporary_obstack, "$", 1);
+
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 name of the `class' field. */
+
+static tree
+mangle_class_field (class)
+ tree class;
+{
+ /* We know that we can use `class$' to mangle the class object,
+ because `class' is a reserved word in Java and thus can't appear
+ as a field or method name. */
+ return mangle_field (class, get_identifier ("class$"));
+}
+
+/* Build the mangled (assembly-level) name of the static field FIELD. */
+
+static tree
+mangle_static_field (field)
+ tree field;
+{
+ return mangle_field (DECL_CONTEXT (field), DECL_NAME (field));
+}
+
/* Build a VAR_DECL for the dispatch table (vtable) for class TYPE. */
tree
build_dtable_decl (type)
tree type;
{
- tree name;
+ tree name, 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
+ TYPE. */
+ if (current_class == type)
+ {
+ tree dummy = NULL_TREE, aomt, n;
+
+ dtype = make_node (RECORD_TYPE);
+ 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);
+ 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, dtable_type);
+ return build_decl (VAR_DECL, name, dtype);
}
/* Pre-pend the TYPE_FIELDS of THIS_CLASS with a dummy FIELD_DECL for the
tree this_class, super_class;
{
tree base_decl;
- push_obstacks (&permanent_obstack, &permanent_obstack);
+ /* Don't insert the field if we're just re-laying the class out. */
+ if (TYPE_FIELDS (this_class) && !DECL_NAME (TYPE_FIELDS (this_class)))
+ return;
base_decl = build_decl (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;
DECL_SIZE (base_decl) = TYPE_SIZE (super_class);
+ DECL_SIZE_UNIT (base_decl) = TYPE_SIZE_UNIT (super_class);
}
/* Handle the different manners we may have to lay out a super class. */
{
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);
super_class = TREE_TYPE (super_class);
else
{
- super_class = do_resolve_class (super_class, NULL_TREE, this_class);
+ super_class = do_resolve_class (NULL_TREE, /* FIXME? */
+ super_class, NULL_TREE, this_class);
if (!super_class)
return NULL_TREE; /* FIXME, NULL_TREE not checked by caller. */
super_class = TREE_TYPE (super_class);
layout_class (this_class)
tree this_class;
{
+ static tree list = NULL_TREE;
+ static int initialized_p;
tree super_class = CLASSTYPE_SUPER (this_class);
tree field;
+
+ /* Register LIST with the garbage collector. */
+ if (!initialized_p)
+ {
+ ggc_add_tree_root (&list, 1);
+ initialized_p = 1;
+ }
+
+ list = tree_cons (this_class, NULL_TREE, 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;
+ current = TREE_CHAIN (current))
+ {
+ tree decl = TYPE_NAME (TREE_PURPOSE (current));
+ sprintf (buffer, "\n which inherits from `%s' (%s:%d)",
+ IDENTIFIER_POINTER (DECL_NAME (decl)),
+ DECL_SOURCE_FILE (decl),
+ DECL_SOURCE_LINE (decl));
+ obstack_grow (&temporary_obstack, buffer, strlen (buffer));
+ }
+ obstack_1grow (&temporary_obstack, '\0');
+ report = 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)
{
- 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);
return;
}
if (TYPE_SIZE (this_class) == NULL_TREE)
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;
+ list = TREE_CHAIN (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);
}
void
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);
}
else
dtable_count = integer_zero_node;
-
+
TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type));
for (method_decl = TYPE_METHODS (handle_type);
#ifdef JAVA_USE_HANDLES
layout_type (handle_type);
#endif
- pop_obstacks ();
+}
+
+/* A sorted list of all C++ keywords. */
+
+static const char *cxx_keywords[] =
+{
+ "asm",
+ "auto",
+ "bool",
+ "const_cast",
+ "delete",
+ "dynamic_cast",
+ "enum",
+ "explicit",
+ "extern",
+ "friend",
+ "inline",
+ "mutable",
+ "namespace",
+ "overload",
+ "register",
+ "reinterpret_cast",
+ "signed",
+ "sizeof",
+ "static_cast",
+ "struct",
+ "template",
+ "typedef",
+ "typeid",
+ "typename",
+ "typenameopt",
+ "union",
+ "unsigned",
+ "using",
+ "virtual",
+ "volatile",
+ "wchar_t"
+};
+
+/* Return 0 if NAME is equal to STR, -1 if STR is "less" than NAME,
+ and 1 if STR is "greater" than NAME. */
+
+static int
+utf8_cmp (str, length, name)
+ const unsigned char *str;
+ int length;
+ const char *name;
+{
+ const unsigned char *limit = str + length;
+ int i;
+
+ for (i = 0; name[i]; ++i)
+ {
+ int ch = UTF8_GET (str, limit);
+ if (ch != name[i])
+ return ch - name[i];
+ }
+
+ return str == limit ? 0 : 1;
+}
+
+/* Return true if NAME is a C++ keyword. */
+
+static int
+cxx_keyword_p (name, length)
+ const char *name;
+ int length;
+{
+ int last = ARRAY_SIZE (cxx_keywords);
+ int first = 0;
+ int mid = (last + first) / 2;
+ int old = -1;
+
+ for (mid = (last + first) / 2;
+ mid != old;
+ old = mid, mid = (last + first) / 2)
+ {
+ int kwl = strlen (cxx_keywords[mid]);
+ int min_length = kwl > length ? length : kwl;
+ int r = utf8_cmp (name, min_length, cxx_keywords[mid]);
+
+ if (r == 0)
+ {
+ int i;
+ /* We've found a match if all the remaining characters are
+ `$'. */
+ for (i = min_length; i < length && name[i] == '$'; ++i)
+ ;
+ if (i == length)
+ return 1;
+ r = 1;
+ }
+
+ if (r < 0)
+ last = mid;
+ else
+ first = mid;
+ }
+ return 0;
}
/* Lay METHOD_DECL out, returning a possibly new value of
if (method_name_is_wfl)
method_name = java_get_real_method_name (method_decl);
- if (method_name != init_identifier_node
- && method_name != finit_identifier_node)
+ if (!ID_INIT_P (method_name) && !ID_FINIT_P (method_name))
{
int encoded_len
= unicode_mangling_length (IDENTIFIER_POINTER (method_name),
IDENTIFIER_POINTER (method_name),
IDENTIFIER_LENGTH (method_name));
}
+
+ /* Mangle C++ keywords by appending a `$'. */
+ /* FIXME: NO_DOLLAR_IN_LABEL */
+ if (cxx_keyword_p (IDENTIFIER_POINTER (method_name),
+ IDENTIFIER_LENGTH (method_name)))
+ obstack_grow (&temporary_obstack, "$", 1);
}
-
+
obstack_grow (&temporary_obstack, "__", 2);
- if (method_name == finit_identifier_node)
+ 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;
it's an interface method that isn't clinit. */
if (! METHOD_ABSTRACT (method_decl)
|| (CLASS_INTERFACE (TYPE_NAME (this_class))
- && (IS_CLINIT (method_decl))))
+ && (DECL_CLINIT_P (method_decl))))
make_function_rtl (method_decl);
obstack_free (&temporary_obstack, asm_name);
- if (method_name == init_identifier_node)
+ if (ID_INIT_P (method_name))
{
const char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class)));
for (ptr = p; *ptr; )
&& dtable_count)
{
DECL_VINDEX (method_decl) = dtable_count;
- dtable_count = build_int_2 (1+TREE_INT_CST_LOW (dtable_count), 0);
+ dtable_count = fold (build (PLUS_EXPR, integer_type_node,
+ dtable_count, integer_one_node));
}
}
+
return dtable_count;
}
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);
init_class_processing ()
{
registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterClass");
+ ggc_add_tree_root (®istered_class, 1);
+ ggc_add_rtx_root (®isterClass_libfunc, 1);
+ gcc_obstack_init (&temporary_obstack);
}