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: r50131
This commit is contained in:
Bryce McKinlay 2002-02-28 11:42:10 +00:00
parent 83ec9a87ee
commit beca58816c
9 changed files with 162 additions and 129 deletions

View File

@ -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-22 Tom Tromey <tromey@redhat.com>
Fix for PR java/2369:
@ -8,7 +31,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).

View File

@ -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. */

View File

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

View File

@ -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

View File

@ -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;
@ -1106,6 +1109,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));

View File

@ -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}\

View File

@ -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") },

View File

@ -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

View File

@ -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