From 5a07934689b1f153fe1a5ddcc7c98f0a1e5639dd Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 15 Jul 2025 14:55:53 -0700 Subject: [PATCH 1/3] fix OpaqueFrameException related issues --- .../classes/com/sun/jdi/ThreadReference.java | 10 ++--- .../com/sun/tools/jdi/StackFrameImpl.java | 40 +++++++++---------- .../sun/tools/jdi/ThreadReferenceImpl.java | 6 +-- 3 files changed, 26 insertions(+), 30 deletions(-) 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 bccdf4cc8bf57..5ca7a917b2ac8 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -402,8 +402,8 @@ List ownedMonitorsAndFrames() * @throws java.lang.IllegalArgumentException if frame * is not on this thread's call stack. * - * @throws OpaqueFrameException if this thread is a suspended virtual thread and the - * target VM was unable to pop the frames. + * @throws OpaqueFrameException if target VM is unable to pop this frame + * (e.g. a virtual thread is not suspended at an event). * * @throws NativeMethodException if one of the frames that would be * popped is that of a native method or if the frame previous to @@ -484,8 +484,8 @@ List ownedMonitorsAndFrames() * @throws IncompatibleThreadStateException if this * thread is not suspended. * - * @throws OpaqueFrameException if this thread is a suspended virtual thread and the - * target VM is unable to force the method to return. + * @throws OpaqueFrameException if target VM is unable to pop this frame + * (e.g. a virtual thread is not suspended at an event). * * @throws NativeMethodException if the frame to be returned from * is that of a native method. 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 e242bd7313bbf..c33f9794d014b 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, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, 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 @@ -395,29 +395,25 @@ public PacketStream send() { } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.OPAQUE_FRAME: - if (thread.isVirtual()) { - // 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(); - } + // 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(); } + // No native frames involved. Must have been due to virtual thread + // not being mounted or some other reason such as failure to deopt. + throw new OpaqueFrameException(); case JDWP.Error.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( "Thread not current or suspended"); 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 0f99fe9987183..e5dce0718f40e 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,10 +597,10 @@ public void forceEarlyReturn(Value returnValue) throws InvalidTypeException, } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.OPAQUE_FRAME: - if (isVirtual() && !meth.isNative()) { - throw new OpaqueFrameException(); - } else { + if (meth.isNative()) { throw new NativeMethodException(); + } else { + throw new OpaqueFrameException(); } case JDWP.Error.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( From 05cce179a9a37280be6f84e018becbf3c6deb267 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 15 Jul 2025 20:29:00 -0700 Subject: [PATCH 2/3] update based on feedback --- .../share/classes/com/sun/tools/jdi/StackFrameImpl.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 c33f9794d014b..a36e5695f696f 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 @@ -398,15 +398,14 @@ public PacketStream send() { // 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; + StackFrame sf; try { - sf = (StackFrameImpl)thread.frame(i); + sf = 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(); + Method meth = sf.location().method(); if (meth.isNative()) { throw new NativeMethodException(); } From e63768563bf6f8a1a30f952ab4dcf4df0ba550e5 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 18 Jul 2025 16:50:56 -0700 Subject: [PATCH 3/3] minor rewording --- .../share/classes/com/sun/jdi/ThreadReference.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 5ca7a917b2ac8..67b8e391bf30d 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java @@ -402,8 +402,8 @@ List ownedMonitorsAndFrames() * @throws java.lang.IllegalArgumentException if frame * is not on this thread's call stack. * - * @throws OpaqueFrameException if target VM is unable to pop this frame - * (e.g. a virtual thread is not suspended at an event). + * @throws OpaqueFrameException if the target VM is unable to pop this frame + * (e.g. a virtual thread is suspended, but not at an event). * * @throws NativeMethodException if one of the frames that would be * popped is that of a native method or if the frame previous to @@ -484,8 +484,8 @@ List ownedMonitorsAndFrames() * @throws IncompatibleThreadStateException if this * thread is not suspended. * - * @throws OpaqueFrameException if target VM is unable to pop this frame - * (e.g. a virtual thread is not suspended at an event). + * @throws OpaqueFrameException if the target VM is unable to force the method to return + * (e.g. a virtual thread is suspended, but not at an event). * * @throws NativeMethodException if the frame to be returned from * is that of a native method.