• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import art.Locals;
18 import art.StackTrace;
19 import art.Suspension;
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Executable;
22 import java.lang.reflect.Method;
23 import java.nio.ByteBuffer;
24 import java.time.Instant;
25 import java.util.concurrent.Semaphore;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.List;
29 import java.util.Set;
30 import java.util.function.Function;
31 import java.util.function.Predicate;
32 import java.util.function.Supplier;
33 import java.util.function.Consumer;
34 
35 public class Main {
36   public static final int SET_VALUE = 1337;
37   public static final String TARGET_VAR = "TARGET";
38 
main(String[] args)39   public static void main(String[] args) throws Exception {
40     System.loadLibrary(args[0]);
41     Locals.EnableLocalVariableAccess();
42     runGet();
43     runSet();
44   }
45 
reportValue(Object val)46   public static void reportValue(Object val) {
47     System.out.println("\tValue is '" + val + "'");
48   }
49 
50   public static class IntRunner implements Runnable {
51     private volatile boolean continueBusyLoop;
52     private volatile boolean inBusyLoop;
53     private final boolean expectOsr;
IntRunner(boolean expectOsr)54     public IntRunner(boolean expectOsr) {
55       this.continueBusyLoop = true;
56       this.inBusyLoop = false;
57       this.expectOsr = expectOsr;
58     }
run()59     public void run() {
60       int TARGET = 42;
61       boolean normalJit = hasJit() && getJitThreshold() != 0;  // Excluding JIT-at-first-use.
62       if (normalJit && expectOsr && !Main.isInterpreted()) {
63           System.out.println("Unexpectedly in jit code prior to restarting the JIT!");
64       }
65       startJit();
66       // We will suspend the thread during this loop.
67       while (continueBusyLoop) {
68         inBusyLoop = true;
69       }
70       // Wait up to 300 seconds for OSR to kick in if we expect it. If we don't give up after only
71       // 3 seconds.
72       Instant osrDeadline = Instant.now().plusSeconds(expectOsr ? 600 : 3);
73       do {
74         // Don't actually do anything here.
75         inBusyLoop = true;
76       } while (normalJit && !Main.isInOsrCode("run") && osrDeadline.compareTo(Instant.now()) > 0);
77       // We shouldn't be doing OSR since we are using JVMTI and the set prevents OSR.
78       // Set local will also push us to interpreter but the get local may remain in compiled code.
79       if (normalJit) {
80         boolean inOsr = Main.isInOsrCode("run");
81         if (expectOsr && !inOsr) {
82           throw new Error(
83               "Expected to be in OSR but was not. interpreter: " + Main.isInterpreted());
84         } else if (!expectOsr && inOsr) {
85           throw new Error(
86               "Expected not to be in OSR but was. interpreter: " + Main.isInterpreted());
87         }
88       }
89       reportValue(TARGET);
90     }
waitForBusyLoopStart()91     public void waitForBusyLoopStart() { while (!inBusyLoop) {} }
finish()92     public void finish() {
93       continueBusyLoop = false;
94     }
95   }
96 
runGet()97   public static void runGet() throws Exception {
98     Method target = IntRunner.class.getDeclaredMethod("run");
99     // Stop jit temporarily. It will be restarted by the test itself.
100     stopJit();
101     // Get Int.
102     IntRunner int_runner = new IntRunner(true);
103     Thread target_get = new Thread(int_runner, "GetLocalInt - Target");
104     target_get.start();
105     int_runner.waitForBusyLoopStart();
106     try {
107       Suspension.suspend(target_get);
108     } catch (Exception e) {
109       System.out.println("FAIL: got " + e);
110       e.printStackTrace();
111       int_runner.finish();
112       target_get.join();
113       return;
114     }
115     try {
116       StackTrace.StackFrameData frame = FindStackFrame(target_get, target);
117       int depth = frame.depth;
118       if (depth != 0) { throw new Error("Expected depth 0 but got " + depth); }
119       int slot = FindSlot(frame);
120       int value = Locals.GetLocalVariableInt(target_get, depth, slot);
121       System.out.println("From GetLocalInt(), value is " + value);
122     } finally {
123       Suspension.resume(target_get);
124       int_runner.finish();
125       target_get.join();
126     }
127   }
128 
runSet()129   public static void runSet() throws Exception {
130     Method target = IntRunner.class.getDeclaredMethod("run");
131     // Stop jit temporarily. It will be restarted by the test itself.
132     stopJit();
133     // Set Int. Even if we start out in JIT code somehow we should be pushed out of it.
134     IntRunner int_runner = new IntRunner(false);
135     Thread target_set = new Thread(int_runner, "SetLocalInt - Target");
136     target_set.start();
137     int_runner.waitForBusyLoopStart();
138     try {
139       Suspension.suspend(target_set);
140     } catch (Exception e) {
141       System.out.println("FAIL: got " + e);
142       e.printStackTrace();
143       int_runner.finish();
144       target_set.join();
145       return;
146     }
147     try {
148       StackTrace.StackFrameData frame = FindStackFrame(target_set, target);
149       int depth = frame.depth;
150       if (depth != 0) { throw new Error("Expected depth 0 but got " + depth); }
151       int slot = FindSlot(frame);
152       System.out.println("Setting TARGET to " + SET_VALUE);
153       Locals.SetLocalVariableInt(target_set, depth, slot, SET_VALUE);
154     } finally {
155       Suspension.resume(target_set);
156       int_runner.finish();
157       target_set.join();
158     }
159   }
160 
FindSlot(StackTrace.StackFrameData frame)161   public static int FindSlot(StackTrace.StackFrameData frame) throws Exception {
162     long loc = frame.current_location;
163     for (Locals.VariableDescription var : Locals.GetLocalVariableTable(frame.method)) {
164       if (var.start_location <= loc &&
165           var.length + var.start_location > loc &&
166           var.name.equals(TARGET_VAR)) {
167         return var.slot;
168       }
169     }
170     throw new Error(
171         "Unable to find variable " + TARGET_VAR + " in " + frame.method + " at loc " + loc);
172   }
173 
FindStackFrame(Thread thr, Method target)174   private static StackTrace.StackFrameData FindStackFrame(Thread thr, Method target) {
175     for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) {
176       if (frame.method.equals(target)) {
177         return frame;
178       }
179     }
180     throw new Error("Unable to find stack frame in method " + target + " on thread " + thr);
181   }
182 
isInterpreted()183   public static native boolean isInterpreted();
isInOsrCode(String methodName)184   public static native boolean isInOsrCode(String methodName);
stopJit()185   public static native boolean stopJit();
startJit()186   public static native boolean startJit();
hasJit()187   public static native boolean hasJit();
getJitThreshold()188   public static native int getJitThreshold();
189 }
190