RFR: 8342287: C2 fails with "assert(is_IfTrue()) failed: invalid node class: IfFalse" due to Template Assertion Predicate with two UCTs

Christian Hagedorn chagedorn at openjdk.org
Thu Oct 17 11:57:29 UTC 2024


### Assertion Predicates Have the True Projection on the Success Path
By design, Template and Initialized Assertion Predicates have the true projection on the success path and false projection on the failing path. 

### Is a Node a Template Assertion Predicate?
Template Assertion Predicates can have an uncommon trap on or a `Halt` node following the failing/false projection. When trying to find out if a node is a Template Assertion Predicate, we call `TemplateAssertionPredicate::is_predicate()` which checks if the provided node is the success projection of a Template Assertion Predicate. This involves checking if the other projection has a `Halt` node or an UCT (L141):
https://github.com/openjdk/jdk/blob/7a64fbbb9292f4d65a6970206dec1a7d7645046b/src/hotspot/share/opto/predicates.cpp#L135-L144

### New `PredicateIterator` Class

[JDK-8340786](https://bugs.openjdk.org/browse/JDK-8340786) introduced a new `PredicateIterator` class to simplify iteration over predicates and replaced code that was doing some custom iteration. 

#### Usual Usage
Normally, we always start from a loop entry and follow the predicates (i.e. reaching a predicate over its success path).

#### Special Usage
However, I also replaced the predicate skipping in `PhaseIdealLoop::build_loop_late_post_work()` with the new `PredicateIterator` class which could start at any node, including a failing path false projection.

### Problem: Two Uncommon Traps for a Template Assertion Predicate
The fuzzer now found a case where a Template Assertion Predicate has a predicate UCT on the failing **and** the success path due to folding away some dead nodes:

![image](https://github.com/user-attachments/assets/c2a9395e-9eaf-46a0-b978-8847d8e21945)

In the Special Usage mentioned above, we could be using the `PredicateIterator` with `505 IfFalse` as starting node. In the core method `RegularPredicateBlockIterator::for_each()` for the traversal, we call the following with `current` = `505 IfFalse`:
https://github.com/openjdk/jdk/blob/1ea1f33f66326804ca2892fe0659a9acb7ee72ae/src/hotspot/share/opto/predicates.hpp#L628-L629
`TemplateAssertionPredicate::is_predicate()` succeeds because we have a valid Template Assertion Predicate If node and the other projection `504 IfTrue` has a predicate UCT. We then fail when trying to convert the `IfFalse` to an `IfTrue` with `current->as_IfTrue()` on L629.

### Solution
The fix is straight forward: `TemplateAssertionPredicate::is_predicate()` (and `InitiliazedAssertionPredicate::is_predicate()`) should additionally check, if the provided node as an `IfTrue` projection which by definition is the success projection. This avoids to wrongly match a failing path projection as success projection.

### Additional Tweaks - Probably Not Worth to Do Separatly
- While working on this, I noticed that predicate iteration can be limited if `UseLoopPredicate/UseProfiledLoopPredicate` is disabled.
- Made `AssertionPredicatesWithHalt` work with only non-null nodes and moved the null check to the only usage from `CountedLoopNode::skip_assertion_predicates_with_halt()`. There it could be possible, that we have a dying `CountedLoopNode` where the entry control was already replaced with null. 

Thanks,
Christian

-------------

Commit messages:
 - 8342287: C2 fails with "assert(is_IfTrue()) failed: invalid node class: IfFalse" due to Template Assertion Predicate with two UCTs

Changes: https://git.openjdk.org/jdk/pull/21561/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=21561&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8342287
  Stats: 88 lines in 4 files changed: 82 ins; 0 del; 6 mod
  Patch: https://git.openjdk.org/jdk/pull/21561.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/21561/head:pull/21561

PR: https://git.openjdk.org/jdk/pull/21561


More information about the hotspot-compiler-dev mailing list