Skip to content

Commit 3fe5886

Browse files
committed
8252696: Loop unswitching may cause out of bound array load to be executed
Reviewed-by: neliasso, chagedorn
1 parent 226faa5 commit 3fe5886

File tree

3 files changed

+18
-23
lines changed

3 files changed

+18
-23
lines changed

src/hotspot/share/opto/loopPredicate.cpp

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node*
210210
}
211211

212212
//--------------------------clone_predicate-----------------------
213-
ProjNode* PhaseIdealLoop::clone_loop_predicate(ProjNode* predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason,
213+
ProjNode* PhaseIdealLoop::clone_predicate_to_unswitched_loop(ProjNode* predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason,
214214
bool is_slow_loop, uint idx_before_clone, Node_List &old_new) {
215215
ProjNode* new_predicate_proj = create_new_if_for_predicate(predicate_proj, new_entry, reason, Op_If);
216216
IfNode* iff = new_predicate_proj->in(0)->as_If();
@@ -225,13 +225,14 @@ ProjNode* PhaseIdealLoop::clone_loop_predicate(ProjNode* predicate_proj, Node* n
225225
register_new_node(bol, ctrl);
226226
_igvn.hash_delete(iff);
227227
iff->set_req(1, bol);
228-
clone_concrete_loop_predicates(reason, predicate_proj, new_predicate_proj, is_slow_loop, idx_before_clone, old_new);
228+
clone_skeleton_predicates_to_unswitched_loop(reason, predicate_proj, new_predicate_proj, is_slow_loop, idx_before_clone, old_new);
229229
return new_predicate_proj;
230230
}
231231

232-
// Clones all non-empty loop predicates (including skeleton predicates) starting at 'old_predicate_proj' to 'new_predicate_proj'
233-
// and rewires the control edges of data nodes in the loop to the old predicates to the new cloned predicates.
234-
void PhaseIdealLoop::clone_concrete_loop_predicates(Deoptimization::DeoptReason reason, ProjNode* old_predicate_proj,
232+
// Clones skeleton predicates starting at 'old_predicate_proj' to
233+
// 'new_predicate_proj' and rewires the control edges of data nodes in
234+
// the loop from the old predicates to the new cloned predicates.
235+
void PhaseIdealLoop::clone_skeleton_predicates_to_unswitched_loop(Deoptimization::DeoptReason reason, ProjNode* old_predicate_proj,
235236
ProjNode* new_predicate_proj, bool is_slow_loop, uint idx_before_clone,
236237
Node_List &old_new) {
237238
assert(old_predicate_proj->is_Proj(), "must be projection");
@@ -249,7 +250,7 @@ void PhaseIdealLoop::clone_concrete_loop_predicates(Deoptimization::DeoptReason
249250
uncommon_proj = iff->proj_out(1 - predicate->as_Proj()->_con);
250251
if (uncommon_proj->unique_ctrl_out() != rgn)
251252
break;
252-
if (iff->is_RangeCheck()) {
253+
if (iff->in(1)->Opcode() == Op_Opaque4 && skeleton_predicate_has_opaque(iff)) {
253254
// Only need to clone range check predicates as those can be changed and duplicated by inserting pre/main/post loops
254255
// and doing loop unrolling. Push the original predicates on a list to later process them in reverse order to keep the
255256
// original predicate order.
@@ -274,11 +275,11 @@ void PhaseIdealLoop::clone_concrete_loop_predicates(Deoptimization::DeoptReason
274275
predicate = list.at(i);
275276
assert(predicate->in(0)->is_If(), "must be If node");
276277
iff = predicate->in(0)->as_If();
277-
assert(predicate->is_Proj() && predicate->as_Proj()->is_IfProj() && iff->is_RangeCheck(), "predicate must be a projection of a range check");
278+
assert(predicate->is_Proj() && predicate->as_Proj()->is_IfProj(), "predicate must be a projection of an if node");
278279
IfProjNode* predicate_proj = predicate->as_IfProj();
279280

280281
// cloned_proj is the same type of projection as the original predicate projection (IfTrue or IfFalse)
281-
ProjNode* cloned_proj = create_new_if_for_predicate(new_predicate_proj, NULL, reason, Op_RangeCheck, predicate_proj->is_IfTrue());
282+
ProjNode* cloned_proj = create_new_if_for_predicate(new_predicate_proj, NULL, reason, iff->Opcode(), predicate_proj->is_IfTrue());
282283

283284
// Replace bool input by input from original predicate
284285
_igvn.replace_input_of(cloned_proj->in(0), 1, iff->in(1));
@@ -297,12 +298,6 @@ void PhaseIdealLoop::clone_concrete_loop_predicates(Deoptimization::DeoptReason
297298
}
298299
assert(slow_node->_idx <= idx_before_clone || old_new[slow_node->_idx] == NULL, "mapping of cloned nodes must be null");
299300
}
300-
301-
// Let old predicates before unswitched loops which were cloned die if all their control edges were rewired
302-
// to the cloned predicates in the unswitched loops.
303-
if (predicate->outcnt() == 1) {
304-
_igvn.replace_input_of(iff, 1, _igvn.intcon(predicate_proj->_con));
305-
}
306301
} else {
307302
// Fast loop
308303
for (DUIterator i = predicate->outs(); predicate->has_out(i); i++) {
@@ -324,7 +319,7 @@ void PhaseIdealLoop::clone_concrete_loop_predicates(Deoptimization::DeoptReason
324319

325320
//--------------------------clone_loop_predicates-----------------------
326321
// Clone loop predicates to cloned loops when unswitching a loop.
327-
Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry, bool clone_limit_check,
322+
Node* PhaseIdealLoop::clone_predicates_to_unswitched_loop(Node* old_entry, Node* new_entry, bool clone_limit_check,
328323
bool is_slow_loop, uint idx_before_clone, Node_List &old_new) {
329324
#ifdef ASSERT
330325
assert(LoopUnswitching, "sanity - only called when unswitching a loop");
@@ -354,7 +349,7 @@ Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry, bo
354349
}
355350
if (predicate_proj != NULL) { // right pattern that can be used by loop predication
356351
// clone predicate
357-
new_entry = clone_loop_predicate(predicate_proj, new_entry, Deoptimization::Reason_predicate, is_slow_loop,
352+
new_entry = clone_predicate_to_unswitched_loop(predicate_proj, new_entry, Deoptimization::Reason_predicate, is_slow_loop,
358353
idx_before_clone, old_new);
359354
assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone predicate");
360355
if (TraceLoopPredicate) {
@@ -364,7 +359,7 @@ Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry, bo
364359
}
365360
if (profile_predicate_proj != NULL) { // right pattern that can be used by loop predication
366361
// clone predicate
367-
new_entry = clone_loop_predicate(profile_predicate_proj, new_entry,Deoptimization::Reason_profile_predicate,
362+
new_entry = clone_predicate_to_unswitched_loop(profile_predicate_proj, new_entry,Deoptimization::Reason_profile_predicate,
368363
is_slow_loop, idx_before_clone, old_new);
369364
assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone predicate");
370365
if (TraceLoopPredicate) {
@@ -376,7 +371,7 @@ Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry, bo
376371
// Clone loop limit check last to insert it before loop.
377372
// Don't clone a limit check which was already finalized
378373
// for this counted loop (only one limit check is needed).
379-
new_entry = clone_loop_predicate(limit_check_proj, new_entry, Deoptimization::Reason_loop_limit_check,
374+
new_entry = clone_predicate_to_unswitched_loop(limit_check_proj, new_entry, Deoptimization::Reason_loop_limit_check,
380375
is_slow_loop, idx_before_clone, old_new);
381376
assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone limit check");
382377
if (TraceLoopLimitCheck) {

src/hotspot/share/opto/loopUnswitch.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,10 @@ ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop,
284284
assert(old_new[head->_idx]->is_Loop(), "" );
285285

286286
// Fast (true) control
287-
Node* iffast_pred = clone_loop_predicates(entry, iffast, !counted_loop, false, idx_before_clone, old_new);
287+
Node* iffast_pred = clone_predicates_to_unswitched_loop(entry, iffast, !counted_loop, false, idx_before_clone, old_new);
288288

289289
// Slow (false) control
290-
Node* ifslow_pred = clone_loop_predicates(entry, ifslow, !counted_loop, true, idx_before_clone, old_new);
290+
Node* ifslow_pred = clone_predicates_to_unswitched_loop(entry, ifslow, !counted_loop, true, idx_before_clone, old_new);
291291

292292
Node* l = head->skip_strip_mined();
293293
_igvn.replace_input_of(l, LoopNode::EntryControl, iffast_pred);

src/hotspot/share/opto/loopnode.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,11 +1431,11 @@ class PhaseIdealLoop : public PhaseTransform {
14311431
}
14321432

14331433
// Clone loop predicates to slow and fast loop when unswitching a loop
1434-
Node* clone_loop_predicates(Node* old_entry, Node* new_entry, bool clone_limit_check, bool is_slow_loop,
1434+
Node* clone_predicates_to_unswitched_loop(Node* old_entry, Node* new_entry, bool clone_limit_check, bool is_slow_loop,
14351435
uint idx_before_clone, Node_List &old_new);
1436-
ProjNode* clone_loop_predicate(ProjNode* predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason,
1436+
ProjNode* clone_predicate_to_unswitched_loop(ProjNode* predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason,
14371437
bool is_slow_loop, uint idx_before_clone, Node_List &old_new);
1438-
void clone_concrete_loop_predicates(Deoptimization::DeoptReason reason, ProjNode* old_predicate_proj,
1438+
void clone_skeleton_predicates_to_unswitched_loop(Deoptimization::DeoptReason reason, ProjNode* old_predicate_proj,
14391439
ProjNode* new_predicate_proj, bool is_slow_loop,
14401440
uint idx_before_clone, Node_List &old_new);
14411441

0 commit comments

Comments
 (0)