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.io.PrintWriter; 20 import java.io.StringWriter; 21 import java.util.concurrent.Semaphore; 22 import java.util.Arrays; 23 import java.lang.reflect.Executable; 24 import java.lang.reflect.Method; 25 import java.util.List; 26 import java.util.Set; 27 import java.util.ArrayList; 28 import java.util.HashSet; 29 import java.util.function.IntUnaryOperator; 30 import java.util.function.Function; 31 32 public class Test1924 { handleFramePop(Executable m, boolean exception, long location)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 recurTimesA(int times, Runnable safepoint)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 recurTimesB(int times, Runnable safepoint)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 recurTimesC(int times, Runnable safepoint)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 recurTimesD(int times, Runnable safepoint)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 recurTimesE(int times, Runnable safepoint)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 recurTimesF(int times, Runnable safepoint)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 recurTimesG(int times, Runnable safepoint)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 recurTimesH(int times, Runnable safepoint)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 recurTimesI(int times, Runnable safepoint)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 recurTimesJ(int times, Runnable safepoint)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 { RecursionError(String s)119 public RecursionError(String s) { super(s); } 120 } recurTimesK(int times, Runnable safepoint)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 ThreadPauser()134 public ThreadPauser() { 135 sem_wakeup_main = new Semaphore(0); 136 sem_wait = new Semaphore(0); 137 } 138 run()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 waitForOtherThreadToPause()148 public void waitForOtherThreadToPause() throws Exception { 149 sem_wakeup_main.acquire(); 150 } 151 wakeupOtherThread()152 public void wakeupOtherThread() throws Exception { 153 sem_wait.release(); 154 } 155 } 156 doRecurTestWith(final int times, int watch_frame)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(null, 161 () -> { 162 try { 163 recurTimesA(times, safepoint); 164 System.out.println("Ran recurTimes(" + times + ") without errors!"); 165 } catch (RecursionError e) { 166 System.out.println("Caught exception " + e + " while running recurTimes(" + times + ")"); 167 } 168 }, 169 "RecurTimes(" + times + ") watching: " + watch_frame + " runner.", 170 // 4000 kb stack since ASAN can make us stack-overflow otherwise 171 4000 * 1024); 172 target.start(); 173 safepoint.waitForOtherThreadToPause(); 174 Suspension.suspend(target); 175 // Safe block 176 int cnt = 0; 177 StackTrace.StackFrameData target_frame = null; 178 for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(target)) { 179 if (frame.method.getName().startsWith(target_method_name_start)) { 180 if (times - cnt == watch_frame) { 181 target_frame = frame; 182 break; 183 } else { 184 cnt++; 185 } 186 } 187 } 188 if (target_frame != null) { 189 FramePop.notifyFramePop(target, target_frame.depth); 190 } else { 191 System.out.println( 192 "Unable to find stack frame for " + watch_frame + " depth of " 193 + target_method_name_start); 194 } 195 Suspension.resume(target); 196 toggleFramePop(null); 197 safepoint.wakeupOtherThread(); 198 target.join(); 199 } 200 run()201 public static void run() throws Exception { 202 // TODO Investigate what thread argument means for FramePop event enable. 203 // Listen for events on all threads. 204 FramePop.enableFramePopEvent( 205 Test1924.class, 206 Test1924.class.getDeclaredMethod( 207 "handleFramePop", Executable.class, Boolean.TYPE, Long.TYPE), 208 null); 209 doRecurTestWith(10, 0); 210 doRecurTestWith(10, 5); 211 doRecurTestWith(10, 10); 212 doRecurTestWith(100, 95); 213 } 214 toggleFramePop(Thread thr)215 public static native void toggleFramePop(Thread thr); 216 } 217