mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-14 18:03:44 +00:00
8369505: jhsdb jstack cannot handle continuation stub
Reviewed-by: cjplummer, pchilanomate
This commit is contained in:
parent
5fc3904bfe
commit
1653999871
@ -39,6 +39,7 @@ class RegisterMap;
|
||||
|
||||
// Metadata stored in the continuation entry frame
|
||||
class ContinuationEntry {
|
||||
friend class VMStructs;
|
||||
friend class JVMCIVMStructs;
|
||||
ContinuationEntryPD _pd;
|
||||
#ifdef ASSERT
|
||||
|
||||
@ -616,6 +616,7 @@
|
||||
nonstatic_field(JavaThread, _active_handles, JNIHandleBlock*) \
|
||||
nonstatic_field(JavaThread, _monitor_owner_id, int64_t) \
|
||||
volatile_nonstatic_field(JavaThread, _terminated, JavaThread::TerminatedTypes) \
|
||||
nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \
|
||||
nonstatic_field(Thread, _osthread, OSThread*) \
|
||||
\
|
||||
/************/ \
|
||||
@ -796,7 +797,8 @@
|
||||
nonstatic_field(Mutex, _name, const char*) \
|
||||
static_field(Mutex, _mutex_array, Mutex**) \
|
||||
static_field(Mutex, _num_mutex, int) \
|
||||
volatile_nonstatic_field(Mutex, _owner, Thread*)
|
||||
volatile_nonstatic_field(Mutex, _owner, Thread*) \
|
||||
static_field(ContinuationEntry, _return_pc, address)
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// VM_TYPES
|
||||
@ -1270,6 +1272,7 @@
|
||||
declare_toplevel_type(FileMapHeader) \
|
||||
declare_toplevel_type(CDSFileMapRegion) \
|
||||
declare_toplevel_type(UpcallStub::FrameData) \
|
||||
declare_toplevel_type(ContinuationEntry) \
|
||||
\
|
||||
/************/ \
|
||||
/* GC types */ \
|
||||
|
||||
@ -180,6 +180,8 @@ public class CodeBlob extends VMObject {
|
||||
|
||||
public boolean isUpcallStub() { return getKind() == UpcallKind; }
|
||||
|
||||
public boolean isContinuationStub() { return getName().equals("StubRoutines (continuation stubs)"); }
|
||||
|
||||
public boolean isJavaMethod() { return false; }
|
||||
|
||||
public boolean isNativeMethod() { return false; }
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, NTT DATA.
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.runtime;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
|
||||
public class ContinuationEntry extends VMObject {
|
||||
private static long size;
|
||||
private static Address returnPC;
|
||||
|
||||
static {
|
||||
VM.registerVMInitializedObserver((o, d) -> initialize(VM.getVM().getTypeDataBase()));
|
||||
}
|
||||
|
||||
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
|
||||
Type type = db.lookupType("ContinuationEntry");
|
||||
size = type.getSize();
|
||||
returnPC = type.getAddressField("_return_pc").getValue();
|
||||
}
|
||||
|
||||
public ContinuationEntry(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public Address getEntryPC() {
|
||||
return returnPC;
|
||||
}
|
||||
|
||||
public Address getEntrySP(){
|
||||
return this.getAddress();
|
||||
}
|
||||
|
||||
public Address getEntryFP(){
|
||||
return this.getAddress().addOffsetTo(size);
|
||||
}
|
||||
|
||||
}
|
||||
@ -47,6 +47,7 @@ public class JavaThread extends Thread {
|
||||
private static AddressField stackBaseField;
|
||||
private static CIntegerField stackSizeField;
|
||||
private static CIntegerField terminatedField;
|
||||
private static AddressField contEntryField;
|
||||
private static AddressField activeHandlesField;
|
||||
private static CIntegerField monitorOwnerIDField;
|
||||
private static long oopPtrSize;
|
||||
@ -95,6 +96,7 @@ public class JavaThread extends Thread {
|
||||
stackBaseField = type.getAddressField("_stack_base");
|
||||
stackSizeField = type.getCIntegerField("_stack_size");
|
||||
terminatedField = type.getCIntegerField("_terminated");
|
||||
contEntryField = type.getAddressField("_cont_entry");
|
||||
activeHandlesField = type.getAddressField("_active_handles");
|
||||
monitorOwnerIDField = type.getCIntegerField("_monitor_owner_id");
|
||||
|
||||
@ -340,6 +342,10 @@ public class JavaThread extends Thread {
|
||||
return (int) terminatedField.getValue(addr);
|
||||
}
|
||||
|
||||
public ContinuationEntry getContEntry() {
|
||||
return VMObjectFactory.newObject(ContinuationEntry.class, contEntryField.getValue(addr));
|
||||
}
|
||||
|
||||
/** Gets the Java-side thread object for this JavaThread */
|
||||
public Oop getThreadObj() {
|
||||
Oop obj = null;
|
||||
|
||||
@ -270,7 +270,13 @@ public class AARCH64Frame extends Frame {
|
||||
}
|
||||
|
||||
if (cb != null) {
|
||||
return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb);
|
||||
if (cb.isUpcallStub()) {
|
||||
return senderForUpcallStub(map, (UpcallStub)cb);
|
||||
} else if (cb.isContinuationStub()) {
|
||||
return senderForContinuationStub(map, cb);
|
||||
} else {
|
||||
return senderForCompiledFrame(map, cb);
|
||||
}
|
||||
}
|
||||
|
||||
// Must be native-compiled frame, i.e. the marshaling code for native
|
||||
@ -356,6 +362,16 @@ public class AARCH64Frame extends Frame {
|
||||
map.setLocation(fp, savedFPAddr);
|
||||
}
|
||||
|
||||
private Frame senderForContinuationStub(AARCH64RegisterMap map, CodeBlob cb) {
|
||||
var contEntry = map.getThread().getContEntry();
|
||||
|
||||
Address senderSP = contEntry.getEntrySP();
|
||||
Address senderPC = contEntry.getEntryPC();
|
||||
Address senderFP = contEntry.getEntryFP();
|
||||
|
||||
return new AARCH64Frame(senderSP, senderFP, senderPC);
|
||||
}
|
||||
|
||||
private Frame senderForCompiledFrame(AARCH64RegisterMap map, CodeBlob cb) {
|
||||
if (DEBUG) {
|
||||
System.out.println("senderForCompiledFrame");
|
||||
|
||||
@ -262,7 +262,13 @@ public class RISCV64Frame extends Frame {
|
||||
}
|
||||
|
||||
if (cb != null) {
|
||||
return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb);
|
||||
if (cb.isUpcallStub()) {
|
||||
return senderForUpcallStub(map, (UpcallStub)cb);
|
||||
} else if (cb.isContinuationStub()) {
|
||||
return senderForContinuationStub(map, cb);
|
||||
} else {
|
||||
return senderForCompiledFrame(map, cb);
|
||||
}
|
||||
}
|
||||
|
||||
// Must be native-compiled frame, i.e. the marshaling code for native
|
||||
@ -348,6 +354,16 @@ public class RISCV64Frame extends Frame {
|
||||
map.setLocation(fp, savedFPAddr);
|
||||
}
|
||||
|
||||
private Frame senderForContinuationStub(RISCV64RegisterMap map, CodeBlob cb) {
|
||||
var contEntry = map.getThread().getContEntry();
|
||||
|
||||
Address senderSP = contEntry.getEntrySP();
|
||||
Address senderPC = contEntry.getEntryPC();
|
||||
Address senderFP = contEntry.getEntryFP();
|
||||
|
||||
return new RISCV64Frame(senderSP, senderFP, senderPC);
|
||||
}
|
||||
|
||||
private Frame senderForCompiledFrame(RISCV64RegisterMap map, CodeBlob cb) {
|
||||
if (DEBUG) {
|
||||
System.out.println("senderForCompiledFrame");
|
||||
|
||||
@ -270,7 +270,13 @@ public class X86Frame extends Frame {
|
||||
}
|
||||
|
||||
if (cb != null) {
|
||||
return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb);
|
||||
if (cb.isUpcallStub()) {
|
||||
return senderForUpcallStub(map, (UpcallStub)cb);
|
||||
} else if (cb.isContinuationStub()) {
|
||||
return senderForContinuationStub(map, cb);
|
||||
} else {
|
||||
return senderForCompiledFrame(map, cb);
|
||||
}
|
||||
}
|
||||
|
||||
// Must be native-compiled frame, i.e. the marshaling code for native
|
||||
@ -356,6 +362,16 @@ public class X86Frame extends Frame {
|
||||
map.setLocation(rbp, savedFPAddr);
|
||||
}
|
||||
|
||||
private Frame senderForContinuationStub(X86RegisterMap map, CodeBlob cb) {
|
||||
var contEntry = map.getThread().getContEntry();
|
||||
|
||||
Address senderSP = contEntry.getEntrySP();
|
||||
Address senderPC = contEntry.getEntryPC();
|
||||
Address senderFP = contEntry.getEntryFP();
|
||||
|
||||
return new X86Frame(senderSP, senderFP, senderPC);
|
||||
}
|
||||
|
||||
private Frame senderForCompiledFrame(X86RegisterMap map, CodeBlob cb) {
|
||||
if (DEBUG) {
|
||||
System.out.println("senderForCompiledFrame");
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, NTT DATA
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.foreign.Arena;
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
import java.lang.foreign.Linker;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.SymbolLookup;
|
||||
import java.lang.foreign.ValueLayout;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import jdk.test.lib.apps.LingeredApp;
|
||||
|
||||
public class LingeredAppWithVirtualThread extends LingeredApp implements Runnable {
|
||||
|
||||
private static final String THREAD_NAME = "target thread";
|
||||
|
||||
private static final MethodHandle hndSleep;
|
||||
|
||||
private static final int sleepArg;
|
||||
|
||||
private static final CountDownLatch signal = new CountDownLatch(1);
|
||||
|
||||
static {
|
||||
MemorySegment func;
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
func = SymbolLookup.libraryLookup("Kernel32", Arena.global())
|
||||
.findOrThrow("Sleep");
|
||||
sleepArg = 3600_000; // 1h in milliseconds
|
||||
} else {
|
||||
func = Linker.nativeLinker()
|
||||
.defaultLookup()
|
||||
.findOrThrow("sleep");
|
||||
sleepArg = 3600; // 1h in seconds
|
||||
}
|
||||
|
||||
var desc = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT);
|
||||
hndSleep = Linker.nativeLinker().downcallHandle(func, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Thread.yield();
|
||||
signal.countDown();
|
||||
try {
|
||||
hndSleep.invoke(sleepArg);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
Thread.ofVirtual()
|
||||
.name(THREAD_NAME)
|
||||
.start(new LingeredAppWithVirtualThread());
|
||||
|
||||
signal.await();
|
||||
LingeredApp.main(args);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, NTT DATA
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jdk.test.lib.JDKToolLauncher;
|
||||
import jdk.test.lib.SA.SATestUtils;
|
||||
import jdk.test.lib.Utils;
|
||||
import jdk.test.lib.apps.LingeredApp;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8369505
|
||||
* @requires vm.hasSA
|
||||
* @requires (os.arch == "amd64" | os.arch == "x86_64" | os.arch == "aarch64" | os.arch == "riscv64")
|
||||
* @library /test/lib
|
||||
* @run driver TestJhsdbJstackWithVirtualThread
|
||||
*/
|
||||
public class TestJhsdbJstackWithVirtualThread {
|
||||
|
||||
private static void runJstack(LingeredApp app) throws Exception {
|
||||
JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb");
|
||||
launcher.addVMArgs(Utils.getTestJavaOpts());
|
||||
launcher.addToolArg("jstack");
|
||||
launcher.addToolArg("--pid");
|
||||
launcher.addToolArg(Long.toString(app.getPid()));
|
||||
|
||||
ProcessBuilder pb = SATestUtils.createProcessBuilder(launcher);
|
||||
Process jhsdb = pb.start();
|
||||
OutputAnalyzer out = new OutputAnalyzer(jhsdb);
|
||||
|
||||
jhsdb.waitFor();
|
||||
|
||||
System.out.println(out.getStdout());
|
||||
System.err.println(out.getStderr());
|
||||
|
||||
out.stderrShouldBeEmptyIgnoreDeprecatedWarnings();
|
||||
out.shouldNotContain("must have non-zero frame size");
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work.
|
||||
LingeredApp app = null;
|
||||
|
||||
try {
|
||||
app = new LingeredAppWithVirtualThread();
|
||||
LingeredApp.startApp(app);
|
||||
System.out.println("Started LingeredApp with pid " + app.getPid());
|
||||
runJstack(app);
|
||||
System.out.println("Test Completed");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
} finally {
|
||||
LingeredApp.stopApp(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user