mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-12 00:05:14 +08:00
expr.c (java_array_data_offset): Removed function.
* expr.c (java_array_data_offset): Removed function. (JAVA_ARRAY_LENGTH_OFFSET): Removed macro. (build_java_array_length_access): Obtain "length" value using a COMPONENT_REF, instead of INDIRECT_REF and arithmetic. (build_java_arrayaccess): Correct comment. Access "data" using a COMPONENT_REF, and return an ARRAY_REF instead of an INDIRECT_REF. (build_java_arraystore_check): New function. (expand_java_arraystore): Use build_java_arraystore_check. * parse.y (patch_assignment): Simplify code to insert a store check when lvalue is an ARRAY_REF. Use build_java_arraystore_check. * check-init.c (check_init): Update to reflect that an array length access is now a COMPONENT_REF. * gcj.texi (Code Generation): Improve documentation of -fno-bounds-check. Add documentation for -fno-store-check. * java-tree.h (flag_store_check): Declare. (build_java_arraystore_check): Declare. * lang.c (flag_store_check): Initialize to 1. (lang_f_options): Add store-check option. * jvspec.c: Don't pass store-check option to jvgenmain. * lang-options.h: Add help string for -fno-store-check. From-SVN: r50129
This commit is contained in:
parent
70da1d030d
commit
022dcc4605
@ -1,3 +1,26 @@
|
||||
2002-02-28 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
|
||||
|
||||
* expr.c (java_array_data_offset): Removed function.
|
||||
(JAVA_ARRAY_LENGTH_OFFSET): Removed macro.
|
||||
(build_java_array_length_access): Obtain "length" value using a
|
||||
COMPONENT_REF, instead of INDIRECT_REF and arithmetic.
|
||||
(build_java_arrayaccess): Correct comment. Access "data" using a
|
||||
COMPONENT_REF, and return an ARRAY_REF instead of an INDIRECT_REF.
|
||||
(build_java_arraystore_check): New function.
|
||||
(expand_java_arraystore): Use build_java_arraystore_check.
|
||||
* parse.y (patch_assignment): Simplify code to insert a store check
|
||||
when lvalue is an ARRAY_REF. Use build_java_arraystore_check.
|
||||
* check-init.c (check_init): Update to reflect that an array length
|
||||
access is now a COMPONENT_REF.
|
||||
* gcj.texi (Code Generation): Improve documentation of
|
||||
-fno-bounds-check. Add documentation for -fno-store-check.
|
||||
* java-tree.h (flag_store_check): Declare.
|
||||
(build_java_arraystore_check): Declare.
|
||||
* lang.c (flag_store_check): Initialize to 1.
|
||||
(lang_f_options): Add store-check option.
|
||||
* jvspec.c: Don't pass store-check option to jvgenmain.
|
||||
* lang-options.h: Add help string for -fno-store-check.
|
||||
|
||||
2002-02-28 Neil Booth <neil@daikokuya.demon.co.uk>
|
||||
|
||||
* decl.c (copy_lang_decl): Rename java_dup_lang_specific_decl.
|
||||
@ -20,7 +43,7 @@
|
||||
|
||||
2002-02-22 Per Bothner <per@bothner.com>
|
||||
|
||||
* class.c: Change vtable to be more compatible with g++ v3 abi.
|
||||
* class.c: Change vtable to be more compatible with g++ v3 abi.
|
||||
(get_dispatch_table): Prepend offset-to-top (always 0) and
|
||||
type_info pointer (currently unimplemented hence NULL) to vtable.
|
||||
Specifically, prepend offset-to-top and typeinfo ptr (currently null).
|
||||
|
@ -558,7 +558,7 @@ check_init (exp, before)
|
||||
final_assign_error (DECL_NAME (decl));
|
||||
break;
|
||||
}
|
||||
else if (TREE_CODE (tmp) == INDIRECT_REF && IS_ARRAY_LENGTH_ACCESS (tmp))
|
||||
else if (TREE_CODE (tmp) == COMPONENT_REF && IS_ARRAY_LENGTH_ACCESS (tmp))
|
||||
{
|
||||
/* We can't emit a more specific message here, because when
|
||||
compiling to bytecodes we don't get here. */
|
||||
|
138
gcc/java/expr.c
138
gcc/java/expr.c
@ -79,7 +79,6 @@ static void java_push_constant_from_pool PARAMS ((struct JCF *, int));
|
||||
static void java_stack_pop PARAMS ((int));
|
||||
static tree build_java_throw_out_of_bounds_exception PARAMS ((tree));
|
||||
static tree build_java_check_indexed_type PARAMS ((tree, tree));
|
||||
static tree java_array_data_offset PARAMS ((tree));
|
||||
static tree case_identity PARAMS ((tree, tree));
|
||||
static unsigned char peek_opcode_at_pc PARAMS ((struct JCF *, int, int));
|
||||
static bool emit_init_test_initialization PARAMS ((struct hash_entry *,
|
||||
@ -628,11 +627,6 @@ build_java_ret (location)
|
||||
|
||||
/* Implementation of operations on array: new, load, store, length */
|
||||
|
||||
/* Array core info access macros */
|
||||
|
||||
#define JAVA_ARRAY_LENGTH_OFFSET(A) \
|
||||
byte_position (TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (TREE_TYPE (A)))))
|
||||
|
||||
tree
|
||||
decode_newarray_type (atype)
|
||||
int atype;
|
||||
@ -699,6 +693,7 @@ build_java_array_length_access (node)
|
||||
tree node;
|
||||
{
|
||||
tree type = TREE_TYPE (node);
|
||||
tree array_type = TREE_TYPE (type);
|
||||
HOST_WIDE_INT length;
|
||||
|
||||
if (!is_array_type_p (type))
|
||||
@ -707,13 +702,13 @@ build_java_array_length_access (node)
|
||||
length = java_array_type_length (type);
|
||||
if (length >= 0)
|
||||
return build_int_2 (length, 0);
|
||||
node = build1 (INDIRECT_REF, int_type_node,
|
||||
fold (build (PLUS_EXPR, ptr_type_node,
|
||||
java_check_reference (node,
|
||||
flag_check_references),
|
||||
JAVA_ARRAY_LENGTH_OFFSET(node))));
|
||||
|
||||
node = build (COMPONENT_REF, int_type_node,
|
||||
build_java_indirect_ref (array_type, node,
|
||||
flag_check_references),
|
||||
lookup_field (&array_type, get_identifier ("length")));
|
||||
IS_ARRAY_LENGTH_ACCESS (node) = 1;
|
||||
return fold (node);
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Optionally checks a reference against the NULL pointer. ARG1: the
|
||||
@ -752,19 +747,6 @@ build_java_indirect_ref (type, expr, check)
|
||||
return build1 (INDIRECT_REF, type, java_check_reference (expr, check));
|
||||
}
|
||||
|
||||
static tree
|
||||
java_array_data_offset (array)
|
||||
tree array;
|
||||
{
|
||||
tree array_type = TREE_TYPE (TREE_TYPE (array));
|
||||
tree data_fld = TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (array_type)));
|
||||
|
||||
if (data_fld == NULL_TREE)
|
||||
return size_in_bytes (array_type);
|
||||
else
|
||||
return byte_position (data_fld);
|
||||
}
|
||||
|
||||
/* Implement array indexing (either as l-value or r-value).
|
||||
Returns a tree for ARRAY[INDEX], assume TYPE is the element type.
|
||||
Optionally performs bounds checking and/or test to NULL.
|
||||
@ -774,12 +756,10 @@ tree
|
||||
build_java_arrayaccess (array, type, index)
|
||||
tree array, type, index;
|
||||
{
|
||||
tree arith, node, throw = NULL_TREE;
|
||||
|
||||
arith = fold (build (PLUS_EXPR, int_type_node,
|
||||
java_array_data_offset (array),
|
||||
fold (build (MULT_EXPR, int_type_node,
|
||||
index, size_in_bytes(type)))));
|
||||
tree node, throw = NULL_TREE;
|
||||
tree data_field;
|
||||
tree ref;
|
||||
tree array_type = TREE_TYPE (TREE_TYPE (array));
|
||||
|
||||
if (flag_bounds_check)
|
||||
{
|
||||
@ -803,23 +783,86 @@ build_java_arrayaccess (array, type, index)
|
||||
}
|
||||
}
|
||||
|
||||
/* The SAVE_EXPR is for correct evaluation order. It would be
|
||||
cleaner to use force_evaluation_order (see comment there), but
|
||||
that is difficult when we also have to deal with bounds
|
||||
checking. The SAVE_EXPR is not necessary to do that when we're
|
||||
not checking for array bounds. */
|
||||
if (TREE_SIDE_EFFECTS (index) && throw)
|
||||
throw = build (COMPOUND_EXPR, int_type_node, save_expr (array), throw);
|
||||
/* If checking bounds, wrap the index expr with a COMPOUND_EXPR in order
|
||||
to have the bounds check evaluated first. */
|
||||
if (throw != NULL_TREE)
|
||||
index = build (COMPOUND_EXPR, int_type_node, throw, index);
|
||||
|
||||
data_field = lookup_field (&array_type, get_identifier ("data"));
|
||||
|
||||
node = build1 (INDIRECT_REF, type,
|
||||
fold (build (PLUS_EXPR, ptr_type_node,
|
||||
java_check_reference (array,
|
||||
flag_check_references),
|
||||
(throw ? build (COMPOUND_EXPR, int_type_node,
|
||||
throw, arith ) : arith))));
|
||||
ref = build (COMPONENT_REF, TREE_TYPE (data_field),
|
||||
build_java_indirect_ref (array_type, array,
|
||||
flag_check_references),
|
||||
data_field);
|
||||
|
||||
node = build (ARRAY_REF, type, ref, index);
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Generate code to throw an ArrayStoreException if OBJECT is not assignable
|
||||
(at runtime) to an element of ARRAY. A NOP_EXPR is returned if it can
|
||||
determine that no check is required. */
|
||||
|
||||
tree
|
||||
build_java_arraystore_check (array, object)
|
||||
tree array;
|
||||
tree object;
|
||||
{
|
||||
tree check, element_type;
|
||||
tree array_type_p = TREE_TYPE (array);
|
||||
tree object_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (object)));
|
||||
|
||||
if (! is_array_type_p (array_type_p))
|
||||
abort ();
|
||||
|
||||
/* Get the TYPE_DECL for ARRAY's element type. */
|
||||
element_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (TREE_TYPE (array_type_p))));
|
||||
|
||||
if (TREE_CODE (element_type) != TYPE_DECL
|
||||
|| TREE_CODE (object_type) != TYPE_DECL)
|
||||
abort ();
|
||||
|
||||
if (!flag_store_check)
|
||||
return build1 (NOP_EXPR, array_type_p, array);
|
||||
|
||||
/* No check is needed if the element type is final or is itself an array.
|
||||
Also check that element_type matches object_type, since in the bytecode
|
||||
compilation case element_type may be the actual element type of the arra
|
||||
rather than its declared type. */
|
||||
if (element_type == object_type
|
||||
&& (TYPE_ARRAY_P (TREE_TYPE (element_type))
|
||||
|| CLASS_FINAL (element_type)))
|
||||
return build1 (NOP_EXPR, array_type_p, array);
|
||||
|
||||
/* Avoid the check if OBJECT was just loaded from the same array. */
|
||||
if (TREE_CODE (object) == ARRAY_REF)
|
||||
{
|
||||
tree target;
|
||||
tree source = TREE_OPERAND (object, 0); /* COMPONENT_REF. */
|
||||
source = TREE_OPERAND (source, 0); /* INDIRECT_REF. */
|
||||
source = TREE_OPERAND (source, 0); /* Source array's DECL or SAVE_EXPR. */
|
||||
if (TREE_CODE (source) == SAVE_EXPR)
|
||||
source = TREE_OPERAND (source, 0);
|
||||
|
||||
target = array;
|
||||
if (TREE_CODE (target) == SAVE_EXPR)
|
||||
target = TREE_OPERAND (target, 0);
|
||||
|
||||
if (source == target)
|
||||
return build1 (NOP_EXPR, array_type_p, array);
|
||||
}
|
||||
|
||||
/* Build an invocation of _Jv_CheckArrayStore */
|
||||
check = build (CALL_EXPR, void_type_node,
|
||||
build_address_of (soft_checkarraystore_node),
|
||||
tree_cons (NULL_TREE, array,
|
||||
build_tree_list (NULL_TREE, object)),
|
||||
NULL_TREE);
|
||||
TREE_SIDE_EFFECTS (check) = 1;
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
/* Makes sure that INDEXED_TYPE is appropriate. If not, make it from
|
||||
ARRAY_NODE. This function is used to retrieve something less vague than
|
||||
a pointer type when indexing the first dimension of something like [[<t>.
|
||||
@ -973,12 +1016,7 @@ expand_java_arraystore (rhs_type_node)
|
||||
|
||||
if (TREE_CODE (rhs_type_node) == POINTER_TYPE)
|
||||
{
|
||||
tree check = build (CALL_EXPR, void_type_node,
|
||||
build_address_of (soft_checkarraystore_node),
|
||||
tree_cons (NULL_TREE, array,
|
||||
build_tree_list (NULL_TREE, rhs_node)),
|
||||
NULL_TREE);
|
||||
TREE_SIDE_EFFECTS (check) = 1;
|
||||
tree check = build_java_arraystore_check (array, rhs_node);
|
||||
expand_expr_stmt (check);
|
||||
}
|
||||
|
||||
|
@ -392,9 +392,20 @@ directory.
|
||||
|
||||
@item -fno-bounds-check
|
||||
By default, @code{gcj} generates code which checks the bounds of all
|
||||
array indexing operations. With this option, these checks are omitted.
|
||||
Note that this can result in unpredictable behavior if the code in
|
||||
question actually does violate array bounds constraints.
|
||||
array indexing operations. With this option, these checks are omitted, which
|
||||
can improve performance for code that uses arrays extensively. Note that this
|
||||
can result in unpredictable behavior if the code in question actually does
|
||||
violate array bounds constraints. It is safe to use this option if you are
|
||||
sure that your code will never throw an @code{ArrayIndexOutOfBoundsException}.
|
||||
|
||||
@item -fno-store-check
|
||||
Don't generate array store checks. When storing objects into arrays, a runtime
|
||||
check is normally generated in order to ensure that the object is assignment
|
||||
compatible with the component type of the array (which may not be known
|
||||
at compile-time). With this option, these checks are omitted. This can
|
||||
improve performance for code which stores objects into arrays frequently.
|
||||
It is safe to use this option if you are sure your code will never throw an
|
||||
@code{ArrayStoreException}.
|
||||
|
||||
@item -fjni
|
||||
With @code{gcj} there are two options for writing native methods: CNI
|
||||
|
@ -213,6 +213,9 @@ extern int flag_optimize_sci;
|
||||
in order to improve binary compatibility. */
|
||||
extern int flag_indirect_dispatch;
|
||||
|
||||
/* When zero, don't generate runtime array store checks. */
|
||||
extern int flag_store_check;
|
||||
|
||||
/* Encoding used for source files. */
|
||||
extern const char *current_encoding;
|
||||
|
||||
@ -1107,6 +1110,7 @@ extern tree build_java_binop PARAMS ((enum tree_code, tree, tree, tree));
|
||||
extern tree build_java_soft_divmod PARAMS ((enum tree_code, tree, tree, tree));
|
||||
extern tree binary_numeric_promotion PARAMS ((tree, tree, tree *, tree *));
|
||||
extern tree build_java_arrayaccess PARAMS ((tree, tree, tree));
|
||||
extern tree build_java_arraystore_check PARAMS ((tree, tree));
|
||||
extern tree build_newarray PARAMS ((int, tree));
|
||||
extern tree build_anewarray PARAMS ((tree, tree));
|
||||
extern tree build_new_array PARAMS ((tree, tree));
|
||||
|
@ -66,6 +66,7 @@ static const char jvgenmain_spec[] =
|
||||
%{<femit-class-file} %{<femit-class-files} %{<fencoding*}\
|
||||
%{<fuse-boehm-gc} %{<fhash-synchronization} %{<fjni}\
|
||||
%{<findirect-dispatch} \
|
||||
%{<fno-store-check}\
|
||||
%{<fclasspath*} %{<fCLASSPATH*} %{<foutput-class-dir}\
|
||||
%{<fuse-divide-subroutine} %{<fno-use-divide-subroutine}\
|
||||
%{<fcheck-references} %{<fno-check-references}\
|
||||
|
@ -30,6 +30,8 @@ DEFINE_LANG_NAME ("Java")
|
||||
{ "-fbounds-check", "" },
|
||||
{ "-fno-bounds-check",
|
||||
N_("Disable automatic array bounds checking") },
|
||||
{ "-fno-store-check",
|
||||
N_("Disable assignability checks for stores into object arrays") },
|
||||
{ "-fjni",
|
||||
N_("Assume native functions are implemented using JNI") },
|
||||
{ "--CLASSPATH",
|
||||
@ -54,3 +56,5 @@ DEFINE_LANG_NAME ("Java")
|
||||
N_("Always check for non gcj generated classes archives") },
|
||||
{ "-fno-optimize-static-class-initialization",
|
||||
N_("Never optimize static class initialization code") },
|
||||
{ "-findirect-dispatch",
|
||||
N_("Use offset tables for virtual method calls") },
|
||||
|
@ -157,6 +157,9 @@ int flag_optimize_sci = 1;
|
||||
in order to improve binary compatibility. */
|
||||
int flag_indirect_dispatch = 0;
|
||||
|
||||
/* When zero, don't generate runtime array store checks. */
|
||||
int flag_store_check = 1;
|
||||
|
||||
/* When non zero, print extra version information. */
|
||||
static int version_flag = 0;
|
||||
|
||||
@ -179,7 +182,8 @@ lang_f_options[] =
|
||||
{"check-references", &flag_check_references, 1},
|
||||
{"force-classes-archive-check", &flag_force_classes_archive_check, 1},
|
||||
{"optimize-static-class-initialization", &flag_optimize_sci, 1 },
|
||||
{"indirect-dispatch", &flag_indirect_dispatch, 1}
|
||||
{"indirect-dispatch", &flag_indirect_dispatch, 1},
|
||||
{"store-check", &flag_store_check, 1}
|
||||
};
|
||||
|
||||
static const struct string_option
|
||||
|
@ -12585,9 +12585,8 @@ patch_assignment (node, wfl_op1)
|
||||
{
|
||||
lhs_type = TREE_TYPE (lvalue);
|
||||
}
|
||||
/* Or Lhs can be a array access. Should that be lvalue ? FIXME +
|
||||
comment on reason why */
|
||||
else if (TREE_CODE (wfl_op1) == ARRAY_REF)
|
||||
/* Or Lhs can be an array access. */
|
||||
else if (TREE_CODE (lvalue) == ARRAY_REF)
|
||||
{
|
||||
lhs_type = TREE_TYPE (lvalue);
|
||||
lvalue_from_array = 1;
|
||||
@ -12689,80 +12688,29 @@ patch_assignment (node, wfl_op1)
|
||||
&& lvalue_from_array
|
||||
&& JREFERENCE_TYPE_P (TYPE_ARRAY_ELEMENT (lhs_type)))
|
||||
{
|
||||
tree check;
|
||||
tree base = lvalue;
|
||||
tree array, store_check, base, index_expr;
|
||||
|
||||
/* We need to retrieve the right argument for
|
||||
_Jv_CheckArrayStore. This is somewhat complicated by bounds
|
||||
and null pointer checks, both of which wrap the operand in
|
||||
one layer of COMPOUND_EXPR. */
|
||||
if (TREE_CODE (lvalue) == COMPOUND_EXPR)
|
||||
base = TREE_OPERAND (lvalue, 0);
|
||||
else
|
||||
/* Get the INDIRECT_REF. */
|
||||
array = TREE_OPERAND (TREE_OPERAND (lvalue, 0), 0);
|
||||
/* Get the array pointer expr. */
|
||||
array = TREE_OPERAND (array, 0);
|
||||
store_check = build_java_arraystore_check (array, new_rhs);
|
||||
|
||||
index_expr = TREE_OPERAND (lvalue, 1);
|
||||
|
||||
if (TREE_CODE (index_expr) == COMPOUND_EXPR)
|
||||
{
|
||||
tree op = TREE_OPERAND (base, 0);
|
||||
|
||||
/* We can have a SAVE_EXPR here when doing String +=. */
|
||||
if (TREE_CODE (op) == SAVE_EXPR)
|
||||
op = TREE_OPERAND (op, 0);
|
||||
/* We can have a COMPOUND_EXPR here when doing bounds check. */
|
||||
if (TREE_CODE (op) == COMPOUND_EXPR)
|
||||
op = TREE_OPERAND (op, 1);
|
||||
base = TREE_OPERAND (op, 0);
|
||||
/* Strip the last PLUS_EXPR to obtain the base. */
|
||||
if (TREE_CODE (base) == PLUS_EXPR)
|
||||
base = TREE_OPERAND (base, 0);
|
||||
/* A COMPOUND_EXPR here is a bounds check. The bounds check must
|
||||
happen before the store check, so prepare to insert the store
|
||||
check within the second operand of the existing COMPOUND_EXPR. */
|
||||
base = index_expr;
|
||||
}
|
||||
|
||||
/* Build the invocation of _Jv_CheckArrayStore */
|
||||
new_rhs = save_expr (new_rhs);
|
||||
check = build (CALL_EXPR, void_type_node,
|
||||
build_address_of (soft_checkarraystore_node),
|
||||
tree_cons (NULL_TREE, base,
|
||||
build_tree_list (NULL_TREE, new_rhs)),
|
||||
NULL_TREE);
|
||||
TREE_SIDE_EFFECTS (check) = 1;
|
||||
|
||||
/* We have to decide on an insertion point */
|
||||
if (TREE_CODE (lvalue) == COMPOUND_EXPR)
|
||||
{
|
||||
tree t;
|
||||
if (flag_bounds_check)
|
||||
{
|
||||
t = TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (lvalue, 1), 0), 0);
|
||||
TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (lvalue, 1), 0), 0) =
|
||||
build (COMPOUND_EXPR, void_type_node, t, check);
|
||||
}
|
||||
else
|
||||
TREE_OPERAND (lvalue, 1) = build (COMPOUND_EXPR, lhs_type,
|
||||
check, TREE_OPERAND (lvalue, 1));
|
||||
}
|
||||
else if (flag_bounds_check)
|
||||
{
|
||||
tree hook = lvalue;
|
||||
tree compound = TREE_OPERAND (lvalue, 0);
|
||||
tree bound_check, new_compound;
|
||||
|
||||
if (TREE_CODE (compound) == SAVE_EXPR)
|
||||
{
|
||||
compound = TREE_OPERAND (compound, 0);
|
||||
hook = TREE_OPERAND (hook, 0);
|
||||
}
|
||||
|
||||
/* Find the array bound check, hook the original array access. */
|
||||
bound_check = TREE_OPERAND (compound, 0);
|
||||
TREE_OPERAND (hook, 0) = TREE_OPERAND (compound, 1);
|
||||
|
||||
/* Make sure the bound check will happen before the store check */
|
||||
new_compound =
|
||||
build (COMPOUND_EXPR, void_type_node, bound_check, check);
|
||||
|
||||
/* Re-assemble the augmented array access. */
|
||||
lvalue = build (COMPOUND_EXPR, TREE_TYPE (lvalue),
|
||||
new_compound, lvalue);
|
||||
}
|
||||
else
|
||||
lvalue = build (COMPOUND_EXPR, TREE_TYPE (lvalue), check, lvalue);
|
||||
base = lvalue;
|
||||
|
||||
index_expr = TREE_OPERAND (base, 1);
|
||||
TREE_OPERAND (base, 1) = build (COMPOUND_EXPR, TREE_TYPE (index_expr),
|
||||
store_check, index_expr);
|
||||
}
|
||||
|
||||
/* Final locals can be used as case values in switch
|
||||
|
Loading…
Reference in New Issue
Block a user