Test1923.java revision e814f9d09c0fb1b678e610780d11ce3577db3599
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.io.PrintWriter;
20import java.io.StringWriter;
21import java.util.concurrent.Semaphore;
22import java.util.Arrays;
23import java.lang.reflect.Executable;
24import java.lang.reflect.Method;
25import java.util.List;
26import java.util.Set;
27import java.util.ArrayList;
28import java.util.HashSet;
29import java.util.function.IntUnaryOperator;
30import java.util.function.Function;
31
32public class Test1923 {
33  public static void handleFramePop(Executable m, boolean exception, long location) {
34    System.out.println(
35        m + " pop. Line=" + Breakpoint.locationToLine(m, location) + " exception:" + exception);
36  }
37
38  public static void recurTimesA(int times, Runnable safepoint) {
39    if (times == 0) {
40      safepoint.run();
41      return;
42    }
43    recurTimesB(times - 1, safepoint);
44  }
45
46  public static void recurTimesB(int times, Runnable safepoint) {
47    if (times == 0) {
48      safepoint.run();
49      return;
50    }
51    recurTimesC(times - 1, safepoint);
52  }
53
54  public static void recurTimesC(int times, Runnable safepoint) {
55    if (times == 0) {
56      safepoint.run();
57      return;
58    }
59    recurTimesD(times - 1, safepoint);
60  }
61
62  public static void recurTimesD(int times, Runnable safepoint) {
63    if (times == 0) {
64      safepoint.run();
65      return;
66    }
67    recurTimesE(times - 1, safepoint);
68  }
69
70  public static void recurTimesE(int times, Runnable safepoint) {
71    if (times == 0) {
72      safepoint.run();
73      return;
74    }
75    recurTimesF(times - 1, safepoint);
76  }
77
78  public static void recurTimesF(int times, Runnable safepoint) {
79    if (times == 0) {
80      safepoint.run();
81      return;
82    }
83    recurTimesG(times - 1, safepoint);
84  }
85
86  public static void recurTimesG(int times, Runnable safepoint) {
87    if (times == 0) {
88      safepoint.run();
89      return;
90    }
91    recurTimesH(times - 1, safepoint);
92  }
93
94  public static void recurTimesH(int times, Runnable safepoint) {
95    if (times == 0) {
96      safepoint.run();
97      return;
98    }
99    recurTimesI(times - 1, safepoint);
100  }
101
102  public static void recurTimesI(int times, Runnable safepoint) {
103    if (times == 0) {
104      safepoint.run();
105      return;
106    }
107    recurTimesJ(times - 1, safepoint);
108  }
109
110  public static void recurTimesJ(int times, Runnable safepoint) {
111    if (times == 0) {
112      safepoint.run();
113      return;
114    }
115    recurTimesK(times - 1, safepoint);
116  }
117
118  public static class RecursionError extends Error {
119    public RecursionError(String s) { super(s); }
120  }
121  public static void recurTimesK(int times, Runnable safepoint) {
122    if (times == 0) {
123      safepoint.run();
124      return;
125    }
126    safepoint.run();
127    throw new RecursionError("Unable recur further. Still " + times + " outstanding!");
128  }
129
130  public static class ThreadPauser implements Runnable {
131    public final Semaphore sem_wakeup_main;
132    public final Semaphore sem_wait;
133
134    public ThreadPauser() {
135      sem_wakeup_main = new Semaphore(0);
136      sem_wait = new Semaphore(0);
137    }
138
139    public void run() {
140      try {
141        sem_wakeup_main.release();
142        sem_wait.acquire();
143      } catch (Exception e) {
144        throw new Error("Error with semaphores!", e);
145      }
146    }
147
148    public void waitForOtherThreadToPause() throws Exception {
149      sem_wakeup_main.acquire();
150    }
151
152    public void wakeupOtherThread() throws Exception {
153      sem_wait.release();
154    }
155  }
156
157  public static void doRecurTestWith(final int times, int watch_frame) throws Exception {
158    final String target_method_name_start = "recurTimes";
159    final ThreadPauser safepoint = new ThreadPauser();
160    Thread target = new Thread(() -> {
161      try {
162        recurTimesA(times, safepoint);
163        System.out.println("Ran recurTimes(" + times + ") without errors!");
164      } catch (RecursionError e) {
165        System.out.println("Caught exception " + e + " while running recurTimes(" + times + ")");
166      }
167    });
168    target.start();
169    safepoint.waitForOtherThreadToPause();
170    Suspension.suspend(target);
171    // Safe block
172    int cnt = 0;
173    StackTrace.StackFrameData target_frame = null;
174    for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(target)) {
175      if (frame.method.getName().startsWith(target_method_name_start)) {
176        if (times - cnt == watch_frame) {
177          target_frame = frame;
178          break;
179        } else {
180          cnt++;
181        }
182      }
183    }
184    if (target_frame != null) {
185      FramePop.notifyFramePop(target, target_frame.depth);
186    } else {
187      System.out.println(
188          "Unable to find stack frame for " + watch_frame + " depth of "
189          + target_method_name_start);
190    }
191    Suspension.resume(target);
192    safepoint.wakeupOtherThread();
193    target.join();
194  }
195
196  public static void run() throws Exception {
197    // TODO Investigate what thread argument means for FramePop event enable.
198    // Listen for events on all threads.
199    FramePop.enableFramePopEvent(
200        Test1923.class,
201        Test1923.class.getDeclaredMethod(
202            "handleFramePop", Executable.class, Boolean.TYPE, Long.TYPE),
203        null);
204    doRecurTestWith(10, 0);
205    doRecurTestWith(10, 5);
206    doRecurTestWith(10, 10);
207    doRecurTestWith(100, 95);
208  }
209}
210