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