1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package art; 16 17 import static art.SuspendEvents.EVENT_TYPE_CLASS_LOAD; 18 import static art.SuspendEvents.setupFieldSuspendFor; 19 import static art.SuspendEvents.setupSuspendBreakpointFor; 20 import static art.SuspendEvents.setupSuspendClassEvent; 21 import static art.SuspendEvents.setupSuspendExceptionEvent; 22 import static art.SuspendEvents.setupSuspendMethodEvent; 23 import static art.SuspendEvents.setupSuspendPopFrameEvent; 24 import static art.SuspendEvents.setupSuspendSingleStepAt; 25 import static art.SuspendEvents.setupTest; 26 import static art.SuspendEvents.waitForSuspendHit; 27 28 import java.io.*; 29 import java.lang.reflect.Executable; 30 import java.lang.reflect.Field; 31 import java.lang.reflect.Method; 32 import java.util.concurrent.CountDownLatch; 33 import java.util.function.Consumer; 34 import java.util.function.Supplier; 35 36 public class Test1969 { 37 public static final boolean PRINT_STACK_TRACE = false; 38 39 public final boolean canRunClassLoadTests; 40 doNothing()41 public static void doNothing() {} 42 43 public static interface TestSuspender { setupForceReturnRun(Thread thr)44 public void setupForceReturnRun(Thread thr); 45 waitForSuspend(Thread thr)46 public void waitForSuspend(Thread thr); 47 cleanup(Thread thr)48 public void cleanup(Thread thr); 49 performForceReturn(Thread thr)50 public default void performForceReturn(Thread thr) { 51 System.out.println("Will force return of " + thr.getName()); 52 NonStandardExit.forceEarlyReturnVoid(thr); 53 } 54 setupNormalRun(Thread thr)55 public default void setupNormalRun(Thread thr) {} 56 } 57 58 public static interface ThreadRunnable { run(Thread thr)59 public void run(Thread thr); 60 } 61 makeSuspend(final ThreadRunnable setup, final ThreadRunnable clean)62 public static TestSuspender makeSuspend(final ThreadRunnable setup, final ThreadRunnable clean) { 63 return new TestSuspender() { 64 public void setupForceReturnRun(Thread thr) { 65 setup.run(thr); 66 } 67 68 public void waitForSuspend(Thread thr) { 69 waitForSuspendHit(thr); 70 } 71 72 public void cleanup(Thread thr) { 73 clean.run(thr); 74 } 75 }; 76 } 77 78 public void runTestOn(Supplier<Runnable> testObj, ThreadRunnable su, ThreadRunnable cl) 79 throws Exception { 80 runTestOn(testObj, makeSuspend(su, cl)); 81 } 82 83 private static void SafePrintStackTrace(StackTraceElement st[]) { 84 System.out.println(safeDumpStackTrace(st, "\t")); 85 } 86 87 private static String safeDumpStackTrace(StackTraceElement st[], String prefix) { 88 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 89 PrintStream os = new PrintStream(baos); 90 for (StackTraceElement e : st) { 91 os.println( 92 prefix 93 + e.getClassName() 94 + "." 95 + e.getMethodName() 96 + "(" 97 + (e.isNativeMethod() ? "Native Method" : e.getFileName()) 98 + ")"); 99 if (e.getClassName().equals("art.Test1969") && e.getMethodName().equals("runTests")) { 100 os.println(prefix + "<Additional frames hidden>"); 101 break; 102 } 103 } 104 os.flush(); 105 return baos.toString(); 106 } 107 108 static long ID_COUNTER = 0; 109 110 public Runnable Id(final Runnable tr) { 111 final long my_id = ID_COUNTER++; 112 return new Runnable() { 113 public void run() { 114 tr.run(); 115 } 116 117 public String toString() { 118 return "(ID: " + my_id + ") " + tr.toString(); 119 } 120 }; 121 } 122 123 public static long THREAD_COUNT = 0; 124 125 public Thread mkThread(Runnable r) { 126 Thread t = new Thread(r, "Test1969 target thread - " + THREAD_COUNT++); 127 t.setUncaughtExceptionHandler( 128 (thr, e) -> { 129 System.out.println( 130 "Uncaught exception in thread " 131 + thr 132 + " - " 133 + e.getClass().getName() 134 + ": " 135 + e.getLocalizedMessage()); 136 SafePrintStackTrace(e.getStackTrace()); 137 }); 138 return t; 139 } 140 141 final class TestConfig { 142 public final Runnable testObj; 143 public final TestSuspender suspender; 144 145 public TestConfig(Runnable obj, TestSuspender su) { 146 this.testObj = obj; 147 this.suspender = su; 148 } 149 } 150 151 public void runTestOn(Supplier<Runnable> testObjGen, TestSuspender su) throws Exception { 152 runTestOn(() -> new TestConfig(testObjGen.get(), su)); 153 } 154 155 public void runTestOn(Supplier<TestConfig> config) throws Exception { 156 TestConfig normal_config = config.get(); 157 Runnable normal_run = Id(normal_config.testObj); 158 try { 159 System.out.println("NORMAL RUN: Single call with no interference on " + normal_run); 160 Thread normal_thread = mkThread(normal_run); 161 normal_config.suspender.setupNormalRun(normal_thread); 162 normal_thread.start(); 163 normal_thread.join(); 164 System.out.println("NORMAL RUN: result for " + normal_run + " on " + normal_thread.getName()); 165 } catch (Exception e) { 166 System.out.println("NORMAL RUN: Ended with exception for " + normal_run + "!"); 167 e.printStackTrace(System.out); 168 } 169 170 TestConfig force_return_config = config.get(); 171 Runnable testObj = Id(force_return_config.testObj); 172 TestSuspender su = force_return_config.suspender; 173 System.out.println("Single call with force-early-return on " + testObj); 174 final CountDownLatch continue_latch = new CountDownLatch(1); 175 final CountDownLatch startup_latch = new CountDownLatch(1); 176 Runnable await = 177 () -> { 178 try { 179 startup_latch.countDown(); 180 continue_latch.await(); 181 } catch (Exception e) { 182 throw new Error("Failed to await latch", e); 183 } 184 }; 185 Thread thr = 186 mkThread( 187 () -> { 188 await.run(); 189 testObj.run(); 190 }); 191 thr.start(); 192 193 // Wait until the other thread is started. 194 startup_latch.await(); 195 196 // Setup suspension method on the thread. 197 su.setupForceReturnRun(thr); 198 199 // Let the other thread go. 200 continue_latch.countDown(); 201 202 // Wait for the other thread to hit the breakpoint/watchpoint/whatever and 203 // suspend itself 204 // (without re-entering java) 205 su.waitForSuspend(thr); 206 207 // Cleanup the breakpoint/watchpoint/etc. 208 su.cleanup(thr); 209 210 try { 211 // Pop the frame. 212 su.performForceReturn(thr); 213 } catch (Exception e) { 214 System.out.println("Failed to force-return due to " + e); 215 SafePrintStackTrace(e.getStackTrace()); 216 } 217 218 // Start the other thread going again. 219 Suspension.resume(thr); 220 221 // Wait for the other thread to finish. 222 thr.join(); 223 224 // See how many times calledFunction was called. 225 System.out.println("result for " + testObj + " on " + thr.getName()); 226 } 227 228 public abstract static class AbstractTestObject implements Runnable { 229 public AbstractTestObject() {} 230 231 public void run() { 232 // This function should be force-early-returned. 233 calledFunction(); 234 } 235 236 public abstract void calledFunction(); 237 } 238 239 public static class FieldBasedTestObject extends AbstractTestObject implements Runnable { 240 public int TARGET_FIELD; 241 public int cnt = 0; 242 243 public FieldBasedTestObject() { 244 super(); 245 TARGET_FIELD = 0; 246 } 247 248 public void calledFunction() { 249 cnt++; 250 // We put a watchpoint here and force-early-return when we are at it. 251 TARGET_FIELD += 10; 252 cnt++; 253 } 254 255 public String toString() { 256 return "FieldBasedTestObject { TARGET_FIELD: " + TARGET_FIELD + ", cnt: " + cnt + " }"; 257 } 258 } 259 260 public static class StandardTestObject extends AbstractTestObject implements Runnable { 261 public int cnt; 262 263 public StandardTestObject() { 264 super(); 265 cnt = 0; 266 } 267 268 public void calledFunction() { 269 cnt++; // line +0 270 // We put a breakpoint here and force-early-return when we are at it. 271 doNothing(); // line +2 272 cnt++; // line +3 273 return; // line +4 274 } 275 276 public String toString() { 277 return "StandardTestObject { cnt: " + cnt + " }"; 278 } 279 } 280 281 public static class SynchronizedFunctionTestObject extends AbstractTestObject 282 implements Runnable { 283 public int cnt; 284 285 public SynchronizedFunctionTestObject() { 286 super(); 287 cnt = 0; 288 } 289 290 public synchronized void calledFunction() { 291 cnt++; // line +0 292 // We put a breakpoint here and PopFrame when we are at it. 293 doNothing(); // line +2 294 cnt++; // line +3 295 return; 296 } 297 298 public String toString() { 299 return "SynchronizedFunctionTestObject { cnt: " + cnt + " }"; 300 } 301 } 302 303 public static class SynchronizedTestObject extends AbstractTestObject implements Runnable { 304 public final Object lock; 305 public int cnt; 306 307 public SynchronizedTestObject() { 308 super(); 309 lock = new Object(); 310 cnt = 0; 311 } 312 313 public void calledFunction() { 314 synchronized (lock) { // line +0 315 cnt++; // line +1 316 // We put a breakpoint here and PopFrame when we are at it. 317 doNothing(); // line +3 318 cnt++; // line +4 319 return; // line +5 320 } 321 } 322 323 public String toString() { 324 return "SynchronizedTestObject { cnt: " + cnt + " }"; 325 } 326 } 327 328 public static class ExceptionCatchTestObject extends AbstractTestObject implements Runnable { 329 public static class TestError extends Error {} 330 331 public int cnt; 332 333 public ExceptionCatchTestObject() { 334 super(); 335 cnt = 0; 336 } 337 338 public void calledFunction() { 339 cnt++; 340 try { 341 doThrow(); 342 cnt += 100; 343 } catch (TestError e) { 344 System.out.println(e.getClass().getName() + " caught in called function."); 345 cnt++; 346 } 347 return; 348 } 349 350 public Object doThrow() { 351 throw new TestError(); 352 } 353 354 public String toString() { 355 return "ExceptionCatchTestObject { cnt: " + cnt + " }"; 356 } 357 } 358 359 public static class ExceptionThrowFarTestObject implements Runnable { 360 public static class TestError extends Error {} 361 362 public int cnt; 363 public int baseCallCnt; 364 public final boolean catchInCalled; 365 366 public ExceptionThrowFarTestObject(boolean catchInCalled) { 367 super(); 368 cnt = 0; 369 baseCallCnt = 0; 370 this.catchInCalled = catchInCalled; 371 } 372 373 public void run() { 374 baseCallCnt++; 375 try { 376 callingFunction(); 377 } catch (TestError e) { 378 System.out.println(e.getClass().getName() + " thrown and caught!"); 379 } 380 baseCallCnt++; 381 } 382 383 public void callingFunction() { 384 calledFunction(); 385 } 386 387 public void calledFunction() { 388 cnt++; 389 if (catchInCalled) { 390 try { 391 cnt += 100; 392 throw new TestError(); // We put a watch here. 393 } catch (TestError e) { 394 System.out.println(e.getClass().getName() + " caught in same function."); 395 doNothing(); 396 cnt += 10; 397 return; 398 } 399 } else { 400 cnt++; 401 throw new TestError(); // We put a watch here. 402 } 403 } 404 405 public String toString() { 406 return "ExceptionThrowFarTestObject { cnt: " + cnt + ", baseCnt: " + baseCallCnt + " }"; 407 } 408 } 409 410 public static class ExceptionOnceObject extends AbstractTestObject { 411 public static final class TestError extends Error {} 412 413 public int cnt; 414 public final boolean throwInSub; 415 416 public ExceptionOnceObject(boolean throwInSub) { 417 super(); 418 cnt = 0; 419 this.throwInSub = throwInSub; 420 } 421 422 public void calledFunction() { 423 cnt++; 424 if (cnt == 1) { 425 if (throwInSub) { 426 doThrow(); 427 } else { 428 throw new TestError(); 429 } 430 } 431 return; 432 } 433 434 public void doThrow() { 435 throw new TestError(); 436 } 437 438 public String toString() { 439 return "ExceptionOnceObject { cnt: " + cnt + ", throwInSub: " + throwInSub + " }"; 440 } 441 } 442 443 public static class ExceptionThrowTestObject implements Runnable { 444 public static class TestError extends Error {} 445 446 public int cnt; 447 public int baseCallCnt; 448 public final boolean catchInCalled; 449 450 public ExceptionThrowTestObject(boolean catchInCalled) { 451 super(); 452 cnt = 0; 453 baseCallCnt = 0; 454 this.catchInCalled = catchInCalled; 455 } 456 457 public void run() { 458 baseCallCnt++; 459 try { 460 calledFunction(); 461 } catch (TestError e) { 462 System.out.println(e.getClass().getName() + " thrown and caught!"); 463 } 464 baseCallCnt++; 465 } 466 467 public void calledFunction() { 468 cnt++; 469 if (catchInCalled) { 470 try { 471 cnt += 10; 472 throw new TestError(); // We put a watch here. 473 } catch (TestError e) { 474 System.out.println(e.getClass().getName() + " caught in same function."); 475 doNothing(); 476 cnt += 100; 477 return; 478 } 479 } else { 480 cnt += 1; 481 throw new TestError(); // We put a watch here. 482 } 483 } 484 485 public String toString() { 486 return "ExceptionThrowTestObject { cnt: " + cnt + ", baseCnt: " + baseCallCnt + " }"; 487 } 488 } 489 490 public static class NativeCalledObject extends AbstractTestObject { 491 public int cnt = 0; 492 493 public native void calledFunction(); 494 495 public String toString() { 496 return "NativeCalledObject { cnt: " + cnt + " }"; 497 } 498 } 499 500 public static class NativeCallerObject implements Runnable { 501 public Object returnValue = null; 502 public int cnt = 0; 503 504 public Object getReturnValue() { 505 return returnValue; 506 } 507 508 public native void run(); 509 510 public void calledFunction() { 511 cnt++; 512 // We will stop using a MethodExit event. 513 doNothing(); 514 cnt++; 515 return; 516 } 517 518 public String toString() { 519 return "NativeCallerObject { cnt: " + cnt + " }"; 520 } 521 } 522 523 public static class ClassLoadObject implements Runnable { 524 public int cnt; 525 526 public static final String[] CLASS_NAMES = 527 new String[] { 528 "Lart/Test1969$ClassLoadObject$TC0;", 529 "Lart/Test1969$ClassLoadObject$TC1;", 530 "Lart/Test1969$ClassLoadObject$TC2;", 531 "Lart/Test1969$ClassLoadObject$TC3;", 532 "Lart/Test1969$ClassLoadObject$TC4;", 533 "Lart/Test1969$ClassLoadObject$TC5;", 534 "Lart/Test1969$ClassLoadObject$TC6;", 535 "Lart/Test1969$ClassLoadObject$TC7;", 536 "Lart/Test1969$ClassLoadObject$TC8;", 537 "Lart/Test1969$ClassLoadObject$TC9;", 538 }; 539 540 private static int curClass = 0; 541 542 private static class TC0 { public static int foo; static { foo = 100 + curClass; } } 543 544 private static class TC1 { public static int foo; static { foo = 200 + curClass; } } 545 546 private static class TC2 { public static int foo; static { foo = 300 + curClass; } } 547 548 private static class TC3 { public static int foo; static { foo = 400 + curClass; } } 549 550 private static class TC4 { public static int foo; static { foo = 500 + curClass; } } 551 552 private static class TC5 { public static int foo; static { foo = 600 + curClass; } } 553 554 private static class TC6 { public static int foo; static { foo = 700 + curClass; } } 555 556 private static class TC7 { public static int foo; static { foo = 800 + curClass; } } 557 558 private static class TC8 { public static int foo; static { foo = 900 + curClass; } } 559 560 private static class TC9 { public static int foo; static { foo = 1000 + curClass; } } 561 562 public ClassLoadObject() { 563 super(); 564 cnt = 0; 565 } 566 567 public void run() { 568 if (curClass == 0) { 569 calledFunction0(); 570 } else if (curClass == 1) { 571 calledFunction1(); 572 } else if (curClass == 2) { 573 calledFunction2(); 574 } else if (curClass == 3) { 575 calledFunction3(); 576 } else if (curClass == 4) { 577 calledFunction4(); 578 } else if (curClass == 5) { 579 calledFunction5(); 580 } else if (curClass == 6) { 581 calledFunction6(); 582 } else if (curClass == 7) { 583 calledFunction7(); 584 } else if (curClass == 8) { 585 calledFunction8(); 586 } else if (curClass == 9) { 587 calledFunction9(); 588 } 589 curClass++; 590 } 591 592 public void calledFunction0() { 593 cnt++; 594 System.out.println("TC0.foo == " + TC0.foo); 595 } 596 597 public void calledFunction1() { 598 cnt++; 599 System.out.println("TC1.foo == " + TC1.foo); 600 } 601 602 public void calledFunction2() { 603 cnt++; 604 System.out.println("TC2.foo == " + TC2.foo); 605 } 606 607 public void calledFunction3() { 608 cnt++; 609 System.out.println("TC3.foo == " + TC3.foo); 610 } 611 612 public void calledFunction4() { 613 cnt++; 614 System.out.println("TC4.foo == " + TC4.foo); 615 } 616 617 public void calledFunction5() { 618 cnt++; 619 System.out.println("TC5.foo == " + TC5.foo); 620 } 621 622 public void calledFunction6() { 623 cnt++; 624 System.out.println("TC6.foo == " + TC6.foo); 625 } 626 627 public void calledFunction7() { 628 cnt++; 629 System.out.println("TC7.foo == " + TC7.foo); 630 } 631 632 public void calledFunction8() { 633 cnt++; 634 System.out.println("TC8.foo == " + TC8.foo); 635 } 636 637 public void calledFunction9() { 638 cnt++; 639 System.out.println("TC9.foo == " + TC9.foo); 640 } 641 642 public String toString() { 643 return "ClassLoadObject { cnt: " + cnt + ", curClass: " + curClass + "}"; 644 } 645 } 646 647 public static class ObjectInitTestObject implements Runnable { 648 // TODO How do we do this for <clinit> 649 public int cnt = 0; 650 public static final class ObjectInitTarget { 651 public ObjectInitTarget(Runnable r) { 652 super(); // line +0 653 r.run(); // line +1 654 // We set a breakpoint here and force-early-return 655 doNothing(); // line +3 656 r.run(); // line +4 657 } 658 } 659 660 public void run() { 661 new ObjectInitTarget(() -> cnt++); 662 } 663 664 public String toString() { 665 return "ObjectInitTestObject { cnt: " + cnt + " }"; 666 } 667 } 668 669 public static class SuspendSuddenlyObject extends AbstractTestObject { 670 public volatile boolean should_spin = true; 671 public volatile boolean is_spinning = false; 672 public int cnt = 0; 673 674 public void calledFunction() { 675 cnt++; 676 do { 677 is_spinning = true; 678 } while (should_spin); 679 cnt++; 680 return; 681 } 682 683 public String toString() { 684 return "SuspendSuddenlyObject { cnt: " + cnt + ", spun: " + is_spinning + " }"; 685 } 686 } 687 688 public static final class StaticMethodObject implements Runnable { 689 public int cnt = 0; 690 691 public static void calledFunction(Runnable incr) { 692 incr.run(); // line +0 693 // We put a breakpoint here to force the return. 694 doNothing(); // line +2 695 incr.run(); // line +3 696 return; // line +4 697 } 698 699 public void run() { 700 calledFunction(() -> cnt++); 701 } 702 703 public final String toString() { 704 return "StaticMethodObject { cnt: " + cnt + " }"; 705 } 706 } 707 708 // Only used by CTS to run without class-load tests. 709 public static void run() throws Exception { 710 new Test1969(false).runTests(); 711 } 712 public static void run(boolean canRunClassLoadTests) throws Exception { 713 new Test1969(canRunClassLoadTests).runTests(); 714 } 715 716 public Test1969(boolean canRunClassLoadTests) { 717 this.canRunClassLoadTests = canRunClassLoadTests; 718 } 719 720 public static void no_runTestOn(Supplier<Object> a, ThreadRunnable b, ThreadRunnable c) {} 721 722 public void runTests() throws Exception { 723 setupTest(); 724 725 final Method calledFunction = StandardTestObject.class.getDeclaredMethod("calledFunction"); 726 // Add a breakpoint on the second line after the start of the function 727 final int line = Breakpoint.locationToLine(calledFunction, 0) + 2; 728 final long loc = Breakpoint.lineToLocation(calledFunction, line); 729 System.out.println("Test stopped using breakpoint"); 730 runTestOn( 731 StandardTestObject::new, 732 (thr) -> setupSuspendBreakpointFor(calledFunction, loc, thr), 733 SuspendEvents::clearSuspendBreakpointFor); 734 735 final Method syncFunctionCalledFunction = 736 SynchronizedFunctionTestObject.class.getDeclaredMethod("calledFunction"); 737 // Add a breakpoint on the second line after the start of the function 738 // Annoyingly r8 generally 739 // has the first instruction (a monitor enter) not be marked as being on any 740 // line but javac has 741 // it marked as being on the first line of the function. Just use the second 742 // entry on the 743 // line-number table to get the breakpoint. This should be good for both. 744 final long syncFunctionLoc = 745 Breakpoint.getLineNumberTable(syncFunctionCalledFunction)[1].location; 746 System.out.println("Test stopped using breakpoint with declared synchronized function"); 747 runTestOn( 748 SynchronizedFunctionTestObject::new, 749 (thr) -> setupSuspendBreakpointFor(syncFunctionCalledFunction, syncFunctionLoc, thr), 750 SuspendEvents::clearSuspendBreakpointFor); 751 752 final Method syncCalledFunction = 753 SynchronizedTestObject.class.getDeclaredMethod("calledFunction"); 754 // Add a breakpoint on the second line after the start of the function 755 final int syncLine = Breakpoint.locationToLine(syncCalledFunction, 0) + 3; 756 final long syncLoc = Breakpoint.lineToLocation(syncCalledFunction, syncLine); 757 System.out.println("Test stopped using breakpoint with synchronized block"); 758 runTestOn( 759 SynchronizedTestObject::new, 760 (thr) -> setupSuspendBreakpointFor(syncCalledFunction, syncLoc, thr), 761 SuspendEvents::clearSuspendBreakpointFor); 762 763 System.out.println("Test stopped on single step"); 764 runTestOn( 765 StandardTestObject::new, 766 (thr) -> setupSuspendSingleStepAt(calledFunction, loc, thr), 767 SuspendEvents::clearSuspendSingleStepFor); 768 769 final Field target_field = FieldBasedTestObject.class.getDeclaredField("TARGET_FIELD"); 770 System.out.println("Test stopped on field access"); 771 runTestOn( 772 FieldBasedTestObject::new, 773 (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, true, thr), 774 SuspendEvents::clearFieldSuspendFor); 775 776 System.out.println("Test stopped on field modification"); 777 runTestOn( 778 FieldBasedTestObject::new, 779 (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, false, thr), 780 SuspendEvents::clearFieldSuspendFor); 781 782 System.out.println("Test stopped during Method Exit of calledFunction"); 783 runTestOn( 784 StandardTestObject::new, 785 (thr) -> setupSuspendMethodEvent(calledFunction, /* enter */ false, thr), 786 SuspendEvents::clearSuspendMethodEvent); 787 788 System.out.println("Test stopped during Method Enter of calledFunction"); 789 runTestOn( 790 StandardTestObject::new, 791 (thr) -> setupSuspendMethodEvent(calledFunction, /* enter */ true, thr), 792 SuspendEvents::clearSuspendMethodEvent); 793 794 final Method exceptionOnceCalledMethod = 795 ExceptionOnceObject.class.getDeclaredMethod("calledFunction"); 796 System.out.println("Test stopped during Method Exit due to exception thrown in same function"); 797 runTestOn( 798 () -> new ExceptionOnceObject(/* throwInSub */ false), 799 (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /* enter */ false, thr), 800 SuspendEvents::clearSuspendMethodEvent); 801 802 System.out.println("Test stopped during Method Exit due to exception thrown in subroutine"); 803 runTestOn( 804 () -> new ExceptionOnceObject(/* throwInSub */ true), 805 (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /* enter */ false, thr), 806 SuspendEvents::clearSuspendMethodEvent); 807 808 final Method exceptionThrowCalledMethod = 809 ExceptionThrowTestObject.class.getDeclaredMethod("calledFunction"); 810 System.out.println( 811 "Test stopped during notifyFramePop with exception on pop of calledFunction"); 812 runTestOn( 813 () -> new ExceptionThrowTestObject(false), 814 (thr) -> setupSuspendPopFrameEvent(0, exceptionThrowCalledMethod, thr), 815 SuspendEvents::clearSuspendPopFrameEvent); 816 817 final Method exceptionCatchThrowMethod = 818 ExceptionCatchTestObject.class.getDeclaredMethod("doThrow"); 819 System.out.println("Test stopped during notifyFramePop with exception on pop of doThrow"); 820 runTestOn( 821 ExceptionCatchTestObject::new, 822 (thr) -> setupSuspendPopFrameEvent(0, exceptionCatchThrowMethod, thr), 823 SuspendEvents::clearSuspendPopFrameEvent); 824 825 System.out.println( 826 "Test stopped during ExceptionCatch event of calledFunction " 827 + "(catch in called function, throw in called function)"); 828 runTestOn( 829 () -> new ExceptionThrowTestObject(true), 830 (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /* catch */ true, thr), 831 SuspendEvents::clearSuspendExceptionEvent); 832 833 final Method exceptionCatchCalledMethod = 834 ExceptionCatchTestObject.class.getDeclaredMethod("calledFunction"); 835 System.out.println( 836 "Test stopped during ExceptionCatch event of calledFunction " 837 + "(catch in called function, throw in subroutine)"); 838 runTestOn( 839 ExceptionCatchTestObject::new, 840 (thr) -> setupSuspendExceptionEvent(exceptionCatchCalledMethod, /* catch */ true, thr), 841 SuspendEvents::clearSuspendExceptionEvent); 842 843 System.out.println( 844 "Test stopped during Exception event of calledFunction " + "(catch in calling function)"); 845 runTestOn( 846 () -> new ExceptionThrowTestObject(false), 847 (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /* catch */ false, thr), 848 SuspendEvents::clearSuspendExceptionEvent); 849 850 System.out.println( 851 "Test stopped during Exception event of calledFunction (catch in called function)"); 852 runTestOn( 853 () -> new ExceptionThrowTestObject(true), 854 (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /* catch */ false, thr), 855 SuspendEvents::clearSuspendExceptionEvent); 856 857 final Method exceptionThrowFarCalledMethod = 858 ExceptionThrowFarTestObject.class.getDeclaredMethod("calledFunction"); 859 System.out.println( 860 "Test stopped during Exception event of calledFunction " 861 + "(catch in parent of calling function)"); 862 runTestOn( 863 () -> new ExceptionThrowFarTestObject(false), 864 (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /* catch */ false, thr), 865 SuspendEvents::clearSuspendExceptionEvent); 866 867 System.out.println( 868 "Test stopped during Exception event of calledFunction " + "(catch in called function)"); 869 runTestOn( 870 () -> new ExceptionThrowFarTestObject(true), 871 (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /* catch */ false, thr), 872 SuspendEvents::clearSuspendExceptionEvent); 873 874 System.out.println("Test stopped during random Suspend."); 875 runTestOn( 876 () -> { 877 final SuspendSuddenlyObject sso = new SuspendSuddenlyObject(); 878 return new TestConfig( 879 sso, 880 new TestSuspender() { 881 public void setupForceReturnRun(Thread thr) {} 882 883 public void setupNormalRun(Thread thr) { 884 sso.should_spin = false; 885 } 886 887 public void waitForSuspend(Thread thr) { 888 while (!sso.is_spinning) {} 889 Suspension.suspend(thr); 890 } 891 892 public void cleanup(Thread thr) {} 893 }); 894 }); 895 896 System.out.println("Test stopped during a native method fails"); 897 runTestOn( 898 NativeCalledObject::new, 899 SuspendEvents::setupWaitForNativeCall, 900 SuspendEvents::clearWaitForNativeCall); 901 902 System.out.println("Test stopped in a method called by native succeeds"); 903 final Method nativeCallerMethod = NativeCallerObject.class.getDeclaredMethod("calledFunction"); 904 runTestOn( 905 NativeCallerObject::new, 906 (thr) -> setupSuspendMethodEvent(nativeCallerMethod, /* enter */ false, thr), 907 SuspendEvents::clearSuspendMethodEvent); 908 909 910 System.out.println("Test stopped in a static method"); 911 final Method staticCalledMethod = StaticMethodObject.class.getDeclaredMethod("calledFunction", Runnable.class); 912 final int staticFunctionLine= Breakpoint.locationToLine(staticCalledMethod, 0) + 2; 913 final long staticFunctionLoc = Breakpoint.lineToLocation(staticCalledMethod, staticFunctionLine); 914 runTestOn( 915 StaticMethodObject::new, 916 (thr) -> setupSuspendBreakpointFor(staticCalledMethod, staticFunctionLoc, thr), 917 SuspendEvents::clearSuspendMethodEvent); 918 919 System.out.println("Test stopped in a Object <init> method"); 920 final Executable initCalledMethod = ObjectInitTestObject.ObjectInitTarget.class.getConstructor(Runnable.class); 921 final int initFunctionLine= Breakpoint.locationToLine(initCalledMethod, 0) + 3; 922 final long initFunctionLoc = Breakpoint.lineToLocation(initCalledMethod, initFunctionLine); 923 runTestOn( 924 ObjectInitTestObject::new, 925 (thr) -> setupSuspendBreakpointFor(initCalledMethod, initFunctionLoc, thr), 926 SuspendEvents::clearSuspendMethodEvent); 927 928 if (canRunClassLoadTests && CanRunClassLoadingTests()) { 929 System.out.println("Test stopped during class-load."); 930 runTestOn( 931 ClassLoadObject::new, 932 (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_LOAD, ClassLoadObject.CLASS_NAMES, thr), 933 SuspendEvents::clearSuspendClassEvent); 934 System.out.println("Test stopped during class-load."); 935 runTestOn( 936 ClassLoadObject::new, 937 (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_LOAD, ClassLoadObject.CLASS_NAMES, thr), 938 SuspendEvents::clearSuspendClassEvent); 939 } 940 } 941 942 943 // Volatile is to prevent any future optimizations that could invalidate this test by doing 944 // constant propagation and eliminating the failing paths before the verifier is able to load the 945 // class. 946 static volatile boolean ranClassLoadTest = false; 947 static boolean classesPreverified = false; 948 private static final class RCLT0 { public void foo() {} } 949 private static final class RCLT1 { public void foo() {} } 950 // If classes are not preverified for some reason (interp-ac, no-image, etc) the verifier will 951 // actually load classes as it runs. This means that we cannot use the class-load tests as they 952 // are written. TODO Support this. 953 public boolean CanRunClassLoadingTests() { 954 if (ranClassLoadTest) { 955 return classesPreverified; 956 } 957 if (!ranClassLoadTest) { 958 // Only this will ever be executed. 959 new RCLT0().foo(); 960 } else { 961 // This will never be executed. If classes are not preverified the verifier will load RCLT1 962 // when the enclosing method is run. This behavior makes the class-load/prepare test cases 963 // impossible to successfully run (they will deadlock). 964 new RCLT1().foo(); 965 System.out.println("FAILURE: UNREACHABLE Location!"); 966 } 967 classesPreverified = !isClassLoaded("Lart/Test1969$RCLT1;"); 968 ranClassLoadTest = true; 969 return classesPreverified; 970 } 971 972 public static native boolean isClassLoaded(String name); 973 } 974