Skip to content

Commit 3ffc5b9

Browse files
8359344: C2: Malformed control flow after intrinsic bailout
Reviewed-by: thartmann, kvn
1 parent 529049b commit 3ffc5b9

File tree

7 files changed

+283
-118
lines changed

7 files changed

+283
-118
lines changed

src/hotspot/share/opto/callnode.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ class JVMState : public ResourceObj {
330330
class SafePointNode : public MultiNode {
331331
friend JVMState;
332332
friend class GraphKit;
333+
friend class LibraryCallKit;
333334

334335
virtual bool cmp( const Node &n ) const;
335336
virtual uint size_of() const; // Size is bigger

src/hotspot/share/opto/library_call.cpp

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms) {
135135

136136
// The intrinsic bailed out
137137
assert(ctrl == kit.control(), "Control flow was added although the intrinsic bailed out");
138+
assert(jvms->map() == kit.map(), "Out of sync JVM state");
138139
if (jvms->has_method()) {
139140
// Not a root compile.
140141
const char* msg;
@@ -1724,18 +1725,15 @@ bool LibraryCallKit::inline_string_char_access(bool is_store) {
17241725
}
17251726

17261727
// Save state and restore on bailout
1727-
uint old_sp = sp();
1728-
SafePointNode* old_map = clone_map();
1728+
SavedState old_state(this);
17291729

17301730
value = must_be_not_null(value, true);
17311731

17321732
Node* adr = array_element_address(value, index, T_CHAR);
17331733
if (adr->is_top()) {
1734-
set_map(old_map);
1735-
set_sp(old_sp);
17361734
return false;
17371735
}
1738-
destruct_map_clone(old_map);
1736+
old_state.discard();
17391737
if (is_store) {
17401738
access_store_at(value, adr, TypeAryPtr::BYTES, ch, TypeInt::CHAR, T_CHAR, IN_HEAP | MO_UNORDERED | C2_MISMATCHED);
17411739
} else {
@@ -2373,6 +2371,47 @@ DecoratorSet LibraryCallKit::mo_decorator_for_access_kind(AccessKind kind) {
23732371
}
23742372
}
23752373

2374+
LibraryCallKit::SavedState::SavedState(LibraryCallKit* kit) :
2375+
_kit(kit),
2376+
_sp(kit->sp()),
2377+
_jvms(kit->jvms()),
2378+
_map(kit->clone_map()),
2379+
_discarded(false)
2380+
{
2381+
for (DUIterator_Fast imax, i = kit->control()->fast_outs(imax); i < imax; i++) {
2382+
Node* out = kit->control()->fast_out(i);
2383+
if (out->is_CFG()) {
2384+
_ctrl_succ.push(out);
2385+
}
2386+
}
2387+
}
2388+
2389+
LibraryCallKit::SavedState::~SavedState() {
2390+
if (_discarded) {
2391+
_kit->destruct_map_clone(_map);
2392+
return;
2393+
}
2394+
_kit->jvms()->set_map(_map);
2395+
_kit->jvms()->set_sp(_sp);
2396+
_map->set_jvms(_kit->jvms());
2397+
_kit->set_map(_map);
2398+
_kit->set_sp(_sp);
2399+
for (DUIterator_Fast imax, i = _kit->control()->fast_outs(imax); i < imax; i++) {
2400+
Node* out = _kit->control()->fast_out(i);
2401+
if (out->is_CFG() && out->in(0) == _kit->control() && out != _kit->map() && !_ctrl_succ.member(out)) {
2402+
_kit->_gvn.hash_delete(out);
2403+
out->set_req(0, _kit->C->top());
2404+
_kit->C->record_for_igvn(out);
2405+
--i; --imax;
2406+
_kit->_gvn.hash_find_insert(out);
2407+
}
2408+
}
2409+
}
2410+
2411+
void LibraryCallKit::SavedState::discard() {
2412+
_discarded = true;
2413+
}
2414+
23762415
bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, const AccessKind kind, const bool unaligned) {
23772416
if (callee()->is_static()) return false; // caller must have the capability!
23782417
DecoratorSet decorators = C2_UNSAFE_ACCESS;
@@ -2434,8 +2473,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
24342473
offset = ConvL2X(offset);
24352474

24362475
// Save state and restore on bailout
2437-
uint old_sp = sp();
2438-
SafePointNode* old_map = clone_map();
2476+
SavedState old_state(this);
24392477

24402478
Node* adr = make_unsafe_address(base, offset, type, kind == Relaxed);
24412479
assert(!stopped(), "Inlining of unsafe access failed: address construction stopped unexpectedly");
@@ -2444,8 +2482,6 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
24442482
if (type != T_OBJECT) {
24452483
decorators |= IN_NATIVE; // off-heap primitive access
24462484
} else {
2447-
set_map(old_map);
2448-
set_sp(old_sp);
24492485
return false; // off-heap oop accesses are not supported
24502486
}
24512487
} else {
@@ -2463,8 +2499,6 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
24632499

24642500
const TypePtr* adr_type = _gvn.type(adr)->isa_ptr();
24652501
if (adr_type == TypePtr::NULL_PTR) {
2466-
set_map(old_map);
2467-
set_sp(old_sp);
24682502
return false; // off-heap access with zero address
24692503
}
24702504

@@ -2474,8 +2508,6 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
24742508

24752509
if (alias_type->adr_type() == TypeInstPtr::KLASS ||
24762510
alias_type->adr_type() == TypeAryPtr::RANGE) {
2477-
set_map(old_map);
2478-
set_sp(old_sp);
24792511
return false; // not supported
24802512
}
24812513

@@ -2494,16 +2526,14 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
24942526
}
24952527
if ((bt == T_OBJECT) != (type == T_OBJECT)) {
24962528
// Don't intrinsify mismatched object accesses
2497-
set_map(old_map);
2498-
set_sp(old_sp);
24992529
return false;
25002530
}
25012531
mismatched = (bt != type);
25022532
} else if (alias_type->adr_type()->isa_oopptr()) {
25032533
mismatched = true; // conservatively mark all "wide" on-heap accesses as mismatched
25042534
}
25052535

2506-
destruct_map_clone(old_map);
2536+
old_state.discard();
25072537
assert(!mismatched || alias_type->adr_type()->is_oopptr(), "off-heap access can't be mismatched");
25082538

25092539
if (mismatched) {
@@ -2739,8 +2769,7 @@ bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadSt
27392769
// 32-bit machines ignore the high half of long offsets
27402770
offset = ConvL2X(offset);
27412771
// Save state and restore on bailout
2742-
uint old_sp = sp();
2743-
SafePointNode* old_map = clone_map();
2772+
SavedState old_state(this);
27442773
Node* adr = make_unsafe_address(base, offset,type, false);
27452774
const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
27462775

@@ -2749,12 +2778,10 @@ bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadSt
27492778
if (bt != T_ILLEGAL &&
27502779
(is_reference_type(bt) != (type == T_OBJECT))) {
27512780
// Don't intrinsify mismatched object accesses.
2752-
set_map(old_map);
2753-
set_sp(old_sp);
27542781
return false;
27552782
}
27562783

2757-
destruct_map_clone(old_map);
2784+
old_state.discard();
27582785

27592786
// For CAS, unlike inline_unsafe_access, there seems no point in
27602787
// trying to refine types. Just use the coarse types here.

src/hotspot/share/opto/library_call.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,29 @@ class LibraryCallKit : public GraphKit {
129129

130130
virtual int reexecute_sp() { return _reexecute_sp; }
131131

132+
/* When an intrinsic makes changes before bailing out, it's necessary to restore the graph
133+
* as it was. See JDK-8359344 for what can happen wrong. It's also not always possible to
134+
* bailout before making changes because the bailing out decision might depend on new nodes
135+
* (their types, for instance).
136+
*
137+
* So, if an intrinsic might cause this situation, one must start by saving the state in a
138+
* SavedState by constructing it, and the state will be restored on destruction. If the
139+
* intrinsic is not bailing out, one need to call discard to prevent restoring the old state.
140+
*/
141+
class SavedState {
142+
LibraryCallKit* _kit;
143+
uint _sp;
144+
JVMState* _jvms;
145+
SafePointNode* _map;
146+
Unique_Node_List _ctrl_succ;
147+
bool _discarded;
148+
149+
public:
150+
SavedState(LibraryCallKit*);
151+
~SavedState();
152+
void discard();
153+
};
154+
132155
// Helper functions to inline natives
133156
Node* generate_guard(Node* test, RegionNode* region, float true_prob);
134157
Node* generate_slow_guard(Node* test, RegionNode* region);

0 commit comments

Comments
 (0)