OSDN Git Service

ART: Fix deopt from optimized code under inlining
authorDavid Brazdil <dbrazdil@google.com>
Wed, 28 Oct 2015 17:19:06 +0000 (12:19 -0500)
committerDavid Brazdil <dbrazdil@google.com>
Thu, 29 Oct 2015 01:16:06 +0000 (20:16 -0500)
Deoptimization of inlined frames would use the outer method's
vreg map, thus starting interpreter in bogus state.

Bug: 25331616
Change-Id: I1d4aefc731bb1386f3e6186a89b59981836480b3

runtime/quick_exception_handler.cc
runtime/stack.h
test/541-regression-inlined-deopt/expected.txt [new file with mode: 0644]
test/541-regression-inlined-deopt/info.txt [new file with mode: 0644]
test/541-regression-inlined-deopt/smali/TestCase.smali [new file with mode: 0644]
test/541-regression-inlined-deopt/src/Main.java [new file with mode: 0644]

index 53b4f3a..1552318 100644 (file)
@@ -372,9 +372,14 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor {
     StackMapEncoding encoding = code_info.ExtractEncoding();
     StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
     const size_t number_of_vregs = m->GetCodeItem()->registers_size_;
-    DexRegisterMap vreg_map = code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_vregs);
     MemoryRegion stack_mask = stack_map.GetStackMask(encoding);
     uint32_t register_mask = stack_map.GetRegisterMask(encoding);
+    DexRegisterMap vreg_map = IsInInlinedFrame()
+        ? code_info.GetDexRegisterMapAtDepth(GetCurrentInliningDepth() - 1,
+                                             code_info.GetInlineInfoOf(stack_map, encoding),
+                                             encoding,
+                                             number_of_vregs)
+        : code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_vregs);
 
     for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) {
       if (updated_vregs != nullptr && updated_vregs[vreg]) {
index 1276b24..aa7b616 100644 (file)
@@ -698,6 +698,10 @@ class StackVisitor {
     return current_inlining_depth_ != 0;
   }
 
+  size_t GetCurrentInliningDepth() const {
+    return current_inlining_depth_;
+  }
+
   uintptr_t GetCurrentQuickFramePc() const {
     return cur_quick_frame_pc_;
   }
diff --git a/test/541-regression-inlined-deopt/expected.txt b/test/541-regression-inlined-deopt/expected.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/541-regression-inlined-deopt/info.txt b/test/541-regression-inlined-deopt/info.txt
new file mode 100644 (file)
index 0000000..209588f
--- /dev/null
@@ -0,0 +1,4 @@
+Regression test for deopt from optimized code which would use the top-level
+stack map for deopting inlined frames. Test case is written in smali for full
+control over vregs because the previous test 449 would pass because the vreg
+maps at the various inlining depths were similar.
diff --git a/test/541-regression-inlined-deopt/smali/TestCase.smali b/test/541-regression-inlined-deopt/smali/TestCase.smali
new file mode 100644 (file)
index 0000000..a109775
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright (C) 2015 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.
+
+.class public LTestCase;
+.super Ljava/lang/Object;
+
+.method private static $inline$depth1([I)V
+    .registers 3
+
+    # Expects array in v2.
+
+    const v0, 0x0
+
+    const v1, 0x3
+    aput v0, p0, v1
+
+    const v1, 0x4
+    aput v0, p0, v1
+
+    return-void
+.end method
+
+.method private static $inline$depth0([I)V
+    .registers 1
+
+    # Expects array in v0.
+
+    invoke-static {p0}, LTestCase;->$inline$depth1([I)V
+    return-void
+.end method
+
+.method public static foo()V
+    .registers 10
+
+    # Create a new array short enough to throw AIOOB in $inline$depth1.
+    # Make sure the reference is not stored in the same vreg as used by
+    # the inlined methods.
+
+    const v5, 0x3
+    new-array v6, v5, [I
+
+    invoke-static {v6}, LTestCase;->$inline$depth0([I)V
+    return-void
+.end method
diff --git a/test/541-regression-inlined-deopt/src/Main.java b/test/541-regression-inlined-deopt/src/Main.java
new file mode 100644 (file)
index 0000000..fa79590
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+import java.lang.reflect.*;
+
+public class Main {
+
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String[] args) throws Throwable {
+    try {
+      Class<?> c = Class.forName("TestCase");
+      Method m = c.getMethod("foo");
+      m.invoke(null, (Object[]) null);
+    } catch (InvocationTargetException ex) {
+      // Code should have thrown AIOOB.
+      if (!(ex.getCause() instanceof ArrayIndexOutOfBoundsException)) {
+        throw ex;
+      }
+    }
+  }
+}