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