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