8308237: add JDWP and JDI virtual thread support for ThreadReference.PopFrames
8308481: JDI TestScaffold does not support passing app arguments to the debuggee 8305632: Test com/sun/jdi/PopAndInvokeTest.java fails with OpaqueFrameException Reviewed-by: alanb, sspitsyn, lmesnik
This commit is contained in:
parent
d10467e27b
commit
89f2d458a2
@ -2692,10 +2692,9 @@ JDWP "Java(tm) Debug Wire Protocol"
|
||||
"<code>objectref</code> is added back as well. The Java virtual machine "
|
||||
"program counter is restored to the opcode of the invoke instruction."
|
||||
"<p>"
|
||||
"The target VM may not support, or may only provide limited support, for this "
|
||||
"command when the thread is a virtual thread. It may, for example, only support "
|
||||
"this command when the virtual thread is suspended at a breakpoint or singlestep "
|
||||
"event."
|
||||
"This command may be used to pop frames of a virtual thread when "
|
||||
"it is suspended at an event. An implementation may support popping "
|
||||
"the frames of a suspended virtual thread in other cases."
|
||||
"<p>"
|
||||
"Since JDWP version 1.4. Requires canPopFrames capability - see "
|
||||
"<a href=\"#JDWP_VirtualMachine_CapabilitiesNew\">CapabilitiesNew</a>."
|
||||
@ -2713,8 +2712,8 @@ JDWP "Java(tm) Debug Wire Protocol"
|
||||
(Error NO_MORE_FRAMES)
|
||||
(Error OPAQUE_FRAME "If one or more of the frames to pop is a native "
|
||||
"method or its caller is a native method, or the "
|
||||
"thread is a virtual thread and the implementation "
|
||||
"is unable to pop the frames.")
|
||||
"thread is a suspended virtual thread and the implementation "
|
||||
"was unable to pop the frames.")
|
||||
(Error NOT_IMPLEMENTED)
|
||||
(Error VM_DEAD)
|
||||
)
|
||||
|
@ -370,15 +370,14 @@ public interface ThreadReference extends ObjectReference {
|
||||
* Thus the target program may
|
||||
* proceed differently than the user would expect.
|
||||
* <P>
|
||||
* The specified thread must be suspended.
|
||||
* This thread must be suspended.
|
||||
* <P>
|
||||
* All <code>StackFrame</code> objects for this thread are
|
||||
* invalidated.
|
||||
* <p>
|
||||
* The target VM may not support, or may only provide limited support,
|
||||
* for popping stack frames when the thread is a virtual thread.
|
||||
* It may, for example, only support this operation when the virtual
|
||||
* thread is suspended at a breakpoint or singlestep event.
|
||||
* This method may be used to pop frames of a virtual thread when
|
||||
* it is suspended at an event. An implementation may support popping
|
||||
* the frames of a suspended virtual thread in other cases.
|
||||
* <P>
|
||||
* No events are generated by this method.
|
||||
* <P>
|
||||
@ -403,8 +402,8 @@ public interface ThreadReference extends ObjectReference {
|
||||
* @throws java.lang.IllegalArgumentException if <CODE>frame</CODE>
|
||||
* is not on this thread's call stack.
|
||||
*
|
||||
* @throws OpaqueFrameException if this thread is a virtual thread and the
|
||||
* target VM is unable to pop the frames.
|
||||
* @throws OpaqueFrameException if this thread is a suspended virtual thread and the
|
||||
* target VM was unable to pop the frames.
|
||||
*
|
||||
* @throws NativeMethodException if one of the frames that would be
|
||||
* popped is that of a native method or if the frame previous to
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -396,9 +396,27 @@ public class StackFrameImpl extends MirrorImpl
|
||||
switch (exc.errorCode()) {
|
||||
case JDWP.Error.OPAQUE_FRAME:
|
||||
if (thread.isVirtual()) {
|
||||
throw new OpaqueFrameException(); // can only happen with virtual threads
|
||||
// We first need to find out if the current frame is native, or if the
|
||||
// previous frame is native, in which case we throw NativeMethodException
|
||||
for (int i = 0; i < 2; i++) {
|
||||
StackFrameImpl sf;
|
||||
try {
|
||||
sf = (StackFrameImpl)thread.frame(i);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
// This should never happen, but we need to check for it.
|
||||
break;
|
||||
}
|
||||
sf.validateStackFrame();
|
||||
MethodImpl meth = (MethodImpl)sf.location().method();
|
||||
if (meth.isNative()) {
|
||||
throw new NativeMethodException();
|
||||
}
|
||||
}
|
||||
// No native frames involved. Must have been due to thread
|
||||
// not being mounted.
|
||||
throw new OpaqueFrameException();
|
||||
} else {
|
||||
throw new NativeMethodException(); // can only happen with platform threads
|
||||
throw new NativeMethodException();
|
||||
}
|
||||
case JDWP.Error.THREAD_NOT_SUSPENDED:
|
||||
throw new IncompatibleThreadStateException(
|
||||
|
@ -94,32 +94,6 @@ vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java 8300707 generic-all
|
||||
|
||||
vmTestbase/nsk/jdi/ExceptionEvent/catchLocation/location002/TestDescription.java 8278470 generic-all
|
||||
|
||||
####
|
||||
## JVMTI PopFrame() is returning OPAQUE_FRAME because vthreads are not supported.
|
||||
## Note: vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001 was converted
|
||||
## to support vthreads and expect the OPAQUE_FRAME error. The others were
|
||||
## not because they don't add any additional value.
|
||||
|
||||
vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java 8285414 generic-all
|
||||
|
||||
vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses002/TestDescription.java 8285414 generic-all
|
||||
|
||||
vmTestbase/nsk/jdi/Scenarios/invokeMethod/popframes001/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/BScenarios/hotswap/tc01x002/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/BScenarios/hotswap/tc02x001/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/BScenarios/hotswap/tc02x002/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/BScenarios/hotswap/tc04x001/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/BScenarios/hotswap/tc04x002/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/BScenarios/hotswap/tc06x001/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/BScenarios/hotswap/tc08x001/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/BScenarios/hotswap/tc10x002/TestDescription.java 8285414 generic-all
|
||||
|
||||
vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes002/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes003/TestDescription.java 8285414 generic-all
|
||||
vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes004/TestDescription.java 8285414 generic-all
|
||||
|
||||
vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001/TestDescription.java 8308237 generic-all
|
||||
|
||||
####
|
||||
## JVMTI ForceEarlyReturn not supported for vthreads (JVMTI_ERROR_OPAQUE_FRAME)
|
||||
## Note forceEarlyReturn002 was converted to support vthreads. The rest were not
|
||||
|
@ -93,8 +93,6 @@ import java.io.*;
|
||||
|
||||
public class popframes001 extends JDIBase {
|
||||
|
||||
static boolean vthreadMode = "Virtual".equals(System.getProperty("main.wrapper"));
|
||||
|
||||
public static void main (String argv[]) {
|
||||
|
||||
int result = run(argv, System.out);
|
||||
@ -221,10 +219,6 @@ public class popframes001 extends JDIBase {
|
||||
try {
|
||||
testRun();
|
||||
|
||||
if (vthreadMode) {
|
||||
return 0; // just exit. we already got the expected OpaqueFrameException
|
||||
}
|
||||
|
||||
log2("waiting for VMDeathEvent");
|
||||
getEventSet();
|
||||
if (eventIterator.nextEvent() instanceof VMDeathEvent)
|
||||
@ -356,24 +350,10 @@ public class popframes001 extends JDIBase {
|
||||
log2("......thread2Ref.popFrames(stackFrame);");
|
||||
try {
|
||||
thread2Ref.popFrames(stackFrame);
|
||||
if (vthreadMode) {
|
||||
log3("ERROR: Expected OpaqueFrameException");
|
||||
testExitCode = FAILED;
|
||||
}
|
||||
} catch ( Exception e ) {
|
||||
if (vthreadMode && (e instanceof OpaqueFrameException)) {
|
||||
// pass. resume thread and exit
|
||||
log2("......got expected OpaqueFrameException");
|
||||
log2("......thread2Ref.resume();");
|
||||
thread2Ref.resume();
|
||||
breakpointForCommunication();
|
||||
vm.resume();
|
||||
break;
|
||||
} else {
|
||||
log3("ERROR: " + e.getClass().getSimpleName());
|
||||
testExitCode = FAILED;
|
||||
throw e;
|
||||
}
|
||||
} catch ( IncompatibleThreadStateException e ) {
|
||||
log3("ERROR: IncompatibleThreadStateException");
|
||||
testExitCode = FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
log2("......thread2Ref.resume();");
|
||||
|
@ -36,9 +36,6 @@ com/sun/jdi/JdbStopThreadTest.java 8285422 generic-all
|
||||
com/sun/jdi/JdbStopThreadidTest.java 8285422 generic-all
|
||||
com/sun/jdi/MethodEntryExitEvents.java 8285422 generic-all
|
||||
com/sun/jdi/MultiBreakpointsTest.java 8285422 generic-all
|
||||
com/sun/jdi/PopAndStepTest.java 8285422 generic-all
|
||||
com/sun/jdi/PopAsynchronousTest.java 8285422 generic-all
|
||||
com/sun/jdi/PopSynchronousTest.java 8285422 generic-all
|
||||
com/sun/jdi/RedefineCrossStart.java 8285422 generic-all
|
||||
com/sun/jdi/RedefineG.java 8285422 generic-all
|
||||
com/sun/jdi/RedefineNestmateAttr/TestNestmateAttr.java 8285422 generic-all
|
||||
@ -46,7 +43,6 @@ com/sun/jdi/RedefineTTYLineNumber.java 8285422 generic-all
|
||||
com/sun/jdi/ReferrersTest.java 8285422 generic-all
|
||||
com/sun/jdi/SetLocalWhileThreadInNative.java 8285422 generic-all
|
||||
com/sun/jdi/StepTest.java 8285422 generic-all
|
||||
com/sun/jdi/PopAndInvokeTest.java 8305632 generic-all
|
||||
com/sun/jdi/cds/CDSBreakpointTest.java 8307778 generic-all
|
||||
com/sun/jdi/cds/CDSDeleteAllBkptsTest.java 8307778 generic-all
|
||||
com/sun/jdi/cds/CDSFieldWatchpoints.java 8307778 generic-all
|
||||
|
362
test/jdk/com/sun/jdi/PopFramesTest.java
Normal file
362
test/jdk/com/sun/jdi/PopFramesTest.java
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Call popFrames() on threads in various states not covered
|
||||
* well by other tests. Most notably, this test includes
|
||||
* test cases for a suspended but unmounted virtual thread.
|
||||
* It is mostly for testing for OpaqueFrameException and
|
||||
* NativeMethodException.
|
||||
*
|
||||
* @run build TestScaffold VMConnection TargetListener TargetAdapter
|
||||
* @run compile -g PopFramesTest.java
|
||||
* @run driver PopFramesTest SLEEP_NATIVE
|
||||
* @run driver PopFramesTest LOOP_NATIVE
|
||||
* @run driver PopFramesTest SLEEP_PRENATIVE
|
||||
* @run driver PopFramesTest LOOP_PRENATIVE
|
||||
* @run driver PopFramesTest SLEEP_NONATIVE
|
||||
* @run driver PopFramesTest LOOP_NONATIVE
|
||||
*/
|
||||
import com.sun.jdi.*;
|
||||
import com.sun.jdi.event.*;
|
||||
import java.util.*;
|
||||
|
||||
/*
|
||||
* There are six test modes covered by this test:
|
||||
* SLEEP_NATIVE
|
||||
* LOOP_NATIVE
|
||||
* SLEEP_PRENATIVE
|
||||
* LOOP_PRENATIVE
|
||||
* SLEEP_NONATIVE
|
||||
* LOOP_NONATIVE
|
||||
*
|
||||
* SLEEP: the debuggee blocks in Thread.sleep().
|
||||
* LOOP: the debuggee sits in a tight loop.
|
||||
* NATIVE: there is a native frame within the set of frames to pop.
|
||||
* PRENATIVE: there is a native frame before the set of frames to pop.
|
||||
* NONATIVE: there is no native frame (purposefully) present in the stack.
|
||||
*
|
||||
* In all cases the thread is suspended and errors such as IllegalArgumentException
|
||||
* and InvalidStackFrameException should not happen. The popFrames() calls should
|
||||
* either pass, or produce OpaqueFrameException or NativeMethodException.
|
||||
*
|
||||
* Call stacks for each test mode (and expected result):
|
||||
* - Note in all cases the popMethod() frame is the frame passed to popFrames().
|
||||
* - Note that Thread.sleep() usually results in the native Thread.sleep0() frame
|
||||
* being at the top of the stack. However, for a mounted virtual thread
|
||||
* it does not result in any native frames due to how the VM parks virtual threads.
|
||||
*
|
||||
* SLEEP_NATIVE (NativeMethodException):
|
||||
* Thread.sleep() + methods called by Thread.sleep()
|
||||
* loopOrSleep()
|
||||
* upcallMethod()
|
||||
* doUpcall() <-- native method
|
||||
* popMethod()
|
||||
* main()
|
||||
*
|
||||
* LOOP_NATIVE (NativeMethodException):
|
||||
* loopOrSleep() <-- tight loop
|
||||
* upcallMethod()
|
||||
* doUpcall() <-- native method
|
||||
* popMethod()
|
||||
* main()
|
||||
*
|
||||
* SLEEP_PRENATIVE (NativeMethodException due to Thread.sleep() blocking in a native method):
|
||||
* Thread.sleep() + methods called by Thread.sleep()
|
||||
* loopOrSleep()
|
||||
* popMethod()
|
||||
* upcallMethod()
|
||||
* doUpcall() <-- native method
|
||||
* main()
|
||||
*
|
||||
* LOOP_PRENATIVE (no exception):
|
||||
* loopOrSleep() <-- tight loop
|
||||
* popMethod()
|
||||
* upcallMethod()
|
||||
* doUpcall() <-- native method
|
||||
* main()
|
||||
*
|
||||
* SLEEP_NONATIVE (NativeMethodException for platform thread or OpaqueFrameException
|
||||
* for virtual thread. See explanation in runTests().):
|
||||
* Thread.sleep() + methods called by Thread.sleep()
|
||||
* loopOrSleep()
|
||||
* popMethod()
|
||||
* main()
|
||||
*
|
||||
* LOOP_NONATIVE (no exception):
|
||||
* loopOrSleep() <-- tight loop
|
||||
* popMethod()
|
||||
* main()
|
||||
*/
|
||||
|
||||
class PopFramesTestTarg {
|
||||
static TestMode mode;
|
||||
|
||||
static {
|
||||
System.loadLibrary("PopFramesTestTarg");
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the method whose frame (and all those after it) will be popped.
|
||||
*/
|
||||
public static void popMethod() {
|
||||
System.out.println(" debuggee: in popMethod");
|
||||
if (mode.isCallNative()) {
|
||||
doUpcall();
|
||||
} else {
|
||||
loopOrSleep();
|
||||
}
|
||||
}
|
||||
|
||||
public static void loopOrSleep() {
|
||||
if (mode.isDoLoop()) {
|
||||
while (true);
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static native void doUpcall(); // native method that will call upcallMethod()
|
||||
|
||||
public static void upcallMethod() {
|
||||
if (mode.isCallPrenative()) {
|
||||
popMethod();
|
||||
} else {
|
||||
loopOrSleep();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(" debuggee: Howdy!");
|
||||
|
||||
// We expect just one argument, which is the test mode, such as SLEEP_NONATIVE.
|
||||
if (args.length != 1) {
|
||||
throw new RuntimeException("Must pass 1 arguments to PopFramesTestTarg");
|
||||
}
|
||||
System.out.println(" debuggee: args[0]: " + args[0]);
|
||||
mode = Enum.valueOf(TestMode.class, args[0]); // convert test mode string to an enum
|
||||
System.out.println(" debuggee: test mode: " + mode);
|
||||
|
||||
if (mode.isCallNative()) {
|
||||
popMethod(); // call popMethod() directly, and it will call out to native
|
||||
} else if (mode.isCallPrenative()) {
|
||||
doUpcall(); // call native method that will call back into java to call popMethod()
|
||||
} else {
|
||||
popMethod(); // call popMethod() directly
|
||||
}
|
||||
|
||||
System.out.println(" debuggee: Goodbye from PopFramesTest!");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The different modes the test can be run in. See test description comment above.
|
||||
*/
|
||||
enum TestMode {
|
||||
SLEEP_NATIVE,
|
||||
LOOP_NATIVE,
|
||||
SLEEP_PRENATIVE,
|
||||
LOOP_PRENATIVE,
|
||||
SLEEP_NONATIVE,
|
||||
LOOP_NONATIVE;
|
||||
|
||||
// Returns true if debuggee should block in an infinite loop. Otherwise it calls Thread.sleep().
|
||||
boolean isDoLoop() {
|
||||
return this == LOOP_NATIVE || this == LOOP_PRENATIVE || this == LOOP_NONATIVE;
|
||||
}
|
||||
|
||||
// Returns true if debuggee should introduce a native frame within the set of frames to pop.
|
||||
boolean isCallNative() {
|
||||
return this == LOOP_NATIVE || this == SLEEP_NATIVE;
|
||||
}
|
||||
|
||||
// Returns true if debuggee should introduce a native frame before the set of frames to pop.
|
||||
// The purpose is to cause the virtual thread to be pinned.
|
||||
boolean isCallPrenative() {
|
||||
return this == LOOP_PRENATIVE || this == SLEEP_PRENATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/********** test program **********/
|
||||
|
||||
public class PopFramesTest extends TestScaffold {
|
||||
private static TestMode mode;
|
||||
|
||||
PopFramesTest(String args[]) {
|
||||
super(args);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// We should get one argument that indicates the test mode, such as SLEEP_NONATIVE.
|
||||
if (args.length != 1) {
|
||||
throw new RuntimeException("Must pass one argument to PopFramesTestTarg");
|
||||
}
|
||||
mode = Enum.valueOf(TestMode.class, args[0]); // convert test mode string to an enum
|
||||
|
||||
/*
|
||||
* The @run command looks something like:
|
||||
* @run driver PopFramesTest SLEEP_NONATIVE
|
||||
* We need to pass SLEEP_NONATIVE to the debuggee. We also need to insert
|
||||
* -Djava.library.path so the native method can be accessed if called.
|
||||
*/
|
||||
String nativePath = "-Djava.library.path=" + System.getProperty("java.library.path");
|
||||
String[] newArgs = new String[2];
|
||||
newArgs[0] = nativePath;
|
||||
newArgs[1] = args[0]; // pass test mode, such as SLEEP_NONATIVE
|
||||
|
||||
new PopFramesTest(newArgs).startTests();
|
||||
}
|
||||
|
||||
StackFrame frameFor(ThreadReference thread, String methodName) throws Exception {
|
||||
Iterator it = thread.frames().iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
StackFrame frame = (StackFrame)it.next();
|
||||
if (frame.location().method().name().equals(methodName)) {
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
failure("FAIL: " + methodName + " not on stack");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void printStack(ThreadReference thread, String msg) throws Exception {
|
||||
System.out.println(msg);
|
||||
List<StackFrame> stack_frames = thread.frames();
|
||||
int i = 0;
|
||||
String sourceName;
|
||||
for (StackFrame f : stack_frames) {
|
||||
try {
|
||||
sourceName = f.location().sourceName();
|
||||
} catch (AbsentInformationException aie) {
|
||||
sourceName = "Unknown source";
|
||||
}
|
||||
System.out.println("frame[" + i++ +"]: " + f.location().method() +
|
||||
" (bci:"+ f.location().codeIndex() + ")" +
|
||||
" (" + sourceName + ":"+ f.location().lineNumber() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/********** test core **********/
|
||||
|
||||
protected void runTests() throws Exception {
|
||||
BreakpointEvent bpe = startTo("PopFramesTestTarg", "loopOrSleep", "()V");
|
||||
ClassType targetClass = (ClassType)bpe.location().declaringType();
|
||||
ThreadReference mainThread = bpe.thread();
|
||||
|
||||
// Resume main thread until it is in Thread.sleep() or the infinite loop.
|
||||
mainThread.resume();
|
||||
try {
|
||||
Thread.sleep(1000); // give thread chance to get into Thread.sleep() or loop
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
mainThread.suspend(); // Suspend thread while in Thread.sleep() or loop
|
||||
printStack(mainThread, "Debuggee stack before popFrames():");
|
||||
|
||||
/*
|
||||
* Figure out which exception popFrames() should throw.
|
||||
*/
|
||||
Class expected_exception;
|
||||
switch(mode) {
|
||||
case SLEEP_NATIVE:
|
||||
case LOOP_NATIVE:
|
||||
case SLEEP_PRENATIVE:
|
||||
/*
|
||||
* For the two NATIVE cases, there is a native frame within the set of frames
|
||||
* to pop. For the SLEEP_PRENATIVE case, there also ends up being a native
|
||||
* frame. It will either be Thread.sleep0() for platform threads or
|
||||
* Unsafe.park() for virtual threads. See the SLEEP_NATIVE comment below
|
||||
* for more details.
|
||||
*/
|
||||
expected_exception = NativeMethodException.class;
|
||||
break;
|
||||
case LOOP_PRENATIVE:
|
||||
case LOOP_NONATIVE:
|
||||
/*
|
||||
* For these two test cases, there are no native frames within the set of
|
||||
* frames to pop, nor in the frame previous to the frame to pop, so no
|
||||
* exception is expected.
|
||||
*/
|
||||
expected_exception = null;
|
||||
break;
|
||||
case SLEEP_NONATIVE:
|
||||
/*
|
||||
* For platform threads, Thread.sleep() results in the Thread.sleep0() native
|
||||
* frame on the stack, so the end result is NativeMethodException. For virtual
|
||||
* threads it is not quite so simple. If the thead is pinned (such as when
|
||||
* there is already a native method on the stack), you end up in
|
||||
* VirtualThread.parkOnCarrierThread(), which calls Unsafe.park(), which is a
|
||||
* native method, so again this results in NativeMethodException. However, for
|
||||
* a virtual thread that is not pinned (which is true for this test case), you
|
||||
* end up with no native methods on the stack due to how Continuation.yield()
|
||||
* works. So you have an unmounted virtual thread with no native frames, which
|
||||
* results in OpaqueFrameException being thrown.
|
||||
*/
|
||||
String mainWrapper = System.getProperty("main.wrapper");
|
||||
if ("Virtual".equals(mainWrapper)) {
|
||||
expected_exception = OpaqueFrameException.class;
|
||||
} else {
|
||||
expected_exception = NativeMethodException.class;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Bad test mode: " + mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pop all the frames up to and including the popMethod() frame.
|
||||
*/
|
||||
try {
|
||||
mainThread.popFrames(frameFor(mainThread, "popMethod"));
|
||||
if (expected_exception != null) {
|
||||
failure("failure: popFrames() did not get expected exception: " + expected_exception);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
if (expected_exception == ex.getClass()) {
|
||||
System.out.println("success: popFrames() got expected exception: " + ex);
|
||||
} else {
|
||||
failure("failure: popFrames() got unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
printStack(mainThread, "Debuggee stack after popFrames():");
|
||||
|
||||
/*
|
||||
* Most tests do a listenUntilVMDisconnect() here, but there is no real need for it
|
||||
* with this test, and doing so would require finding a way to get the debuggee
|
||||
* to exit the endless loop it might be in. When we return, TestScaffold will
|
||||
* call TestScaffold.shutdown(), causing the debuggee process to be terminated quickly.
|
||||
*/
|
||||
|
||||
if (testFailed) {
|
||||
throw new Exception("PopFramesTest failed");
|
||||
}
|
||||
System.out.println("Passed:");
|
||||
}
|
||||
}
|
@ -361,8 +361,44 @@ abstract public class TestScaffold extends TargetAdapter {
|
||||
}
|
||||
|
||||
protected void startUp(String targetName) {
|
||||
List<String> argList = new ArrayList(Arrays.asList(args));
|
||||
argList.add(targetName);
|
||||
/*
|
||||
* args[] contains all VM arguments followed by the app arguments.
|
||||
* We need to insert targetName between the two types of arguments.
|
||||
*/
|
||||
boolean expectSecondArg = false;
|
||||
boolean foundFirstAppArg = false;
|
||||
List<String> argList = new ArrayList();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
String arg = args[i].trim();
|
||||
if (foundFirstAppArg) {
|
||||
argList.add(arg);
|
||||
continue;
|
||||
}
|
||||
if (expectSecondArg) {
|
||||
expectSecondArg = false;
|
||||
argList.add(arg);
|
||||
continue;
|
||||
}
|
||||
if (doubleWordArgs.contains(arg)) {
|
||||
expectSecondArg = true;
|
||||
argList.add(arg);
|
||||
continue;
|
||||
}
|
||||
if (arg.startsWith("-")) {
|
||||
argList.add(arg);
|
||||
continue;
|
||||
}
|
||||
// We reached the first app argument.
|
||||
argList.add(targetName);
|
||||
argList.add(arg);
|
||||
foundFirstAppArg = true;
|
||||
}
|
||||
|
||||
if (!foundFirstAppArg) {
|
||||
// Add the target since we didn't do that in the above loop.
|
||||
argList.add(targetName);
|
||||
}
|
||||
|
||||
println("run args: " + argList);
|
||||
connect(argList.toArray(args));
|
||||
waitForVMStart();
|
||||
@ -461,8 +497,11 @@ abstract public class TestScaffold extends TargetAdapter {
|
||||
testFailed = true;
|
||||
}
|
||||
|
||||
final List<String> doubleWordArgs = List.of("-cp", "-classpath", "--add-opens", "--class-path",
|
||||
"--upgrade-module-path", "--add-modules", "-d", "--add-exports", "--patch-module", "--module-path");
|
||||
final List<String> doubleWordArgs = List.of(
|
||||
"-connect", "-trace", // special TestScaffold args
|
||||
"-cp", "-classpath", "--add-opens", "--class-path",
|
||||
"--upgrade-module-path", "--add-modules", "-d", "--add-exports",
|
||||
"--patch-module", "--module-path");
|
||||
|
||||
private ArgInfo parseArgs(String args[]) {
|
||||
ArgInfo argInfo = new ArgInfo();
|
||||
|
60
test/jdk/com/sun/jdi/libPopFramesTestTarg.c
Normal file
60
test/jdk/com/sun/jdi/libPopFramesTestTarg.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
static jclass test_class;
|
||||
static jmethodID mid;
|
||||
static jint current_jni_version = JNI_VERSION_19;
|
||||
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *env;
|
||||
jclass cl;
|
||||
|
||||
(*vm)->GetEnv(vm, (void **) &env, current_jni_version);
|
||||
|
||||
cl = (*env)->FindClass(env, "PopFramesTestTarg");
|
||||
test_class = (*env)->NewGlobalRef(env, cl);
|
||||
mid = (*env)->GetStaticMethodID(env, test_class, "upcallMethod", "()V");
|
||||
|
||||
return current_jni_version;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: NativeMethod
|
||||
* Method: doUpcall
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_PopFramesTestTarg_doUpcall(JNIEnv *env, jobject obj) {
|
||||
(*env)->CallStaticVoidMethod(env, obj, mid);
|
||||
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->FatalError(env, "Exception thrown");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user