expr.c (java_array_data_offset): Removed function.
authorBryce McKinlay <bryce@gcc.gnu.org>
Thu, 28 Feb 2002 11:40:29 +0000 (11:40 +0000)
committerBryce McKinlay <bryce@gcc.gnu.org>
Thu, 28 Feb 2002 11:40:29 +0000 (11:40 +0000)
* 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
gcc/java/check-init.c
gcc/java/expr.c
gcc/java/gcj.texi
gcc/java/java-tree.h
gcc/java/jvspec.c
gcc/java/lang-options.h
gcc/java/lang.c
gcc/java/parse.y

index a4ef231a15912dbb3211e9f27c8f1f1c53b237c6..2250b1d8ee7dd15725b064cab33525717aa5f6d2 100644 (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-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).
index 2a4e3c377ac9889929b041f8340bc72cfa4bcfa8..679353355c890d83d8b1c66ee7cadd10ed240683 100644 (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. */
index 045931079f26b0d79dd8d7adbea9039b0d56be43..80b2910872568a0ae45187f4ee3a61f612435437 100644 (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);
-
-  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 [[<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);
     }
   
index e7b97d26df7e60a10719a449d2f64d5dbda3371d..e88e8fb2cde0f0a74058bba562636a8f425b2060 100644 (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
index 7097b56d720df7e06d4fd8997992d3e6c923ec53..898c851cc9ec0a2f03571be06626d445e71eda4e 100644 (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;
 
@@ -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));
index 5bb3e9d164b2a779cc0470f9ee9abbe5196fe697..202c7c8e0475ba0cc7361542dbf3e64e7ce7543a 100644 (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}\
index 130060c59e4f2be7d4d6230579464e0c3f7c5825..3397fa8def85d13bd212210e3e36c2464ded0cd9 100644 (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") },
index 6be8f2bafa5a05cb85eb2474b4c640a3b77e326a..9732f1a6eee56c37df57e1a289f4decce7ca31c5 100644 (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
index 9f14076f1ee05374aa91809ce221d3e297669b6c..d005b4e8f9665ad519ca7657e32289d5dc5adfee 100644 (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);
-       }
-
-      /* 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));
+         /* 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;
        }
-      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