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
17package art;
18
19import java.lang.reflect.Constructor;
20import java.lang.reflect.Executable;
21import java.lang.reflect.Method;
22import java.nio.ByteBuffer;
23import java.util.concurrent.Semaphore;
24import java.util.Arrays;
25import java.util.Collection;
26import java.util.List;
27import java.util.Set;
28import java.util.function.Function;
29import java.util.function.Predicate;
30import java.util.function.Supplier;
31import java.util.function.Consumer;
32
33public class Test1916 {
34  public static final int SET_VALUE = 1337;
35  public static final String TARGET_VAR = "TARGET";
36
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;
44    public IntRunner() {
45      this.continueBusyLoop = true;
46      this.inBusyLoop = false;
47    }
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    }
56    public void waitForBusyLoopStart() { while (!inBusyLoop) {} }
57    public void finish() { continueBusyLoop = false; }
58  }
59
60  public static void run() throws Exception {
61    Locals.EnableLocalVariableAccess();
62    runGet();
63    runSet();
64  }
65
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
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
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
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