diff --git a/src/java.se/share/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec index 0c4c5ed5c24..323a48e591e 100644 --- a/src/java.se/share/data/jdwp/jdwp.spec +++ b/src/java.se/share/data/jdwp/jdwp.spec @@ -2104,10 +2104,10 @@ JDWP "Java(tm) Debug Wire Protocol" "command and resumption of thread execution, the " "state of the stack is undefined. " "
" - "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 force a return from the current frame " + "of a virtual thread when it is suspended at an event. " + "An implementation may support forcing a return from the current frame " + "of a suspended virtual thread in other cases." "
" "No further instructions are executed in the called " "method. Specifically, finally blocks are not executed. Note: " @@ -2147,7 +2147,7 @@ JDWP "Java(tm) Debug Wire Protocol" (Error THREAD_NOT_SUSPENDED) (Error OPAQUE_FRAME "Attempted to return early from a frame " "corresponding to a native method, " - "the thread is a virtual thread and the target " + "the thread is a suspended virtual thread and the target " "VM is unable to force its current frame to return, " "or the implementation is unable to provide this " "functionality on this frame.") diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java index 3cf0cb96960..9a47111677f 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java @@ -436,10 +436,10 @@ public interface ThreadReference extends ObjectReference { * this method and resumption of thread execution, the * state of the stack is undefined. *
- * The target VM may not support, or may only provide limited support, - * for forcing a method to return 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 force a return from the current frame + * of a virtual thread when it is suspended at an event. + * An implementation may support forcing a return from the current frame + * of a suspended virtual thread in other cases. *
* No further instructions are executed in the called
* method. Specifically, finally blocks are not executed. Note:
@@ -484,7 +484,7 @@ public interface ThreadReference extends ObjectReference {
* @throws IncompatibleThreadStateException if this
* thread is not suspended.
*
- * @throws OpaqueFrameException if this thread is a virtual thread and the
+ * @throws OpaqueFrameException if this thread is a suspended virtual thread and the
* target VM is unable to force the method to return.
*
* @throws NativeMethodException if the frame to be returned from
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java
index 79e11e32751..0f99fe99871 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java
@@ -597,11 +597,10 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
} catch (JDWPException exc) {
switch (exc.errorCode()) {
case JDWP.Error.OPAQUE_FRAME:
- if (meth.isNative()) {
- throw new NativeMethodException();
- } else {
- assert isVirtual(); // can only happen with virtual threads
+ if (isVirtual() && !meth.isNative()) {
throw new OpaqueFrameException();
+ } else {
+ throw new NativeMethodException();
}
case JDWP.Error.THREAD_NOT_SUSPENDED:
throw new IncompatibleThreadStateException(
diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt
index c36cc6d5481..e5ca8b77649 100644
--- a/test/hotspot/jtreg/ProblemList-Virtual.txt
+++ b/test/hotspot/jtreg/ProblemList-Virtual.txt
@@ -105,16 +105,6 @@ vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java 8300707 generic-all
vmTestbase/nsk/jdi/ExceptionEvent/catchLocation/location002/TestDescription.java 8278470 generic-all
-####
-## JVMTI ForceEarlyReturn not supported for vthreads (JVMTI_ERROR_OPAQUE_FRAME)
-## Note forceEarlyReturn002 was converted to support vthreads. The rest were not
-## since there is no added value (JVMTI_ERROR_OPAQUE_FRAME is expected).
-
-vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java
-vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn014/forceEarlyReturn014.java 8285415 generic-all
-vmTestbase/nsk/jdi/stress/serial/forceEarlyReturn001/TestDescription.java 8285415 generic-all
-vmTestbase/nsk/jdi/stress/serial/forceEarlyReturn002/TestDescription.java 8285415 generic-all
-
###
# This test always times out on windows. This is due to the test forcing OOME in the
# debuggee, which has the side affect of making the Read-Poller thread exit. Because
diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java
index f5b8a7581a9..c4bbfe51b82 100644
--- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -147,30 +147,17 @@ public class forceEarlyReturn002 extends ForceEarlyReturnDebugger {
// get value for early return
ObjectReference returnValue = (ObjectReference) referenceType.getValue(referenceType.fieldByName("expectedValue"));
- boolean vthreadMode = "Virtual".equals(System.getProperty("main.wrapper"));
+
try {
- // don't expect any exception, except for vthreads expect OpaqueFrameException
+ // don't expect any exception
threadReference.forceEarlyReturn(returnValue);
- if (vthreadMode) {
- setSuccess(false);
- log.complain("Expected OpaqueFrameException");
- }
} catch (Exception e) {
- if (vthreadMode && (e instanceof OpaqueFrameException)) {
- // pass
- } else {
- setSuccess(false);
- log.complain("Unexpected exception: " + e);
- e.printStackTrace(log.getOutStream());
- }
+ setSuccess(false);
+ log.complain("Unexpected exception: " + e);
+ e.printStackTrace(log.getOutStream());
}
- if (vthreadMode) {
- // MethodExit event won't be as expected if using vthreads, so just resume
- threadReference.resume();
- } else {
- testMethodExitEvent(threadReference, ClassUsingTestClass.breakpointMethodName);
- }
+ testMethodExitEvent(threadReference, ClassUsingTestClass.breakpointMethodName);
if (!isDebuggeeReady())
return;
diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java
index 9664271bd73..1351c7dacfd 100644
--- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/forceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -83,9 +83,7 @@ public class forceEarlyReturn002a extends AbstractJDIDebuggee {
classUsingTestClass.createExpectedValue();
Object value = classUsingTestClass.testClassMethod();
- boolean vthreadMode = "Virtual".equals(System.getProperty("main.wrapper"));
- // expectedValue should be set as expected unless in vthread mode
- if (vthreadMode == (ClassUsingTestClass.expectedValue == value)) {
+ if (ClassUsingTestClass.expectedValue != value) {
setSuccess(false);
log.complain("Unexpected result of testClassMethod: " + value);
}
diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt
index 6fb6b69e47d..b754527ecfe 100644
--- a/test/jdk/ProblemList-Virtual.txt
+++ b/test/jdk/ProblemList-Virtual.txt
@@ -28,7 +28,6 @@ com/sun/jdi/EATests.java#id0 8264699 generic-
#
com/sun/jdi/DeferredStepTest.java 8285422 generic-all
-com/sun/jdi/EarlyReturnTest.java 8285422 generic-all
com/sun/jdi/ExceptionEvents.java 8285422 generic-all
com/sun/jdi/JdbMethodExitTest.java 8285422 generic-all
com/sun/jdi/JdbStepTest.java 8285422 generic-all
diff --git a/test/jdk/com/sun/jdi/ForceEarlyReturnTest.java b/test/jdk/com/sun/jdi/ForceEarlyReturnTest.java
new file mode 100644
index 00000000000..97b3db044d3
--- /dev/null
+++ b/test/jdk/com/sun/jdi/ForceEarlyReturnTest.java
@@ -0,0 +1,263 @@
+/*
+ * 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 forceEarlyReturn() on threads in various states not covered
+ * well by other tests. Most notably, this test includes a
+ * test case for a suspended but unmounted virtual thread.
+ *
+ * @run build TestScaffold VMConnection TargetListener TargetAdapter
+ * @run compile -g ForceEarlyReturnTest.java
+ * @run driver ForceEarlyReturnTest NATIVE
+ * @run driver ForceEarlyReturnTest LOOP
+ * @run driver ForceEarlyReturnTest SLEEP
+ */
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import java.util.*;
+
+/*
+ * There are three test modes covered by this test:
+ * NATIVE: the debuggee sits in a native method.
+ * SLEEP: the debuggee blocks in Thread.sleep().
+ * LOOP: the debuggee sits in a tight loop.
+ *
+ * In all cases the thread is suspended and errors such as IllegalArgumentException
+ * and InvalidStackFrameException should not happen. The forceEarlyReturn() calls should
+ * either pass, or produce OpaqueFrameException or NativeMethodException.
+ *
+ * Call stacks for each test mode (and expected result):
+ *
+ * NATIVE (NativeMethodException):
+ * nativeMethod() <-- native method, which sleeps
+ * loopOrSleep()
+ * main()
+ *
+ * LOOP (no exception):
+ * loopOrSleep() <-- tight loop
+ * main()
+ *
+ * SLEEP (NativeMethodException for platform thread or OpaqueFrameException
+ * for virtual thread. See explanation in runTests().):
+ * Thread.sleep() + methods called by Thread.sleep()
+ * loopOrSleep()
+ * main()
+ */
+
+class ForceEarlyReturnTestTarg {
+ static TestMode mode;
+
+ static {
+ System.loadLibrary("ForceEarlyReturnTestTarg");
+ }
+
+ public static void loopOrSleep() {
+ switch (mode) {
+ case TestMode.LOOP:
+ while (true);
+ case TestMode.SLEEP:
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ break;
+ case TestMode.NATIVE:
+ nativeMethod();
+ break;
+ }
+ }
+
+ public static native void nativeMethod(); // native method that does a very long sleep
+
+ public static void main(String[] args) {
+ System.out.println(" debuggee: Howdy!");
+
+ // We expect just one argument, which is the test mode, such as SLEEP.
+ if (args.length != 1) {
+ throw new RuntimeException("Must pass 1 arguments to ForceEarlyReturnTestTarg");
+ }
+ 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);
+
+ loopOrSleep();
+
+ System.out.println(" debuggee: Goodbye from ForceEarlyReturnTest!");
+ }
+}
+
+/*
+ * The different modes the test can be run in. See test description comment above.
+ */
+enum TestMode {
+ NATIVE,
+ SLEEP,
+ LOOP;
+}
+
+/********** test program **********/
+
+public class ForceEarlyReturnTest extends TestScaffold {
+ private static TestMode mode;
+
+ ForceEarlyReturnTest(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.
+ if (args.length != 1) {
+ throw new RuntimeException("Must pass one argument to ForceEarlyReturnTestTarg");
+ }
+ mode = Enum.valueOf(TestMode.class, args[0]); // convert test mode string to an enum
+
+ /*
+ * The @run command looks something like:
+ * @run driver ForceEarlyReturnTest SLEEP
+ * We need to pass SLEEP 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 ForceEarlyReturnTest(newArgs).startTests();
+ }
+
+ public void printStack(ThreadReference thread, String msg) throws Exception {
+ System.out.println(msg);
+ List