From 022dcc46051ffd0114ac3382cc7e50928f17d995 Mon Sep 17 00:00:00 2001 From: Bryce McKinlay Date: Thu, 28 Feb 2002 11:40:29 +0000 Subject: [PATCH] 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 --- gcc/java/ChangeLog | 25 ++++++- gcc/java/check-init.c | 2 +- gcc/java/expr.c | 140 +++++++++++++++++++++++++--------------- gcc/java/gcj.texi | 17 ++++- gcc/java/java-tree.h | 4 ++ gcc/java/jvspec.c | 1 + gcc/java/lang-options.h | 4 ++ gcc/java/lang.c | 6 +- gcc/java/parse.y | 94 ++++++--------------------- 9 files changed, 163 insertions(+), 130 deletions(-) diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index a4ef231a159..2250b1d8ee7 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,26 @@ +2002-02-28 Bryce McKinlay + + * 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 * decl.c (copy_lang_decl): Rename java_dup_lang_specific_decl. @@ -20,7 +43,7 @@ 2002-02-22 Per Bothner - * 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). diff --git a/gcc/java/check-init.c b/gcc/java/check-init.c index 2a4e3c377ac..679353355c8 100644 --- a/gcc/java/check-init.c +++ b/gcc/java/check-init.c @@ -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. */ diff --git a/gcc/java/expr.c b/gcc/java/expr.c index 045931079f2..80b29108725 100644 --- a/gcc/java/expr.c +++ b/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); - - 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)))); + /* 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")); + + 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 [[. @@ -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); } diff --git a/gcc/java/gcj.texi b/gcc/java/gcj.texi index e7b97d26df7..e88e8fb2cde 100644 --- a/gcc/java/gcj.texi +++ b/gcc/java/gcj.texi @@ -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 diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 7097b56d720..898c851cc9e 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -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)); diff --git a/gcc/java/jvspec.c b/gcc/java/jvspec.c index 5bb3e9d164b..202c7c8e047 100644 --- a/gcc/java/jvspec.c +++ b/gcc/java/jvspec.c @@ -66,6 +66,7 @@ static const char jvgenmain_spec[] = %{