8sa1-gcc/gcc/java/class.c
Alexandre Petit-Bianco 22eed1e678 class.c (layout_class): Don't mangle <finit>, produce __finit<class> instead.
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
1998-10-28 05:06:17 -08:00

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");
}