diff options
Diffstat (limited to 'gcc/java/decl.c')
-rw-r--r-- | gcc/java/decl.c | 1561 |
1 files changed, 1561 insertions, 0 deletions
diff --git a/gcc/java/decl.c b/gcc/java/decl.c new file mode 100644 index 0000000..a12931f --- /dev/null +++ b/gcc/java/decl.c @@ -0,0 +1,1561 @@ +/* Process declarations and variables for the GNU compiler for the + Java(TM) language. + + Copyright (C) 1996, 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. */ + +/* Hacked by Per Bothner <bothner@cygnus.com> February 1996. */ + +#include "config.h" +#include "tree.h" +#include "java-tree.h" +#include "jcf.h" +#include "system.h" + +/* The DECL_MAP is a mapping from (index, type) to a decl node. + If index < max_locals, it is the index of a local variable. + if index >= max_locals, then index-max_locals is a stack slot. + The DECL_MAP mapping is represented as a TREE_VEC whose elements + are a list of decls (VAR_DECL or PARM_DECL) chained by + DECL_LOCAL_SLOT_CHAIN; the index finds the TREE_VEC element, and then + we search the chain for a decl with a matching TREE_TYPE. */ + +tree decl_map; + +/* A list of local variables VAR_DECLs for this method that we have seen + debug information, but we have not reached their starting (byte) PC yet. */ + +tree pending_local_decls = NULL_TREE; + +/* Push a local variable or stack slot into the decl_map, + and assign it an rtl. */ + +tree +push_jvm_slot (index, decl) + int index; + tree decl; +{ + struct rtx_def *rtl = NULL; + tree type = TREE_TYPE (decl); + tree tmp; + + DECL_CONTEXT (decl) = current_function_decl; + layout_decl (decl, 0); + + /* See if we have an appropriate rtl (i.e. same mode) at this index. + If so, we must use it. */ + tmp = TREE_VEC_ELT (decl_map, index); + while (tmp != NULL_TREE) + { + if (TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp))) + rtl = DECL_RTL (tmp); + if (rtl != NULL) + break; + tmp = DECL_LOCAL_SLOT_CHAIN (tmp); + } + if (rtl != NULL) + DECL_RTL (decl) = rtl; + else + { + if (index >= DECL_MAX_LOCALS (current_function_decl)) + DECL_REGISTER (decl) = 1; + expand_decl (decl); + } + + /* Now link the decl into the decl_map. */ + if (DECL_LANG_SPECIFIC (decl) == NULL) + { + DECL_LANG_SPECIFIC (decl) + = (struct lang_decl *) permalloc (sizeof (struct lang_decl_var)); + DECL_LOCAL_START_PC (decl) = 0; + DECL_LOCAL_END_PC (decl) = DECL_CODE_LENGTH (current_function_decl); + DECL_LOCAL_SLOT_NUMBER (decl) = index; + } + DECL_LOCAL_SLOT_CHAIN (decl) = TREE_VEC_ELT (decl_map, index); + TREE_VEC_ELT (decl_map, index) = decl; + return decl; +} + +/* Find a VAR_DECL (or PARM_DECL) at local index INDEX that has type TYPE, + that is valid at PC (or -1 if any pc). + If there is no existing matching decl, allocate one. + If we find a decl with matching modes but different types, + we re-use the rtl, but create a new decl. */ + +tree +find_local_variable (index, type, pc) + int index; + tree type; + int pc; +{ + struct rtx_def *rtl = NULL; + tree decl = TREE_VEC_ELT (decl_map, index); + tree best = NULL_TREE; + while (decl != NULL_TREE) + { + int in_range; + in_range = pc < 0 + || (pc >= DECL_LOCAL_START_PC (decl) + && pc < DECL_LOCAL_END_PC (decl)); + + if ((TREE_TYPE (decl) == type + || (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE + && type == ptr_type_node)) + && in_range) + { + if (best == NULL_TREE + || (TREE_TYPE (decl) == type && TREE_TYPE (best) != type) + || DECL_LOCAL_START_PC (decl) > DECL_LOCAL_START_PC (best) + || DECL_LOCAL_END_PC (decl) < DECL_LOCAL_START_PC (decl)) + best = decl; + } + decl = DECL_LOCAL_SLOT_CHAIN (decl); + } + if (best != NULL_TREE) + return best; + return push_jvm_slot (index, build_decl (VAR_DECL, NULL_TREE, type)); +} + + +/* Same as find_local_index, except that INDEX is a stack index. */ + +tree +find_stack_slot (index, type) + int index; + tree type; +{ + return find_local_variable (index + DECL_MAX_LOCALS (current_function_decl), + type, -1); +} + +struct binding_level + { + /* A chain of _DECL nodes for all variables, constants, functions, + * and typedef types. These are in the reverse of the order supplied. + */ + tree names; + + /* For each level, a list of shadowed outer-level local definitions + to be restored when this level is popped. + Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and + whose TREE_VALUE is its old definition (a kind of ..._DECL node). */ + tree shadowed; + + /* For each level (except not the global one), + a chain of BLOCK nodes for all the levels + that were entered and exited one level down. */ + tree blocks; + + /* The BLOCK node for this level, if one has been preallocated. + If 0, the BLOCK is allocated (if needed) when the level is popped. */ + tree this_block; + + /* The binding level which this one is contained in (inherits from). */ + struct binding_level *level_chain; + + /* 1 means make a BLOCK for this level regardless of all else. + 2 for temporary binding contours created by the compiler. */ + char keep; + + /* Nonzero means make a BLOCK if this level has any subblocks. */ + char keep_if_subblocks; + + /* Nonzero if this level can safely have additional + cleanup-needing variables added to it. */ + char more_cleanups_ok; + char have_cleanups; + + /* The bytecode PC that marks the end of this level. */ + int end_pc; + }; + +#define NULL_BINDING_LEVEL (struct binding_level *) NULL + +/* The binding level currently in effect. */ + +static struct binding_level *current_binding_level; + +/* A chain of binding_level structures awaiting reuse. */ + +static struct binding_level *free_binding_level; + +/* The outermost binding level, for names of file scope. + This is created when the compiler is started and exists + through the entire run. */ + +static struct binding_level *global_binding_level; + +/* Binding level structures are initialized by copying this one. */ + +static struct binding_level clear_binding_level + = {NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, + NULL_BINDING_LEVEL, 0, 0, 0, 0, 1000000000}; + +#if 0 +/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function + that have names. Here so we can clear out their names' definitions + at the end of the function. */ + +static tree named_labels; + +/* A list of LABEL_DECLs from outer contexts that are currently shadowed. */ + +static tree shadowed_labels; +#endif + +int flag_traditional; + +/* Nonzero means unconditionally make a BLOCK for the next level pushed. */ + +static int keep_next_level_flag; + +/* Nonzero means make a BLOCK for the next level pushed + if it has subblocks. */ + +static int keep_next_if_subblocks; + +/* The FUNCTION_DECL for the function currently being compiled, + or 0 if between functions. */ +tree current_function_decl; + +/* The type node for the ordinary character type. */ +tree char_type_node; + +tree object_type_node; +tree object_ptr_type_node; +tree string_type_node; +tree throwable_type_node; + +tree boolean_type_node; + +tree float_type_node; +tree double_type_node; + +/* a VOID_TYPE node. */ + +tree void_type_node; +tree ptr_type_node; +tree return_address_type_node; + +tree integer_type_node; + +tree byte_type_node; +tree short_type_node; +tree int_type_node; +tree long_type_node; + +tree promoted_byte_type_node; +tree promoted_short_type_node; +tree promoted_char_type_node; +tree promoted_boolean_type_node; + +tree unsigned_byte_type_node; +tree unsigned_short_type_node; +tree unsigned_int_type_node; +tree unsigned_long_type_node; + +/* The type for struct methodtable. */ +tree methodtable_type; +tree methodtable_ptr_type; + +tree utf8const_type; +tree utf8const_ptr_type; +tree class_type_node; +tree class_ptr_type; +tree field_type_node; +tree field_ptr_type_node; +tree field_info_union_node; +tree jexception_type; +tree jexception_ptr_type; +tree lineNumberEntry_type; +tree lineNumbers_type; +tree constants_type_node; +tree dtable_type; +tree dtable_ptr_type; +tree method_type_node; +tree method_ptr_type_node; +tree nativecode_ptr_array_type_node; +tree one_elt_array_domain_type; +tree access_flags_type_node; +tree class_dtable_decl; + +/* a node which has tree code ERROR_MARK, and whose type is itself. + All erroneous expressions are replaced with this node. All functions + that accept nodes as arguments should avoid generating error messages + if this node is one of the arguments, since it is undesirable to get + multiple error messages from one error in the input. */ + +tree error_mark_node; + +/* Two expressions that are constants with value zero. + The first is of type `int', the second of type `void *'. */ +tree integer_zero_node; +tree null_pointer_node; + +/* Nodes for boolean constants TRUE and FALSE. */ +tree boolean_true_node, boolean_false_node; + +tree TYPE_identifier_node; +tree init_identifier_node; +tree clinit_identifier_node; +tree finalize_identifier_node; +tree void_signature_node; +tree length_identifier_node; +tree this_identifier_node; +tree super_identifier_node; + +/* References to internal libjava functions we use. */ +tree alloc_object_node; +tree soft_instanceof_node; +tree soft_checkcast_node; +tree soft_initclass_node; +tree soft_newarray_node; +tree soft_anewarray_node; +tree soft_multianewarray_node; +tree soft_badarrayindex_node; +tree throw_node; +tree soft_checkarraystore_node; +tree soft_monitorenter_node; +tree soft_monitorexit_node; +tree soft_lookupinterfacemethod_node; +tree soft_fmod_node; + +/* Build (and pushdecl) a "promoted type" for all standard + types shorter than int. */ + +static tree +push_promoted_type (name, actual_type) + char *name; + tree actual_type; +{ + tree type = make_node (TREE_CODE (actual_type)); +#if 1 + tree in_min = TYPE_MIN_VALUE (int_type_node); + tree in_max = TYPE_MAX_VALUE (int_type_node); +#else + tree in_min = TYPE_MIN_VALUE (actual_type); + tree in_max = TYPE_MAX_VALUE (actual_type); +#endif + TYPE_MIN_VALUE (type) = build_int_2 (TREE_INT_CST_LOW (in_min), + TREE_INT_CST_HIGH (in_min)); + TREE_TYPE (TYPE_MIN_VALUE (type)) = type; + TYPE_MAX_VALUE (type) = build_int_2 (TREE_INT_CST_LOW (in_max), + TREE_INT_CST_HIGH (in_max)); + TREE_TYPE (TYPE_MAX_VALUE (type)) = type; + TYPE_PRECISION (type) = TYPE_PRECISION (int_type_node); + layout_type (type); + pushdecl (build_decl (TYPE_DECL, get_identifier (name), type)); + return type; +} + +/* Nodes for integer constants. */ +tree integer_one_node, integer_two_node, integer_four_node; +tree integer_negative_one_node; + +/* Return a definition for a builtin function named NAME and whose data type + is TYPE. TYPE should be a function type with argument types. + FUNCTION_CODE tells later passes how to compile calls to this function. + See tree.h for its possible values. + + If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME, + the name to be called if we can't opencode the function. */ + +tree +builtin_function (name, type, function_code, library_name) + char *name; + tree type; + enum built_in_function function_code; + char *library_name; +{ + tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + if (library_name) + DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name); + make_decl_rtl (decl, NULL_PTR, 1); + pushdecl (decl); + if (function_code != NOT_BUILT_IN) + { + DECL_BUILT_IN (decl) = 1; + DECL_FUNCTION_CODE (decl) = function_code; + } + return decl; +} + +void +init_decl_processing () +{ + tree field; + tree t; + + current_function_decl = NULL; + current_binding_level = NULL_BINDING_LEVEL; + free_binding_level = NULL_BINDING_LEVEL; + pushlevel (0); /* make the binding_level structure for global names */ + global_binding_level = current_binding_level; + + error_mark_node = make_node (ERROR_MARK); + TREE_TYPE (error_mark_node) = error_mark_node; + + /* Create sizetype first - needed for other types. */ + sizetype = make_unsigned_type (POINTER_SIZE); + size_zero_node = build_int_2 (0, 0); + TREE_TYPE (size_zero_node) = sizetype; + size_one_node = build_int_2 (1, 0); + TREE_TYPE (size_one_node) = sizetype; + + byte_type_node = make_signed_type (8); + pushdecl (build_decl (TYPE_DECL, get_identifier ("byte"), byte_type_node)); + short_type_node = make_signed_type (16); + pushdecl (build_decl (TYPE_DECL, get_identifier ("short"), short_type_node)); + int_type_node = make_signed_type (32); + pushdecl (build_decl (TYPE_DECL, get_identifier ("int"), int_type_node)); + long_type_node = make_signed_type (64); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long"), long_type_node)); + + unsigned_byte_type_node = make_unsigned_type (8); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned byte"), + unsigned_byte_type_node)); + unsigned_short_type_node = make_unsigned_type (16); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned short"), + unsigned_short_type_node)); + unsigned_int_type_node = make_unsigned_type (32); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned int"), + unsigned_int_type_node)); + unsigned_long_type_node = make_unsigned_type (64); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned long"), + unsigned_long_type_node)); + + integer_type_node = int_type_node; + + integer_zero_node = build_int_2 (0, 0); + integer_one_node = build_int_2 (1, 0); + integer_two_node = build_int_2 (2, 0); + integer_four_node = build_int_2 (4, 0); + integer_negative_one_node = build_int_2 (-1, 0); + + void_type_node = make_node (VOID_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("void"), void_type_node)); + layout_type (void_type_node); /* Uses size_zero_node */ + ptr_type_node = build_pointer_type (void_type_node); + t = make_node (VOID_TYPE); + layout_type (t); /* Uses size_zero_node */ + return_address_type_node = build_pointer_type (t); + + null_pointer_node = build_int_2 (0, 0); + TREE_TYPE (null_pointer_node) = ptr_type_node; + +#if 0 + /* Make a type to be the domain of a few array types + whose domains don't really matter. + 200 is small enough that it always fits in size_t + and large enough that it can hold most function names for the + initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */ + short_array_type_node = build_prim_array_type (short_type_node, 200); +#endif + char_type_node = make_node (CHAR_TYPE); + TYPE_PRECISION (char_type_node) = 16; + fixup_unsigned_type (char_type_node); + pushdecl (build_decl (TYPE_DECL, get_identifier ("char"), char_type_node)); + + boolean_type_node = make_node (BOOLEAN_TYPE); + TYPE_PRECISION (boolean_type_node) = 1; + fixup_unsigned_type (boolean_type_node); + pushdecl (build_decl (TYPE_DECL, get_identifier ("boolean"), + boolean_type_node)); + boolean_false_node = TYPE_MIN_VALUE (boolean_type_node); + boolean_true_node = TYPE_MAX_VALUE (boolean_type_node); + + promoted_byte_type_node + = push_promoted_type ("promoted_byte", byte_type_node); + promoted_short_type_node + = push_promoted_type ("promoted_short", short_type_node); + promoted_char_type_node + = push_promoted_type ("promoted_char", char_type_node); + promoted_boolean_type_node + = push_promoted_type ("promoted_boolean", boolean_type_node); + + float_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float_type_node) = 32; + pushdecl (build_decl (TYPE_DECL, get_identifier ("float"), + float_type_node)); + layout_type (float_type_node); + + double_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (double_type_node) = 64; + pushdecl (build_decl (TYPE_DECL, get_identifier ("double"), + double_type_node)); + layout_type (double_type_node); + + object_type_node = lookup_class (get_identifier ("java.lang.Object")); + object_ptr_type_node = promote_type (object_type_node); + string_type_node = lookup_class (get_identifier ("java.lang.String")); + class_type_node = lookup_class (get_identifier ("java.lang.Class")); + throwable_type_node = lookup_class (get_identifier ("java.lang.Throwable")); + + methodtable_type = make_node (RECORD_TYPE); + layout_type (methodtable_type); + pushdecl (build_decl (TYPE_DECL, get_identifier ("methodtable"), + methodtable_type)); + methodtable_ptr_type = build_pointer_type (methodtable_type); + + TYPE_identifier_node = get_identifier ("TYPE"); + init_identifier_node = get_identifier ("<init>"); + clinit_identifier_node = get_identifier ("<clinit>"); + finalize_identifier_node = get_identifier ("finalize"); + void_signature_node = get_identifier ("()V"); + length_identifier_node = get_identifier ("length"); + this_identifier_node = get_identifier ("this"); + super_identifier_node = get_identifier ("super"); + + /* for lack of a better place to put this stub call */ + init_expr_processing(); + + utf8const_type = make_node (RECORD_TYPE); + PUSH_FIELD (utf8const_type, field, "hash", unsigned_short_type_node); + PUSH_FIELD (utf8const_type, field, "length", unsigned_short_type_node); + FINISH_RECORD (utf8const_type); + utf8const_ptr_type = build_pointer_type (utf8const_type); + + constants_type_node = make_node (RECORD_TYPE); + PUSH_FIELD (constants_type_node, field, "size", unsigned_int_type_node); + PUSH_FIELD (constants_type_node, field, "tags", ptr_type_node); + PUSH_FIELD (constants_type_node, field, "data", ptr_type_node); + FINISH_RECORD (constants_type_node); + pushdecl (build_decl (TYPE_DECL, get_identifier ("constants"), + constants_type_node)); + + access_flags_type_node = unsigned_short_type_node; + + dtable_type = make_node (RECORD_TYPE); + dtable_ptr_type = build_pointer_type (dtable_type); + + PUSH_FIELD (object_type_node, field, "dtable", dtable_ptr_type); + PUSH_FIELD (object_type_node, field, "sync_info", ptr_type_node); + for (t = TYPE_FIELDS (object_type_node); t != NULL_TREE; t = TREE_CHAIN (t)) + FIELD_PRIVATE (t) = 1; + FINISH_RECORD (object_type_node); + + class_dtable_decl = build_dtable_decl (class_type_node); + TREE_STATIC (class_dtable_decl) = 1; + DECL_ARTIFICIAL (class_dtable_decl) = 1; + DECL_IGNORED_P (class_dtable_decl) = 1; + rest_of_decl_compilation (class_dtable_decl, (char*) 0, 1, 0); + + field_type_node = make_node (RECORD_TYPE); + field_ptr_type_node = build_pointer_type (field_type_node); + method_type_node = make_node (RECORD_TYPE); + method_ptr_type_node = build_pointer_type (method_type_node); + + set_super_info (0, class_type_node, object_type_node, 0); + set_super_info (0, string_type_node, object_type_node, 0); + class_ptr_type = build_pointer_type (class_type_node); + + PUSH_FIELD (class_type_node, field, "next", class_ptr_type); + PUSH_FIELD (class_type_node, field, "name", utf8const_ptr_type); + PUSH_FIELD (class_type_node, field, "accflags", access_flags_type_node); + PUSH_FIELD (class_type_node, field, "superclass", class_ptr_type); + PUSH_FIELD (class_type_node, field, "subclass_head", class_ptr_type); + PUSH_FIELD (class_type_node, field, "subclass_next", class_ptr_type); + PUSH_FIELD (class_type_node, field, "constants", constants_type_node); + PUSH_FIELD (class_type_node, field, "methods", method_ptr_type_node); + PUSH_FIELD (class_type_node, field, "nmethods", short_type_node); + PUSH_FIELD (class_type_node, field, "msize", short_type_node); + PUSH_FIELD (class_type_node, field, "fields", field_ptr_type_node); + PUSH_FIELD (class_type_node, field, "bfsize", int_type_node); + PUSH_FIELD (class_type_node, field, "nfields", short_type_node); + PUSH_FIELD (class_type_node, field, "nsfields", short_type_node); + PUSH_FIELD (class_type_node, field, "dtable", dtable_ptr_type); + PUSH_FIELD (class_type_node, field, "interfaces", + build_pointer_type (class_ptr_type)); + PUSH_FIELD (class_type_node, field, "loader", ptr_type_node); + PUSH_FIELD (class_type_node, field, "interface_len", short_type_node); + PUSH_FIELD (class_type_node, field, "state", byte_type_node); + PUSH_FIELD (class_type_node, field, "final", byte_type_node); + for (t = TYPE_FIELDS (class_type_node); t != NULL_TREE; t = TREE_CHAIN (t)) + FIELD_PRIVATE (t) = 1; + push_super_field (class_type_node, object_type_node); + FINISH_RECORD (class_type_node); + pushdecl (build_decl (TYPE_DECL, get_identifier ("Class"), class_type_node)); + + field_info_union_node = make_node (UNION_TYPE); + PUSH_FIELD (field_info_union_node, field, "boffset", int_type_node); + PUSH_FIELD (field_info_union_node, field, "addr", ptr_type_node); +#if 0 + PUSH_FIELD (field_info_union_node, field, "idx", unsigned_short_type_node); +#endif + layout_type (field_info_union_node); + + PUSH_FIELD (field_type_node, field, "name", utf8const_ptr_type); + PUSH_FIELD (field_type_node, field, "type", class_ptr_type); + PUSH_FIELD (field_type_node, field, "accflags", access_flags_type_node); + PUSH_FIELD (field_type_node, field, "bsize", unsigned_short_type_node); + PUSH_FIELD (field_type_node, field, "info", field_info_union_node); + FINISH_RECORD (field_type_node); + CLASS_LOADED_P (field_type_node) = 1; + pushdecl (build_decl (TYPE_DECL, get_identifier ("Field"), field_type_node)); + + one_elt_array_domain_type = build_index_type (integer_one_node); + nativecode_ptr_array_type_node + = build_array_type (nativecode_ptr_type_node, one_elt_array_domain_type); + + PUSH_FIELD (dtable_type, field, "class", class_ptr_type); + PUSH_FIELD (dtable_type, field, "methods", nativecode_ptr_array_type_node); + FINISH_RECORD (dtable_type); + pushdecl (build_decl (TYPE_DECL, get_identifier ("dispatchTable"), dtable_type)); + +#define jint_type int_type_node +#define jint_ptr_type ptr_type_node + + jexception_type = make_node (RECORD_TYPE); + PUSH_FIELD (jexception_type, field, "start_pc", ptr_type_node); + PUSH_FIELD (jexception_type, field, "end_pc", ptr_type_node); + PUSH_FIELD (jexception_type, field, "handler_pc", ptr_type_node); + PUSH_FIELD (jexception_type, field, "catch_type", class_ptr_type); + FINISH_RECORD (jexception_type); + pushdecl (build_decl (TYPE_DECL, get_identifier ("jexception"), field_type_node)); + jexception_ptr_type = build_pointer_type (jexception_type); + + lineNumberEntry_type = make_node (RECORD_TYPE); + PUSH_FIELD (lineNumberEntry_type, field, "line_nr", unsigned_short_type_node); + PUSH_FIELD (lineNumberEntry_type, field, "start_pc", ptr_type_node); + FINISH_RECORD (lineNumberEntry_type); + + lineNumbers_type = make_node (RECORD_TYPE); + PUSH_FIELD (lineNumbers_type, field, "length", unsigned_int_type_node); + FINISH_RECORD (lineNumbers_type); + +#define instn_ptr_type_node ptr_type_node /* XXX JH */ + +#define lineNumbers_ptr_type_node build_pointer_type(lineNumbers_type) + + PUSH_FIELD (method_type_node, field, "name", utf8const_ptr_type); + PUSH_FIELD (method_type_node, field, "signature", utf8const_ptr_type); + PUSH_FIELD (method_type_node, field, "accflags", access_flags_type_node); + PUSH_FIELD (method_type_node, field, "ncode", nativecode_ptr_type_node); + FINISH_RECORD (method_type_node); + CLASS_LOADED_P (method_type_node) = 1; + pushdecl (build_decl (TYPE_DECL, get_identifier ("Method"), method_type_node)); + + t = tree_cons (NULL_TREE, class_ptr_type, + build_tree_list (NULL_TREE, int_type_node)); + alloc_object_node = builtin_function ("_Jv_AllocObject", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR); + soft_initclass_node = builtin_function ("_Jv_InitClass", + build_function_type (void_type_node, + t), + NOT_BUILT_IN, NULL_PTR); + t = build_tree_list (NULL_TREE, void_type_node); + throw_node = builtin_function ("_Jv_Throw", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR); + soft_monitorenter_node + = builtin_function ("_Jv_MonitorEnter", + build_function_type (int_type_node, t), + NOT_BUILT_IN, NULL_PTR); + soft_monitorexit_node + = builtin_function ("_Jv_MonitorExit", + build_function_type (int_type_node, t), + NOT_BUILT_IN, NULL_PTR); + + t = tree_cons (NULL_TREE, int_type_node, + build_tree_list (NULL_TREE, int_type_node)); + soft_newarray_node + = builtin_function ("_Jv_NewArray", + build_function_type(ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR ); + + t = tree_cons (NULL_TREE, int_type_node, + tree_cons (NULL_TREE, class_ptr_type, + build_tree_list (NULL_TREE, object_ptr_type_node))); + soft_anewarray_node + = builtin_function ("_Jv_NewObjectArray", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR ); + + t = tree_cons (NULL_TREE, ptr_type_node, + build_tree_list (NULL_TREE, int_type_node)); + soft_multianewarray_node + = builtin_function ("_Jv_NewMultiArray", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR ); + + t = build_function_type (void_type_node, NULL_TREE); + soft_badarrayindex_node + = builtin_function ("_Jv_ThrowBadArrayIndex", t, NOT_BUILT_IN, NULL_PTR ); + TREE_THIS_VOLATILE (soft_badarrayindex_node) = 1; + TREE_SIDE_EFFECTS (soft_badarrayindex_node) = 1; + + t = tree_cons (NULL_TREE, class_ptr_type, + build_tree_list (NULL_TREE, object_ptr_type_node)); + soft_checkcast_node + = builtin_function ("_Jv_CheckCast", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR); + t = tree_cons (NULL_TREE, object_ptr_type_node, + build_tree_list (NULL_TREE, class_ptr_type)); + soft_instanceof_node + = builtin_function ("_Jv_IsInstanceOf", + build_function_type (promoted_boolean_type_node, t), + NOT_BUILT_IN, NULL_PTR); + t = tree_cons (NULL_TREE, object_ptr_type_node, + build_tree_list (NULL_TREE, object_ptr_type_node)); + soft_checkarraystore_node + = builtin_function ("_Jv_CheckArrayStore", + build_function_type (void_type_node, t), + NOT_BUILT_IN, NULL_PTR); + t = tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + build_tree_list (NULL_TREE, ptr_type_node))); + soft_lookupinterfacemethod_node + = builtin_function ("_Jv_LookupInterfaceMethod", + build_function_type(ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR); + t = tree_cons (NULL_TREE, double_type_node, + build_tree_list (NULL_TREE, double_type_node)); + soft_fmod_node + = builtin_function ("__builtin_fmod", + build_function_type (double_type_node, t), + BUILT_IN_FMOD, "fmod"); +#if 0 + t = tree_cons (NULL_TREE, float_type_node, + build_tree_list (NULL_TREE, float_type_node)); + soft_fmodf_node + = builtin_function ("__builtin_fmodf", + build_function_type (float_type_node, t), + BUILT_IN_FMOD, "fmodf"); +#endif + + init_class_processing (); +} + + +/* Look up NAME in the current binding level and its superiors + in the namespace of variables, functions and typedefs. + Return a ..._DECL node of some kind representing its definition, + or return 0 if it is undefined. */ + +tree +lookup_name (name) + tree name; +{ + register tree val; + if (current_binding_level != global_binding_level + && IDENTIFIER_LOCAL_VALUE (name)) + val = IDENTIFIER_LOCAL_VALUE (name); + else + val = IDENTIFIER_GLOBAL_VALUE (name); + return val; +} + +/* Similar to `lookup_name' but look only at current binding level and + the previous one if its the parameter level. */ + +tree +lookup_name_current_level (name) + tree name; +{ + register tree t; + + if (current_binding_level == global_binding_level) + return IDENTIFIER_GLOBAL_VALUE (name); + + if (IDENTIFIER_LOCAL_VALUE (name) == 0) + return 0; + + for (t = current_binding_level->names; t; t = TREE_CHAIN (t)) + if (DECL_NAME (t) == name) + break; + + return t; +} + +/* Use a binding level to record a labeled block declaration */ + +void +push_labeled_block (lb) + tree lb; +{ + register tree name = DECL_NAME (LABELED_BLOCK_LABEL (lb)); + register struct binding_level *b = current_binding_level; + tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); + if (oldlocal != 0) + b->shadowed = tree_cons (name, oldlocal, b->shadowed); + TREE_CHAIN (lb) = b->names; + b->names = lb; + IDENTIFIER_LOCAL_VALUE (name) = lb; +} + +/* Pop the current binding level, reinstalling values for the previous + labeled block */ + +void +pop_labeled_block () +{ + struct binding_level *b = current_binding_level; + tree label = b->names; + IDENTIFIER_LOCAL_VALUE (DECL_NAME (LABELED_BLOCK_LABEL (label))) = + NULL_TREE; + if (b->shadowed) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (b->shadowed)) = + TREE_VALUE (b->shadowed); + + /* Pop the current level, and free the structure for reuse. */ + current_binding_level = current_binding_level->level_chain; + b->level_chain = free_binding_level; + free_binding_level = b; +} + +/* Record a decl-node X as belonging to the current lexical scope. + Check for errors (such as an incompatible declaration for the same + name already seen in the same scope). + + Returns either X or an old decl for the same name. + If an old decl is returned, it may have been smashed + to agree with what X says. */ + +tree +pushdecl (x) + tree x; +{ + register tree t; + register tree name = DECL_NAME (x); + register struct binding_level *b = current_binding_level; + + DECL_CONTEXT (x) = current_function_decl; + if (name) + { + char *file; + int line; + int different_binding_level = 0; + + t = lookup_name_current_level (name); + if (t != 0 && t == error_mark_node) + /* error_mark_node is 0 for a while during initialization! */ + { + t = 0; + error_with_decl (x, "`%s' used prior to declaration"); + } + + if (t != 0) + { + file = DECL_SOURCE_FILE (t); + line = DECL_SOURCE_LINE (t); + } + + /* If we're naming a hitherto-unnamed type, set its TYPE_NAME + to point to the TYPE_DECL. + Since Java does not have typedefs, a type can only have + one (true) name, given by a class, interface, or builtin. */ + if (TREE_CODE (x) == TYPE_DECL + && TYPE_NAME (TREE_TYPE (x)) == 0 + && TREE_TYPE (x) != error_mark_node) + { + TYPE_NAME (TREE_TYPE (x)) = x; + TYPE_STUB_DECL (TREE_TYPE (x)) = x; + } + + /* This name is new in its binding level. + Install the new declaration and return it. */ + if (b == global_binding_level) + { + /* Install a global value. */ + + IDENTIFIER_GLOBAL_VALUE (name) = x; + } + else + { + /* Here to install a non-global value. */ + tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); + tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name); + IDENTIFIER_LOCAL_VALUE (name) = x; + +#if 0 + /* Warn if shadowing an argument at the top level of the body. */ + if (oldlocal != 0 && !DECL_EXTERNAL (x) + /* This warning doesn't apply to the parms of a nested fcn. */ + && ! current_binding_level->parm_flag + /* Check that this is one level down from the parms. */ + && current_binding_level->level_chain->parm_flag + /* Check that the decl being shadowed + comes from the parm level, one level up. */ + && chain_member (oldlocal, current_binding_level->level_chain->names)) + { + if (TREE_CODE (oldlocal) == PARM_DECL) + pedwarn ("declaration of `%s' shadows a parameter", + IDENTIFIER_POINTER (name)); + else + pedwarn ("declaration of `%s' shadows a symbol from the parameter list", + IDENTIFIER_POINTER (name)); + } + + /* Maybe warn if shadowing something else. */ + else if (warn_shadow && !DECL_EXTERNAL (x) + /* No shadow warnings for internally generated vars. */ + && DECL_SOURCE_LINE (x) != 0 + /* No shadow warnings for vars made for inlining. */ + && ! DECL_FROM_INLINE (x)) + { + char *warnstring = 0; + + if (TREE_CODE (x) == PARM_DECL + && current_binding_level->level_chain->parm_flag) + /* Don't warn about the parm names in function declarator + within a function declarator. + It would be nice to avoid warning in any function + declarator in a declaration, as opposed to a definition, + but there is no way to tell it's not a definition. */ + ; + else if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL) + warnstring = "declaration of `%s' shadows a parameter"; + else if (oldlocal != 0) + warnstring = "declaration of `%s' shadows previous local"; + else if (IDENTIFIER_GLOBAL_VALUE (name) != 0 + && IDENTIFIER_GLOBAL_VALUE (name) != error_mark_node) + warnstring = "declaration of `%s' shadows global declaration"; + + if (warnstring) + warning (warnstring, IDENTIFIER_POINTER (name)); + } +#endif + + /* If storing a local value, there may already be one (inherited). + If so, record it for restoration when this binding level ends. */ + if (oldlocal != 0) + b->shadowed = tree_cons (name, oldlocal, b->shadowed); + } + } + + /* Put decls on list in reverse order. + We will reverse them later if necessary. */ + TREE_CHAIN (x) = b->names; + b->names = x; + + return x; +} +void +pushdecl_force_head (x) + tree x; +{ + current_binding_level->names = x; +} + +/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate. */ + +tree +pushdecl_top_level (x) + tree x; +{ + register tree t; + register struct binding_level *b = current_binding_level; + + current_binding_level = global_binding_level; + t = pushdecl (x); + current_binding_level = b; + return t; +} + +/* Nonzero if we are currently in the global binding level. */ + +int +global_bindings_p () +{ + return current_binding_level == global_binding_level; +} + +/* Return the list of declarations of the current level. + Note that this list is in reverse order unless/until + you nreverse it; and when you do nreverse it, you must + store the result back using `storedecls' or you will lose. */ + +tree +getdecls () +{ + return current_binding_level->names; +} + +/* Create a new `struct binding_level'. */ + +static +struct binding_level * +make_binding_level () +{ + /* NOSTRICT */ + return (struct binding_level *) xmalloc (sizeof (struct binding_level)); +} + +void +pushlevel (unused) + int unused; +{ + register struct binding_level *newlevel = NULL_BINDING_LEVEL; + +#if 0 + /* If this is the top level of a function, + just make sure that NAMED_LABELS is 0. */ + + if (current_binding_level == global_binding_level) + named_labels = 0; +#endif + + /* Reuse or create a struct for this binding level. */ + + if (free_binding_level) + { + newlevel = free_binding_level; + free_binding_level = free_binding_level->level_chain; + } + else + { + newlevel = make_binding_level (); + } + + /* Add this level to the front of the chain (stack) of levels that + are active. */ + + *newlevel = clear_binding_level; + newlevel->level_chain = current_binding_level; + current_binding_level = newlevel; + newlevel->keep = keep_next_level_flag; + keep_next_level_flag = 0; + newlevel->keep_if_subblocks = keep_next_if_subblocks; + keep_next_if_subblocks = 0; +} + +/* Exit a binding level. + Pop the level off, and restore the state of the identifier-decl mappings + that were in effect when this level was entered. + + If KEEP is nonzero, this level had explicit declarations, so + and create a "block" (a BLOCK node) for the level + to record its declarations and subblocks for symbol table output. + + If FUNCTIONBODY is nonzero, this level is the body of a function, + so create a block as if KEEP were set and also clear out all + label names. + + If REVERSE is nonzero, reverse the order of decls before putting + them into the BLOCK. */ + +tree +poplevel (keep, reverse, functionbody) + int keep; + int reverse; + int functionbody; +{ + register tree link; + /* The chain of decls was accumulated in reverse order. + Put it into forward order, just for cleanliness. */ + tree decls; + tree subblocks = current_binding_level->blocks; + tree block = 0; + tree decl; + int block_previously_created; + + keep |= current_binding_level->keep; + + /* Get the decls in the order they were written. + Usually current_binding_level->names is in reverse order. + But parameter decls were previously put in forward order. */ + + if (reverse) + current_binding_level->names + = decls = nreverse (current_binding_level->names); + else + decls = current_binding_level->names; + + /* Output any nested inline functions within this block + if they weren't already output. */ + + for (decl = decls; decl; decl = TREE_CHAIN (decl)) + if (TREE_CODE (decl) == FUNCTION_DECL + && ! TREE_ASM_WRITTEN (decl) + && DECL_INITIAL (decl) != 0 + && TREE_ADDRESSABLE (decl)) + { + /* If this decl was copied from a file-scope decl + on account of a block-scope extern decl, + propagate TREE_ADDRESSABLE to the file-scope decl. + + DECL_ABSTRACT_ORIGIN can be set to itself if warn_return_type is + true, since then the decl goes through save_for_inline_copying. */ + if (DECL_ABSTRACT_ORIGIN (decl) != 0 + && DECL_ABSTRACT_ORIGIN (decl) != decl) + TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; + else + { + push_function_context (); + output_inline_function (decl); + pop_function_context (); + } + } + + /* If there were any declarations in that level, + or if this level is a function body, + create a BLOCK to record them for the life of this function. */ + + block = 0; + block_previously_created = (current_binding_level->this_block != 0); + if (block_previously_created) + block = current_binding_level->this_block; + else if (keep || functionbody + || (current_binding_level->keep_if_subblocks && subblocks != 0)) + block = make_node (BLOCK); + if (block != 0) + { + BLOCK_VARS (block) = decls; + BLOCK_TYPE_TAGS (block) = NULL_TREE; + BLOCK_SUBBLOCKS (block) = subblocks; + remember_end_note (block); + } + + /* In each subblock, record that this is its superior. */ + + for (link = subblocks; link; link = TREE_CHAIN (link)) + BLOCK_SUPERCONTEXT (link) = block; + + /* Clear out the meanings of the local variables of this level. */ + + for (link = decls; link; link = TREE_CHAIN (link)) + { + tree name = DECL_NAME (link); + if (name != 0 && IDENTIFIER_LOCAL_VALUE (name) == link) + { + /* If the ident. was used or addressed via a local extern decl, + don't forget that fact. */ + if (DECL_EXTERNAL (link)) + { + if (TREE_USED (link)) + TREE_USED (name) = 1; + if (TREE_ADDRESSABLE (link)) + TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1; + } + IDENTIFIER_LOCAL_VALUE (name) = 0; + } + } + + /* Restore all name-meanings of the outer levels + that were shadowed by this level. */ + + for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + + /* If the level being exited is the top level of a function, + check over all the labels, and clear out the current + (function local) meanings of their names. */ + + if (functionbody) + { + /* If this is the top level block of a function, + the vars are the function's parameters. + Don't leave them in the BLOCK because they are + found in the FUNCTION_DECL instead. */ + + BLOCK_VARS (block) = 0; + + /* Clear out the definitions of all label names, + since their scopes end here, + and add them to BLOCK_VARS. */ + +#if 0 + for (link = named_labels; link; link = TREE_CHAIN (link)) + { + register tree label = TREE_VALUE (link); + + if (DECL_INITIAL (label) == 0) + { + error_with_decl (label, "label `%s' used but not defined"); + /* Avoid crashing later. */ + define_label (input_filename, lineno, + DECL_NAME (label)); + } + else if (warn_unused && !TREE_USED (label)) + warning_with_decl (label, "label `%s' defined but not used"); + IDENTIFIER_LABEL_VALUE (DECL_NAME (label)) = 0; + + /* Put the labels into the "variables" of the + top-level block, so debugger can see them. */ + TREE_CHAIN (label) = BLOCK_VARS (block); + BLOCK_VARS (block) = label; + } +#endif + } + + /* Pop the current level, and free the structure for reuse. */ + + { + register struct binding_level *level = current_binding_level; + current_binding_level = current_binding_level->level_chain; + + level->level_chain = free_binding_level; + free_binding_level = level; + } + + /* Dispose of the block that we just made inside some higher level. */ + if (functionbody) + DECL_INITIAL (current_function_decl) = block; + else if (block) + { + if (!block_previously_created) + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); + } + /* If we did not make a block for the level just exited, + any blocks made for inner levels + (since they cannot be recorded as subblocks in that level) + must be carried forward so they will later become subblocks + of something else. */ + else if (subblocks) + current_binding_level->blocks + = chainon (current_binding_level->blocks, subblocks); + + /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this + binding contour so that they point to the appropriate construct, i.e. + either to the current FUNCTION_DECL node, or else to the BLOCK node + we just constructed. + + Note that for tagged types whose scope is just the formal parameter + list for some function type specification, we can't properly set + their TYPE_CONTEXTs here, because we don't have a pointer to the + appropriate FUNCTION_TYPE node readily available to us. For those + cases, the TYPE_CONTEXTs of the relevant tagged type nodes get set + in `grokdeclarator' as soon as we have created the FUNCTION_TYPE + node which will represent the "scope" for these "parameter list local" + tagged types. + */ + + if (block) + TREE_USED (block) = 1; + return block; +} + +void +maybe_pushlevels (pc) + int pc; +{ + while (pending_local_decls != NULL_TREE && + DECL_LOCAL_START_PC (pending_local_decls) <= pc) + { + tree *ptr = &pending_local_decls; + tree decl = *ptr; + int end_pc = DECL_LOCAL_END_PC (decl); + + while (*ptr != NULL_TREE + && DECL_LOCAL_START_PC (*ptr) <= pc + && DECL_LOCAL_END_PC (*ptr) == end_pc) + ptr = &TREE_CHAIN (*ptr); + pending_local_decls = *ptr; + *ptr = NULL_TREE; + + /* Force non-nested range to be nested in current range. */ + if (end_pc > current_binding_level->end_pc) + end_pc = current_binding_level->end_pc; + + pushlevel (1); + expand_start_bindings (0); + current_binding_level->end_pc = end_pc; + + current_binding_level->names = decl; + for ( ; decl != NULL_TREE; decl = TREE_CHAIN (decl)) + { + push_jvm_slot (DECL_LOCAL_SLOT_NUMBER (decl), decl); + } + } +} + +void +maybe_poplevels (pc) + int pc; +{ + while (current_binding_level->end_pc <= pc) + { + expand_end_bindings (getdecls (), 1, 0); + poplevel (1, 0, 0); + } +} + +/* Insert BLOCK at the end of the list of subblocks of the + current binding level. This is used when a BIND_EXPR is expanded, + to handle the BLOCK node inside the BIND_EXPR. */ + +void +insert_block (block) + tree block; +{ + TREE_USED (block) = 1; + abort (); + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); +} + +/* Set the BLOCK node for the innermost scope + (the one we are currently in). */ + +void +set_block (block) + register tree block; +{ + current_binding_level->this_block = block; +} + +/* integrate_decl_tree calls this function. */ + +void +copy_lang_decl (node) + tree node; +{ + int lang_decl_size + = TREE_CODE (node) == VAR_DECL ? sizeof (struct lang_decl_var) + : sizeof (struct lang_decl); + struct lang_decl *x = (struct lang_decl *) oballoc (lang_decl_size); + bcopy (DECL_LANG_SPECIFIC (node), x, lang_decl_size); + DECL_LANG_SPECIFIC (node) = x; +} + +/* If DECL has a cleanup, build and return that cleanup here. + This is a callback called by expand_expr. */ + +tree +maybe_build_cleanup (decl) + tree decl; +{ + /* There are no cleanups in Java (I think). */ + return NULL_TREE; +} + +void +give_name_to_locals (jcf) + JCF *jcf; +{ + int i, n = DECL_LOCALVARIABLES_OFFSET (current_function_decl); + tree parm; + pending_local_decls = NULL_TREE; + if (n == 0) + return; + JCF_SEEK (jcf, n); + n = JCF_readu2 (jcf); + for (i = 0; i < n; i++) + { + int start_pc = JCF_readu2 (jcf); + int length = JCF_readu2 (jcf); + int name_index = JCF_readu2 (jcf); + int signature_index = JCF_readu2 (jcf); + int slot = JCF_readu2 (jcf); + tree name = get_name_constant (jcf, name_index); + tree type = promote_type (parse_signature (jcf, signature_index)); + if (slot < DECL_ARG_SLOT_COUNT (current_function_decl) + && start_pc == 0 + && length == DECL_CODE_LENGTH (current_function_decl)) + { + tree decl = TREE_VEC_ELT (decl_map, slot); + DECL_NAME (decl) = name; + DECL_ASSEMBLER_NAME (decl) = name; + if (TREE_CODE (decl) != PARM_DECL || TREE_TYPE (decl) != type) + warning ("bad type in parameter debug info"); + } + else + { + tree *ptr; + int end_pc = start_pc + length; + tree decl = build_decl (VAR_DECL, name, type); + if (end_pc > DECL_CODE_LENGTH (current_function_decl)) + { + warning_with_decl (decl, + "bad PC range for debug info for local `%s'"); + end_pc = DECL_CODE_LENGTH (current_function_decl); + } + DECL_LANG_SPECIFIC (decl) + = (struct lang_decl *) permalloc (sizeof (struct lang_decl_var)); + DECL_LOCAL_SLOT_NUMBER (decl) = slot; + DECL_LOCAL_START_PC (decl) = start_pc; + DECL_LOCAL_END_PC (decl) = end_pc; + + /* Now insert the new decl in the proper place in + pending_local_decls. We are essentially doing an insertion sort, + which works fine, since the list input will normally already + be sorted. */ + ptr = &pending_local_decls; + while (*ptr != NULL_TREE + && (DECL_LOCAL_START_PC (*ptr) > start_pc + || (DECL_LOCAL_START_PC (*ptr) == start_pc + && DECL_LOCAL_END_PC (*ptr) < end_pc))) + ptr = &TREE_CHAIN (*ptr); + TREE_CHAIN (decl) = *ptr; + *ptr = decl; + } + } + + pending_local_decls = nreverse (pending_local_decls); + + /* Fill in default names for the parameters. */ + for (parm = DECL_ARGUMENTS (current_function_decl), i = 0; + parm != NULL_TREE; parm = TREE_CHAIN (parm), i++) + { + if (DECL_NAME (parm) == NULL_TREE) + { + int arg_i = METHOD_STATIC (current_function_decl) ? i+1 : i; + if (arg_i == 0) + DECL_NAME (parm) = get_identifier ("this"); + else + { + char buffer[12]; + sprintf (buffer, "ARG_%d", arg_i); + DECL_NAME (parm) = get_identifier (buffer); + } + DECL_ASSEMBLER_NAME (parm) = DECL_NAME (parm); + } + } +} + +void +complete_start_java_method (fndecl) + tree fndecl; +{ + + DECL_RESULT (fndecl) = build_decl (RESULT_DECL, NULL_TREE, + TREE_TYPE (TREE_TYPE (fndecl))); + + if (! flag_emit_class_files) + { + /* Initialize the RTL code for the function. */ + init_function_start (fndecl, input_filename, lineno); + + /* Set up parameters and prepare for return, for the function. */ + expand_function_start (fndecl, 0); + } + + /* Allocate further tree nodes temporarily during compilation + of this function only. */ + temporary_allocation (); + +#if 0 + /* If this fcn was already referenced via a block-scope `extern' decl (or + an implicit decl), propagate certain information about the usage. */ + if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl))) + TREE_ADDRESSABLE (current_function_decl) = 1; + +#endif + + if (METHOD_SYNCHRONIZED (fndecl)) + { + /* FIXME: surround the function body by a try/finally set. */ + } + + /* Push local variables. Function compiled from source code are + using a different local variables management, and for them, + pushlevel shouldn't be called from here. */ + if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (fndecl))) + + { + pushlevel (2); + if (! flag_emit_class_files) + expand_start_bindings (1); + } +} + +void +start_java_method (fndecl) + tree fndecl; +{ + tree tem, *ptr; + int i; + + current_function_decl = fndecl; + announce_function (fndecl); + + i = DECL_MAX_LOCALS(fndecl) + DECL_MAX_STACK(fndecl); + decl_map = make_tree_vec (i); + type_map = (tree *) oballoc (i * sizeof (tree)); + + pushlevel (1); /* Push parameters. */ + + ptr = &DECL_ARGUMENTS (fndecl); + for (tem = TYPE_ARG_TYPES (TREE_TYPE (fndecl)), i = 0; + tem != NULL_TREE; tem = TREE_CHAIN (tem), i++) + { + tree parm_name = NULL_TREE, parm_decl; + if (i >= DECL_MAX_LOCALS(fndecl)) + fatal ("function has more parameters than local slots"); + + parm_decl = build_decl (PARM_DECL, parm_name, TREE_VALUE (tem)); + DECL_CONTEXT (parm_decl) = fndecl; + DECL_ARG_TYPE (parm_decl) = TREE_TYPE (parm_decl); + + *ptr = parm_decl; + ptr = &TREE_CHAIN (parm_decl); + + /* Add parm_decl to the decl_map. */ + push_jvm_slot (i, parm_decl); + + type_map[i] = TREE_TYPE (parm_decl); + if (TYPE_IS_WIDE (TREE_TYPE (parm_decl))) + { + i++; + type_map[i] = void_type_node; + } + } + *ptr = NULL_TREE; + DECL_ARG_SLOT_COUNT (current_function_decl) = i; + + while (i < DECL_MAX_LOCALS(fndecl)) + type_map[i++] = NULL_TREE; + + complete_start_java_method (fndecl); +} + +void +end_java_method () +{ + tree fndecl = current_function_decl; + + expand_end_bindings (getdecls (), 1, 0); + /* pop out of function */ + poplevel (1, 1, 0); + + /* pop out of its parameters */ + poplevel (1, 0, 1); + + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + emit_handlers (); + + /* Generate rtl for function exit. */ + expand_function_end (input_filename, lineno, 0); + + /* Run the optimizers and output assembler code for this function. */ + rest_of_compilation (fndecl); + + current_function_decl = NULL_TREE; + permanent_allocation (1); +} + +tree +build_decl_no_layout (code, name, type) + enum tree_code code; + tree name, type; +{ + tree decl = build_decl (TYPE_DECL, name, type); + TREE_SET_CODE (decl, code); + return decl; +} |