diff options
Diffstat (limited to 'gcc/java/class.c')
-rw-r--r-- | gcc/java/class.c | 1601 |
1 files changed, 1601 insertions, 0 deletions
diff --git a/gcc/java/class.c b/gcc/java/class.c new file mode 100644 index 0000000..9dc49dc --- /dev/null +++ b/gcc/java/class.c @@ -0,0 +1,1601 @@ +/* Functions related to building classes and their related objects. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +Java and all Java-based marks are trademarks or registered trademarks +of Sun Microsystems, Inc. in the United States and other countries. +The Free Software Foundation is independent of Sun Microsystems, Inc. */ + +/* Written by Per Bothner <bothner@cygnus.com> */ + +#include <stdio.h> +#include "config.h" +#include "tree.h" +#include "rtl.h" +#include "java-tree.h" +#include "jcf.h" +#include "obstack.h" + +static tree mangle_class_field PROTO ((tree class)); + +static rtx registerClass_libfunc; + +extern struct obstack permanent_obstack; +extern struct obstack temporary_obstack; + +/* Return an IDENTIFIER_NODE the same as (OLD_NAME, OLD_LENGTH). + except that characters matching OLD_CHAR are substituted by NEW_CHAR. + 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; +{ + int prefix_len = strlen (prefix); + int suffix_len = strlen (suffix); + int i = prefix_len + old_length + suffix_len + 1; +#ifdef __GNUC__ + char buffer[i]; +#else + char *buffer = (char *)alloca (i); +#endif + strcpy (buffer, prefix); + for (i = 0; i < old_length; i++) + { + char ch = old_name[i]; + if (ch == old_char) + ch = new_char; + buffer[prefix_len + i] = ch; + } + strcpy (buffer + prefix_len + old_length, suffix); + return get_identifier (buffer); +} + +/* Return an IDENTIFIER_NODE the same as OLD_ID, + except that characters matching OLD_CHAR are substituted by NEW_CHAR. + 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; +{ + return ident_subst (IDENTIFIER_POINTER (old_id), IDENTIFIER_LENGTH (old_id), + prefix, old_char, new_char, suffix); +} + +/* Generate a valid C identifier from the name of the class TYPE, + prefixed by PREFIX. */ + +tree +mangled_classname (prefix, type) + char *prefix; + tree type; +{ + tree ident = TYPE_NAME (type); + if (TREE_CODE (ident) != IDENTIFIER_NODE) + ident = DECL_NAME (ident); + return identifier_subst (ident, prefix, '/', '_', ""); +} + +tree +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 + CLASS_P (type) = 1; + pop_obstacks (); + + return type; +} + +/* Given a fully-qualified classname in NAME (whose length is NAME_LENGTH), + and where each of the constituents is separated by '/', + return a corresponding IDENTIFIER_NODE, except using '.' as separator. */ + +tree +unmangle_classname (name, name_length) + const char *name; int name_length; +{ + return ident_subst (name, name_length, "", '/', '.', ""); +} + +tree +push_class (class_type, class_name) + tree class_type, class_name; +{ + tree decl, signature; + char *save_input_filename = input_filename; + int save_lineno = lineno; + tree source_name = identifier_subst (class_name, "", '.', '/', ".java"); + push_obstacks (&permanent_obstack, &permanent_obstack); + input_filename = IDENTIFIER_POINTER (source_name); + lineno = 0; + decl = build_decl (TYPE_DECL, class_name, class_type); + input_filename = save_input_filename; + lineno = save_lineno; + signature = identifier_subst (class_name, "L", '.', '/', ";"); + IDENTIFIER_SIGNATURE_TYPE (signature) = class_type; + + /* Setting DECL_ARTIFICAL 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; +} + +/* Finds the (global) class named NAME. Creates the class if not found. + Also creates associated TYPE_DECL. + Does not check if the class actually exists, load the class, + fill in field or methods, or do layout_type. */ + +tree +lookup_class (name) + tree name; +{ + tree decl = IDENTIFIER_CLASS_VALUE (name); + if (decl == NULL_TREE) + decl = push_class (make_class (), name); + return TREE_TYPE (decl); +} + +void +set_super_info (access_flags, this_class, super_class, interfaces_count) + int access_flags; + tree this_class; + tree super_class; + int interfaces_count; +{ + int total_supers = interfaces_count; + tree class_decl = TYPE_NAME (this_class); + if (super_class) + total_supers++; + + push_obstacks (&permanent_obstack, &permanent_obstack); + TYPE_BINFO_BASETYPES (this_class) = make_tree_vec (total_supers); + if (super_class) + { + tree super_binfo = make_tree_vec (6); + 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; + } + 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; +} + +/* 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; +{ + int depth = 0; + if (! CLASS_LOADED_P (clas)) + load_class (clas, 1); + while (clas != object_type_node) + { + depth++; + clas = TYPE_BINFO_BASETYPE (clas, 0); + } + return depth; +} + +/* Return true iff TYPE2 is an interface that extends interface TYPE1 */ + +int +interface_of_p (type1, type2) + tree type1, type2; +{ + int n, i; + tree basetype_vec; + + if (!(basetype_vec = TYPE_BINFO_BASETYPES (type2))) + return 0; + n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; i < n; i++) + { + tree vec_elt = TREE_VEC_ELT (basetype_vec, i); + if (vec_elt && BINFO_TYPE (vec_elt) == type1) + return 1; + } + for (i = 0; i < n; i++) + { + tree vec_elt = TREE_VEC_ELT (basetype_vec, i); + if (vec_elt && BINFO_TYPE (vec_elt) + && interface_of_p (type1, BINFO_TYPE (vec_elt))) + return 1; + } + return 0; +} + +/* Return true iff TYPE1 inherits from TYPE2. */ + +int +inherits_from_p (type1, type2) + tree type1, type2; +{ + while (type1 != NULL_TREE && TREE_CODE (type1) == RECORD_TYPE) + { + if (type1 == type2) + return 1; + type1 = CLASSTYPE_SUPER (type1); + } + return 0; +} + +static void +add_interface_do (basetype_vec, interface_class, i) + tree basetype_vec, interface_class; + int i; +{ + tree interface_binfo = make_tree_vec (6); + BINFO_TYPE (interface_binfo) = interface_class; + BINFO_OFFSET (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; +} + +/* Add INTERFACE_CLASS to THIS_CLASS iff INTERFACE_CLASS can't be + found in THIS_CLASS. Returns NULL_TREE upon success, INTERFACE_CLASS + if attempt is made to add it twice. */ + +tree +maybe_add_interface (this_class, interface_class) + tree this_class, interface_class; +{ + tree basetype_vec = TYPE_BINFO_BASETYPES (this_class); + tree interface_binfo = make_tree_vec (6); + int i; + int n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; ; i++) + { + if (i >= n) + { + error ("internal error - too many interface type"); + return NULL_TREE; + } + else if (TREE_VEC_ELT (basetype_vec, i) == NULL_TREE) + break; + else if (BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i)) == interface_class) + return interface_class; + } + add_interface_do (basetype_vec, interface_class, i); + return NULL_TREE; +} + +/* Add the INTERFACE_CLASS as one of the interfaces of THIS_CLASS. */ + +void +add_interface (this_class, interface_class) + tree this_class, interface_class; +{ + tree basetype_vec = TYPE_BINFO_BASETYPES (this_class); + int i; + int n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; ; i++) + { + if (i >= n) + { + error ("internal error - too many interface type"); + return; + } + else if (TREE_VEC_ELT (basetype_vec, i) == NULL_TREE) + break; + } + add_interface_do (basetype_vec, interface_class, i); +} + +/* Return the address of a pointer to the first FUNCTION_DECL + in the list (*LIST) whose DECL_NAME is NAME. */ + +static tree * +find_named_method (list, name) + tree *list; + tree name; +{ + while (*list && DECL_NAME (*list) != name) + list = &TREE_CHAIN (*list); + return list; +} + +tree +build_java_method_type (fntype, this_class, access_flags) + 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); +} + +tree +add_method_1 (handle_class, access_flags, name, function_type) + tree handle_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); + + fndecl = build_decl (FUNCTION_DECL, name, method_type); + DECL_CONTEXT (fndecl) = handle_class; + + DECL_LANG_SPECIFIC (fndecl) + = (struct lang_decl *) permalloc (sizeof (struct lang_decl)); + bzero (DECL_LANG_SPECIFIC (fndecl), sizeof (struct lang_decl)); + + 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) = 1; + if (access_flags & ACC_NATIVE) METHOD_NATIVE (fndecl) = 1; + if (access_flags & ACC_STATIC) METHOD_STATIC (fndecl) = 1; + if (access_flags & ACC_FINAL) METHOD_FINAL (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; + return fndecl; +} + +/* Add a method to THIS_CLASS. + The method's name is NAME. + 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; +{ + tree handle_class = CLASS_TO_HANDLE_TYPE (this_class); + tree function_type, method_type, fndecl; + unsigned char *sig = (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; +} + +tree +add_field (class, name, field_type, flags) + tree class; + tree name; + tree field_type; + int flags; +{ + int is_static = (flags & ACC_STATIC) != 0; + tree field; + /* Push the obstack of field_type ? FIXME */ + push_obstacks (&permanent_obstack, &permanent_obstack); +#if ! JAVA_PROMOTE_TO_INT + if (TREE_CODE (field_type) == RECORD_TYPE) +#endif + field_type = promote_type (field_type); + 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 (flags & ACC_PUBLIC) FIELD_PUBLIC (field) = 1; + if (flags & ACC_PROTECTED) FIELD_PROTECTED (field) = 1; + if (flags & ACC_PRIVATE) FIELD_PRIVATE (field) = 1; + if (flags & ACC_FINAL) FIELD_FINAL (field) = 1; + if (flags & ACC_VOLATILE) FIELD_VOLATILE (field) = 1; + if (flags & ACC_TRANSIENT) FIELD_TRANSIENT (field) = 1; + if (is_static) + { + FIELD_STATIC (field) = 1; + if (! FIELD_PRIVATE (field) || FIELD_PROTECTED (field)) + TREE_PUBLIC (field) = 1; + } + return field; +} + +/* Associate a constant value CONSTANT with VAR_DECL FIELD. */ + +void +set_constant_value (field, constant) + tree field, 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'", + IDENTIFIER_POINTER (DECL_NAME (field))); + else + DECL_INITIAL (field) = constant; +} + +/* Count the number of Unicode chars encoded in a given Ut8 string. */ + +int +strLengthUtf8 (str, len) + char *str; + int len; +{ + register unsigned char* ptr = (unsigned char*) str; + register unsigned char *limit = ptr + len; + int str_length = 0; + for (; ptr < limit; str_length++) { + if (UTF8_GET (ptr, limit) < 0) + return -1; + } + return str_length; +} + + +/* Calculate a hash value for a string encoded in Utf8 format. + * This returns the same hash value as specified for java.lang.String.hashCode. + */ + +int32 +hashUtf8String (str, len) + char *str; + int len; +{ + register unsigned char* ptr = (unsigned char*) str; + register unsigned char *limit = ptr + len; + int32 hash = 0; + for (; ptr < limit;) + { + int ch = UTF8_GET (ptr, limit); + /* Updated specification from + http://www.javasoft.com/docs/books/jls/clarify.html. */ + hash = (31 * hash) + ch; + } + return hash; +} + +tree utf8_decl_list = NULL_TREE; + +tree +build_utf8_ref (name) + tree name; +{ + char* name_ptr = IDENTIFIER_POINTER(name); + int name_len = IDENTIFIER_LENGTH(name); + char buf[60]; + char *buf_ptr; + tree ctype, field, str_type, cinit, string; + static int utf8_count = 0; + int name_hash; + tree ref = IDENTIFIER_UTF8_REF (name); + tree decl; + 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'. */ + PUSH_FIELD (ctype, field, "hash", unsigned_short_type_node); + PUSH_FIELD (ctype, field, "length", unsigned_short_type_node); + PUSH_FIELD (ctype, field, "data", str_type); + FINISH_RECORD (ctype); + START_RECORD_CONSTRUCTOR (cinit, ctype); + name_hash = hashUtf8String (name_ptr, name_len) & 0xFFFF; + PUSH_FIELD_VALUE (cinit, "hash", build_int_2 (name_hash, 0)); + PUSH_FIELD_VALUE (cinit, "length", build_int_2 (name_len, 0)); + string = build_string (name_len, name_ptr); + TREE_TYPE (string) = str_type; + PUSH_FIELD_VALUE (cinit, "data", string); + FINISH_RECORD_CONSTRUCTOR (cinit); + + /* Build a unique identifier based on buf. */ + sprintf(buf, "_Utf%d", ++utf8_count); + buf_ptr = &buf[strlen (buf)]; + while (--name_len >= 0) + { + 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; + DECL_INITIAL (decl) = cinit; + 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); + ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl); + IDENTIFIER_UTF8_REF (name) = ref; + pop_obstacks (); + return ref; +} + +/* Build a reference to the class TYPE. + Also handles primitive types and array types. */ + +tree +build_class_ref (type) + 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 (TREE_CODE (type) == RECORD_TYPE) + { + if (TYPE_SIZE (type) == error_mark_node) + return null_pointer_node; + decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)), + "", '/', '/', ".class"); + decl = IDENTIFIER_GLOBAL_VALUE (decl_name); + if (decl == NULL_TREE) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + decl = build_decl (VAR_DECL, decl_name, class_type_node); + DECL_SIZE (decl) = TYPE_SIZE (class_type_node); + TREE_STATIC (decl) = 1; + 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 (); + } + } + else + { + char *name; + char buffer[20]; + decl_name = TYPE_NAME (type); + if (TREE_CODE (decl_name) == TYPE_DECL) + decl_name = DECL_NAME (decl_name); + name = IDENTIFIER_POINTER (decl_name); + if (strncmp (name, "promoted_", 9) == 0) + name += 9; + sprintf (buffer, "%sClass", name); + decl_name = get_identifier (buffer); + 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); + pushdecl_top_level (decl); + if (is_compiled == 1) + DECL_EXTERNAL (decl) = 1; + pop_obstacks (); + } + } + + ref = build1 (ADDR_EXPR, class_ptr_type, decl); + return ref; + } + else + { + 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; + } +} + +tree +build_static_field_ref (fdecl) + tree fdecl; +{ + tree fclass = DECL_CONTEXT (fdecl); + int is_compiled = is_compiled_class (fclass); + if (is_compiled) + { + 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; + } + return fdecl; + } + else + { + /* 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)); + + for (fld = TYPE_FIELDS (fclass); ; fld = TREE_CHAIN (fld)) + { + if (fld == fdecl) + break; + if (fld == NULL_TREE) + fatal ("field '%s' not found in class", + IDENTIFIER_POINTER (DECL_NAME (fdecl))); + if (FIELD_STATIC (fld)) + field_index++; + } + field_index *= int_size_in_bytes (field_type_node); + ref = fold (build (PLUS_EXPR, field_ptr_type_node, + ref, build_int_2 (field_index, 0))); + ref = build1 (INDIRECT_REF, field_type_node, ref); + ref = build (COMPONENT_REF, field_info_union_node, + ref, lookup_field (&field_type_node, info_ident)); + ref = build (COMPONENT_REF, ptr_type_node, + ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node))); + return fold (build1 (INDIRECT_REF, TREE_TYPE(fdecl), ref)); + } +} + +int +get_access_flags_from_decl (decl) + tree decl; +{ + int access_flags = 0; + if (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL) + { + if (FIELD_STATIC (decl)) + access_flags |= ACC_STATIC; + if (FIELD_PUBLIC (decl)) + access_flags |= ACC_PUBLIC; + if (FIELD_PROTECTED (decl)) + access_flags |= ACC_PROTECTED; + if (FIELD_PRIVATE (decl)) + access_flags |= ACC_PRIVATE; + if (FIELD_FINAL (decl)) + access_flags |= ACC_FINAL; + if (FIELD_VOLATILE (decl)) + access_flags |= ACC_VOLATILE; + if (FIELD_TRANSIENT (decl)) + access_flags |= ACC_TRANSIENT; + return access_flags; + } + if (TREE_CODE (decl) == TYPE_DECL) + { + if (CLASS_PUBLIC (decl)) + access_flags |= ACC_PUBLIC; + if (CLASS_FINAL (decl)) + access_flags |= ACC_FINAL; + if (CLASS_SUPER (decl)) + access_flags |= ACC_SUPER; + if (CLASS_INTERFACE (decl)) + access_flags |= ACC_INTERFACE; + if (CLASS_ABSTRACT (decl)) + access_flags |= ACC_ABSTRACT; + return access_flags; + } + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (METHOD_PUBLIC (decl)) + access_flags |= ACC_PUBLIC; + if (METHOD_PRIVATE (decl)) + access_flags |= ACC_PRIVATE; + if (METHOD_PROTECTED (decl)) + access_flags |= ACC_PROTECTED; + if (METHOD_STATIC (decl)) + access_flags |= ACC_STATIC; + if (METHOD_FINAL (decl)) + access_flags |= ACC_FINAL; + if (METHOD_SYNCHRONIZED (decl)) + access_flags |= ACC_SYNCHRONIZED; + if (METHOD_NATIVE (decl)) + access_flags |= ACC_NATIVE; + if (METHOD_ABSTRACT (decl)) + access_flags |= ACC_ABSTRACT; + if (METHOD_TRANSIENT (decl)) + access_flags |= ACC_TRANSIENT; + return access_flags; + } + abort (); +} + +tree +make_field_value (tree fdecl) +{ + tree finit, info; + int bsize, 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) + type = build_class_ref (type); + else + type = build_utf8_ref (build_java_signature (type)); + 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); + + FINISH_RECORD_CONSTRUCTOR (finit); + return finit; +} + +tree +make_method_value (mdecl, this_class_addr) + tree mdecl; + tree this_class_addr; +{ + tree minit; + tree code; +#define ACC_TRANSLATED 0x4000 + int accflags = get_access_flags_from_decl (mdecl) | ACC_TRANSLATED; + code = null_pointer_node; + if (DECL_RTL (mdecl)) + code = build1 (ADDR_EXPR, nativecode_ptr_type_node, mdecl); + START_RECORD_CONSTRUCTOR (minit, method_type_node); + PUSH_FIELD_VALUE (minit, "name", + build_utf8_ref (DECL_CONSTRUCTOR_P (mdecl) ? + init_identifier_node + : DECL_NAME (mdecl))); + PUSH_FIELD_VALUE (minit, "signature", + build_utf8_ref (build_java_signature (TREE_TYPE (mdecl)))); + PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0)); + PUSH_FIELD_VALUE (minit, "ncode", code); + FINISH_RECORD_CONSTRUCTOR (minit); + return minit; +} + +tree +get_dispatch_vector (type) + tree type; +{ + tree vtable = TYPE_VTABLE (type); + if (vtable == NULL) + { + int i; + tree method; + tree super = CLASSTYPE_SUPER (type); + int nvirtuals = TREE_INT_CST_LOW (TYPE_NVIRTUALS (type)); + 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; ) + 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; + } + } + } + return vtable; +} + +tree +get_dispatch_table (type, this_class_addr) + tree type, this_class_addr; +{ + tree vtable = get_dispatch_vector (type); + int i; + tree list = NULL_TREE; + int nvirtuals = TREE_VEC_LENGTH (vtable); + 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); + } + /* Dummy entry for compatibility with G++ -fvtable-thunks. */ + list = tree_cons (integer_zero_node, null_pointer_node, 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); +} + +void +make_class_data (type) + tree type; +{ + tree decl, cons, temp; + tree field, fields_decl; + tree static_fields = NULL_TREE; + tree instance_fields = NULL_TREE; + HOST_WIDE_INT static_field_count = 0; + HOST_WIDE_INT instance_field_count = 0; + HOST_WIDE_INT field_count; + tree field_array_type; + tree method; + tree methods = NULL_TREE; + tree dtable_decl = NULL_TREE; + HOST_WIDE_INT method_count = 0; + tree method_array_type; + tree methods_decl; + tree super; + tree this_class_addr; + tree constant_pool_constructor; + tree interfaces = null_pointer_node; + int interface_len = 0; + tree type_decl = TYPE_NAME (type); + + this_class_addr = build_class_ref (type); + decl = TREE_OPERAND (this_class_addr, 0); + + /* Build Field array. */ + field = TYPE_FIELDS (type); + if (DECL_NAME (field) == NULL_TREE) + field = TREE_CHAIN (field); /* Skip dummy field for inherited data. */ + for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) + { + if (! DECL_ARTIFICIAL (field)) + { + tree init = make_field_value (field); + if (FIELD_STATIC (field)) + { + static_field_count++; + static_fields = tree_cons (NULL_TREE, init, static_fields); + rest_of_decl_compilation (field, (char*) 0, 1, 1); + } + else + { + instance_field_count++; + instance_fields = tree_cons (NULL_TREE, init, instance_fields); + } + } + } + field_count = static_field_count + instance_field_count; + if (field_count > 0) + { + static_fields = nreverse (static_fields); + instance_fields = nreverse (instance_fields); + static_fields = chainon (static_fields, instance_fields); + field_array_type = build_prim_array_type (field_type_node, field_count); + fields_decl = build_decl (VAR_DECL, mangled_classname ("_FL_", type), + field_array_type); + DECL_INITIAL (fields_decl) = build (CONSTRUCTOR, field_array_type, + NULL_TREE, static_fields); + TREE_STATIC (fields_decl) = 1; + DECL_ARTIFICIAL (fields_decl) = 1; + DECL_IGNORED_P (fields_decl) = 1; + rest_of_decl_compilation (fields_decl, (char*) 0, 1, 0); + } + else + fields_decl = NULL_TREE; + + /* Build Method array. */ + for (method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (type)); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + tree init = make_method_value (method, this_class_addr); + method_count++; + methods = tree_cons (NULL_TREE, init, methods); + } + method_array_type = build_prim_array_type (method_type_node, method_count); + methods_decl = build_decl (VAR_DECL, mangled_classname ("_MT_", type), + method_array_type); + DECL_INITIAL (methods_decl) = build (CONSTRUCTOR, method_array_type, + NULL_TREE, 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 (flag_assume_compiled + && ! CLASS_ABSTRACT (type_decl) && ! CLASS_INTERFACE (type_decl)) + { + tree dtable = get_dispatch_table (type, this_class_addr); + dtable_decl = build_dtable_decl (type); + DECL_INITIAL (dtable_decl) = dtable; + TREE_STATIC (dtable_decl) = 1; + DECL_ARTIFICIAL (dtable_decl) = 1; + DECL_IGNORED_P (dtable_decl) = 1; + TREE_PUBLIC (dtable_decl) = 1; + rest_of_decl_compilation (dtable_decl, (char*) 0, 1, 0); + } + + super = CLASSTYPE_SUPER (type); + if (super == NULL_TREE) + super = null_pointer_node; + else if (flag_assume_compiled) + super = build_class_ref (super); + else + { + int super_index = alloc_class_constant (super); + super = build_int_2 (super_index, 0); + TREE_TYPE (super) == ptr_type_node; + } + + /* Build and emit the array of implemented interfaces. */ + if (type != object_type_node) + interface_len = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)) - 1; + if (interface_len > 0) + { + tree init = NULL_TREE; + int i; + tree interface_array_type, idecl; + interface_array_type + = build_prim_array_type (class_ptr_type, interface_len); + idecl = build_decl (VAR_DECL, mangled_classname ("_IF_", type), + interface_array_type); + for (i = interface_len; i > 0; i--) + { + tree child = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i); + tree iclass = BINFO_TYPE (child); + tree index; + if (flag_assume_compiled) + index = build_class_ref (iclass); + else + { + int int_index = alloc_class_constant (iclass); + index = build_int_2 (int_index, 0); + TREE_TYPE (index) == ptr_type_node; + } + init = tree_cons (NULL_TREE, index, init); + } + DECL_INITIAL (idecl) = build (CONSTRUCTOR, interface_array_type, + NULL_TREE, init); + TREE_STATIC (idecl) = 1; + DECL_ARTIFICIAL (idecl) = 1; + DECL_IGNORED_P (idecl) = 1; + interfaces = build1 (ADDR_EXPR, ptr_type_node, idecl); + rest_of_decl_compilation (idecl, (char*) 0, 1, 0); + } + + constant_pool_constructor = build_constants_constructor (); + + START_RECORD_CONSTRUCTOR (temp, object_type_node); +#if 0 + PUSH_FIELD_VALUE (temp, "dtable", NULL_TREE); +#else + PUSH_FIELD_VALUE (temp, "dtable", + build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl)); +#endif + PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node); + FINISH_RECORD_CONSTRUCTOR (temp); + START_RECORD_CONSTRUCTOR (cons, class_type_node); + PUSH_SUPER_VALUE (cons, temp); + PUSH_FIELD_VALUE (cons, "next", null_pointer_node); + PUSH_FIELD_VALUE (cons, "name", + build_utf8_ref (build_internal_class_name (type))); + PUSH_FIELD_VALUE (cons, "accflags", + build_int_2 (get_access_flags_from_decl (type_decl), 0)); + + PUSH_FIELD_VALUE (cons, "superclass", super); + PUSH_FIELD_VALUE (cons, "subclass_head", null_pointer_node); + PUSH_FIELD_VALUE (cons, "subclass_next", null_pointer_node); + PUSH_FIELD_VALUE (cons, "constants", constant_pool_constructor); + PUSH_FIELD_VALUE (cons, "methods", + build1 (ADDR_EXPR, method_ptr_type_node, methods_decl)); + PUSH_FIELD_VALUE (cons, "nmethods", build_int_2 (method_count, 0)); + PUSH_FIELD_VALUE (cons, "msize", 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, "bfsize", size_in_bytes (type)); + PUSH_FIELD_VALUE (cons, "nfields", build_int_2 (field_count, 0)); + PUSH_FIELD_VALUE (cons, "nsfields", build_int_2 (static_field_count, 0)); + /* For now, we let Kaffe fill in the dtable. */ + PUSH_FIELD_VALUE (cons, "dtable", + dtable_decl == NULL_TREE ? null_pointer_node + : build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl)); + PUSH_FIELD_VALUE (cons, "interfaces", interfaces); + PUSH_FIELD_VALUE (cons, "loader", null_pointer_node); + PUSH_FIELD_VALUE (cons, "interface_len", build_int_2 (interface_len, 0)); + PUSH_FIELD_VALUE (cons, "state", + flag_assume_compiled ? integer_four_node + : integer_two_node); + + method = lookup_java_method (type, + finalize_identifier_node, void_signature_node); + PUSH_FIELD_VALUE (cons, "final", + method == NULL ? integer_zero_node : integer_one_node); + + FINISH_RECORD_CONSTRUCTOR (cons); + + DECL_INITIAL (decl) = cons; + rest_of_decl_compilation (decl, (char*) 0, 1, 0); +} + +/* Return 2 if CLASS is compiled by this compilation job; + return 1 if CLASS can otherwise be assumed to be compiled; + 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; +{ + if (TREE_CODE (class) == POINTER_TYPE) + class = TREE_TYPE (class); + if (TREE_CODE (class) != RECORD_TYPE) /* Primitive types are static. */ + return 1; + if (TYPE_ARRAY_P (class)) + return 0; + if (class == current_class) + return 2; + if ((TYPE_LANG_SPECIFIC (class) && TYPE_LANG_SPECIFIC (class)->jcf && + TYPE_LANG_SPECIFIC (class)->jcf->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 + been loaded already. Load it if necessary. This prevent + build_class_ref () from crashing. This should take into + consideration class specified in a multiple class file + command line. FIXME if necessary. */ + + if (!CLASS_LOADED_P (class)) + load_class (class, 1); + return 2; + } + + if (flag_assume_compiled) + { + if (!CLASS_LOADED_P (class)) + load_class (class, 1); + return 1; + } + + return 0; +} + +/* Append the mangled name of TYPE onto OBSTACK. */ + +void +append_gpp_mangled_type (obstack, type) + struct obstack *obstack; + tree type; +{ + char buf[8]; + int len; + char *ptr; + 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 + { + 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. */ + +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; + 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); +} + +/* Pre-pend the TYPE_FIELDS of THIS_CLASS with a dummy FIELD_DECL for the + fields inherited from SUPER_CLASS. */ + +void +push_super_field (this_class, super_class) + tree this_class, super_class; +{ + tree base_decl; + 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; + DECL_SIZE (base_decl) = TYPE_SIZE (super_class); +} + +void +layout_class (this_class) + tree this_class; +{ + tree super_class = CLASSTYPE_SUPER (this_class); + tree handle_type = CLASS_TO_HANDLE_TYPE (this_class); + tree method_decl, field; + tree dtable_count; + int i; + + if (super_class) + { + /* Class seen in source are now complete and can be layed out. + Once layed out, a class seen in the source has its + CLASS_LOADED_P flag set */ + if (CLASS_FROM_SOURCE_P (super_class) && !CLASS_LOADED_P (super_class)) + safe_layout_class (super_class); + if (! CLASS_LOADED_P (super_class)) + load_class (super_class, 1); + if (TREE_CODE (TYPE_SIZE (super_class)) == ERROR_MARK) + { + TYPE_SIZE (this_class) = error_mark_node; + return; + } + dtable_count = TYPE_NVIRTUALS (super_class); + + if (TYPE_SIZE (this_class) == NULL_TREE) + push_super_field (this_class, super_class); + } + else + { + dtable_count = integer_zero_node; + } + + for (field = TYPE_FIELDS (this_class); + field != NULL_TREE; field = TREE_CHAIN (field)) + { + if (FIELD_STATIC (field)) + { + /* Set DECL_ASSEMBLER_NAME to something suitably mangled. */ + DECL_ASSEMBLER_NAME (field) = mangle_static_field (field); + } + } + + layout_type (this_class); + + TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type)); + + for (method_decl = TYPE_METHODS (handle_type), i = 0; + method_decl; method_decl = TREE_CHAIN (method_decl), i++) + { + char *ptr; + char buf[8]; + char *asm_name; + tree method_name = DECL_NAME (method_decl); +#if 1 + /* Remove this once we no longer need old (Kaffe / JDK 1.0) mangling. */ + if (! flag_assume_compiled && METHOD_NATIVE (method_decl)) + { + for (ptr = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); + *ptr; ) + { + int ch = *ptr++; + if (ch == '.') + ch = '_'; + obstack_1grow (&temporary_obstack, (char) ch); + } + obstack_1grow (&temporary_obstack, (char) '_'); + if (method_name == init_identifier_node) + obstack_grow (&temporary_obstack, "INIT", 4); + else + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name)); + } + else +#endif + { + int len; tree arg, arglist, t; + int method_name_needs_escapes = 0; + if (method_name != init_identifier_node) + { + 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); + 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 != NULL_TREE; ) + { + 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 != NULL_TREE && 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); + if (! METHOD_ABSTRACT (method_decl)) + make_function_rtl (method_decl); + obstack_free (&temporary_obstack, asm_name); + + if (method_name == init_identifier_node) + { + char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); + for (ptr = p; *ptr; ) + { + if (*ptr++ == '.') + p = ptr; + } + DECL_NAME (method_decl) = get_identifier (p); + DECL_CONSTRUCTOR_P (method_decl) = 1; + } + else if (! METHOD_STATIC (method_decl)) + { + tree method_sig = build_java_argument_signature (TREE_TYPE (method_decl)); + tree super_method = lookup_argument_method (super_class, method_name, + method_sig); + if (super_method != NULL_TREE) + { + DECL_VINDEX (method_decl) = DECL_VINDEX (super_method); + if (DECL_VINDEX (method_decl) == NULL_TREE) + 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) + && ! CLASS_FINAL (TYPE_NAME (this_class))) + { + DECL_VINDEX (method_decl) = dtable_count; + dtable_count = build_int_2 (1+TREE_INT_CST_LOW (dtable_count), 0); + } + } + } + TYPE_NVIRTUALS (this_class) = dtable_count; + +#ifdef JAVA_USE_HANDLES + layout_type (handle_type); +#endif +} + +static tree registered_class = NULL_TREE; + +void +register_class () +{ + static tree end; + tree node = TREE_OPERAND (build_class_ref (current_class), 0); + tree current = copy_node (node); + + XEXP (DECL_RTL (current), 0) = copy_rtx (XEXP (DECL_RTL(node), 0)); + if (!registered_class) + registered_class = current; + else + TREE_CHAIN (end) = current; + + end = current; +} + +/* Generate a function that gets called at start-up (static contructor) time, + which calls registerClass for all the compiled classes. */ + +void +emit_register_class () +{ + tree decl = getdecls (); + + extern tree get_file_function_name PROTO((int)); + tree init_name = get_file_function_name ('I'); + tree init_type = build_function_type (void_type_node, NULL_TREE); + tree init_decl; + tree t; + + start_sequence (); + 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 */ + extern int flag_inline_functions; + 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)); +} + +void +init_class_processing () +{ + registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "registerClass"); +} |