Skip to content

Commit deeb09a

Browse files
committedSep 7, 2024
8339307: jhsdb jstack could not trace FFM upcall frame
Reviewed-by: cjplummer, jvernee
1 parent fbe2629 commit deeb09a

File tree

12 files changed

+447
-10
lines changed

12 files changed

+447
-10
lines changed
 

‎src/hotspot/share/code/codeBlob.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ class UpcallLinker;
595595

596596
// A (Panama) upcall stub. Not used by JNI.
597597
class UpcallStub: public RuntimeBlob {
598+
friend class VMStructs;
598599
friend class UpcallLinker;
599600
private:
600601
jobject _receiver;

‎src/hotspot/share/runtime/vmStructs.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,12 @@
563563
\
564564
nonstatic_field(DeoptimizationBlob, _unpack_offset, int) \
565565
\
566+
/*****************************************************/ \
567+
/* UpcallStubs (NOTE: incomplete, but only a little) */ \
568+
/*****************************************************/ \
569+
\
570+
nonstatic_field(UpcallStub, _frame_data_offset, ByteSize) \
571+
\
566572
/**************************************************/ \
567573
/* NMethods (NOTE: incomplete, but only a little) */ \
568574
/**************************************************/ \
@@ -1012,7 +1018,9 @@
10121018
nonstatic_field(AccessFlags, _flags, jint) \
10131019
nonstatic_field(elapsedTimer, _counter, jlong) \
10141020
nonstatic_field(elapsedTimer, _active, bool) \
1015-
nonstatic_field(InvocationCounter, _counter, unsigned int)
1021+
nonstatic_field(InvocationCounter, _counter, unsigned int) \
1022+
\
1023+
nonstatic_field(UpcallStub::FrameData, jfa, JavaFrameAnchor)
10161024

10171025
//--------------------------------------------------------------------------------
10181026
// VM_TYPES
@@ -1306,6 +1314,7 @@
13061314
declare_type(nmethod, CodeBlob) \
13071315
declare_type(RuntimeStub, RuntimeBlob) \
13081316
declare_type(SingletonBlob, RuntimeBlob) \
1317+
declare_type(UpcallStub, RuntimeBlob) \
13091318
declare_type(SafepointBlob, SingletonBlob) \
13101319
declare_type(DeoptimizationBlob, SingletonBlob) \
13111320
declare_c2_type(ExceptionBlob, SingletonBlob) \
@@ -1900,6 +1909,7 @@
19001909
declare_integer_type(BasicType) /* FIXME: wrong type (not integer) */ \
19011910
\
19021911
declare_integer_type(CompLevel) \
1912+
declare_integer_type(ByteSize) \
19031913
JVMTI_ONLY(declare_toplevel_type(BreakpointInfo)) \
19041914
JVMTI_ONLY(declare_toplevel_type(BreakpointInfo*)) \
19051915
declare_toplevel_type(CodeBlob*) \
@@ -1948,6 +1958,7 @@
19481958
declare_type(FileMapInfo, CHeapObj<mtInternal>) \
19491959
declare_toplevel_type(FileMapHeader) \
19501960
declare_toplevel_type(CDSFileMapRegion) \
1961+
declare_toplevel_type(UpcallStub::FrameData) \
19511962
\
19521963
/************/ \
19531964
/* GC types */ \

‎src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java

+2
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ public ImmutableOopMapSet getOopMaps() {
143143

144144
public boolean isRuntimeStub() { return false; }
145145

146+
public boolean isUpcallStub() { return false; }
147+
146148
public boolean isDeoptimizationStub() { return false; }
147149

148150
public boolean isUncommonTrapStub() { return false; }

‎src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeCache.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,7 @@ private static synchronized void initialize(TypeDataBase db) {
6060
virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class);
6161
virtualConstructor.addMapping("MethodHandlesAdapterBlob", MethodHandlesAdapterBlob.class);
6262
virtualConstructor.addMapping("VtableBlob", VtableBlob.class);
63+
virtualConstructor.addMapping("UpcallStub", UpcallStub.class);
6364
virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class);
6465
virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class);
6566
if (VM.getVM().isServerCompiler()) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
package sun.jvm.hotspot.code;
26+
27+
import java.util.*;
28+
import sun.jvm.hotspot.debugger.*;
29+
import sun.jvm.hotspot.runtime.*;
30+
import sun.jvm.hotspot.types.*;
31+
import sun.jvm.hotspot.utilities.Observable;
32+
import sun.jvm.hotspot.utilities.Observer;
33+
34+
public class UpcallStub extends RuntimeBlob {
35+
36+
private static CIntegerField frameDataOffsetField;
37+
private static AddressField lastJavaFPField;
38+
private static AddressField lastJavaSPField;
39+
private static AddressField lastJavaPCField;
40+
41+
static {
42+
VM.registerVMInitializedObserver(new Observer() {
43+
public void update(Observable o, Object data) {
44+
initialize(VM.getVM().getTypeDataBase());
45+
}
46+
});
47+
}
48+
49+
private static void initialize(TypeDataBase db) {
50+
Type type = db.lookupType("UpcallStub");
51+
frameDataOffsetField = type.getCIntegerField("_frame_data_offset");
52+
53+
Type anchorType = db.lookupType("JavaFrameAnchor");
54+
lastJavaSPField = anchorType.getAddressField("_last_Java_sp");
55+
lastJavaPCField = anchorType.getAddressField("_last_Java_pc");
56+
57+
try {
58+
lastJavaFPField = anchorType.getAddressField("_last_Java_fp");
59+
} catch (Exception e) {
60+
// Some platforms (e.g. PPC64) does not have this field.
61+
lastJavaFPField = null;
62+
}
63+
}
64+
65+
public UpcallStub(Address addr) {
66+
super(addr);
67+
}
68+
69+
protected Address getJavaFrameAnchor(Frame frame) {
70+
var frameDataOffset = frameDataOffsetField.getValue(addr);
71+
var frameDataAddr = frame.getUnextendedSP().addOffsetTo(frameDataOffset);
72+
var frameData = VMObjectFactory.newObject(FrameData.class, frameDataAddr);
73+
return frameData.getJavaFrameAnchor();
74+
}
75+
76+
public Address getLastJavaSP(Frame frame) {
77+
return lastJavaSPField.getValue(getJavaFrameAnchor(frame));
78+
}
79+
80+
public Address getLastJavaFP(Frame frame) {
81+
return lastJavaFPField == null ? null : lastJavaFPField.getValue(getJavaFrameAnchor(frame));
82+
}
83+
84+
public Address getLastJavaPC(Frame frame) {
85+
return lastJavaPCField.getValue(getJavaFrameAnchor(frame));
86+
}
87+
88+
public boolean isUpcallStub() {
89+
return true;
90+
}
91+
92+
public static class FrameData extends VMObject {
93+
94+
private static AddressField jfaField;
95+
96+
static {
97+
VM.registerVMInitializedObserver(new Observer() {
98+
public void update(Observable o, Object data) {
99+
initialize(VM.getVM().getTypeDataBase());
100+
}
101+
});
102+
}
103+
104+
private static void initialize(TypeDataBase db) {
105+
Type type = db.lookupType("UpcallStub::FrameData");
106+
jfaField = type.getAddressField("jfa");
107+
}
108+
109+
public FrameData(Address addr) {
110+
super(addr);
111+
}
112+
113+
public Address getJavaFrameAnchor() {
114+
return addr.addOffsetTo(jfaField.getOffset());
115+
}
116+
117+
}
118+
119+
}

