publicvoid runTestOn(TestRunnable testObj, TestSuspender su) throws Exception {
System.out.println("Single call with PopFrame on " + testObj + " base-call-count: " +
testObj.getBaseCallCount()); final CountDownLatch continue_latch = new CountDownLatch(1); final CountDownLatch startup_latch = new CountDownLatch(1);
Runnable await = () -> { try {
startup_latch.countDown();
continue_latch.await();
} catch (Exception e) { thrownew Error("Failed to await latch", e);
}
}; Thread thr = newThread(() -> { await.run(); testObj.run(); });
thr.start();
// Wait until the other thread is started.
startup_latch.await();
// Do any final setup.
preTest.accept(testObj);
// Setup suspension method on the thread.
su.setup(thr);
// Let the other thread go.
continue_latch.countDown();
// Wait for the other thread to hit the breakpoint/watchpoint/whatever and suspend itself // (without re-entering java)
su.waitForSuspend(thr);
// Cleanup the breakpoint/watchpoint/etc.
su.cleanup(thr);
try { // Pop the frame.
popFrame(thr);
} catch (Exception e) {
System.out.println("Failed to pop frame due to " + e);
SafePrintStackTrace(e.getStackTrace());
}
// Start the other thread going again.
Suspension.resume(thr);
// Wait for the other thread to finish.
thr.join();
// See how many times calledFunction was called.
System.out.println("result is " + testObj + " base-call count: " + testObj.getBaseCallCount());
}
public EnumSet<RedefineState> redefine_states; public RedefineTestObject() { super();
redefine_states = EnumSet.noneOf(RedefineState.class);
}
public String toString() { return"RedefineTestObject { states: " + redefine_states.toString() + " current: ORIGINAL }";
}
publicvoid calledFunction() {
redefine_states.add(RedefineState.ORIGINAL); // line +0 // We will trigger the redefinition using a breakpoint on the next line.
doNothing(); // line +2
}
}
public Method getCalledMethod() throws Exception { returnthis.getClass().getMethod("jnoprecompile$calledFunction" + curClass);
}
// Give these all a tag to prevent 1954 from compiling them (and loading the class as a // consequence). publicvoid $noprecompile$calledFunction0() {
cnt++;
System.out.println("TC0.foo == " + TC0.foo);
}
publicvoid calledFunction() {
cnt++; // We put a watchpoint here and PopFrame when we are at it.
TARGET_FIELD += 10; if (cnt == 1) { System.out.println("FAILED: No pop on first call!"); }
}
publicvoid calledFunction() {
cnt++; // line +0 // We put a breakpoint here and PopFrame when we are at it.
doNothing(); // line +2 if (check && cnt == 1) { System.out.println("FAILED: No pop on first call!"); }
}
publicvoid calledFunction() { synchronized (lock) { // line +0
cnt++; // line +1 // We put a breakpoint here and PopFrame when we are at it.
doNothing(); // line +3
}
}
publicvoid calledFunction() {
cnt++; if (catchInCalled) { try { thrownew TestError(); // We put a watch here.
} catch (TestError e) {
System.out.println(e.getClass().getName() + " caught in same function.");
}
} else { thrownew TestError(); // We put a watch here.
}
}
public Method getCalledMethod() throws Exception { returnthis.getClass().getMethod("calledFunction");
}
// This entrypoint is used by CTS only. */ publicstaticvoid run() throws Exception { /* TODO: Due to the way that CTS tests are verified we cannot run class-load-tests since the *verifierwillbedelayeduntilruntimeandthenloadtheclassesallatonce.This *makesthetestimpossibletorun.
*/
run(/*canRunClassLoadTests*/ false);
}
final Method calledFunction = StandardTestObject.class.getDeclaredMethod("calledFunction"); final Method doNothingMethod = Test1953.class.getDeclaredMethod("doNothing"); // Add a breakpoint on the second line after the start of the function finalint line = Breakpoint.locationToLine(calledFunction, 0) + 2; finallong loc = Breakpoint.lineToLocation(calledFunction, line);
System.out.println("Test stopped using breakpoint");
runTestOn(new StandardTestObject(),
(thr) -> setupSuspendBreakpointFor(calledFunction, loc, thr),
SuspendEvents::clearSuspendBreakpointFor);
final Method syncFunctionCalledFunction =
SynchronizedFunctionTestObject.class.getDeclaredMethod("calledFunction"); // Add a breakpoint on the second line after the start of the function // Annoyingly r8 generally has the first instruction (a monitor enter) not be marked as being // on any line but javac has it marked as being on the first line of the function. Just use the // second entry on the line-number table to get the breakpoint. This should be good for both. finallong syncFunctionLoc =
Breakpoint.getLineNumberTable(syncFunctionCalledFunction)[1].location;
System.out.println("Test stopped using breakpoint with declared synchronized function");
runTestOn(new SynchronizedFunctionTestObject(),
(thr) -> setupSuspendBreakpointFor(syncFunctionCalledFunction, syncFunctionLoc, thr),
SuspendEvents::clearSuspendBreakpointFor);
final Method syncCalledFunction =
SynchronizedTestObject.class.getDeclaredMethod("calledFunction"); // Add a breakpoint on the second line after the start of the function finalint syncLine = Breakpoint.locationToLine(syncCalledFunction, 0) + 3; finallong syncLoc = Breakpoint.lineToLocation(syncCalledFunction, syncLine);
System.out.println("Test stopped using breakpoint with synchronized block");
Object lock = new Object(); synchronized (lock) {}
runTestOn(new SynchronizedTestObject(lock),
(thr) -> setupSuspendBreakpointFor(syncCalledFunction, syncLoc, thr),
SuspendEvents::clearSuspendBreakpointFor); synchronized (lock) {}
System.out.println("Test stopped on single step");
runTestOn(new StandardTestObject(),
(thr) -> setupSuspendSingleStepAt(calledFunction, loc, thr),
SuspendEvents::clearSuspendSingleStepFor);
final Field target_field = FieldBasedTestObject.class.getDeclaredField("TARGET_FIELD");
System.out.println("Test stopped on field access");
runTestOn(new FieldBasedTestObject(),
(thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, true, thr),
SuspendEvents::clearFieldSuspendFor);
System.out.println("Test stopped on field modification");
runTestOn(new FieldBasedTestObject(),
(thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, false, thr),
SuspendEvents::clearFieldSuspendFor);
System.out.println("Test stopped during Method Exit of doNothing");
runTestOn(new StandardTestObject(false),
(thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ false, thr),
SuspendEvents::clearSuspendMethodEvent);
// NB We need another test to make sure the MethodEntered event is triggered twice.
System.out.println("Test stopped during Method Enter of doNothing");
runTestOn(new StandardTestObject(false),
(thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ true, thr),
SuspendEvents::clearSuspendMethodEvent);
System.out.println("Test stopped during Method Exit of calledFunction");
runTestOn(new StandardTestObject(false),
(thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ false, thr),
SuspendEvents::clearSuspendMethodEvent);
System.out.println("Test stopped during Method Enter of calledFunction");
runTestOn(new StandardTestObject(false),
(thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ true, thr),
SuspendEvents::clearSuspendMethodEvent);
final Method exceptionOnceCalledMethod =
ExceptionOnceObject.class.getDeclaredMethod("calledFunction");
System.out.println("Test stopped during Method Exit due to exception thrown in same function");
runTestOn(new ExceptionOnceObject(/*throwInSub*/ false),
(thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr),
SuspendEvents::clearSuspendMethodEvent);
System.out.println("Test stopped during Method Exit due to exception thrown in subroutine");
runTestOn(new ExceptionOnceObject(/*throwInSub*/ true),
(thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr),
SuspendEvents::clearSuspendMethodEvent);
final Method exceptionThrowCalledMethod =
ExceptionThrowTestObject.class.getDeclaredMethod("calledFunction"); final Method exceptionCatchThrowMethod =
ExceptionCatchTestObject.class.getDeclaredMethod("doThrow"); // Disable more often then we technically need to in order to avoid the need // for a huge number of possible results and allow the test to be easily // used in CTS. if (IS_ART && canRunClassLoadTests && CanRunClassLoadingTests()) {
System.out.println("Test stopped during notifyFramePop without exception on pop of calledFunction");
runTestOn(new StandardTestObject(false),
(thr) -> setupSuspendPopFrameEvent(1, doNothingMethod, thr),
SuspendEvents::clearSuspendPopFrameEvent);
System.out.println("Test stopped during notifyFramePop without exception on pop of doNothing");
runTestOn(new StandardTestObject(false),
(thr) -> setupSuspendPopFrameEvent(0, doNothingMethod, thr),
SuspendEvents::clearSuspendPopFrameEvent);
System.out.println("Test stopped during notifyFramePop with exception on pop of calledFunction");
runTestOn(new ExceptionThrowTestObject(false),
(thr) -> setupSuspendPopFrameEvent(0, exceptionThrowCalledMethod, thr),
SuspendEvents::clearSuspendPopFrameEvent);
System.out.println("Test stopped during notifyFramePop with exception on pop of doThrow");
runTestOn(new ExceptionCatchTestObject(),
(thr) -> setupSuspendPopFrameEvent(0, exceptionCatchThrowMethod, thr),
SuspendEvents::clearSuspendPopFrameEvent);
}
System.out.println("Test stopped during ExceptionCatch event of calledFunction " + "(catch in called function, throw in called function)");
runTestOn(new ExceptionThrowTestObject(true),
(thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ true, thr),
SuspendEvents::clearSuspendExceptionEvent);
final Method exceptionCatchCalledMethod =
ExceptionCatchTestObject.class.getDeclaredMethod("calledFunction");
System.out.println("Test stopped during ExceptionCatch event of calledFunction " + "(catch in called function, throw in subroutine)");
runTestOn(new ExceptionCatchTestObject(),
(thr) -> setupSuspendExceptionEvent(exceptionCatchCalledMethod, /*catch*/ true, thr),
SuspendEvents::clearSuspendExceptionEvent);
System.out.println("Test stopped during Exception event of calledFunction " + "(catch in calling function)");
runTestOn(new ExceptionThrowTestObject(false),
(thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr),
SuspendEvents::clearSuspendExceptionEvent);
System.out.println("Test stopped during Exception event of calledFunction " + "(catch in called function)");
runTestOn(new ExceptionThrowTestObject(true),
(thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr),
SuspendEvents::clearSuspendExceptionEvent);
final Method exceptionThrowFarCalledMethod =
ExceptionThrowFarTestObject.class.getDeclaredMethod("calledFunction");
System.out.println("Test stopped during Exception event of calledFunction " + "(catch in parent of calling function)");
runTestOn(new ExceptionThrowFarTestObject(false),
(thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr),
SuspendEvents::clearSuspendExceptionEvent);
System.out.println("Test stopped during Exception event of calledFunction " + "(catch in called function)");
runTestOn(new ExceptionThrowFarTestObject(true),
(thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr),
SuspendEvents::clearSuspendExceptionEvent);
// These tests are disabled for either the RI (b/116003018) or for jvmti-stress. For the // later it is due to the additional agent causing classes to be loaded earlier as it forces // deeper verification during class redefinition, causing failures. // NB the agent is prevented from popping frames in either of these events in ART. See // b/117615146 for more information about this restriction. if (canRunClassLoadTests && CanRunClassLoadingTests()) { // This test doesn't work on RI since the RI disallows use of PopFrame during a ClassLoad // event. See b/116003018 for more information.
System.out.println("Test stopped during a ClassLoad event.");
runTestOn(new ClassLoadObject(),
(thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_LOAD, ClassLoadObject.CLASS_NAMES, thr),
SuspendEvents::clearSuspendClassEvent);
// The RI handles a PopFrame during a ClassPrepare event incorrectly. See b/116003018 for // more information.
System.out.println("Test stopped during a ClassPrepare event.");
runTestOn(new ClassLoadObject(),
(thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_PREPARE,
ClassLoadObject.CLASS_NAMES,
thr),
SuspendEvents::clearSuspendClassEvent);
}
System.out.println("Test stopped during random Suspend."); final SuspendSuddenlyObject sso = new SuspendSuddenlyObject();
runTestOn(
sso, new TestSuspender() { publicvoid setup(Thread thr) { } publicvoid waitForSuspend(Thread thr) { while (!sso.is_spinning) {}
Suspension.suspend(thr);
} publicvoid cleanup(Thread thr) {
sso.stop_spinning = true;
}
});
System.out.println("Test stopped during a native method fails");
runTestOn(new NativeCalledObject(),
SuspendEvents::setupWaitForNativeCall,
SuspendEvents::clearWaitForNativeCall);
System.out.println("Test stopped in a method called by native fails"); final Method nativeCallerMethod = NativeCallerObject.class.getDeclaredMethod("calledFunction");
runTestOn(new NativeCallerObject(),
(thr) -> setupSuspendMethodEvent(nativeCallerMethod, /*enter*/ false, thr),
SuspendEvents::clearSuspendMethodEvent);
final Object lock2 = new Object(); synchronized (lock2) {}
System.out.println("Test stopped with monitor in enclosing frame.");
runTestOn(new StandardTestObject() {
@Override publicvoid run() { synchronized (lock2) { super.run();
}
}
},
(thr) -> setupSuspendBreakpointFor(calledFunction, loc, thr),
SuspendEvents::clearSuspendBreakpointFor); synchronized (lock2) {}
}
// Volatile is to prevent any future optimizations that could invalidate this test by doing // constant propagation and eliminating the failing paths before the verifier is able to load the // class. staticvolatileboolean ranClassLoadTest = false; staticboolean classesPreverified = false; privatestaticfinalclass RCLT0 { publicvoid foo() {} } privatestaticfinalclass RCLT1 { publicvoid foo() {} } // If classes are not preverified for some reason (interp-ac, no-image, etc) the verifier will // actually load classes as it runs. This means that we cannot use the class-load tests as they // are written. TODO Support this. publicboolean CanRunClassLoadingTests() { if (ranClassLoadTest) { return classesPreverified;
} if (!ranClassLoadTest) { // Only this will ever be executed. new RCLT0().foo();
} else { // This will never be executed. If classes are not preverified the verifier will load RCLT1 // when the enclosing method is run. This behavior makes the class-load/prepare test cases // impossible to successfully run (they will deadlock). new RCLT1().foo();
System.out.println("FAILURE: UNREACHABLE Location!");
}
classesPreverified = !isClassLoaded("Lart/Test1953$RCLT1;");
ranClassLoadTest = true; return classesPreverified;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.