summaryrefslogtreecommitdiff
path: root/test/602-deoptimizeable/src/Main.java
diff options
context:
space:
mode:
author Mingyao Yang <mingyao@google.com> 2016-05-23 12:29:39 -0700
committer Mingyao Yang <mingyao@google.com> 2016-05-26 13:24:54 -0700
commitf711f2cf3c28dfe865e36f17419a16f06a0ebb5a (patch)
tree3657d68b2a2fb67f4919cb97ca279cf9310224e9 /test/602-deoptimizeable/src/Main.java
parentbbfa42aa4c4b5cbc2ed2d8bdea6ff76da615a8aa (diff)
Partial fragment deoptimization
We used to do either single frame deoptimization, or full fragment deoptimization which deoptimizes all the frames in a fragment. This change allows some methods to be not deoptimizeable, likely due to some kind of optimization. So we need another deoptimization mode that unwinds partial fragment. Deoptimizations are now generalized into either full or partial fragment. A full fragment deoptimization will deopt all frames in the fragment, and then returns from the invoke stub to enter interpreter. A partial fragment deoptimization will deopt a single frame, or all frames up to the method that's not deoptimizeable, and then jumps to the interpreter bridge. Currently code not deoptimizeable is the code in boot image since the code may not be compiled with debuggable flag. Bug: 28769520 Change-Id: I875c694791cc8ebd5121abcd92ce7b0db95aca38
Diffstat (limited to 'test/602-deoptimizeable/src/Main.java')
-rw-r--r--test/602-deoptimizeable/src/Main.java212
1 files changed, 212 insertions, 0 deletions
diff --git a/test/602-deoptimizeable/src/Main.java b/test/602-deoptimizeable/src/Main.java
new file mode 100644
index 0000000000..8032ce9116
--- /dev/null
+++ b/test/602-deoptimizeable/src/Main.java
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+
+class DummyObject {
+ public static boolean sHashCodeInvoked = false;
+ private int i;
+
+ public DummyObject(int i) {
+ this.i = i;
+ }
+
+ public boolean equals(Object obj) {
+ return (obj instanceof DummyObject) && (i == ((DummyObject)obj).i);
+ }
+
+ public int hashCode() {
+ sHashCodeInvoked = true;
+ Main.assertIsManaged();
+ Main.deoptimizeAll();
+ Main.assertIsInterpreted();
+ Main.assertCallerIsManaged(); // Caller is from framework code HashMap.
+ return i % 64;
+ }
+}
+
+public class Main {
+ static boolean sFlag = false;
+
+ public static native void deoptimizeAll();
+ public static native void undeoptimizeAll();
+ public static native void assertIsInterpreted();
+ public static native void assertIsManaged();
+ public static native void assertCallerIsInterpreted();
+ public static native void assertCallerIsManaged();
+
+ public static void execute(Runnable runnable) throws Exception {
+ Thread t = new Thread(runnable);
+ t.start();
+ t.join();
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[0]);
+ final HashMap<DummyObject, Long> map = new HashMap<DummyObject, Long>();
+
+ // Single-frame deoptimization that covers partial fragment.
+ execute(new Runnable() {
+ public void run() {
+ int[] arr = new int[3];
+ assertIsManaged();
+ int res = $noinline$run1(arr);
+ assertIsManaged(); // Only single frame is deoptimized.
+ if (res != 79) {
+ System.out.println("Failure 1!");
+ System.exit(0);
+ }
+ }
+ });
+
+ // Single-frame deoptimization that covers a full fragment.
+ execute(new Runnable() {
+ public void run() {
+ try {
+ int[] arr = new int[3];
+ assertIsManaged();
+ // Use reflection to call $noinline$run2 so that it does
+ // full-fragment deoptimization since that is an upcall.
+ Class<?> cls = Class.forName("Main");
+ Method method = cls.getDeclaredMethod("$noinline$run2", int[].class);
+ double res = (double)method.invoke(Main.class, arr);
+ assertIsManaged(); // Only single frame is deoptimized.
+ if (res != 79.3d) {
+ System.out.println("Failure 2!");
+ System.exit(0);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ // Full-fragment deoptimization.
+ execute(new Runnable() {
+ public void run() {
+ assertIsManaged();
+ float res = $noinline$run3B();
+ assertIsInterpreted(); // Every deoptimizeable method is deoptimized.
+ if (res != 0.034f) {
+ System.out.println("Failure 3!");
+ System.exit(0);
+ }
+ }
+ });
+
+ undeoptimizeAll(); // Make compiled code useable again.
+
+ // Partial-fragment deoptimization.
+ execute(new Runnable() {
+ public void run() {
+ try {
+ assertIsManaged();
+ map.put(new DummyObject(10), Long.valueOf(100));
+ assertIsInterpreted(); // Every deoptimizeable method is deoptimized.
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ undeoptimizeAll(); // Make compiled code useable again.
+
+ if (!DummyObject.sHashCodeInvoked) {
+ System.out.println("hashCode() method not invoked!");
+ }
+ if (map.get(new DummyObject(10)) != 100) {
+ System.out.println("Wrong hashmap value!");
+ }
+ System.out.println("Finishing");
+ }
+
+ public static int $noinline$run1(int[] arr) {
+ assertIsManaged();
+ // Prevent inlining.
+ if (sFlag) {
+ throw new Error();
+ }
+ boolean caught = false;
+ // BCE will use deoptimization for the code below.
+ try {
+ arr[0] = 1;
+ arr[1] = 1;
+ arr[2] = 1;
+ // This causes AIOOBE and triggers deoptimization from compiled code.
+ arr[3] = 1;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertIsInterpreted(); // Single-frame deoptimization triggered.
+ caught = true;
+ }
+ if (!caught) {
+ System.out.println("Expected exception");
+ }
+ assertIsInterpreted();
+ return 79;
+ }
+
+ public static double $noinline$run2(int[] arr) {
+ assertIsManaged();
+ // Prevent inlining.
+ if (sFlag) {
+ throw new Error();
+ }
+ boolean caught = false;
+ // BCE will use deoptimization for the code below.
+ try {
+ arr[0] = 1;
+ arr[1] = 1;
+ arr[2] = 1;
+ // This causes AIOOBE and triggers deoptimization from compiled code.
+ arr[3] = 1;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertIsInterpreted(); // Single-frame deoptimization triggered.
+ caught = true;
+ }
+ if (!caught) {
+ System.out.println("Expected exception");
+ }
+ assertIsInterpreted();
+ return 79.3d;
+ }
+
+ public static float $noinline$run3A() {
+ assertIsManaged();
+ // Prevent inlining.
+ if (sFlag) {
+ throw new Error();
+ }
+ // Deoptimize callers.
+ deoptimizeAll();
+ assertIsInterpreted();
+ assertCallerIsInterpreted(); // $noinline$run3B is deoptimizeable.
+ return 0.034f;
+ }
+
+ public static float $noinline$run3B() {
+ assertIsManaged();
+ // Prevent inlining.
+ if (sFlag) {
+ throw new Error();
+ }
+ float res = $noinline$run3A();
+ assertIsInterpreted();
+ return res;
+ }
+}