‎src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2015, 2019, Red Hat Inc.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -292,7 +292,7 @@ public Frame sender(RegisterMap regMap, CodeBlob cb) {
292292
}
293293

294294
if (cb != null) {
295-
return senderForCompiledFrame(map, cb);
295+
return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb);
296296
}
297297

298298
// Must be native-compiled frame, i.e. the marshaling code for native
@@ -327,6 +327,34 @@ private Frame senderForEntryFrame(AARCH64RegisterMap map) {
327327
return fr;
328328
}
329329

330+
private Frame senderForUpcallStub(AARCH64RegisterMap map, UpcallStub stub) {
331+
if (DEBUG) {
332+
System.out.println("senderForUpcallStub");
333+
}
334+
if (Assert.ASSERTS_ENABLED) {
335+
Assert.that(map != null, "map must be set");
336+
}
337+
338+
var lastJavaFP = stub.getLastJavaFP(this);
339+
var lastJavaSP = stub.getLastJavaSP(this);
340+
var lastJavaPC = stub.getLastJavaPC(this);
341+
342+
if (Assert.ASSERTS_ENABLED) {
343+
Assert.that(lastJavaSP.greaterThan(getSP()), "must be above this frame on stack");
344+
}
345+
AARCH64Frame fr;
346+
if (lastJavaPC != null) {
347+
fr = new AARCH64Frame(lastJavaSP, lastJavaFP, lastJavaPC);
348+
} else {
349+
fr = new AARCH64Frame(lastJavaSP, lastJavaFP);
350+
}
351+
map.clear();
352+
if (Assert.ASSERTS_ENABLED) {
353+
Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
354+
}
355+
return fr;
356+
}
357+
330358
//------------------------------------------------------------------------------
331359
// frame::adjust_unextended_sp
332360
private void adjustUnextendedSP() {

‎src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -279,7 +279,7 @@ public Frame sender(RegisterMap regMap, CodeBlob cb) {
279279
}
280280

281281
if (cb != null) {
282-
return senderForCompiledFrame(map, cb);
282+
return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb);
283283
}
284284

