Skip to content

Commit 2735140

Browse files
committed
8370939: C2: SIGSEGV in SafePointNode::verify_input when processing MH call from Compile::process_late_inline_calls_no_inline()
Reviewed-by: thartmann, vlivanov
1 parent 33dda88 commit 2735140

File tree

6 files changed

+122
-12
lines changed

6 files changed

+122
-12
lines changed

src/hotspot/share/opto/callGenerator.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,6 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms)
420420
}
421421
assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline || StressIncrementalInlining, "we're doing late inlining");
422422
_inline_cg = cg;
423-
C->dec_number_of_mh_late_inlines();
424423
return true;
425424
} else {
426425
// Method handle call which has a constant appendix argument should be either inlined or replaced with a direct call
@@ -432,7 +431,7 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms)
432431

433432
CallGenerator* CallGenerator::for_mh_late_inline(ciMethod* caller, ciMethod* callee, bool input_not_const) {
434433
assert(IncrementalInlineMH, "required");
435-
Compile::current()->inc_number_of_mh_late_inlines();
434+
Compile::current()->mark_has_mh_late_inlines();
436435
CallGenerator* cg = new LateInlineMHCallGenerator(caller, callee, input_not_const);
437436
return cg;
438437
}

src/hotspot/share/opto/callnode.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1145,7 +1145,6 @@ Node* CallStaticJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) {
11451145
assert(callee->has_member_arg(), "wrong type of call?");
11461146
if (in(TypeFunc::Parms + callee->arg_size() - 1)->Opcode() == Op_ConP) {
11471147
register_for_late_inline();
1148-
phase->C->inc_number_of_mh_late_inlines();
11491148
}
11501149
}
11511150
} else {

src/hotspot/share/opto/callnode.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -730,9 +730,10 @@ class CallNode : public SafePointNode {
730730
// for some macro nodes whose expansion does not have a safepoint on the fast path.
731731
virtual bool guaranteed_safepoint() { return true; }
732732
// For macro nodes, the JVMState gets modified during expansion. If calls
733-
// use MachConstantBase, it gets modified during matching. So when cloning
734-
// the node the JVMState must be deep cloned. Default is to shallow clone.
735-
virtual bool needs_deep_clone_jvms(Compile* C) { return C->needs_deep_clone_jvms(); }
733+
// use MachConstantBase, it gets modified during matching. If the call is
734+
// late inlined, it also needs the full JVMState. So when cloning the
735+
// node the JVMState must be deep cloned. Default is to shallow clone.
736+
virtual bool needs_deep_clone_jvms(Compile* C) { return _generator != nullptr || C->needs_deep_clone_jvms(); }
736737

737738
// Returns true if the call may modify n
738739
virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase);

src/hotspot/share/opto/compile.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci,
686686
_boxing_late_inlines(comp_arena(), 2, 0, nullptr),
687687
_vector_reboxing_late_inlines(comp_arena(), 2, 0, nullptr),
688688
_late_inlines_pos(0),
689-
_number_of_mh_late_inlines(0),
689+
_has_mh_late_inlines(false),
690690
_oom(false),
691691
_replay_inline_data(nullptr),
692692
_inline_printer(this),
@@ -948,7 +948,7 @@ Compile::Compile(ciEnv* ci_env,
948948
_igvn_worklist(nullptr),
949949
_types(nullptr),
950950
_node_hash(nullptr),
951-
_number_of_mh_late_inlines(0),
951+
_has_mh_late_inlines(false),
952952
_oom(false),
953953
_replay_inline_data(nullptr),
954954
_inline_printer(this),

src/hotspot/share/opto/compile.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,9 @@ class Compile : public Phase {
478478
GrowableArray<CallGenerator*> _vector_reboxing_late_inlines; // same but for vector reboxing operations
479479

480480
int _late_inlines_pos; // Where in the queue should the next late inlining candidate go (emulate depth first inlining)
481-
uint _number_of_mh_late_inlines; // number of method handle late inlining still pending
481+
bool _has_mh_late_inlines; // Can there still be a method handle late inlining pending?
482+
// false: there can't be one
483+
// true: we've enqueued one at some point so there may still be one
482484

483485
// "MemLimit" directive was specified and the memory limit was hit during compilation
484486
bool _oom;
@@ -1096,9 +1098,8 @@ class Compile : public Phase {
10961098
}
10971099
}
10981100

1099-
void inc_number_of_mh_late_inlines() { _number_of_mh_late_inlines++; }
1100-
void dec_number_of_mh_late_inlines() { assert(_number_of_mh_late_inlines > 0, "_number_of_mh_late_inlines < 0 !"); _number_of_mh_late_inlines--; }
1101-
bool has_mh_late_inlines() const { return _number_of_mh_late_inlines > 0; }
1101+
void mark_has_mh_late_inlines() { _has_mh_late_inlines = true; }
1102+
bool has_mh_late_inlines() const { return _has_mh_late_inlines; }
11021103

11031104
bool inline_incrementally_one();
11041105
void inline_incrementally_cleanup(PhaseIterGVN& igvn);
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2025 IBM Corporation. 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+
* @bug 8370939
27+
* @summary C2: SIGSEGV in SafePointNode::verify_input when processing MH call from Compile::process_late_inline_calls_no_inline()
28+
* @run main/othervm -XX:-BackgroundCompilation -XX:CompileOnly=TestLateMHClonedCallNode::test1
29+
* -XX:CompileOnly=TestLateMHClonedCallNode::test2 TestLateMHClonedCallNode
30+
* @run main TestLateMHClonedCallNode
31+
*/
32+
33+
import java.lang.invoke.MethodHandle;
34+
import java.lang.invoke.MethodHandles;
35+
import java.lang.invoke.MethodType;
36+
37+
public class TestLateMHClonedCallNode {
38+
private static int field;
39+
40+
public static void main(String[] args) throws Throwable {
41+
for (int i = 0; i < 20_000; i++) {
42+
test1(true);
43+
test1(false);
44+
test2(true);
45+
test2(false);
46+
}
47+
}
48+
49+
private static int test1(boolean flag) throws Throwable {
50+
return inlined1(flag);
51+
}
52+
53+
private static int inlined1(boolean flag) throws Throwable {
54+
MethodHandle mh = mh1;
55+
for (int i = 0; i < 3; ++i) {
56+
if (i > 1) {
57+
mh = mh2;
58+
}
59+
}
60+
int res = 0;
61+
for (int i = 0; i < 2; i++) {
62+
if (!flag) {
63+
field = 42;
64+
}
65+
res += (int) mh.invokeExact();
66+
}
67+
return res;
68+
}
69+
70+
private static int test2(boolean flag) throws Throwable {
71+
int res = (int)unknownMh.invokeExact();
72+
return inlined2(flag);
73+
}
74+
75+
private static int inlined2(boolean flag) throws Throwable {
76+
MethodHandle mh = mh1;
77+
for (int i = 0; i < 3; ++i) {
78+
if (i > 1) {
79+
mh = mh2;
80+
}
81+
}
82+
int res = 0;
83+
for (int i = 0; i < 2; i++) {
84+
if (!flag) {
85+
field = 42;
86+
}
87+
res += (int) mh.invokeExact();
88+
}
89+
return res;
90+
}
91+
92+
static final MethodHandle mh1;
93+
static final MethodHandle mh2;
94+
static MethodHandle unknownMh;
95+
96+
static {
97+
try {
98+
MethodHandles.Lookup lookup = MethodHandles.lookup();
99+
mh1 = lookup.findStatic(TestLateMHClonedCallNode.class, "method1", MethodType.methodType(int.class));
100+
mh2 = lookup.findStatic(TestLateMHClonedCallNode.class, "method2", MethodType.methodType(int.class));
101+
unknownMh = mh1;
102+
} catch (NoSuchMethodException | IllegalAccessException e) {
103+
e.printStackTrace();
104+
throw new RuntimeException("Method handle lookup failed");
105+
}
106+
}
107+
108+
static int method1() { return 0; }
109+
static int method2() { return 42; }
110+
}

0 commit comments

Comments
 (0)