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 Test1926 { 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 recurTimesK(int times, Runnable safepoint)118 public static void recurTimesK(int times, Runnable safepoint) { 119 if (times == 0) { 120 safepoint.run(); 121 return; 122 } 123 recurTimesL(times - 1, safepoint); 124 } 125 126 public static class RecursionError extends Error { RecursionError(String s)127 public RecursionError(String s) { super(s); } 128 } 129 recurTimesL(int times, Runnable safepoint)130 public static void recurTimesL(int times, Runnable safepoint) { 131 if (times == 0) { 132 safepoint.run(); 133 return; 134 } 135 safepoint.run(); 136 throw new RecursionError("Unable recur further. Still " + times + " outstanding!"); 137 } 138 139 public static class ThreadPauser implements Runnable { 140 public final Semaphore sem_wakeup_main; 141 public final Semaphore sem_wait; 142 ThreadPauser()143 public ThreadPauser() { 144 sem_wakeup_main = new Semaphore(0); 145 sem_wait = new Semaphore(0); 146 } 147 run()148 public void run() { 149 try { 150 sem_wakeup_main.release(); 151 sem_wait.acquire(); 152 } catch (Exception e) { 153 throw new Error("Error with semaphores!", e); 154 } 155 } 156 waitForOtherThreadToPause()157 public void waitForOtherThreadToPause() throws Exception { 158 sem_wakeup_main.acquire(); 159 } 160 wakeupOtherThread()161 public void wakeupOtherThread() throws Exception { 162 sem_wait.release(); 163 } 164 } 165 doRecurTestWith(final int times, int watch_frame)166 public static void doRecurTestWith(final int times, int watch_frame) throws Exception { 167 final String target_method_name_start = "recurTimes"; 168 final ThreadPauser safepoint = new ThreadPauser(); 169 // We need to make the stack bigger since ASAN causes SOE if we don't. 170 Thread target = new Thread( 171 /*thread Group*/ null, 172 () -> { 173 recurTimesA(times, () -> { 174 safepoint.run(); 175 disableFramePop(null); 176 }); 177 System.out.println("Ran recurTimes(" + times + ") without errors after disabling " + 178 "frame pop event!"); 179 System.out.println("renabling frame pop event with similar stack."); 180 recurTimesB(times, () -> { reenableFramePop(null); }); 181 System.out.println("Ran recurTimes(" + times + ") without errors!"); 182 }, 183 "Test1926-Thread", 184 /*10 mb stack*/10 * 1024 * 1024); 185 target.start(); 186 safepoint.waitForOtherThreadToPause(); 187 Suspension.suspend(target); 188 // Safe block 189 int cnt = 0; 190 StackTrace.StackFrameData target_frame = null; 191 for (StackTrace.StackFrameData frame : StackTrace.GetStackTrace(target)) { 192 if (frame.method.getName().startsWith(target_method_name_start)) { 193 if (times - cnt == watch_frame) { 194 target_frame = frame; 195 break; 196 } else { 197 cnt++; 198 } 199 } 200 } 201 if (target_frame != null) { 202 FramePop.notifyFramePop(target, target_frame.depth); 203 } else { 204 System.out.println( 205 "Unable to find stack frame for " + watch_frame + " depth of " 206 + target_method_name_start); 207 } 208 Suspension.resume(target); 209 safepoint.wakeupOtherThread(); 210 target.join(); 211 } 212 run()213 public static void run() throws Exception { 214 // Listen for events on all threads. 215 FramePop.enableFramePopEvent( 216 Test1926.class, 217 Test1926.class.getDeclaredMethod( 218 "handleFramePop", Executable.class, Boolean.TYPE, Long.TYPE), 219 null); 220 doRecurTestWith(10, 0); 221 doRecurTestWith(10, 5); 222 doRecurTestWith(10, 10); 223 } 224 disableFramePop(Thread thr)225 public static native void disableFramePop(Thread thr); reenableFramePop(Thread thr)226 public static native void reenableFramePop(Thread thr); 227 } 228