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.Executable; 20 import java.lang.reflect.Field; 21 import java.lang.reflect.Method; 22 import java.util.Base64; 23 import java.util.EnumSet; 24 import java.util.concurrent.CountDownLatch; 25 import java.util.function.Consumer; 26 27 import static art.SuspendEvents.setupTest; 28 import static art.SuspendEvents.setupSuspendBreakpointFor; 29 import static art.SuspendEvents.clearSuspendBreakpointFor; 30 import static art.SuspendEvents.setupSuspendSingleStepAt; 31 import static art.SuspendEvents.setupFieldSuspendFor; 32 import static art.SuspendEvents.setupSuspendMethodEvent; 33 import static art.SuspendEvents.setupSuspendExceptionEvent; 34 import static art.SuspendEvents.setupSuspendPopFrameEvent; 35 import static art.SuspendEvents.EVENT_TYPE_CLASS_LOAD; 36 import static art.SuspendEvents.EVENT_TYPE_CLASS_PREPARE; 37 import static art.SuspendEvents.setupSuspendClassEvent; 38 39 public class Test1953 { 40 private static boolean IS_ART = System.getProperty("java.vm.name").equals("Dalvik"); 41 public final boolean canRunClassLoadTests; doNothing()42 public static void doNothing() {} 43 44 public interface TestRunnable extends Runnable { getBaseCallCount()45 public int getBaseCallCount(); getCalledMethod()46 public Method getCalledMethod() throws Exception; getCallingMethod()47 public default Method getCallingMethod() throws Exception { 48 return this.getClass().getMethod("run"); 49 }; 50 } 51 52 public static interface TestSuspender { setup(Thread thr)53 public void setup(Thread thr); waitForSuspend(Thread thr)54 public void waitForSuspend(Thread thr); cleanup(Thread thr)55 public void cleanup(Thread thr); 56 } 57 run(Thread thr)58 public static interface ThreadRunnable { public void run(Thread thr); } makeSuspend(final ThreadRunnable setup, final ThreadRunnable clean)59 public static TestSuspender makeSuspend(final ThreadRunnable setup, final ThreadRunnable clean) { 60 return new TestSuspender() { 61 public void setup(Thread thr) { setup.run(thr); } 62 public void waitForSuspend(Thread thr) { SuspendEvents.waitForSuspendHit(thr); } 63 public void cleanup(Thread thr) { clean.run(thr); } 64 }; 65 } 66 67 public void runTestOn(TestRunnable testObj, ThreadRunnable su, ThreadRunnable cl) throws 68 Exception { 69 runTestOn(testObj, makeSuspend(su, cl)); 70 } 71 72 private static void SafePrintStackTrace(StackTraceElement st[]) { 73 for (StackTraceElement e : st) { 74 System.out.println("\t" + e.getClassName() + "." + e.getMethodName() + "(" + 75 (e.isNativeMethod() ? "Native Method" : e.getFileName()) + ")"); 76 if (e.getClassName().equals("art.Test1953") && e.getMethodName().equals("runTests")) { 77 System.out.println("\t<Additional frames hidden>"); 78 break; 79 } 80 } 81 } 82 83 public void runTestOn(TestRunnable testObj, TestSuspender su) throws Exception { 84 System.out.println("Single call with PopFrame on " + testObj + " base-call-count: " + 85 testObj.getBaseCallCount()); 86 final CountDownLatch continue_latch = new CountDownLatch(1); 87 final CountDownLatch startup_latch = new CountDownLatch(1); 88 Runnable await = () -> { 89 try { 90 startup_latch.countDown(); 91 continue_latch.await(); 92 } catch (Exception e) { 93 throw new Error("Failed to await latch", e); 94 } 95 }; 96 Thread thr = new Thread(() -> { await.run(); testObj.run(); }); 97 thr.start(); 98 99 // Wait until the other thread is started. 100 startup_latch.await(); 101 102 // Do any final setup. 103 preTest.accept(testObj); 104 105 // Setup suspension method on the thread. 106 su.setup(thr); 107 108 // Let the other thread go. 109 continue_latch.countDown(); 110 111 // Wait for the other thread to hit the breakpoint/watchpoint/whatever and suspend itself 112 // (without re-entering java) 113 su.waitForSuspend(thr); 114 115 // Cleanup the breakpoint/watchpoint/etc. 116 su.cleanup(thr); 117 118 try { 119 // Pop the frame. 120 popFrame(thr); 121 } catch (Exception e) { 122 System.out.println("Failed to pop frame due to " + e); 123 SafePrintStackTrace(e.getStackTrace()); 124 } 125 126 // Start the other thread going again. 127 Suspension.resume(thr); 128 129 // Wait for the other thread to finish. 130 thr.join(); 131 132 // See how many times calledFunction was called. 133 System.out.println("result is " + testObj + " base-call count: " + testObj.getBaseCallCount()); 134 } 135 136 public static abstract class AbstractTestObject implements TestRunnable { 137 public int callerCnt; 138 139 public AbstractTestObject() { 140 callerCnt = 0; 141 } 142 143 public int getBaseCallCount() { 144 return callerCnt; 145 } 146 147 public void run() { 148 callerCnt++; 149 // This function should be re-executed by the popFrame. 150 calledFunction(); 151 } 152 153 public Method getCalledMethod() throws Exception { 154 return this.getClass().getMethod("calledFunction"); 155 } 156 157 public abstract void calledFunction(); 158 } 159 160 public static class RedefineTestObject extends AbstractTestObject implements Runnable { 161 public static enum RedefineState { ORIGINAL, REDEFINED, }; 162 /* public static class RedefineTestObject extends AbstractTestObject implements Runnable { 163 * public static final byte[] CLASS_BYTES; 164 * public static final byte[] DEX_BYTES; 165 * static { 166 * CLASS_BYTES = null; 167 * DEX_BYTES = null; 168 * } 169 * 170 * public EnumSet<RedefineState> redefine_states; 171 * public RedefineTestObject() { 172 * super(); 173 * redefine_states = EnumSet.noneOf(RedefineState.class); 174 * } 175 * public String toString() { 176 * return "RedefineTestObject { states: " + redefine_states.toString() 177 * + " current: REDEFINED }"; 178 * } 179 * public void calledFunction() { 180 * redefine_states.add(RedefineState.REDEFINED); // line +0 181 * // We will trigger the redefinition using a breakpoint on the next line. 182 * doNothing(); // line +2 183 * } 184 * } 185 */ 186 public static final byte[] CLASS_BYTES = Base64.getDecoder().decode( 187 "yv66vgAAADUATQoADQAjBwAkCgAlACYJAAwAJwoAJQAoEgAAACwJAAIALQoAJQAuCgAvADAJAAwA" + 188 "MQkADAAyBwAzBwA0BwA2AQASUmVkZWZpbmVUZXN0T2JqZWN0AQAMSW5uZXJDbGFzc2VzAQANUmVk" + 189 "ZWZpbmVTdGF0ZQEAC0NMQVNTX0JZVEVTAQACW0IBAAlERVhfQllURVMBAA9yZWRlZmluZV9zdGF0" + 190 "ZXMBABNMamF2YS91dGlsL0VudW1TZXQ7AQAJU2lnbmF0dXJlAQBETGphdmEvdXRpbC9FbnVtU2V0" + 191 "PExhcnQvVGVzdDE5NTMkUmVkZWZpbmVUZXN0T2JqZWN0JFJlZGVmaW5lU3RhdGU7PjsBAAY8aW5p" + 192 "dD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAIdG9TdHJpbmcBABQoKUxqYXZhL2xh" + 193 "bmcvU3RyaW5nOwEADmNhbGxlZEZ1bmN0aW9uAQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQANVGVz" + 194 "dDE5NTMuamF2YQwAGQAaAQAtYXJ0L1Rlc3QxOTUzJFJlZGVmaW5lVGVzdE9iamVjdCRSZWRlZmlu" + 195 "ZVN0YXRlBwA3DAA4ADkMABUAFgwAHQAeAQAQQm9vdHN0cmFwTWV0aG9kcw8GADoIADsMADwAPQwA" + 196 "PgA/DABAAEEHAEIMAEMAGgwAEgATDAAUABMBAB9hcnQvVGVzdDE5NTMkUmVkZWZpbmVUZXN0T2Jq" + 197 "ZWN0AQAfYXJ0L1Rlc3QxOTUzJEFic3RyYWN0VGVzdE9iamVjdAEAEkFic3RyYWN0VGVzdE9iamVj" + 198 "dAEAEmphdmEvbGFuZy9SdW5uYWJsZQEAEWphdmEvdXRpbC9FbnVtU2V0AQAGbm9uZU9mAQAmKExq" + 199 "YXZhL2xhbmcvQ2xhc3M7KUxqYXZhL3V0aWwvRW51bVNldDsKAEQARQEAM1JlZGVmaW5lVGVzdE9i" + 200 "amVjdCB7IHN0YXRlczogASBjdXJyZW50OiBSRURFRklORUQgfQEAF21ha2VDb25jYXRXaXRoQ29u" + 201 "c3RhbnRzAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAlSRURFRklO" + 202 "RUQBAC9MYXJ0L1Rlc3QxOTUzJFJlZGVmaW5lVGVzdE9iamVjdCRSZWRlZmluZVN0YXRlOwEAA2Fk" + 203 "ZAEAFShMamF2YS9sYW5nL09iamVjdDspWgEADGFydC9UZXN0MTk1MwEACWRvTm90aGluZwcARgwA" + 204 "PABJAQAkamF2YS9sYW5nL2ludm9rZS9TdHJpbmdDb25jYXRGYWN0b3J5BwBLAQAGTG9va3VwAQCY" + 205 "KExqYXZhL2xhbmcvaW52b2tlL01ldGhvZEhhbmRsZXMkTG9va3VwO0xqYXZhL2xhbmcvU3RyaW5n" + 206 "O0xqYXZhL2xhbmcvaW52b2tlL01ldGhvZFR5cGU7TGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xh" + 207 "bmcvT2JqZWN0OylMamF2YS9sYW5nL2ludm9rZS9DYWxsU2l0ZTsHAEwBACVqYXZhL2xhbmcvaW52" + 208 "b2tlL01ldGhvZEhhbmRsZXMkTG9va3VwAQAeamF2YS9sYW5nL2ludm9rZS9NZXRob2RIYW5kbGVz" + 209 "ACEADAANAAEADgADABkAEgATAAAAGQAUABMAAAABABUAFgABABcAAAACABgABAABABkAGgABABsA" + 210 "AAAuAAIAAQAAAA4qtwABKhICuAADtQAEsQAAAAEAHAAAAA4AAwAAACEABAAiAA0AIwABAB0AHgAB" + 211 "ABsAAAAlAAEAAQAAAA0qtAAEtgAFugAGAACwAAAAAQAcAAAABgABAAAAJQABAB8AGgABABsAAAAv" + 212 "AAIAAQAAAA8qtAAEsgAHtgAIV7gACbEAAAABABwAAAAOAAMAAAApAAsAKwAOACwACAAgABoAAQAb" + 213 "AAAAKQABAAAAAAAJAbMACgGzAAuxAAAAAQAcAAAADgADAAAAGwAEABwACAAdAAMAIQAAAAIAIgAQ" + 214 "AAAAIgAEAAwALwAPAAkAAgAMABFAGQANAC8ANQQJAEcASgBIABkAKQAAAAgAAQAqAAEAKw=="); 215 public static final byte[] DEX_BYTES = Base64.getDecoder().decode( 216 "ZGV4CjAzNQAaR23N6WpunLRVX+BexSuzzNNiHNOvQpFoBwAAcAAAAHhWNBIAAAAAAAAAAKQGAAAq" + 217 "AAAAcAAAABEAAAAYAQAABQAAAFwBAAAEAAAAmAEAAAwAAAC4AQAAAQAAABgCAAAwBQAAOAIAACID" + 218 "AAA5AwAAQwMAAEsDAABPAwAAXAMAAGcDAABqAwAAbgMAAJEDAADCAwAA5QMAAPUDAAAZBAAAOQQA" + 219 "AFwEAAB7BAAAjgQAAKIEAAC4BAAAzAQAAOcEAAD8BAAAEQUAABwFAAAwBQAATwUAAF4FAABhBQAA" + 220 "ZAUAAGgFAABsBQAAeQUAAH4FAACGBQAAlgUAAKEFAACnBQAArwUAAMAFAADKBQAA0QUAAAgAAAAJ" + 221 "AAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAGwAAABwA" + 222 "AAAeAAAABgAAAAsAAAAAAAAABwAAAAwAAAAMAwAABwAAAA0AAAAUAwAAGwAAAA4AAAAAAAAAHQAA" + 223 "AA8AAAAcAwAAAQABABcAAAACABAABAAAAAIAEAAFAAAAAgANACYAAAAAAAMAAgAAAAIAAwABAAAA" + 224 "AgADAAIAAAACAAMAIgAAAAIAAAAnAAAAAwADACMAAAAMAAMAAgAAAAwAAQAhAAAADAAAACcAAAAN" + 225 "AAQAIAAAAA0AAgAlAAAADQAAACcAAAACAAAAAQAAAAAAAAAEAwAAGgAAAIwGAABRBgAAAAAAAAQA" + 226 "AQACAAAA+gIAAB0AAABUMAMAbhALAAAADAAiAQwAcBAGAAEAGgIZAG4gBwAhAG4gBwABABoAAABu" + 227 "IAcAAQBuEAgAAQAMABEAAAABAAAAAAAAAPQCAAAGAAAAEgBpAAEAaQACAA4AAgABAAEAAADuAgAA" + 228 "DAAAAHAQAAABABwAAQBxEAoAAAAMAFsQAwAOAAMAAQACAAAA/gIAAAsAAABUIAMAYgEAAG4gCQAQ" + 229 "AHEABQAAAA4AIQAOPIcAGwAOPC0AJQAOACkADnk8AAEAAAAKAAAAAQAAAAsAAAABAAAACAAAAAEA" + 230 "AAAJABUgY3VycmVudDogUkVERUZJTkVEIH0ACDxjbGluaXQ+AAY8aW5pdD4AAj47AAtDTEFTU19C" + 231 "WVRFUwAJREVYX0JZVEVTAAFMAAJMTAAhTGFydC9UZXN0MTk1MyRBYnN0cmFjdFRlc3RPYmplY3Q7" + 232 "AC9MYXJ0L1Rlc3QxOTUzJFJlZGVmaW5lVGVzdE9iamVjdCRSZWRlZmluZVN0YXRlOwAhTGFydC9U" + 233 "ZXN0MTk1MyRSZWRlZmluZVRlc3RPYmplY3Q7AA5MYXJ0L1Rlc3QxOTUzOwAiTGRhbHZpay9hbm5v" + 234 "dGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ACFM" + 235 "ZGFsdmlrL2Fubm90YXRpb24vTWVtYmVyQ2xhc3NlczsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWdu" + 236 "YXR1cmU7ABFMamF2YS9sYW5nL0NsYXNzOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5n" + 237 "L1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7" + 238 "ABNMamF2YS91dGlsL0VudW1TZXQ7ABNMamF2YS91dGlsL0VudW1TZXQ8AAlSRURFRklORUQAElJl" + 239 "ZGVmaW5lVGVzdE9iamVjdAAdUmVkZWZpbmVUZXN0T2JqZWN0IHsgc3RhdGVzOiAADVRlc3QxOTUz" + 240 "LmphdmEAAVYAAVoAAlpMAAJbQgALYWNjZXNzRmxhZ3MAA2FkZAAGYXBwZW5kAA5jYWxsZWRGdW5j" + 241 "dGlvbgAJZG9Ob3RoaW5nAARuYW1lAAZub25lT2YAD3JlZGVmaW5lX3N0YXRlcwAIdG9TdHJpbmcA" + 242 "BXZhbHVlAFt+fkQ4eyJtaW4tYXBpIjoxLCJzaGEtMSI6IjUyNzNjM2RmZWUxMDQ2NzIwYWY0MjVm" + 243 "YTg1NTMxNmM5OWM4NmM4ZDIiLCJ2ZXJzaW9uIjoiMS4zLjE4LWRldiJ9AAIHASgcAxcWFwkXAwIE" + 244 "ASgYAwIFAh8ECSQXGAIGASgcARgBAgECAgEZARkDAQGIgASEBQGBgASgBQMByAUBAbgEAAAAAAAB" + 245 "AAAALgYAAAMAAAA6BgAAQAYAAEkGAAB8BgAAAQAAAAAAAAAAAAAAAwAAAHQGAAAQAAAAAAAAAAEA" + 246 "AAAAAAAAAQAAACoAAABwAAAAAgAAABEAAAAYAQAAAwAAAAUAAABcAQAABAAAAAQAAACYAQAABQAA" + 247 "AAwAAAC4AQAABgAAAAEAAAAYAgAAASAAAAQAAAA4AgAAAyAAAAQAAADuAgAAARAAAAQAAAAEAwAA" + 248 "AiAAACoAAAAiAwAABCAAAAQAAAAuBgAAACAAAAEAAABRBgAAAxAAAAMAAABwBgAABiAAAAEAAACM" + 249 "BgAAABAAAAEAAACkBgAA"); 250 251 public EnumSet<RedefineState> redefine_states; 252 public RedefineTestObject() { 253 super(); 254 redefine_states = EnumSet.noneOf(RedefineState.class); 255 } 256 257 public String toString() { 258 return "RedefineTestObject { states: " + redefine_states.toString() + " current: ORIGINAL }"; 259 } 260 261 public void calledFunction() { 262 redefine_states.add(RedefineState.ORIGINAL); // line +0 263 // We will trigger the redefinition using a breakpoint on the next line. 264 doNothing(); // line +2 265 } 266 } 267 268 public static class ClassLoadObject implements TestRunnable { 269 public int cnt; 270 public int baseCallCnt; 271 272 public static final String[] CLASS_NAMES = new String[] { 273 "Lart/Test1953$ClassLoadObject$TC0;", 274 "Lart/Test1953$ClassLoadObject$TC1;", 275 "Lart/Test1953$ClassLoadObject$TC2;", 276 "Lart/Test1953$ClassLoadObject$TC3;", 277 "Lart/Test1953$ClassLoadObject$TC4;", 278 "Lart/Test1953$ClassLoadObject$TC5;", 279 "Lart/Test1953$ClassLoadObject$TC6;", 280 "Lart/Test1953$ClassLoadObject$TC7;", 281 "Lart/Test1953$ClassLoadObject$TC8;", 282 "Lart/Test1953$ClassLoadObject$TC9;", 283 }; 284 285 private static int curClass = 0; 286 287 private static class TC0 { public static int foo; static { foo = 1; } } 288 private static class TC1 { public static int foo; static { foo = 2; } } 289 private static class TC2 { public static int foo; static { foo = 3; } } 290 private static class TC3 { public static int foo; static { foo = 4; } } 291 private static class TC4 { public static int foo; static { foo = 5; } } 292 private static class TC5 { public static int foo; static { foo = 6; } } 293 private static class TC6 { public static int foo; static { foo = 7; } } 294 private static class TC7 { public static int foo; static { foo = 8; } } 295 private static class TC8 { public static int foo; static { foo = 9; } } 296 private static class TC9 { public static int foo; static { foo = 10; } } 297 298 public ClassLoadObject() { 299 super(); 300 cnt = 0; 301 baseCallCnt = 0; 302 } 303 304 public int getBaseCallCount() { 305 return baseCallCnt; 306 } 307 308 public void run() { 309 baseCallCnt++; 310 if (curClass == 0) { 311 $noprecompile$calledFunction0(); 312 } else if (curClass == 1) { 313 $noprecompile$calledFunction1(); 314 } else if (curClass == 2) { 315 $noprecompile$calledFunction2(); 316 } else if (curClass == 3) { 317 $noprecompile$calledFunction3(); 318 } else if (curClass == 4) { 319 $noprecompile$calledFunction4(); 320 } else if (curClass == 5) { 321 $noprecompile$calledFunction5(); 322 } else if (curClass == 6) { 323 $noprecompile$calledFunction6(); 324 } else if (curClass == 7) { 325 $noprecompile$calledFunction7(); 326 } else if (curClass == 8) { 327 $noprecompile$calledFunction8(); 328 } else if (curClass == 9) { 329 $noprecompile$calledFunction9(); 330 } 331 curClass++; 332 } 333 334 public Method getCalledMethod() throws Exception { 335 return this.getClass().getMethod("jnoprecompile$calledFunction" + curClass); 336 } 337 338 // Give these all a tag to prevent 1954 from compiling them (and loading the class as a 339 // consequence). 340 public void $noprecompile$calledFunction0() { 341 cnt++; 342 System.out.println("TC0.foo == " + TC0.foo); 343 } 344 345 public void $noprecompile$calledFunction1() { 346 cnt++; 347 System.out.println("TC1.foo == " + TC1.foo); 348 } 349 350 public void $noprecompile$calledFunction2() { 351 cnt++; 352 System.out.println("TC2.foo == " + TC2.foo); 353 } 354 355 public void $noprecompile$calledFunction3() { 356 cnt++; 357 System.out.println("TC3.foo == " + TC3.foo); 358 } 359 360 public void $noprecompile$calledFunction4() { 361 cnt++; 362 System.out.println("TC4.foo == " + TC4.foo); 363 } 364 365 public void $noprecompile$calledFunction5() { 366 cnt++; 367 System.out.println("TC5.foo == " + TC5.foo); 368 } 369 370 public void $noprecompile$calledFunction6() { 371 cnt++; 372 System.out.println("TC6.foo == " + TC6.foo); 373 } 374 375 public void $noprecompile$calledFunction7() { 376 cnt++; 377 System.out.println("TC7.foo == " + TC7.foo); 378 } 379 380 public void $noprecompile$calledFunction8() { 381 cnt++; 382 System.out.println("TC8.foo == " + TC8.foo); 383 } 384 385 public void $noprecompile$calledFunction9() { 386 cnt++; 387 System.out.println("TC9.foo == " + TC9.foo); 388 } 389 390 public String toString() { 391 return "ClassLoadObject { cnt: " + cnt + ", curClass: " + curClass + "}"; 392 } 393 } 394 395 public static class FieldBasedTestObject extends AbstractTestObject implements Runnable { 396 public int cnt; 397 public int TARGET_FIELD; 398 public FieldBasedTestObject() { 399 super(); 400 cnt = 0; 401 TARGET_FIELD = 0; 402 } 403 404 public void calledFunction() { 405 cnt++; 406 // We put a watchpoint here and PopFrame when we are at it. 407 TARGET_FIELD += 10; 408 if (cnt == 1) { System.out.println("FAILED: No pop on first call!"); } 409 } 410 411 public String toString() { 412 return "FieldBasedTestObject { cnt: " + cnt + ", TARGET_FIELD: " + TARGET_FIELD + " }"; 413 } 414 } 415 416 public static class StandardTestObject extends AbstractTestObject implements Runnable { 417 public int cnt; 418 public final boolean check; 419 420 public StandardTestObject(boolean check) { 421 super(); 422 cnt = 0; 423 this.check = check; 424 } 425 426 public StandardTestObject() { 427 this(true); 428 } 429 430 public void calledFunction() { 431 cnt++; // line +0 432 // We put a breakpoint here and PopFrame when we are at it. 433 doNothing(); // line +2 434 if (check && cnt == 1) { System.out.println("FAILED: No pop on first call!"); } 435 } 436 437 public String toString() { 438 return "StandardTestObject { cnt: " + cnt + " }"; 439 } 440 } 441 442 public static class SynchronizedFunctionTestObject extends AbstractTestObject implements Runnable { 443 public int cnt; 444 445 public SynchronizedFunctionTestObject() { 446 super(); 447 cnt = 0; 448 } 449 450 public synchronized void calledFunction() { 451 cnt++; // line +0 452 // We put a breakpoint here and PopFrame when we are at it. 453 doNothing(); // line +2 454 } 455 456 public String toString() { 457 return "SynchronizedFunctionTestObject { cnt: " + cnt + " }"; 458 } 459 } 460 public static class SynchronizedTestObject extends AbstractTestObject implements Runnable { 461 public int cnt; 462 public final Object lock; 463 464 public SynchronizedTestObject() { 465 this(new Object()); 466 } 467 468 public SynchronizedTestObject(Object l) { 469 super(); 470 cnt = 0; 471 lock = l; 472 } 473 474 public void calledFunction() { 475 synchronized (lock) { // line +0 476 cnt++; // line +1 477 // We put a breakpoint here and PopFrame when we are at it. 478 doNothing(); // line +3 479 } 480 } 481 482 public String toString() { 483 return "SynchronizedTestObject { cnt: " + cnt + " }"; 484 } 485 } 486 487 public static class ExceptionCatchTestObject extends AbstractTestObject implements Runnable { 488 public static class TestError extends Error {} 489 490 public int cnt; 491 public ExceptionCatchTestObject() { 492 super(); 493 cnt = 0; 494 } 495 496 public void calledFunction() { 497 cnt++; 498 try { 499 doThrow(); 500 } catch (TestError e) { 501 System.out.println(e.getClass().getName() + " caught in called function."); 502 } 503 } 504 505 public void doThrow() { 506 throw new TestError(); 507 } 508 509 public String toString() { 510 return "ExceptionCatchTestObject { cnt: " + cnt + " }"; 511 } 512 } 513 514 public static class ExceptionThrowFarTestObject implements TestRunnable { 515 public static class TestError extends Error {} 516 517 public int cnt; 518 public int baseCallCnt; 519 public final boolean catchInCalled; 520 public ExceptionThrowFarTestObject(boolean catchInCalled) { 521 super(); 522 cnt = 0; 523 baseCallCnt = 0; 524 this.catchInCalled = catchInCalled; 525 } 526 527 public int getBaseCallCount() { 528 return baseCallCnt; 529 } 530 531 public void run() { 532 baseCallCnt++; 533 try { 534 callingFunction(); 535 } catch (TestError e) { 536 System.out.println(e.getClass().getName() + " thrown and caught!"); 537 } 538 } 539 540 public void callingFunction() { 541 calledFunction(); 542 } 543 public void calledFunction() { 544 cnt++; 545 if (catchInCalled) { 546 try { 547 throw new TestError(); // We put a watch here. 548 } catch (TestError e) { 549 System.out.println(e.getClass().getName() + " caught in same function."); 550 } 551 } else { 552 throw new TestError(); // We put a watch here. 553 } 554 } 555 556 public Method getCallingMethod() throws Exception { 557 return this.getClass().getMethod("callingFunction"); 558 } 559 560 public Method getCalledMethod() throws Exception { 561 return this.getClass().getMethod("calledFunction"); 562 } 563 564 public String toString() { 565 return "ExceptionThrowFarTestObject { cnt: " + cnt + " }"; 566 } 567 } 568 569 public static class ExceptionOnceObject extends AbstractTestObject { 570 public static final class TestError extends Error {} 571 public int cnt; 572 public final boolean throwInSub; 573 public ExceptionOnceObject(boolean throwInSub) { 574 super(); 575 cnt = 0; 576 this.throwInSub = throwInSub; 577 } 578 579 public void calledFunction() { 580 cnt++; 581 if (cnt == 1) { 582 if (throwInSub) { 583 doThrow(); 584 } else { 585 throw new TestError(); 586 } 587 } 588 } 589 590 public void doThrow() { 591 throw new TestError(); 592 } 593 594 public String toString() { 595 return "ExceptionOnceObject { cnt: " + cnt + ", throwInSub: " + throwInSub + " }"; 596 } 597 } 598 599 public static class ExceptionThrowTestObject implements TestRunnable { 600 public static class TestError extends Error {} 601 602 public int cnt; 603 public int baseCallCnt; 604 public final boolean catchInCalled; 605 public ExceptionThrowTestObject(boolean catchInCalled) { 606 super(); 607 cnt = 0; 608 baseCallCnt = 0; 609 this.catchInCalled = catchInCalled; 610 } 611 612 public int getBaseCallCount() { 613 return baseCallCnt; 614 } 615 616 public void run() { 617 baseCallCnt++; 618 try { 619 calledFunction(); 620 } catch (TestError e) { 621 System.out.println(e.getClass().getName() + " thrown and caught!"); 622 } 623 } 624 625 public void calledFunction() { 626 cnt++; 627 if (catchInCalled) { 628 try { 629 throw new TestError(); // We put a watch here. 630 } catch (TestError e) { 631 System.out.println(e.getClass().getName() + " caught in same function."); 632 } 633 } else { 634 throw new TestError(); // We put a watch here. 635 } 636 } 637 638 public Method getCalledMethod() throws Exception { 639 return this.getClass().getMethod("calledFunction"); 640 } 641 642 public String toString() { 643 return "ExceptionThrowTestObject { cnt: " + cnt + " }"; 644 } 645 } 646 647 public static class NativeCalledObject extends AbstractTestObject { 648 public int cnt = 0; 649 650 public native void calledFunction(); 651 652 public String toString() { 653 return "NativeCalledObject { cnt: " + cnt + " }"; 654 } 655 } 656 657 public static class NativeCallerObject implements TestRunnable { 658 public int baseCnt = 0; 659 public int cnt = 0; 660 661 public int getBaseCallCount() { 662 return baseCnt; 663 } 664 665 public native void run(); 666 667 public void calledFunction() { 668 cnt++; 669 // We will stop using a MethodExit event. 670 } 671 672 public Method getCalledMethod() throws Exception { 673 return this.getClass().getMethod("calledFunction"); 674 } 675 676 public String toString() { 677 return "NativeCallerObject { cnt: " + cnt + " }"; 678 } 679 } 680 public static class SuspendSuddenlyObject extends AbstractTestObject { 681 public volatile boolean stop_spinning = false; 682 public volatile boolean is_spinning = false; 683 public int cnt = 0; 684 685 public void calledFunction() { 686 cnt++; 687 while (!stop_spinning) { 688 is_spinning = true; 689 } 690 } 691 692 public String toString() { 693 return "SuspendSuddenlyObject { cnt: " + cnt + " }"; 694 } 695 } 696 697 public static void run(boolean canRunClassLoadTests) throws Exception { 698 new Test1953(canRunClassLoadTests, (x)-> {}).runTests(); 699 } 700 701 // This entrypoint is used by CTS only. */ 702 public static void run() throws Exception { 703 /* TODO: Due to the way that CTS tests are verified we cannot run class-load-tests since the 704 * verifier will be delayed until runtime and then load the classes all at once. This 705 * makes the test impossible to run. 706 */ 707 run(/*canRunClassLoadTests*/ false); 708 } 709 710 public Test1953(boolean canRunClassLoadTests, Consumer<TestRunnable> preTest) { 711 this.canRunClassLoadTests = canRunClassLoadTests; 712 this.preTest = preTest; 713 } 714 715 private Consumer<TestRunnable> preTest; 716 717 public void runTests() throws Exception { 718 setupTest(); 719 720 final Method calledFunction = StandardTestObject.class.getDeclaredMethod("calledFunction"); 721 final Method doNothingMethod = Test1953.class.getDeclaredMethod("doNothing"); 722 // Add a breakpoint on the second line after the start of the function 723 final int line = Breakpoint.locationToLine(calledFunction, 0) + 2; 724 final long loc = Breakpoint.lineToLocation(calledFunction, line); 725 System.out.println("Test stopped using breakpoint"); 726 runTestOn(new StandardTestObject(), 727 (thr) -> setupSuspendBreakpointFor(calledFunction, loc, thr), 728 SuspendEvents::clearSuspendBreakpointFor); 729 730 final Method syncFunctionCalledFunction = 731 SynchronizedFunctionTestObject.class.getDeclaredMethod("calledFunction"); 732 // Add a breakpoint on the second line after the start of the function 733 // Annoyingly r8 generally has the first instruction (a monitor enter) not be marked as being 734 // on any line but javac has it marked as being on the first line of the function. Just use the 735 // second entry on the line-number table to get the breakpoint. This should be good for both. 736 final long syncFunctionLoc = 737 Breakpoint.getLineNumberTable(syncFunctionCalledFunction)[1].location; 738 System.out.println("Test stopped using breakpoint with declared synchronized function"); 739 runTestOn(new SynchronizedFunctionTestObject(), 740 (thr) -> setupSuspendBreakpointFor(syncFunctionCalledFunction, syncFunctionLoc, thr), 741 SuspendEvents::clearSuspendBreakpointFor); 742 743 final Method syncCalledFunction = 744 SynchronizedTestObject.class.getDeclaredMethod("calledFunction"); 745 // Add a breakpoint on the second line after the start of the function 746 final int syncLine = Breakpoint.locationToLine(syncCalledFunction, 0) + 3; 747 final long syncLoc = Breakpoint.lineToLocation(syncCalledFunction, syncLine); 748 System.out.println("Test stopped using breakpoint with synchronized block"); 749 Object lock = new Object(); 750 synchronized (lock) {} 751 runTestOn(new SynchronizedTestObject(lock), 752 (thr) -> setupSuspendBreakpointFor(syncCalledFunction, syncLoc, thr), 753 SuspendEvents::clearSuspendBreakpointFor); 754 synchronized (lock) {} 755 756 System.out.println("Test stopped on single step"); 757 runTestOn(new StandardTestObject(), 758 (thr) -> setupSuspendSingleStepAt(calledFunction, loc, thr), 759 SuspendEvents::clearSuspendSingleStepFor); 760 761 final Field target_field = FieldBasedTestObject.class.getDeclaredField("TARGET_FIELD"); 762 System.out.println("Test stopped on field access"); 763 runTestOn(new FieldBasedTestObject(), 764 (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, true, thr), 765 SuspendEvents::clearFieldSuspendFor); 766 767 System.out.println("Test stopped on field modification"); 768 runTestOn(new FieldBasedTestObject(), 769 (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, false, thr), 770 SuspendEvents::clearFieldSuspendFor); 771 772 System.out.println("Test stopped during Method Exit of doNothing"); 773 runTestOn(new StandardTestObject(false), 774 (thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ false, thr), 775 SuspendEvents::clearSuspendMethodEvent); 776 777 // NB We need another test to make sure the MethodEntered event is triggered twice. 778 System.out.println("Test stopped during Method Enter of doNothing"); 779 runTestOn(new StandardTestObject(false), 780 (thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ true, thr), 781 SuspendEvents::clearSuspendMethodEvent); 782 783 System.out.println("Test stopped during Method Exit of calledFunction"); 784 runTestOn(new StandardTestObject(false), 785 (thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ false, thr), 786 SuspendEvents::clearSuspendMethodEvent); 787 788 System.out.println("Test stopped during Method Enter of calledFunction"); 789 runTestOn(new StandardTestObject(false), 790 (thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ true, thr), 791 SuspendEvents::clearSuspendMethodEvent); 792 793 final Method exceptionOnceCalledMethod = 794 ExceptionOnceObject.class.getDeclaredMethod("calledFunction"); 795 System.out.println("Test stopped during Method Exit due to exception thrown in same function"); 796 runTestOn(new ExceptionOnceObject(/*throwInSub*/ false), 797 (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr), 798 SuspendEvents::clearSuspendMethodEvent); 799 800 System.out.println("Test stopped during Method Exit due to exception thrown in subroutine"); 801 runTestOn(new ExceptionOnceObject(/*throwInSub*/ true), 802 (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr), 803 SuspendEvents::clearSuspendMethodEvent); 804 805 final Method exceptionThrowCalledMethod = 806 ExceptionThrowTestObject.class.getDeclaredMethod("calledFunction"); 807 final Method exceptionCatchThrowMethod = 808 ExceptionCatchTestObject.class.getDeclaredMethod("doThrow"); 809 // Disable more often then we technically need to in order to avoid the need 810 // for a huge number of possible results and allow the test to be easily 811 // used in CTS. 812 if (IS_ART && canRunClassLoadTests && CanRunClassLoadingTests()) { 813 System.out.println("Test stopped during notifyFramePop without exception on pop of calledFunction"); 814 runTestOn(new StandardTestObject(false), 815 (thr) -> setupSuspendPopFrameEvent(1, doNothingMethod, thr), 816 SuspendEvents::clearSuspendPopFrameEvent); 817 818 System.out.println("Test stopped during notifyFramePop without exception on pop of doNothing"); 819 runTestOn(new StandardTestObject(false), 820 (thr) -> setupSuspendPopFrameEvent(0, doNothingMethod, thr), 821 SuspendEvents::clearSuspendPopFrameEvent); 822 823 System.out.println("Test stopped during notifyFramePop with exception on pop of calledFunction"); 824 runTestOn(new ExceptionThrowTestObject(false), 825 (thr) -> setupSuspendPopFrameEvent(0, exceptionThrowCalledMethod, thr), 826 SuspendEvents::clearSuspendPopFrameEvent); 827 828 System.out.println("Test stopped during notifyFramePop with exception on pop of doThrow"); 829 runTestOn(new ExceptionCatchTestObject(), 830 (thr) -> setupSuspendPopFrameEvent(0, exceptionCatchThrowMethod, thr), 831 SuspendEvents::clearSuspendPopFrameEvent); 832 } 833 834 System.out.println("Test stopped during ExceptionCatch event of calledFunction " + 835 "(catch in called function, throw in called function)"); 836 runTestOn(new ExceptionThrowTestObject(true), 837 (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ true, thr), 838 SuspendEvents::clearSuspendExceptionEvent); 839 840 final Method exceptionCatchCalledMethod = 841 ExceptionCatchTestObject.class.getDeclaredMethod("calledFunction"); 842 System.out.println("Test stopped during ExceptionCatch event of calledFunction " + 843 "(catch in called function, throw in subroutine)"); 844 runTestOn(new ExceptionCatchTestObject(), 845 (thr) -> setupSuspendExceptionEvent(exceptionCatchCalledMethod, /*catch*/ true, thr), 846 SuspendEvents::clearSuspendExceptionEvent); 847 848 System.out.println("Test stopped during Exception event of calledFunction " + 849 "(catch in calling function)"); 850 runTestOn(new ExceptionThrowTestObject(false), 851 (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr), 852 SuspendEvents::clearSuspendExceptionEvent); 853 854 System.out.println("Test stopped during Exception event of calledFunction " + 855 "(catch in called function)"); 856 runTestOn(new ExceptionThrowTestObject(true), 857 (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr), 858 SuspendEvents::clearSuspendExceptionEvent); 859 860 final Method exceptionThrowFarCalledMethod = 861 ExceptionThrowFarTestObject.class.getDeclaredMethod("calledFunction"); 862 System.out.println("Test stopped during Exception event of calledFunction " + 863 "(catch in parent of calling function)"); 864 runTestOn(new ExceptionThrowFarTestObject(false), 865 (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr), 866 SuspendEvents::clearSuspendExceptionEvent); 867 868 System.out.println("Test stopped during Exception event of calledFunction " + 869 "(catch in called function)"); 870 runTestOn(new ExceptionThrowFarTestObject(true), 871 (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr), 872 SuspendEvents::clearSuspendExceptionEvent); 873 874 // These tests are disabled for either the RI (b/116003018) or for jvmti-stress. For the 875 // later it is due to the additional agent causing classes to be loaded earlier as it forces 876 // deeper verification during class redefinition, causing failures. 877 // NB the agent is prevented from popping frames in either of these events in ART. See 878 // b/117615146 for more information about this restriction. 879 if (canRunClassLoadTests && CanRunClassLoadingTests()) { 880 // This test doesn't work on RI since the RI disallows use of PopFrame during a ClassLoad 881 // event. See b/116003018 for more information. 882 System.out.println("Test stopped during a ClassLoad event."); 883 runTestOn(new ClassLoadObject(), 884 (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_LOAD, ClassLoadObject.CLASS_NAMES, thr), 885 SuspendEvents::clearSuspendClassEvent); 886 887 // The RI handles a PopFrame during a ClassPrepare event incorrectly. See b/116003018 for 888 // more information. 889 System.out.println("Test stopped during a ClassPrepare event."); 890 runTestOn(new ClassLoadObject(), 891 (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_PREPARE, 892 ClassLoadObject.CLASS_NAMES, 893 thr), 894 SuspendEvents::clearSuspendClassEvent); 895 } 896 System.out.println("Test stopped during random Suspend."); 897 final SuspendSuddenlyObject sso = new SuspendSuddenlyObject(); 898 runTestOn( 899 sso, 900 new TestSuspender() { 901 public void setup(Thread thr) { } 902 public void waitForSuspend(Thread thr) { 903 while (!sso.is_spinning) {} 904 Suspension.suspend(thr); 905 } 906 public void cleanup(Thread thr) { 907 sso.stop_spinning = true; 908 } 909 }); 910 911 final Method redefineCalledFunction = 912 RedefineTestObject.class.getDeclaredMethod("calledFunction"); 913 final int redefLine = Breakpoint.locationToLine(redefineCalledFunction, 0) + 2; 914 final long redefLoc = Breakpoint.lineToLocation(redefineCalledFunction, redefLine); 915 System.out.println("Test redefining frame being popped."); 916 runTestOn(new RedefineTestObject(), 917 (thr) -> setupSuspendBreakpointFor(redefineCalledFunction, redefLoc, thr), 918 (thr) -> { 919 clearSuspendBreakpointFor(thr); 920 Redefinition.doCommonClassRedefinition(RedefineTestObject.class, 921 RedefineTestObject.CLASS_BYTES, 922 RedefineTestObject.DEX_BYTES); 923 }); 924 925 System.out.println("Test stopped during a native method fails"); 926 runTestOn(new NativeCalledObject(), 927 SuspendEvents::setupWaitForNativeCall, 928 SuspendEvents::clearWaitForNativeCall); 929 930 System.out.println("Test stopped in a method called by native fails"); 931 final Method nativeCallerMethod = NativeCallerObject.class.getDeclaredMethod("calledFunction"); 932 runTestOn(new NativeCallerObject(), 933 (thr) -> setupSuspendMethodEvent(nativeCallerMethod, /*enter*/ false, thr), 934 SuspendEvents::clearSuspendMethodEvent); 935 936 937 final Object lock2 = new Object(); 938 synchronized (lock2) {} 939 System.out.println("Test stopped with monitor in enclosing frame."); 940 runTestOn(new StandardTestObject() { 941 @Override 942 public void run() { 943 synchronized (lock2) { 944 super.run(); 945 } 946 } 947 }, 948 (thr) -> setupSuspendBreakpointFor(calledFunction, loc, thr), 949 SuspendEvents::clearSuspendBreakpointFor); 950 synchronized (lock2) {} 951 } 952 953 // Volatile is to prevent any future optimizations that could invalidate this test by doing 954 // constant propagation and eliminating the failing paths before the verifier is able to load the 955 // class. 956 static volatile boolean ranClassLoadTest = false; 957 static boolean classesPreverified = false; 958 private static final class RCLT0 { public void foo() {} } 959 private static final class RCLT1 { public void foo() {} } 960 // If classes are not preverified for some reason (interp-ac, no-image, etc) the verifier will 961 // actually load classes as it runs. This means that we cannot use the class-load tests as they 962 // are written. TODO Support this. 963 public boolean CanRunClassLoadingTests() { 964 if (ranClassLoadTest) { 965 return classesPreverified; 966 } 967 if (!ranClassLoadTest) { 968 // Only this will ever be executed. 969 new RCLT0().foo(); 970 } else { 971 // This will never be executed. If classes are not preverified the verifier will load RCLT1 972 // when the enclosing method is run. This behavior makes the class-load/prepare test cases 973 // impossible to successfully run (they will deadlock). 974 new RCLT1().foo(); 975 System.out.println("FAILURE: UNREACHABLE Location!"); 976 } 977 classesPreverified = !isClassLoaded("Lart/Test1953$RCLT1;"); 978 ranClassLoadTest = true; 979 return classesPreverified; 980 } 981 982 public static native boolean isClassLoaded(String name); 983 public static native void popFrame(Thread thr); 984 } 985