285285
// Must be native-compiled frame, i.e. the marshaling code for native
@@ -314,6 +314,34 @@ private Frame senderForEntryFrame(PPC64RegisterMap map) {
314314
return fr;
315315
}
316316

317+
private Frame senderForUpcallStub(PPC64RegisterMap map, UpcallStub stub) {
318+
if (DEBUG) {
319+
System.out.println("senderForUpcallStub");
320+
}
321+
if (Assert.ASSERTS_ENABLED) {
322+
Assert.that(map != null, "map must be set");
323+
}
324+
325+
var lastJavaFP = stub.getLastJavaFP(this); // This will be null
326+
var lastJavaSP = stub.getLastJavaSP(this);
327+
var lastJavaPC = stub.getLastJavaPC(this);
328+
329+
if (Assert.ASSERTS_ENABLED) {
330+
Assert.that(lastJavaSP.greaterThan(getSP()), "must be above this frame on stack");
331+
}
332+
PPC64Frame fr;
333+
if (lastJavaPC != null) {
334+
fr = new PPC64Frame(lastJavaSP, lastJavaFP, lastJavaPC);
335+
} else {
336+
fr = new PPC64Frame(lastJavaSP, lastJavaFP);
337+
}
338+
map.clear();
339+
if (Assert.ASSERTS_ENABLED) {
340+
Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
341+
}
342+
return fr;
343+
}
344+
317345
//------------------------------------------------------------------------------
318346
// frame::adjust_unextended_sp
319347
private void adjustUnextendedSP() {

‎src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2015, 2019, Red Hat Inc.
44
* Copyright (c) 2021, 2023, Huawei Technologies Co., Ltd. All rights reserved.
55
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -284,7 +284,7 @@ public Frame sender(RegisterMap regMap, CodeBlob cb) {
284284
}
285285

286286
if (cb != null) {
287-
return senderForCompiledFrame(map, cb);
287+
return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb);
288288
}
289289

290290
// Must be native-compiled frame, i.e. the marshaling code for native
@@ -319,6 +319,34 @@ private Frame senderForEntryFrame(RISCV64RegisterMap map) {
319319
return fr;
320320
}
321321

