Skip to content
This repository was archived by the owner on Sep 2, 2022. It is now read-only.
/ jdk17 Public archive

Commit f25e719

Browse files
committed
8268717: Upstream: 8268673: Stack walk across optimized entry frame on fresh native thread fails
Reviewed-by: mcimadamore, erikj
1 parent 22ebd19 commit f25e719

File tree

12 files changed

+198
-1
lines changed

12 files changed

+198
-1
lines changed

make/test/JtregNativeJdk.gmk

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ BUILD_JDK_JTREG_EXECUTABLES_CFLAGS_exeJliLaunchTest := \
5353
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli \
5454
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjli
5555

56+
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := $(LIBCXX)
57+
5658
# Platform specific setup
5759
ifeq ($(call isTargetOs, windows), true)
5860
BUILD_JDK_JTREG_EXCLUDE += libDirectIO.c libInheritedChannel.c exelauncher.c
@@ -63,6 +65,7 @@ ifeq ($(call isTargetOs, windows), true)
6365
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := $(WIN_LIB_JLI)
6466
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := jvm.lib
6567
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib
68+
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := /EHsc
6669
else
6770
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
6871
BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava

src/hotspot/cpu/aarch64/frame_aarch64.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,11 @@ JavaFrameAnchor* OptimizedEntryBlob::jfa_for_frame(const frame& frame) const {
367367
return nullptr;
368368
}
369369

