Wed Oct 28 08:03:31 1998 Alexandre Petit-Bianco <apbianco@cygnus.com> * class.c (layout_class): Don't mangle <finit>, produce __finit<class> instead. Don't verify artificial methods. * decl.c (finit_identifier_node): New declared global. (init_decl_processing): finit_identifier_node initialized. * java-tree.def (CONDITIONAL_EXPR): New Java tree code. * java-tree.h (finit_identifier_node): Declared as extern. (struct lang_decl): New field called_constructor. (DECL_CONSTRUCTOR_CALLS): Access macro to called_constructor. (CLASS_HAS_FINIT_P): New macro. (CALL_CONSTRUCTOR_P): Leading comment changed. Macro now checks explicit constructor invocation. (CALL_EXPLICIT_CONSTRUCTOR_P, CALL_THIS_CONSTRUCTOR_P, CALL_SUPER_CONSTRUCTOR_P): New macros. (write_classfile): Added prototype. * jcf-parse.c (jcf_parse_source): Parse and remember for generation if the file was seen on the command line. (parse_source_file): Don't write the class file here. (yyparse): Loop on files rewritten. Set current_jcf. (parse_zip_file_entries): Parse class file only if it was found. * lang.c (init_parse): Don't open command line provided filename here. (lang_parse): Don't set main_jcf anymore. * parse.h (ABSTRAC_CHECK): Capitalized arguments. (JCONSTRUCTOR_CHECK): New macro. (JBSC_TYPE_P): New macro. (IN_TRY_BLOCK_P, EXCEPTIONS_P): Fixed leading comment. (COMPLETE_CHECK_OP_2): New macro. (struct parse_ctxt): New field explicit_constructor_p. (check_class_interface_creation): Fixed prototype indentation. (patch_method_invocation_stmt): Prototype reflects added argument. (patch_invoke): Likewise. (complete_method_declaration, build_super_invocation, verify_constructor_circularity, build_this_super_qualified_invocation, get_printable_method_name, patch_conditional_expr, maybe_generate_finit, fix_constructors, verify_constructor_super, create_artificial_method, start_artificial_method_body, end_artificial_method_body, generate_field_initialization_code): New function prototypes. * parse.y: Fixed leading comment (constructor_header:, constructor_body:, block_end:): Rules tagged <node>. (type_declaration:): Call maybe_generate_finit. (method_declaration:): Action for method_body: placed in new function complete_method_declaration, called here. (constructor_declaration:): Defined actions. Removed leading FIXME. (constructor_header:): New rule with action. (constructor_body:): Rule rewritten using block_begin: and block_end:. Defined actions. (constructor_declarator:, explicit_constructor_invocation:): Defined actions. (block:): Use new rules block_begin: block_end:. (block_begin:, block_end:): New rules and actions. (block_statements:): Fixed error message for explicit constructors. (method_invocation:): Call build_this_super_qualified_invocation if primary is `this' or `super' was seen. (conditional_expression:): Action defined. (extra_ctxp_pushed_p): New static global flag. (java_parser_context_save_global): Create parser context if necessary. Use extra_ctxp_pushed_p to remember it. (java_parser_context_restore_global): Pop extra parser context if one exists. (build_array_from_name): Array on primitive types are marked loaded. (register_fields): Restore new name in field initializer expression if type was altered. Non static fields initialized upon declaration marked initialized. (maybe_generate_finit): New function. (maybe_generate_clinit): Use create_artificial_method, start_artificial_method_body, end_artificial_method_body. Generate debug info for enclosed initialization statements. (method_header): Fixed leading comment. Check constructor flags. Detect constructor declarations and set DECL_CONSTRUCTOR_P accordingly. (complete_method_declaration, constructor_circularity_msg, verify_constructor_circularity): New functions. (get_printable_method_name): New function. (check_method_redefinition): Don't rename <finit> methods. Fix declared constructor names. Error message for constructors modified. (java_check_regular_methods): Local variable seen_constructor renamed saw_constructor. Skip verification on constructors. Create default constructor with create_artificial_method. (java_check_methods): Removed unnecessary empty line. (create_artificial_method, start_artificial_method_body, end_artificial_method_body): New functions. (java_layout_classes): Changed leading comment. Reverse fields list if necessary. Always layout java.lang.Object if being defined. (java_complete_expand_methods): Verify constructor circularity. (java_complete_expand_method): Call fix_constructor on constructors. Local variable no_ac_found removed. Restore bindings if method body expansion failed. (fix_constructors, verify_constructor_super, generate_field_initialization_code): New function. (java_expand_classes): Fixed leading comment. Write class file here. (resolve_expression_name): Check for illegal instance variable usage within the argument scope of an explicit constructor invocation. (resolve_qualified_expression_name): Pass extra from_super flag when invoking patch_method_invocation_stmt. New case for conditional expression when used as a primary. Check for error when acquiring super. (patch_method_invocation_stmt): Added extra argument super. New local variable is_static_flag. Set class_to_search according to the nature of the constructor invocation. Don't add `this' argument when expanding NEW_CLASS_EXPR. Check for illegal method invocation within the argument scope of explicit constructor invocation. Set is_static according to is_static_flag. Provide extra `super' argument to patch_invoke invocation. (patch_invoke): New argument from_super. Loop on arguments indentation fixed. Pass from_super to invocation_mode. New switch case INVOKE_SUPER. Fixed error message in switch default case. Don't use CALL_CONSTRUCTOR_P but rather a test on the tree node value. (invocation_mode): Return INVOKE_SUPER mode when appropriate. (lookup_method_invoke): Fixed prototypes in candidates list. Error message takes constructors into account. (find_applicable_accessible_methods_list): Fixed indentation. (qualify_ambiguous_name): Take explicit constructor invocation into account. Deal with a conditional expression as a primary to a method call. (java_complete_tree): Added local wfl_op3. New CONDITIONAL_EXPR case. Added extra argument to patch_method_invocation_stmt. Register calls made to explicit constructor `this'. Don't call save_expr in ARRAY_REF case when emitting class files. Check for illegal use of this when expanding explicit constructor invocation arguments. (complete_function_arguments): Set and reset parser context explicit_constructor_p field value when appropriate. (build_super_invocation, build_this_super_qualified_invocation): New functions. (patch_assignment): Fixed typo. (patch_unaryop): Check on final fields occurs only when a decl exits. (patch_return): Take constructors into account. (patch_conditional_expr): New function. * typeck.c (build_java_signature): Removed unnecessary empty line. This patch implements the conditional operator, fixes the super invokation mode, implements most of what is required for constructors and changes the way source files are handled by the front-end. From-SVN: r23403
1603 lines
47 KiB
C
1603 lines
47 KiB
C
/* 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 "config.h"
|
|
#include "system.h"
|
|
#include "tree.h"
|
|
#include "rtl.h"
|
|
#include "java-tree.h"
|
|
#include "jcf.h"
|
|
#include "obstack.h"
|
|
#include "toplev.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) = build_pointer_type (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);
|
|
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;
|
|
/* Always make field externally visible. This is required so
|
|
that native methods can always access the 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, "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, "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, "size_in_bytes", size_in_bytes (type));
|
|
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));
|
|
/* 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_count", build_int_2 (interface_len, 0));
|
|
PUSH_FIELD_VALUE (cons, "state",
|
|
flag_assume_compiled ? integer_four_node
|
|
: integer_two_node);
|
|
|
|
PUSH_FIELD_VALUE (cons, "thread", null_pointer_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;
|
|
{
|
|
int seen_in_zip;
|
|
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;
|
|
|
|
seen_in_zip = (TYPE_LANG_SPECIFIC (class) && TYPE_LANG_SPECIFIC (class)->jcf
|
|
&& TYPE_LANG_SPECIFIC (class)->jcf->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
|
|
available as a compiled class in the future but may not have
|
|
been loaded already. Load it if necessary. This prevent
|
|
build_class_ref () from crashing. */
|
|
|
|
if (seen_in_zip && !CLASS_LOADED_P (class))
|
|
load_class (class, 1);
|
|
|
|
/* We return 2 for class seen in ZIP and class from files
|
|
belonging to the same compilation unit */
|
|
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
|
|
&& method_name != finit_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);
|
|
if (method_name == finit_identifier_node)
|
|
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 != 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) && !DECL_ARTIFICIAL (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_classes ()
|
|
{
|
|
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, "_Jv_RegisterClass");
|
|
}
|