322+
private Frame senderForUpcallStub(RISCV64RegisterMap map, UpcallStub stub) {
323+
if (DEBUG) {
324+
System.out.println("senderForUpcallStub");
325+
}
326+
if (Assert.ASSERTS_ENABLED) {
327+
Assert.that(map != null, "map must be set");
328+
}
329+
330+
var lastJavaFP = stub.getLastJavaFP(this);
331+
var lastJavaSP = stub.getLastJavaSP(this);
332+
var lastJavaPC = stub.getLastJavaPC(this);
333+
334+
if (Assert.ASSERTS_ENABLED) {
335+
Assert.that(lastJavaSP.greaterThan(getSP()), "must be above this frame on stack");
336+
}
337+
RISCV64Frame fr;
338+
if (lastJavaPC != null) {
339+
fr = new RISCV64Frame(lastJavaSP, lastJavaFP, lastJavaPC);
340+
} else {
341+
fr = new RISCV64Frame(lastJavaSP, lastJavaFP);
342+
}
343+
map.clear();
344+
if (Assert.ASSERTS_ENABLED) {
345+
Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
346+
}
347+
return fr;
348+
}
349+
322350
//------------------------------------------------------------------------------
323351
// frame::adjust_unextended_sp
324352
private void adjustUnextendedSP() {

‎src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -289,7 +289,7 @@ public Frame sender(RegisterMap regMap, CodeBlob cb) {
289289
}
290290

291291
if (cb != null) {
292-
return senderForCompiledFrame(map, cb);
292+
return cb.isUpcallStub() ? senderForUpcallStub(map, (UpcallStub)cb) : senderForCompiledFrame(map, cb);
293293
}
294294

295295
// Must be native-compiled frame, i.e. the marshaling code for native
@@ -324,6 +324,34 @@ private Frame senderForEntryFrame(X86RegisterMap map) {
324324
return fr;
325325
}
326326

327+
private Frame senderForUpcallStub(X86RegisterMap map, UpcallStub stub) {
328+
if (DEBUG) {
329+
System.out.println("senderForUpcallStub");
330+
}
331+
if (Assert.ASSERTS_ENABLED) {
332+
Assert.that(map != null, "map must be set");
333+
}
334+
335+
var lastJavaFP = stub.getLastJavaFP(this);
336+
var lastJavaSP = stub.getLastJavaSP(this);
337+
var lastJavaPC = stub.getLastJavaPC(this);
338+
339+
if (Assert.ASSERTS_ENABLED) {
340+
Assert.that(lastJavaSP.greaterThan(getSP()), "must be above this frame on stack");
341+
}
342+
X86Frame fr;
343+
if (lastJavaPC != null) {
344+
fr = new X86Frame(lastJavaSP, lastJavaFP, lastJavaPC);
345+
} else {
346+
fr = new X86Frame(lastJavaSP, lastJavaFP);
347+
}
348+
map.clear();
349+
if (Assert.ASSERTS_ENABLED) {
350+
Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
351+
}
352+
return fr;
353+
}
354+
327355
//------------------------------------------------------------------------------
328356
// frame::adjust_unextended_sp
329357
private void adjustUnextendedSP() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
/*
3+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation.
9+
*
10+
* This code is distributed in the hope that it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
* version 2 for more details (a copy is included in the LICENSE file that
14+
* accompanied this code).
15+
*
16+
* You should have received a copy of the GNU General Public License version
17+
* 2 along with this work; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*
20+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21+
* or visit www.oracle.com if you need additional information or have any
22+
* questions.
23+
*/
24+
25+
import java.lang.invoke.MethodHandles;
26+
import java.lang.invoke.MethodType;
27+
import java.lang.foreign.Arena;
28+
import java.lang.foreign.FunctionDescriptor;
29+
import java.lang.foreign.Linker;
30+
import java.util.concurrent.CountDownLatch;
31+
32+
import jdk.test.lib.apps.LingeredApp;
33+
34+
public class LingeredAppWithFFMUpcall extends LingeredApp {
35+
36+
public static final String THREAD_NAME = "Upcall thread";
37+
38+
private static final Object lockObj = new Object();
39+
40+
private static final CountDownLatch signal = new CountDownLatch(1);
41+
42+
static {
43+
System.loadLibrary("upcall");
44+
}
45+
46+
public static void upcall() {
47+
signal.countDown();
48+
synchronized(lockObj) {
49+
}
50+
}
51+
52+
public static long createFunctionPointerForUpcall() throws NoSuchMethodException, IllegalAccessException {
53+
var mh = MethodHandles.lookup()
54+
.findStatic(LingeredAppWithFFMUpcall.class, "upcall", MethodType.methodType(void.class));
55+
var stub = Linker.nativeLinker()
56+
.upcallStub(mh, FunctionDescriptor.ofVoid(), Arena.global());
57+
return stub.address();
58+
}
59+
60+
public static native void callJNI(long upcallAddr);
61+
62+
public static void main(String[] args) {
63+
try {
64+
long upcallAddr = createFunctionPointerForUpcall();
65+
var upcallThread = new Thread(() -> callJNI(upcallAddr), THREAD_NAME);
66+
synchronized(lockObj) {
67+
upcallThread.start();
68+
signal.await();
69+
LingeredApp.main(args);
70+
}
71+
} catch (Exception e) {
72+
throw new RuntimeException(e);
73+
}
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import jdk.test.lib.JDKToolLauncher;
25+
import jdk.test.lib.SA.SATestUtils;
26+
import jdk.test.lib.Utils;
27+
import jdk.test.lib.apps.LingeredApp;
28+
import jdk.test.lib.process.OutputAnalyzer;
29+
30+
/**
31+
* @test
32+
* @bug 8339307
33+
* @requires vm.hasSA
34+
* @library /test/lib
35+
* @run driver TestJhsdbJstackUpcall
36+
*/
37+
public class TestJhsdbJstackUpcall {
38+
39+
private static void runJstack(LingeredApp app) throws Exception {
40+
JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb");
41+
launcher.addVMArgs(Utils.getTestJavaOpts());
42+
launcher.addToolArg("jstack");
43+
launcher.addToolArg("--pid");
44+
launcher.addToolArg(Long.toString(app.getPid()));
45+
46+
ProcessBuilder pb = SATestUtils.createProcessBuilder(launcher);
47+
Process jhsdb = pb.start();
48+
OutputAnalyzer out = new OutputAnalyzer(jhsdb);
49+
50+
jhsdb.waitFor();
51+
52+
System.out.println(out.getStdout());
53+
System.err.println(out.getStderr());
54+
55+
out.shouldContain(LingeredAppWithFFMUpcall.THREAD_NAME);
56+
out.shouldContain("LingeredAppWithFFMUpcall.upcall()");
57+
out.shouldContain("jdk.internal.foreign.abi.UpcallStub");
58+
out.shouldContain("LingeredAppWithFFMUpcall.callJNI");
59+
}
60+
61+
public static void main(String... args) throws Exception {
62+
SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work.
63+
LingeredApp app = null;
64+
65+
try {
66+
// Needed for LingeredAppWithFFMUpcall to be able to resolve native library.
67+
String libPath = System.getProperty("java.library.path");
68+
String[] vmArgs = (libPath != null)
69+
? Utils.prependTestJavaOpts("-Djava.library.path=" + libPath)
70+
: Utils.getTestJavaOpts();
71+
72+
app = new LingeredAppWithFFMUpcall();
73+
LingeredApp.startAppExactJvmOpts(app, vmArgs);
74+
System.out.println("Started LingeredAppWithFFMUpcall with pid " + app.getPid());
75+
runJstack(app);
76+
System.out.println("Test Completed");
77+
} catch (Throwable e) {
78+
e.printStackTrace();
79+
throw e;
80+
} finally {
81+
LingeredApp.stopApp(app);
82+
}
83+
}
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
#include <jni.h>
25+
26+
typedef void (*upcall_func)(void);
27+
28+
JNIEXPORT void JNICALL
29+
Java_LingeredAppWithFFMUpcall_callJNI(JNIEnv *env, jclass cls, jlong upcallAddr) {
30+
upcall_func upcall = (upcall_func)upcallAddr;
31+
upcall();
32+
}

0 commit comments

Comments
 (0)
Please sign in to comment.