xref: /aosp_15_r20/art/test/1916-get-set-current-frame/src/art/Test1916.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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 package art;
18 
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Executable;
21 import java.lang.reflect.Method;
22 import java.nio.ByteBuffer;
23 import java.util.concurrent.Semaphore;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.List;
27 import java.util.Set;
28 import java.util.function.Function;
29 import java.util.function.Predicate;
30 import java.util.function.Supplier;
31 import java.util.function.Consumer;
32 
33 public class Test1916 {
34     public static final int SET_VALUE = 1337;
35     public static final String TARGET_VAR = "TARGET";
36 
reportValue(Object val)37     public static void reportValue(Object val) {
38         System.out.println("\tValue is '" + val + "'");
39     }
40 
41     public static class IntRunner implements Runnable {
42         private volatile boolean continueBusyLoop;
43         private volatile boolean inBusyLoop;
IntRunner()44         public IntRunner() {
45             this.continueBusyLoop = true;
46             this.inBusyLoop = false;
47         }
run()48         public void run() {
49             int TARGET = 42;
50             // We will suspend the thread during this loop.
51             while (continueBusyLoop) {
52                 inBusyLoop = true;
53             }
54             reportValue(TARGET);
55         }
waitForBusyLoopStart()56         public void waitForBusyLoopStart() { while (!inBusyLoop) {} }
finish()57         public void finish() { continueBusyLoop = false; }
58     }
59 
run()60     public static void run() throws Exception {
61         Locals.EnableLocalVariableAccess();
62         runGet();
63         runSet();
64     }
65 
runGet()66     public static void runGet() throws Exception {
67         Method target = IntRunner.class.getDeclaredMethod("run");
68         // Get Int
69         IntRunner int_runner = new IntRunner();
70         Thread target_get = new Thread(int_runner, "GetLocalInt - Target");
71         target_get.start();
72         int_runner.waitForBusyLoopStart();
73         try {
74             Suspension.suspend(target_get);
75         } catch (Exception e) {
76             System.out.println("FAIL: got " + e);
77             e.printStackTrace();
78             int_runner.finish();
79             target_get.join();
80             return;
81         }
82         try {
83             StackTrace.StackFrameData frame = FindStackFrame(target_get, target);
84             int depth = frame.depth;
85             if (depth != 0) { throw new Error("Expected depth 0 but got " + depth); }
86             int slot = FindSlot(frame);
87             int value = Locals.GetLocalVariableInt(target_get, depth, slot);
88             System.out.println("From GetLocalInt(), value is " + value);
89         } finally {
90             Suspension.resume(target_get);
91             int_runner.finish();
92             target_get.join();
93         }
94     }
95 
runSet()96     public static void runSet() throws Exception {
97         Method target = IntRunner.class.getDeclaredMethod("run");
98         // Set Int
99         IntRunner int_runner = new IntRunner();
100         Thread target_set = new Thread(int_runner, "SetLocalInt - Target");
101         target_set.start();
102         int_runner.waitForBusyLoopStart();
103         try {
104             Suspension.suspend(target_set);
105         } catch (Exception e) {
106             System.out.println("FAIL: got " + e);
107             e.printStackTrace();
108             int_runner.finish();
109             target_set.join();
110             return;
111         }
112         try {
113             StackTrace.StackFrameData frame = FindStackFrame(target_set, target);
114             int depth = frame.depth;
115             if (depth != 0) { throw new Error("Expected depth 0 but got " + depth); }
116             int slot = FindSlot(frame);
117             System.out.println("Setting TARGET to " + SET_VALUE);
118             Locals.SetLocalVariableInt(target_set, depth, slot, SET_VALUE);
119         } finally {
120             Suspension.resume(target_set);
121             int_runner.finish();
122             target_set.join();
123         }
124     }
125 
FindSlot(StackTrace.StackFrameData frame)126     public static int FindSlot(StackTrace.StackFrameData frame) throws Exception {
127         long loc = frame.current_location;
128         for (Locals.VariableDescription var : Locals.GetLocalVariableTable(frame.method)) {
129             if (var.start_location <= loc &&
130                     var.length + var.start_location > loc &&
131                     var.name.equals(TARGET_VAR)) {
132                 return var.slot;
133             }
134         }
135         throw new Error(
136                 "Unable to find variable " + TARGET_VAR + " in " + frame.method + " at loc " + loc);
137     }
138 
FindStackFrame(Thread thr, Method target)139     private static StackTrace.StackFrameData FindStackFrame(Thread thr, Method target) {
140         for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(thr)) {
141             if (frame.method.equals(target)) {
142                 return frame;
143             }
144         }
145         throw new Error("Unable to find stack frame in method " + target + " on thread " + thr);
146     }
147 }
148 
149