diff options
author | Andrew Haley <aph@redhat.com> | 2004-07-21 16:03:43 +0000 |
---|---|---|
committer | Andrew Haley <aph@gcc.gnu.org> | 2004-07-21 16:03:43 +0000 |
commit | 00150bf9f31d6a0ec576ead73a315f26b1c31749 (patch) | |
tree | 1785e3e0f34d4daf27613e8a698fd2c59ee721f3 | |
parent | 5d16533a079388246d53311790a4a4b2a16aa6c6 (diff) | |
download | gcc-00150bf9f31d6a0ec576ead73a315f26b1c31749.zip gcc-00150bf9f31d6a0ec576ead73a315f26b1c31749.tar.gz gcc-00150bf9f31d6a0ec576ead73a315f26b1c31749.tar.bz2 |
verify.c (verify_jvm_instructions): Comment change only.
2004-07-20 Andrew Haley <aph@redhat.com>
* verify.c (verify_jvm_instructions): Comment change only.
* typeck.c (build_java_array_type): Add size field to array name.
* java-tree.h (LOCAL_SLOT_P): New.
(update_aliases): Add PC argument.
(pushdecl_function_level): New function.
* java-gimplify.c (java_gimplify_expr): Handle VAR_DECL,
MODIFY_EXPR, and SAVE_EXPR.
(java_gimplify_modify_expr): New function.
* expr.c (push_type_0): Call find_stack_slot() to create temporary.
(expand_iinc): Pass PC to update_aliases().
(STORE_INTERNAL): Likewise.
(process_jvm_instruction): Likewise.
* decl.c (base_decl_map): New variable.
(uniq): New variable.
(update_aliases): Rewrite with more thorough checking.
(debug_variable_p): New function.
(push_jvm_slot): Don't initialize local variable. Don't pushdecl.
(check_local_named_variable): Delete whole function.
(initialize_local_variable): New function.
(check_local_unnamed_variable): Add checks and comments.
(find_local_variable): Rewrite.
(java_replace_reference): New function.
(function_binding_level): New variable.
(pushdecl_function_level): New function.
(maybe_pushlevels): Set DECL_LOCAL_END_PC.
(maybe_pushlevels): Call pushdecl() on each of the new decls.
(start_java_method): Reset uniq. Create base_decl_map. Set
function_binding_level.
(end_java_method): Null unused fields to save memory.
From-SVN: r85009
-rw-r--r-- | gcc/java/ChangeLog | 37 | ||||
-rw-r--r-- | gcc/java/decl.c | 333 | ||||
-rw-r--r-- | gcc/java/expr.c | 12 | ||||
-rw-r--r-- | gcc/java/java-gimplify.c | 43 | ||||
-rw-r--r-- | gcc/java/java-tree.h | 9 | ||||
-rw-r--r-- | gcc/java/typeck.c | 12 | ||||
-rw-r--r-- | gcc/java/verify.c | 4 |
7 files changed, 339 insertions, 111 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index b2322fd..2dc5583 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,40 @@ +2004-07-20 Andrew Haley <aph@redhat.com> + + * verify.c (verify_jvm_instructions): Comment change only. + + * typeck.c (build_java_array_type): Add size field to array name. + + * java-tree.h (LOCAL_SLOT_P): New. + (update_aliases): Add PC argument. + (pushdecl_function_level): New function. + + * java-gimplify.c (java_gimplify_expr): Handle VAR_DECL, + MODIFY_EXPR, and SAVE_EXPR. + (java_gimplify_modify_expr): New function. + + * expr.c (push_type_0): Call find_stack_slot() to create temporary. + (expand_iinc): Pass PC to update_aliases(). + (STORE_INTERNAL): Likewise. + (process_jvm_instruction): Likewise. + + * decl.c (base_decl_map): New variable. + (uniq): New variable. + (update_aliases): Rewrite with more thorough checking. + (debug_variable_p): New function. + (push_jvm_slot): Don't initialize local variable. Don't pushdecl. + (check_local_named_variable): Delete whole function. + (initialize_local_variable): New function. + (check_local_unnamed_variable): Add checks and comments. + (find_local_variable): Rewrite. + (java_replace_reference): New function. + (function_binding_level): New variable. + (pushdecl_function_level): New function. + (maybe_pushlevels): Set DECL_LOCAL_END_PC. + (maybe_pushlevels): Call pushdecl() on each of the new decls. + (start_java_method): Reset uniq. Create base_decl_map. Set + function_binding_level. + (end_java_method): Null unused fields to save memory. + 2004-07-20 Nathan Sidwell <nathan@codesourcery.com> * class.c (add_interface_do): Remove. diff --git a/gcc/java/decl.c b/gcc/java/decl.c index 761ebb2..35a9218 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -57,7 +57,6 @@ static tree lookup_name_current_level (tree); static tree push_promoted_type (const char *, tree); static struct binding_level *make_binding_level (void); static tree create_primitive_vtable (const char *); -static tree check_local_named_variable (tree, tree, int, int *); static tree check_local_unnamed_variable (tree, tree, tree); /* Name of the Cloneable class. */ @@ -76,14 +75,20 @@ tree java_io_serializable_identifier_node; static GTY(()) tree decl_map; +/* The base_decl_map is contains one variable of ptr_type: this is + used to contain every variable of reference type that is ever + stored in a local variable slot. */ + +static GTY(()) tree base_decl_map; + +/* An index used to make temporary identifiers unique. */ +static int uniq; + /* 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. */ static GTY(()) tree pending_local_decls; -/* Push a local variable or stack slot into the decl_map, - and assign it an rtl. */ - #if defined(DEBUG_JAVA_BINDING_LEVELS) int binding_depth = 0; int is_class_level = 0; @@ -99,51 +104,67 @@ indent (void) } #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */ -/* Copy the value in decl into every alias in the same local variable - slot. */ +/* True if decl is a named local variable, i.e. if it is an alias + that's used only for debugging purposes. */ + +static bool +debug_variable_p (tree decl) +{ + if (TREE_CODE (decl) == PARM_DECL) + return false; + + if (LOCAL_SLOT_P (decl)) + return false; + + return true; +} + +/* Copy the value in decl into every live alias in the same local + variable slot. Some of these will be dead stores removed by the + optimizer. */ + void -update_aliases (tree decl, int index) +update_aliases (tree decl, int index, int pc) { - tree tmp = TREE_VEC_ELT (decl_map, index); - tree type = TREE_TYPE (decl); - while (tmp != NULL_TREE) + tree decl_type = TREE_TYPE (decl); + tree tmp; + + if (debug_variable_p (decl)) + abort (); + + for (tmp = TREE_VEC_ELT (decl_map, index); + tmp != NULL_TREE; + tmp = DECL_LOCAL_SLOT_CHAIN (tmp)) { + tree tmp_type = TREE_TYPE (tmp); if (tmp != decl - && ! LOCAL_VAR_OUT_OF_SCOPE_P (tmp) - && TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp))) + && LOCAL_SLOT_P (tmp) == 0 + && (pc == -1 + || (pc >= DECL_LOCAL_START_PC (tmp) + && pc <= DECL_LOCAL_END_PC (tmp))) + && (tmp_type == decl_type + || (INTEGRAL_TYPE_P (tmp_type) + && INTEGRAL_TYPE_P (decl_type) + && TYPE_PRECISION (decl_type) <= 32 + && TYPE_PRECISION (tmp_type) <= 32) + || (TREE_CODE (tmp_type) == POINTER_TYPE + && TREE_CODE (decl_type) == POINTER_TYPE))) { - tree src = build1 (NOP_EXPR, TREE_TYPE (tmp), decl); - java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (tmp), tmp, src)); + tree src = build1 (NOP_EXPR, tmp_type, decl); + if (LOCAL_VAR_OUT_OF_SCOPE_P (tmp)) + abort (); + java_add_stmt + (build (MODIFY_EXPR, tmp_type, tmp, src)); } - tmp = DECL_LOCAL_SLOT_CHAIN (tmp); } } static tree push_jvm_slot (int index, tree decl) { - tree type = TREE_TYPE (decl); - tree tmp; - DECL_CONTEXT (decl) = current_function_decl; layout_decl (decl, 0); - /* Look for another variable of the same mode in this slot. */ - tmp = TREE_VEC_ELT (decl_map, index); - while (tmp != NULL_TREE) - { - if (! LOCAL_VAR_OUT_OF_SCOPE_P (tmp) - && TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp))) - { - /* At the point of its creation this decl inherits whatever - is in the slot. */ - tree src = build1 (NOP_EXPR, TREE_TYPE (decl), tmp); - java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (decl), decl, src)); - break; - } - tmp = DECL_LOCAL_SLOT_CHAIN (tmp); - } - /* Now link the decl into the decl_map. */ if (DECL_LANG_SPECIFIC (decl) == NULL) { @@ -155,31 +176,54 @@ push_jvm_slot (int index, tree decl) DECL_LOCAL_SLOT_CHAIN (decl) = TREE_VEC_ELT (decl_map, index); TREE_VEC_ELT (decl_map, index) = decl; - if (TREE_CODE (decl) != PARM_DECL) - pushdecl (decl); return decl; } -/* Find out if 'decl' passed in fits the defined PC location better than - 'best'. Return decl if it does, return best if it doesn't. If decl - is returned, then updated is set to true. */ +/* At the point of its creation a local variable decl inherits + whatever is already in the same slot. In the case of a local + variable that is declared but unused, we won't find anything. */ -static tree -check_local_named_variable (tree best, tree decl, int pc, int *updated) +static void +initialize_local_variable (tree decl, int index) { - if (pc >= DECL_LOCAL_START_PC (decl) - && pc < DECL_LOCAL_END_PC (decl)) + tree decl_type = TREE_TYPE (decl); + if (TREE_CODE (decl_type) == POINTER_TYPE) { - if (best == NULL_TREE - || (DECL_LOCAL_START_PC (decl) > DECL_LOCAL_START_PC (best) - && DECL_LOCAL_END_PC (decl) < DECL_LOCAL_END_PC (best))) + tree tmp = TREE_VEC_ELT (base_decl_map, index); + + if (tmp) { - *updated = 1; - return decl; + /* At the point of its creation this decl inherits whatever + is in the slot. */ + tree src = build1 (NOP_EXPR, decl_type, tmp); + java_add_stmt + (build (MODIFY_EXPR, decl_type, decl, src)); } } + else + { + tree tmp; - return best; + for (tmp = TREE_VEC_ELT (decl_map, index); + tmp != NULL_TREE; + tmp = DECL_LOCAL_SLOT_CHAIN (tmp)) + { + tree tmp_type = TREE_TYPE (tmp); + if (tmp != decl + && ! debug_variable_p (tmp) + && (tmp_type == decl_type + || (INTEGRAL_TYPE_P (tmp_type) + && INTEGRAL_TYPE_P (decl_type) + && TYPE_PRECISION (decl_type) <= 32 + && TYPE_PRECISION (tmp_type) <= 32 + && TYPE_PRECISION (tmp_type) >= TYPE_PRECISION (decl_type)))) + { + java_add_stmt + (build (MODIFY_EXPR, decl_type, decl, tmp)); + return; + } + } + } } /* Find the best declaration based upon type. If 'decl' fits 'type' better @@ -188,16 +232,25 @@ check_local_named_variable (tree best, tree decl, int pc, int *updated) static tree check_local_unnamed_variable (tree best, tree decl, tree type) { - if (TREE_TYPE (decl) == type - || (TREE_CODE (TREE_TYPE (decl)) == TREE_CODE (type) - && TYPE_PRECISION (TREE_TYPE (decl)) <= 32 + tree decl_type = TREE_TYPE (decl); + + if (LOCAL_VAR_OUT_OF_SCOPE_P (decl)) + abort (); + + /* Use the same decl for all integer types <= 32 bits. This is + necessary because sometimes a value is stored as (for example) + boolean but loaded as int. */ + if (decl_type == type + || (INTEGRAL_TYPE_P (decl_type) + && INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (decl_type) <= 32 && TYPE_PRECISION (type) <= 32 - && TREE_CODE (type) != POINTER_TYPE) + && TYPE_PRECISION (decl_type) >= TYPE_PRECISION (type)) || (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE && type == ptr_type_node)) { if (best == NULL_TREE - || (TREE_TYPE (decl) == type && TREE_TYPE (best) != type)) + || (decl_type == type && TREE_TYPE (best) != type)) return decl; } @@ -210,63 +263,103 @@ check_local_unnamed_variable (tree best, tree decl, tree type) If there is no existing matching decl, allocate one. */ tree -find_local_variable (int index, tree type, int pc) +find_local_variable (int index, tree type, int pc ATTRIBUTE_UNUSED) { - tree decl = TREE_VEC_ELT (decl_map, index); - tree best = NULL_TREE; - int found_scoped_var = 0; + tree tmp = TREE_VEC_ELT (decl_map, index); + tree decl = NULL_TREE; - /* Scan through every declaration that has been created in this slot. */ - while (decl != NULL_TREE) + /* Scan through every declaration that has been created in this + slot. We're only looking for variables that correspond to local + index declarations and PARM_DECLs, not named variables: such + local variables are used only for debugging information. */ + while (tmp != NULL_TREE) { - bool has_name = false; - tree name = DECL_NAME (decl); - if (name && IDENTIFIER_POINTER (name)) - has_name = IDENTIFIER_POINTER (name)[0] != '#'; - - /* Variables created in give_name_to_locals() have a name and have - a specified scope, so we can handle them specifically. We want - to use the specific decls created for those so they are assigned - the right variables in the debugging information. */ - if (has_name) - { - /* This is a variable we have a name for, so it has a scope - supplied in the class file. But it only matters when we - actually have a PC to use. If pc<0, then we are asking - for a stack slot and this decl won't be one of those. */ - if (pc >= 0) - best = check_local_named_variable (best, decl, pc, - &found_scoped_var); - } - /* We scan for type information unless we found a variable in the - proper scope already. */ - else if (!found_scoped_var) - { - /* If we don't have scoping information for a variable, we use - a different method to look it up. */ - best = check_local_unnamed_variable (best, decl, type); - } - - decl = DECL_LOCAL_SLOT_CHAIN (decl); + if (! debug_variable_p (tmp)) + decl = check_local_unnamed_variable (decl, tmp, type); + tmp = DECL_LOCAL_SLOT_CHAIN (tmp); } - if (best != NULL_TREE) - return best; - /* If we don't find a match, create one with the type passed in. - Ths name of the variable is #n#m, which n is the variable index + The name of the variable is #n#m, which n is the variable index in the local variable area and m is a dummy identifier for uniqueness -- multiple variables may share the same local - variable index. */ + variable index. We don't call pushdecl() to push pointer types + into a binding expr because they'll all be replaced by a single + variable that is used for every reference in that local variable + slot. */ + if (! decl) { char buf[64]; tree name; - static int uniq; - sprintf (buf, "#%d#%d", index, uniq++); - name = get_identifier (buf); + sprintf (buf, "#slot#%d#%d", index, uniq++); + name = get_identifier (buf); + decl = build_decl (VAR_DECL, name, type); + DECL_IGNORED_P (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + decl = push_jvm_slot (index, decl); + LOCAL_SLOT_P (decl) = 1; + + if (TREE_CODE (type) != POINTER_TYPE) + pushdecl_function_level (decl); + } - return push_jvm_slot (index, build_decl (VAR_DECL, name, type)); - } + /* As well as creating a local variable that matches the type, we + also create a base variable (of ptr_type) that will hold all its + aliases. */ + if (TREE_CODE (type) == POINTER_TYPE + && ! TREE_VEC_ELT (base_decl_map, index)) + { + char buf[64]; + tree name; + tree base_decl; + sprintf (buf, "#ref#%d#%d", index, uniq++); + name = get_identifier (buf); + base_decl + = TREE_VEC_ELT (base_decl_map, index) + = build_decl (VAR_DECL, name, ptr_type_node); + pushdecl_function_level (base_decl); + DECL_IGNORED_P (base_decl) = 1; + DECL_ARTIFICIAL (base_decl) = 1; + } + + return decl; +} + +/* Called during gimplification for every variable. If the variable + is a temporary of pointer type, replace it with a common variable + thath is used to hold all pointer types that are ever stored in + that slot. Set WANT_LVALUE if you want a variable that is to be + written to. */ + +tree +java_replace_reference (tree var_decl, bool want_lvalue) +{ + tree decl_type; + + if (! base_decl_map) + return var_decl; + + decl_type = TREE_TYPE (var_decl); + + if (TREE_CODE (decl_type) == POINTER_TYPE) + { + if (DECL_LANG_SPECIFIC (var_decl) + && LOCAL_SLOT_P (var_decl)) + { + int index = DECL_LOCAL_SLOT_NUMBER (var_decl); + tree base_decl = TREE_VEC_ELT (base_decl_map, index); + + if (! base_decl) + abort (); + + if (! want_lvalue) + base_decl = build1 (NOP_EXPR, decl_type, base_decl); + + return base_decl; + } + } + + return var_decl; } @@ -331,6 +424,11 @@ static GTY(()) struct binding_level *free_binding_level; static GTY(()) struct binding_level *global_binding_level; +/* The binding level that holds variables declared at the outermost + level within a function body. */ + +static struct binding_level *function_binding_level; + /* A PC value bigger than any PC value we may ever may encounter. */ #define LARGEST_PC (( (unsigned int)1 << (HOST_BITS_PER_INT - 1)) - 1) @@ -1174,6 +1272,20 @@ pushdecl_top_level (tree x) return t; } +/* Like pushdecl, only it places X in FUNCTION_BINDING_LEVEL, if appropriate. */ + +tree +pushdecl_function_level (tree x) +{ + tree t; + struct binding_level *b = current_binding_level; + + current_binding_level = function_binding_level; + t = pushdecl (x); + current_binding_level = b; + return t; +} + /* Nonzero if we are currently in the global binding level. */ int @@ -1497,9 +1609,13 @@ maybe_pushlevels (int pc) pending_local_decls = *ptr; *ptr = NULL_TREE; - /* Force non-nested range to be nested in current range. */ + /* Force non-nested range to be nested in current range by + truncating variable lifetimes. */ if (end_pc > current_binding_level->end_pc) - end_pc = current_binding_level->end_pc; + { + end_pc = current_binding_level->end_pc; + DECL_LOCAL_END_PC (decl) = end_pc; + } maybe_start_try (pc, end_pc); @@ -1512,6 +1628,8 @@ maybe_pushlevels (int pc) { next = TREE_CHAIN (decl); push_jvm_slot (DECL_LOCAL_SLOT_NUMBER (decl), decl); + pushdecl (decl); + initialize_local_variable (decl, DECL_LOCAL_SLOT_NUMBER (decl)); } } @@ -1698,11 +1816,14 @@ start_java_method (tree fndecl) tree tem, *ptr; int i; + uniq = 0; + current_function_decl = fndecl; announce_function (fndecl); i = DECL_MAX_LOCALS(fndecl) + DECL_MAX_STACK(fndecl); decl_map = make_tree_vec (i); + base_decl_map = make_tree_vec (i); type_map = xrealloc (type_map, i * sizeof (tree)); #if defined(DEBUG_JAVA_BINDING_LEVELS) @@ -1751,6 +1872,8 @@ start_java_method (tree fndecl) /* Push local variables. */ pushlevel (2); + + function_binding_level = current_binding_level; } void @@ -1777,6 +1900,14 @@ end_java_method (void) DECL_STRUCT_FUNCTION (fndecl) = NULL; DECL_INITIAL (fndecl) = NULL_TREE; } + if (! flag_unit_at_a_time) + { + /* Nulling these fields when we no longer need them saves + memory. */ + DECL_SAVED_TREE (fndecl) = NULL; + DECL_STRUCT_FUNCTION (fndecl) = NULL; + DECL_INITIAL (fndecl) = NULL_TREE; + } current_function_decl = NULL_TREE; } diff --git a/gcc/java/expr.c b/gcc/java/expr.c index 228c1d1..73e3e81 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -255,6 +255,9 @@ push_type_0 (tree type) n_words = 1 + TYPE_IS_WIDE (type); if (stack_pointer + n_words > DECL_MAX_STACK (current_function_decl)) return 0; + /* Allocate decl for this variable now, so we get a temporary that + survives the whole method. */ + find_stack_slot (stack_pointer, type); stack_type_map[stack_pointer++] = type; n_words--; while (--n_words >= 0) @@ -368,7 +371,7 @@ pop_type (tree type) return type; } -/* Return 1f if SOURCE_TYPE can be safely widened to TARGET_TYPE. +/* Return 1 if SOURCE_TYPE can be safely widened to TARGET_TYPE. Handles array types and interfaces. */ int @@ -1289,7 +1292,7 @@ expand_iinc (unsigned int local_var_index, int ival, int pc) constant_value = build_int_2 (ival, ival < 0 ? -1 : 0); res = fold (build2 (PLUS_EXPR, int_type_node, local_var, constant_value)); java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (local_var), local_var, res)); - update_aliases (local_var, local_var_index); + update_aliases (local_var, local_var_index, pc); } @@ -2758,7 +2761,8 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops, { \ int saw_index = 0; \ int index = OPERAND_VALUE; \ - build_java_ret (find_local_variable (index, ptr_type_node, oldpc)); \ + build_java_ret \ + (find_local_variable (index, return_address_type_node, oldpc)); \ } #define JSR(OPERAND_TYPE, OPERAND_VALUE) \ @@ -2937,7 +2941,7 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops, decl = find_local_variable (index, type, oldpc); \ set_local_type (index, type); \ java_add_stmt (build2 (MODIFY_EXPR, type, decl, value)); \ - update_aliases (decl, index); \ + update_aliases (decl, index, PC); \ } #define STORE(OPERAND_TYPE, OPERAND_VALUE) \ diff --git a/gcc/java/java-gimplify.c b/gcc/java/java-gimplify.c index 64cb7ce..eb277f8 100644 --- a/gcc/java/java-gimplify.c +++ b/gcc/java/java-gimplify.c @@ -37,6 +37,7 @@ static tree java_gimplify_default_expr (tree); static tree java_gimplify_block (tree); static tree java_gimplify_new_array_init (tree); static tree java_gimplify_try_expr (tree); +static tree java_gimplify_modify_expr (tree); static void dump_java_tree (enum tree_dump_index, tree); @@ -117,6 +118,21 @@ java_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED, *expr_p = build_exception_object_ref (TREE_TYPE (*expr_p)); break; + case VAR_DECL: + *expr_p = java_replace_reference (*expr_p, /* want_lvalue */ false); + return GS_UNHANDLED; + + case MODIFY_EXPR: + *expr_p = java_gimplify_modify_expr (*expr_p); + return GS_UNHANDLED; + + case SAVE_EXPR: + if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == VAR_DECL) + TREE_OPERAND (*expr_p, 0) + = java_replace_reference (TREE_OPERAND (*expr_p, 0), + /* want_lvalue */ false); + return GS_UNHANDLED; + /* These should already be lowered before we get here. */ case URSHIFT_EXPR: case COMPARE_EXPR: @@ -140,6 +156,33 @@ java_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED, return GS_OK; } +/* This is specific to the bytecode compiler. If a variable has + LOCAL_SLOT_P set, replace an assignment to it with an assignment to + the corresponding variable that holds all its aliases. */ + +static tree +java_gimplify_modify_expr (tree modify_expr) +{ + tree lhs = TREE_OPERAND (modify_expr, 0); + tree rhs = TREE_OPERAND (modify_expr, 1); + tree lhs_type = TREE_TYPE (lhs); + + if (TREE_CODE (lhs) == VAR_DECL + && DECL_LANG_SPECIFIC (lhs) + && LOCAL_SLOT_P (lhs) + && TREE_CODE (lhs_type) == POINTER_TYPE) + { + tree new_lhs = java_replace_reference (lhs, /* want_lvalue */ true); + tree new_rhs = build1 (NOP_EXPR, TREE_TYPE (new_lhs), rhs); + modify_expr = build (MODIFY_EXPR, TREE_TYPE (new_lhs), + new_lhs, new_rhs); + modify_expr = build1 (NOP_EXPR, lhs_type, modify_expr); + } + + return modify_expr; +} + + static tree java_gimplify_case_expr (tree expr) { diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 5f33ec5..44a2ed9 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -925,6 +925,8 @@ union lang_tree_node /* True if NODE is a variable that is out of scope. */ #define LOCAL_VAR_OUT_OF_SCOPE_P(NODE) \ (DECL_LANG_SPECIFIC (NODE)->u.v.freed) +#define LOCAL_SLOT_P(NODE) \ + (DECL_LANG_SPECIFIC (NODE)->u.v.local_slot) /* Create a DECL_LANG_SPECIFIC if necessary. */ #define MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC(T) \ if (DECL_LANG_SPECIFIC (T) == NULL) \ @@ -1010,7 +1012,8 @@ struct lang_decl_var GTY(()) tree owner; unsigned int final_iud : 1; /* Final initialized upon declaration */ unsigned int cif : 1; /* True: decl is a class initialization flag */ - unsigned int freed; /* Decl is no longer in scope. */ + unsigned int freed : 1; /* Decl is no longer in scope. */ + unsigned int local_slot : 1; /* Decl is a temporary in the stack frame. */ }; /* This is what 'lang_decl' really points to. */ @@ -1176,7 +1179,7 @@ extern void set_java_signature (tree, tree); extern tree build_static_field_ref (tree); extern tree build_address_of (tree); extern tree find_local_variable (int index, tree type, int pc); -extern void update_aliases (tree decl, int index); +extern void update_aliases (tree decl, int index, int pc); extern tree find_stack_slot (int index, tree type); extern tree build_prim_array_type (tree, HOST_WIDE_INT); extern tree build_java_array_type (tree, HOST_WIDE_INT); @@ -1254,6 +1257,8 @@ extern void java_layout_seen_class_methods (void); extern void check_for_initialization (tree, tree); extern tree pushdecl_top_level (tree); +extern tree pushdecl_function_level (tree); +extern tree java_replace_reference (tree, bool); extern int alloc_class_constant (tree); extern void init_expr_processing (void); extern void push_super_field (tree, tree); diff --git a/gcc/java/typeck.c b/gcc/java/typeck.c index 0e6e404..5c38bb8 100644 --- a/gcc/java/typeck.c +++ b/gcc/java/typeck.c @@ -391,9 +391,17 @@ build_java_array_type (tree element_type, HOST_WIDE_INT length) el_name = TYPE_NAME (el_name); if (TREE_CODE (el_name) == TYPE_DECL) el_name = DECL_NAME (el_name); - TYPE_NAME (t) = build_decl (TYPE_DECL, - identifier_subst (el_name, "", '.', '.', "[]"), + { + char suffix[12]; + if (length >= 0) + sprintf (suffix, "[%d]", (int)length); + else + strcpy (suffix, "[]"); + TYPE_NAME (t) + = build_decl (TYPE_DECL, + identifier_subst (el_name, "", '.', '.', suffix), t); + } set_java_signature (t, sig); set_super_info (0, t, object_type_node, 0); diff --git a/gcc/java/verify.c b/gcc/java/verify.c index 8482469..89b9d95 100644 --- a/gcc/java/verify.c +++ b/gcc/java/verify.c @@ -734,8 +734,8 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) handlers. */ prev_eh_ranges = NULL_EH_RANGE; - /* Allocate decl and rtx for this variable now, so if we're not - optimizing, we get a temporary that survives the whole method. */ + /* Allocate decl for this variable now, so we get a temporary +! that survives the whole method. */ find_local_variable (index, type, oldpc); if (TYPE_IS_WIDE (type)) |