diff --git a/src/java.se/share/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec index a7d489b2813..0c4c5ed5c24 100644 --- a/src/java.se/share/data/jdwp/jdwp.spec +++ b/src/java.se/share/data/jdwp/jdwp.spec @@ -2692,10 +2692,9 @@ JDWP "Java(tm) Debug Wire Protocol" "objectref is added back as well. The Java virtual machine " "program counter is restored to the opcode of the invoke instruction." "

" - "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." "

" "Since JDWP version 1.4. Requires canPopFrames capability - see " "CapabilitiesNew." @@ -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) ) 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 a201e7ed137..3cf0cb96960 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java @@ -370,15 +370,14 @@ public interface ThreadReference extends ObjectReference { * Thus the target program may * proceed differently than the user would expect. *

- * The specified thread must be suspended. + * This thread must be suspended. *

* All StackFrame objects for this thread are * invalidated. *

- * 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. *

* No events are generated by this method. *

@@ -403,8 +402,8 @@ public interface ThreadReference extends ObjectReference { * @throws java.lang.IllegalArgumentException if frame * 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 diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java index 0ad0b08e72f..e242bd7313b 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java @@ -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( diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index 66ef137957b..efe88a86045 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -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 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001.java index 5a0461ad085..51f51da29ef 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/popFrames/popframes001.java @@ -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();"); diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index d5b9009a430..35fbc3870eb 100644 --- a/test/jdk/ProblemList-Virtual.txt +++ b/test/jdk/ProblemList-Virtual.txt @@ -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 diff --git a/test/jdk/com/sun/jdi/PopFramesTest.java b/test/jdk/com/sun/jdi/PopFramesTest.java new file mode 100644 index 00000000000..1fc45e2a191 --- /dev/null +++ b/test/jdk/com/sun/jdi/PopFramesTest.java @@ -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 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:"); + } +} diff --git a/test/jdk/com/sun/jdi/TestScaffold.java b/test/jdk/com/sun/jdi/TestScaffold.java index 168352fd243..831dac0247e 100644 --- a/test/jdk/com/sun/jdi/TestScaffold.java +++ b/test/jdk/com/sun/jdi/TestScaffold.java @@ -361,8 +361,44 @@ abstract public class TestScaffold extends TargetAdapter { } protected void startUp(String targetName) { - List 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 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 doubleWordArgs = List.of("-cp", "-classpath", "--add-opens", "--class-path", - "--upgrade-module-path", "--add-modules", "-d", "--add-exports", "--patch-module", "--module-path"); + final List 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(); diff --git a/test/jdk/com/sun/jdi/libPopFramesTestTarg.c b/test/jdk/com/sun/jdi/libPopFramesTestTarg.c new file mode 100644 index 00000000000..151146c411e --- /dev/null +++ b/test/jdk/com/sun/jdi/libPopFramesTestTarg.c @@ -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 +#include + +#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"); + } +}