Back to back Loop Limit Check Parse Predicates from different loops are wrongly grouped into a single Predicate Block when trying to find all Predicates of a loop. As a result, we do not eliminate the second Loop Limit Check Parse Predicate and the Parse Predicates above belonging to an already folded loop. In the test case, we then create a Hoisted Check Predicate with one of the Parse Predicate from the folded loop. This Hoisted Check Predicate fails at runtime and we jump to the wrong location in the interpreter. We re-execute a store and we observe a wrong execution.
The fix is to make sure each Predicate Block can only contain one Parse Predicate. This constraint was broken with JDK-8305636.
Original report
--------------------
Attached test run with:
$ javac Test.java FuzzerUtils.java -d .; java -XX:-BackgroundCompilation -XX:CompileOnly=Test::iMeth -XX:CompileCommand=quiet -XX:-UseOnStackReplacement Test > out; java -XX:-BackgroundCompilation -Xint Test > out2; diff out out2
Note: FuzzerUtils.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
34c34
< vMeth1_check_sum: -13486
—
> vMeth1_check_sum: -13108
It doesn't reproduce with jdk 21.
iMeth is compiled multiple times. The last one is the one that looks wrong to me. I see:
ParsePredicate #242
IfTrue #251
ParsePredicate #300
IfTrue #309
CountedLoop #567
#242 is for Test::vMeth1 @ bci:84
#300 is for Test::iMeth @ bci:48
So they are back to back but not for the same loop.
StoreL #288 is control depend on #251
After some rounds of loop opts, #567 is unswitched. Predicates #242 is cloned above both unswitched loops. Problem is #242 is not for this loop and captures state before the StoreL but is now after it. I think a deoptimization at state from #242 causes the load, increment, store sequence to be wrongly reexecuted.