370+
bool frame::optimized_entry_frame_is_first() const {
371+
ShouldNotCallThis();
372+
return false;
373+
}
374+
370375
frame frame::sender_for_optimized_entry_frame(RegisterMap* map) const {
371376
ShouldNotCallThis();
372377
return {};

src/hotspot/cpu/arm/frame_arm.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const {
313313
return fr;
314314
}
315315

316+
bool frame::optimized_entry_frame_is_first() const {
317+
ShouldNotCallThis();
318+
return false;
319+
}
320+
316321
//------------------------------------------------------------------------------
317322
// frame::verify_deopt_original_pc
318323
//

src/hotspot/cpu/ppc/frame_ppc.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const {
197197
return fr;
198198
}
199199

200+
bool frame::optimized_entry_frame_is_first() const {
201+
ShouldNotCallThis();
202+
return false;
203+
}
204+
200205
frame frame::sender_for_interpreter_frame(RegisterMap *map) const {
201206
// Pass callers initial_caller_sp as unextended_sp.
202207
return frame(sender_sp(), sender_pc(), (intptr_t*)get_ijava_state()->sender_sp);

src/hotspot/cpu/s390/frame_s390.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,11 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const {
208208
return fr;
209209
}
210210

211+
bool frame::optimized_entry_frame_is_first() const {
212+
ShouldNotCallThis();
213+
return false;
214+
}
215+
211216
frame frame::sender_for_interpreter_frame(RegisterMap *map) const {
212217
// Pass callers sender_sp as unextended_sp.
213218
return frame(sender_sp(), sender_pc(), (intptr_t*)(ijava_state()->sender_sp));

src/hotspot/cpu/x86/frame_x86.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,20 @@ JavaFrameAnchor* OptimizedEntryBlob::jfa_for_frame(const frame& frame) const {
358358
return reinterpret_cast<JavaFrameAnchor*>(reinterpret_cast<char*>(frame.unextended_sp()) + in_bytes(jfa_sp_offset()));
359359
}
360360

361+
bool frame::optimized_entry_frame_is_first() const {
362+
assert(is_optimized_entry_frame(), "must be optimzed entry frame");
363+
OptimizedEntryBlob* blob = _cb->as_optimized_entry_blob();
364+
JavaFrameAnchor* jfa = blob->jfa_for_frame(*this);
365+
return jfa->last_Java_sp() == NULL;
366+
}
367+
361368
frame frame::sender_for_optimized_entry_frame(RegisterMap* map) const {
362369
assert(map != NULL, "map must be set");
363370
OptimizedEntryBlob* blob = _cb->as_optimized_entry_blob();
364371
// Java frame called from C; skip all C frames and return top C
365372
// frame of that chunk as the sender
366373
JavaFrameAnchor* jfa = blob->jfa_for_frame(*this);
374+
assert(!optimized_entry_frame_is_first(), "must have a frame anchor to go back to");
367375
assert(jfa->last_Java_sp() > sp(), "must be above this frame on stack");
368376
// Since we are walking the stack now this nested anchor is obviously walkable
369377
// even if it wasn't when it was stacked.

src/hotspot/cpu/zero/frame_zero.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const {
6161
return frame(zeroframe()->next(), sender_sp());
6262
}
6363

64+
bool frame::optimized_entry_frame_is_first() const {
65+
ShouldNotCallThis();
66+
return false;
67+
}
68+
6469
frame frame::sender_for_nonentry_frame(RegisterMap *map) const {
6570
assert(zeroframe()->is_interpreter_frame() ||
6671
zeroframe()->is_fake_stub_frame(), "wrong type of frame");

src/hotspot/share/prims/whitebox.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -2306,6 +2306,7 @@ WB_ENTRY(void, WB_VerifyFrames(JNIEnv* env, jobject wb, jboolean log, jboolean u
23062306
tty_token = ttyLocker::hold_tty();
23072307
tty->print_cr("[WhiteBox::VerifyFrames] Walking Frames");
23082308
}
2309+
ResourceMark rm; // for verify
23092310
for (StackFrameStream fst(JavaThread::current(), update_map, true); !fst.is_done(); fst.next()) {
23102311
frame* current_frame = fst.current();
23112312
if (log) {

src/hotspot/share/runtime/frame.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ class frame {
342342

343343
// tells whether there is another chunk of Delta stack above
344344
bool entry_frame_is_first() const;
345+
bool optimized_entry_frame_is_first() const;
345346

346347
// Safepoints
347348

src/hotspot/share/runtime/frame.inline.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ inline bool frame::is_stub_frame() const {
5050
}
5151

5252
inline bool frame::is_first_frame() const {
53-
return is_entry_frame() && entry_frame_is_first();
53+
return (is_entry_frame() && entry_frame_is_first())
54+
// Optimized entry frames are only present on certain platforms
55+
|| (is_optimized_entry_frame() && optimized_entry_frame_is_first());
5456
}
5557

5658
inline bool frame::is_optimized_entry_frame() const {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright (c) 2021, 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+
* @test
26+
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
27+
* @library /test/lib
28+
* @build sun.hotspot.WhiteBox
29+
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
30+
*
31+
* @run main/othervm
32+
* -Xbootclasspath/a:.
33+
* -XX:+UnlockDiagnosticVMOptions
34+
* -XX:+WhiteBoxAPI
35+
* -Djdk.internal.foreign.ProgrammableInvoker.USE_INTRINSICS=true
36+
* --enable-native-access=ALL-UNNAMED
37+
* -Xbatch
38+
* TestAsyncStackWalk
39+
*
40+
* @run main/othervm
41+
* -Xbootclasspath/a:.
42+
* -XX:+UnlockDiagnosticVMOptions
43+
* -XX:+WhiteBoxAPI
44+
* -Djdk.internal.foreign.ProgrammableInvoker.USE_INTRINSICS=false
45+
* --enable-native-access=ALL-UNNAMED
46+
* -Xbatch
47+
* TestAsyncStackWalk
48+
*/
49+
50+
import jdk.incubator.foreign.CLinker;
51+
import jdk.incubator.foreign.FunctionDescriptor;
52+
import jdk.incubator.foreign.SymbolLookup;
53+
import jdk.incubator.foreign.MemoryAddress;
54+
55+
import java.lang.invoke.MethodHandle;
56+
import java.lang.invoke.MethodType;
57+
58+
import jdk.incubator.foreign.ResourceScope;
59+
import sun.hotspot.WhiteBox;
60+
61+
import static java.lang.invoke.MethodHandles.lookup;
62+
import static jdk.incubator.foreign.CLinker.C_POINTER;
63+
import static jdk.test.lib.Asserts.assertTrue;
64+
65+
public class TestAsyncStackWalk {
66+
static final WhiteBox WB = WhiteBox.getWhiteBox();
67+
68+
static final CLinker linker = CLinker.getInstance();
69+
70+
static final MethodHandle MH_asyncStackWalk;
71+
static final MethodHandle MH_m;
72+
73+
static {
74+
try {
75+
System.loadLibrary("AsyncStackWalk");
76+
SymbolLookup lookup = SymbolLookup.loaderLookup();
77+
MH_asyncStackWalk = linker.downcallHandle(
78+
lookup.lookup("asyncStackWalk").get(),
79+
MethodType.methodType(void.class, MemoryAddress.class),
80+
FunctionDescriptor.ofVoid(C_POINTER));
81+
MH_m = lookup().findStatic(TestAsyncStackWalk.class, "m", MethodType.methodType(void.class));
82+
} catch (ReflectiveOperationException e) {
83+
throw new RuntimeException(e);
84+
}
85+
}
86+
87+
static int invocations;
88+
static boolean didStackWalk;
89+
90+
public static void main(String[] args) throws Throwable {
91+
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
92+
MemoryAddress stub = linker.upcallStub(MH_m, FunctionDescriptor.ofVoid(), scope);
93+
MemoryAddress stubAddress = stub.address();
94+
invocations = 0;
95+
didStackWalk = false;
96+
payload(stubAddress);
97+
assertTrue(didStackWalk);
98+
}
99+
}
100+
101+
static void payload(MemoryAddress cb) throws Throwable {
102+
MH_asyncStackWalk.invokeExact(cb);
103+
}
104+
105+
static void m() {
106+
if (invocations++ >= 20000) { // warmup
107+
didStackWalk = true;
108+
WB.verifyFrames(/*log=*/true, /*updateRegisterMap=*/true);
109+
WB.verifyFrames(/*log=*/true, /*updateRegisterMap=*/false); // triggers different code paths
110+
}
111+
}
112+
113+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2021, 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+
#include <thread>
26+
27+
#ifdef _WIN64
28+
#define EXPORT __declspec(dllexport)
29+
#else
30+
#define EXPORT
31+
#endif
32+
33+
static void start(void (*cb)(void)) {
34+
for (int i = 0; i < 25000; i++) {
35+
cb();
36+
}
37+
}
38+
39+
extern "C" {
40+
EXPORT void asyncStackWalk(void (*cb)(void)) {
41+
std::thread thrd(start, cb);
42+
thrd.join();
43+
}
44+
}

0 commit comments

Comments
 (0)