OSDN Git Service

Fix ARM64 Baker's read barrier fast path for ArraySet.
authorRoland Levillain <rpl@google.com>
Tue, 9 Feb 2016 12:49:18 +0000 (12:49 +0000)
committerRoland Levillain <rpl@google.com>
Tue, 9 Feb 2016 12:49:18 +0000 (12:49 +0000)
Do not exhaust the pool of scratch (temporary) registers
gratuitously when emitting an instrumented array load with a
large constant index.

Bug: 26817006
Bug: 12687968
Change-Id: I65a4fe676aa3c9e2c8d7e26195d9af6432c83ff9

compiler/optimizing/code_generator_arm64.cc
test/572-checker-array-get-regression/expected.txt [new file with mode: 0644]
test/572-checker-array-get-regression/info.txt [new file with mode: 0644]
test/572-checker-array-get-regression/src/Main.java [new file with mode: 0644]

index e20e044..cfdf6b1 100644 (file)
@@ -4880,20 +4880,18 @@ void CodeGeneratorARM64::GenerateReferenceLoadWithBakerReadBarrier(HInstruction*
     static_assert(
         sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
         "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
-    temp2 = temps.AcquireW();
     // /* HeapReference<Object> */ ref =
     //     *(obj + offset + index * sizeof(HeapReference<Object>))
-    MemOperand source = HeapOperand(obj);
+    const size_t shift_amount = Primitive::ComponentSizeShift(type);
     if (index.IsConstant()) {
-      uint32_t computed_offset =
-          offset + (Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type));
-      source = HeapOperand(obj, computed_offset);
+      uint32_t computed_offset = offset + (Int64ConstantFrom(index) << shift_amount);
+      Load(type, ref_reg, HeapOperand(obj, computed_offset));
     } else {
+      temp2 = temps.AcquireW();
       __ Add(temp2, obj, offset);
-      source = HeapOperand(temp2, XRegisterFrom(index), LSL, Primitive::ComponentSizeShift(type));
+      Load(type, ref_reg, HeapOperand(temp2, XRegisterFrom(index), LSL, shift_amount));
+      temps.Release(temp2);
     }
-    Load(type, ref_reg, source);
-    temps.Release(temp2);
   } else {
     // /* HeapReference<Object> */ ref = *(obj + offset)
     MemOperand field = HeapOperand(obj, offset);
diff --git a/test/572-checker-array-get-regression/expected.txt b/test/572-checker-array-get-regression/expected.txt
new file mode 100644 (file)
index 0000000..c08d783
--- /dev/null
@@ -0,0 +1 @@
+1048575
diff --git a/test/572-checker-array-get-regression/info.txt b/test/572-checker-array-get-regression/info.txt
new file mode 100644 (file)
index 0000000..023d5b0
--- /dev/null
@@ -0,0 +1,3 @@
+Regression test for the ARM64 Baker's read barrier fast path compiler
+instrumentatin of array loads with a large constant index, where we
+used to require too many scratch (temporary) registers.
diff --git a/test/572-checker-array-get-regression/src/Main.java b/test/572-checker-array-get-regression/src/Main.java
new file mode 100644 (file)
index 0000000..bc13af9
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+  public static void main(String[] args) {
+    System.out.println(test().intValue());
+  }
+
+  /// CHECK-START: java.lang.Integer Main.test() ssa_builder (after)
+  /// CHECK-DAG:     <<Method:j\d+>>       CurrentMethod
+  /// CHECK-DAG:     <<Const2P20:i\d+>>    IntConstant 1048576
+  /// CHECK-DAG:     <<ConstM1:i\d+>>      IntConstant -1
+  /// CHECK-DAG:     <<Array:l\d+>>        NewArray [<<Const2P20>>,<<Method>>]
+  /// CHECK-DAG:     <<NullCheck1:l\d+>>   NullCheck [<<Array>>]
+  /// CHECK-DAG:     <<Length1:i\d+>>      ArrayLength [<<NullCheck1>>]
+  /// CHECK-DAG:     <<Index:i\d+>>        Add [<<Length1>>,<<ConstM1>>]
+  /// CHECK-DAG:     <<NullCheck2:l\d+>>   NullCheck [<<Array>>]
+  /// CHECK-DAG:     <<Length2:i\d+>>      ArrayLength [<<NullCheck2>>]
+  /// CHECK-DAG:     <<BoundsCheck:i\d+>>  BoundsCheck [<<Index>>,<<Length2>>]
+  /// CHECK-DAG:     <<LastElement:l\d+>>  ArrayGet [<<NullCheck2>>,<<BoundsCheck>>]
+  /// CHECK-DAG:                           Return [<<LastElement>>]
+
+  /// CHECK-START: java.lang.Integer Main.test() register (before)
+  /// CHECK-DAG:     <<Method:j\d+>>       CurrentMethod
+  /// CHECK-DAG:     <<Const2P20:i\d+>>    IntConstant 1048576
+  /// CHECK-DAG:     <<Const2P20M1:i\d+>>  IntConstant 1048575
+  /// CHECK-DAG:     <<Array:l\d+>>        NewArray [<<Const2P20>>,<<Method>>]
+  /// CHECK-DAG:     <<LastElement:l\d+>>  ArrayGet [<<Array>>,<<Const2P20M1>>]
+  /// CHECK-DAG:                           Return [<<LastElement>>]
+
+  public static Integer test() {
+    Integer[] integers = new Integer[1024 * 1024];
+    initIntegerArray(integers);
+    // Array load with a large constant index (after constant folding
+    // and bounds check elimination).
+    Integer last_integer = integers[integers.length - 1];
+    return last_integer;
+  }
+
+  public static void initIntegerArray(Integer[] integers) {
+    for (int i = 0; i < integers.length; ++i) {
+      integers[i] = new Integer(i);
+    }
+  }
+
+}