Skip to content

Commit ab8d7b0

Browse files
committed
8324517: C2: crash in compiled code because of dependency on removed range check CastIIs
Reviewed-by: epeter, thartmann
1 parent fe8a2af commit ab8d7b0

File tree

6 files changed

+539
-26
lines changed

6 files changed

+539
-26
lines changed

src/hotspot/share/opto/castnode.cpp

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,7 @@ const Type* CastIINode::Value(PhaseGVN* phase) const {
213213

214214
// Similar to ConvI2LNode::Value() for the same reasons
215215
// see if we can remove type assertion after loop opts
216-
// But here we have to pay extra attention:
217-
// Do not narrow the type of range check dependent CastIINodes to
218-
// avoid corruption of the graph if a CastII is replaced by TOP but
219-
// the corresponding range check is not removed.
220-
if (!_range_check_dependency) {
221-
res = widen_type(phase, res, T_INT);
222-
}
216+
res = widen_type(phase, res, T_INT);
223217

224218
return res;
225219
}
@@ -239,11 +233,11 @@ Node *CastIINode::Ideal(PhaseGVN *phase, bool can_reshape) {
239233
if (progress != nullptr) {
240234
return progress;
241235
}
242-
if (can_reshape && !_range_check_dependency && !phase->C->post_loop_opts_phase()) {
236+
if (can_reshape && !phase->C->post_loop_opts_phase()) {
243237
// makes sure we run ::Value to potentially remove type assertion after loop opts
244238
phase->C->record_for_post_loop_opts_igvn(this);
245239
}
246-
if (!_range_check_dependency) {
240+
if (!_type->is_int()->empty()) {
247241
return optimize_integer_cast(phase, T_INT);
248242
}
249243
return nullptr;
@@ -254,13 +248,6 @@ Node* CastIINode::Identity(PhaseGVN* phase) {
254248
if (progress != this) {
255249
return progress;
256250
}
257-
if (_range_check_dependency) {
258-
if (phase->C->post_loop_opts_phase()) {
259-
return this->in(1);
260-
} else {
261-
phase->C->record_for_post_loop_opts_igvn(this);
262-
}
263-
}
264251
return this;
265252
}
266253

src/hotspot/share/opto/compile.cpp

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3464,6 +3464,10 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
34643464
}
34653465
break;
34663466
}
3467+
case Op_CastII: {
3468+
remove_range_check_cast(n->as_CastII());
3469+
}
3470+
break;
34673471
#ifdef _LP64
34683472
case Op_CmpP:
34693473
// Do this transformation here to preserve CmpPNode::sub() and
@@ -3615,16 +3619,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
36153619

36163620
#endif
36173621

3618-
#ifdef ASSERT
3619-
case Op_CastII:
3620-
// Verify that all range check dependent CastII nodes were removed.
3621-
if (n->isa_CastII()->has_range_check()) {
3622-
n->dump(3);
3623-
assert(false, "Range check dependent CastII node was not removed");
3624-
}
3625-
break;
3626-
#endif
3627-
36283622
case Op_ModI:
36293623
if (UseDivMod) {
36303624
// Check if a%b and a/b both exist
@@ -3633,6 +3627,8 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
36333627
// Replace them with a fused divmod if supported
36343628
if (Matcher::has_match_rule(Op_DivModI)) {
36353629
DivModINode* divmod = DivModINode::make(n);
3630+
divmod->add_prec_from(n);
3631+
divmod->add_prec_from(d);
36363632
d->subsume_by(divmod->div_proj(), this);
36373633
n->subsume_by(divmod->mod_proj(), this);
36383634
} else {
@@ -3653,6 +3649,8 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
36533649
// Replace them with a fused divmod if supported
36543650
if (Matcher::has_match_rule(Op_DivModL)) {
36553651
DivModLNode* divmod = DivModLNode::make(n);
3652+
divmod->add_prec_from(n);
3653+
divmod->add_prec_from(d);
36563654
d->subsume_by(divmod->div_proj(), this);
36573655
n->subsume_by(divmod->mod_proj(), this);
36583656
} else {
@@ -3673,6 +3671,8 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
36733671
// Replace them with a fused unsigned divmod if supported
36743672
if (Matcher::has_match_rule(Op_UDivModI)) {
36753673
UDivModINode* divmod = UDivModINode::make(n);
3674+
divmod->add_prec_from(n);
3675+
divmod->add_prec_from(d);
36763676
d->subsume_by(divmod->div_proj(), this);
36773677
n->subsume_by(divmod->mod_proj(), this);
36783678
} else {
@@ -3693,6 +3693,8 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
36933693
// Replace them with a fused unsigned divmod if supported
36943694
if (Matcher::has_match_rule(Op_UDivModL)) {
36953695
UDivModLNode* divmod = UDivModLNode::make(n);
3696+
divmod->add_prec_from(n);
3697+
divmod->add_prec_from(d);
36963698
d->subsume_by(divmod->div_proj(), this);
36973699
n->subsume_by(divmod->mod_proj(), this);
36983700
} else {
@@ -3894,6 +3896,34 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f
38943896
}
38953897
}
38963898

3899+
void Compile::remove_range_check_cast(CastIINode* cast) {
3900+
if (cast->has_range_check()) {
3901+
// Range check CastII nodes feed into an address computation subgraph. Remove them to let that subgraph float freely.
3902+
// For memory access or integer divisions nodes that depend on the cast, record the dependency on the cast's control
3903+
// as a precedence edge, so they can't float above the cast in case that cast's narrowed type helped eliminate a
3904+
// range check or a null divisor check.
3905+
assert(cast->in(0) != nullptr, "All RangeCheck CastII must have a control dependency");
3906+
ResourceMark rm;
3907+
Unique_Node_List wq;
3908+
wq.push(cast);
3909+
for (uint next = 0; next < wq.size(); ++next) {
3910+
Node* m = wq.at(next);
3911+
for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) {
3912+
Node* use = m->fast_out(i);
3913+
if (use->is_Mem() || use->is_div_or_mod(T_INT) || use->is_div_or_mod(T_LONG)) {
3914+
use->ensure_control_or_add_prec(cast->in(0));
3915+
} else if (!use->is_CFG() && !use->is_Phi()) {
3916+
wq.push(use);
3917+
}
3918+
}
3919+
}
3920+
cast->subsume_by(cast->in(1), this);
3921+
if (cast->outcnt() == 0) {
3922+
cast->disconnect_inputs(this);
3923+
}
3924+
}
3925+
}
3926+
38973927
//------------------------------final_graph_reshaping_walk---------------------
38983928
// Replacing Opaque nodes with their input in final_graph_reshaping_impl(),
38993929
// requires that the walk visits a node's inputs before visiting the node.

src/hotspot/share/opto/compile.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class Block;
5353
class Bundle;
5454
class CallGenerator;
5555
class CallStaticJavaNode;
56+
class CastIINode;
5657
class CloneMap;
5758
class CompilationFailureInfo;
5859
class ConnectionGraph;
@@ -1314,6 +1315,8 @@ class Compile : public Phase {
13141315
BasicType out_bt, BasicType in_bt);
13151316

13161317
static Node* narrow_value(BasicType bt, Node* value, const Type* type, PhaseGVN* phase, bool transform_res);
1318+
1319+
void remove_range_check_cast(CastIINode* cast);
13171320
};
13181321

13191322
#endif // SHARE_OPTO_COMPILE_HPP

src/hotspot/share/opto/node.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2878,6 +2878,15 @@ void Node::ensure_control_or_add_prec(Node* c) {
28782878
}
28792879
}
28802880

2881+
void Node::add_prec_from(Node* n) {
2882+
for (uint i = n->req(); i < n->len(); i++) {
2883+
Node* prec = n->in(i);
2884+
if (prec != nullptr) {
2885+
add_prec(prec);
2886+
}
2887+
}
2888+
}
2889+
28812890
bool Node::is_dead_loop_safe() const {
28822891
if (is_Phi()) {
28832892
return true;
@@ -2901,6 +2910,9 @@ bool Node::is_dead_loop_safe() const {
29012910
return false;
29022911
}
29032912

2913+
bool Node::is_div_or_mod(BasicType bt) const { return Opcode() == Op_Div(bt) || Opcode() == Op_Mod(bt) ||
2914+
Opcode() == Op_UDiv(bt) || Opcode() == Op_UMod(bt); }
2915+
29042916
//=============================================================================
29052917
//------------------------------yank-------------------------------------------
29062918
// Find and remove

src/hotspot/share/opto/node.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,7 @@ class Node {
11431143

11441144
// Set control or add control as precedence edge
11451145
void ensure_control_or_add_prec(Node* c);
1146+
void add_prec_from(Node* n);
11461147

11471148
// Visit boundary uses of the node and apply a callback function for each.
11481149
// Recursively traverse uses, stopping and applying the callback when
@@ -1254,6 +1255,8 @@ class Node {
12541255
// Whether this is a memory phi node
12551256
bool is_memory_phi() const { return is_Phi() && bottom_type() == Type::MEMORY; }
12561257

1258+
bool is_div_or_mod(BasicType bt) const;
1259+
12571260
//----------------- Printing, etc
12581261
#ifndef PRODUCT
12591262
public:
@@ -2023,6 +2026,10 @@ Op_IL(URShift)
20232026
Op_IL(LShift)
20242027
Op_IL(Xor)
20252028
Op_IL(Cmp)
2029+
Op_IL(Div)
2030+
Op_IL(Mod)
2031+
Op_IL(UDiv)
2032+
Op_IL(UMod)
20262033

20272034
inline int Op_ConIL(BasicType bt) {
20282035
assert(bt == T_INT || bt == T_LONG, "only for int or longs");

0 commit comments

Comments
 (0)