JDK-8007294 : ReduceFieldZeroing doesn't check for dependent load and can lead to incorrect execution
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2013-01-31
  • Updated: 2014-04-10
  • Resolved: 2013-02-25
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 JDK 8 Other
6u81Fixed 7u40Fixed 8Fixed hs24Fixed
Description
Issue spotted during work on incremental inlining. When stores are captured during igvns, depending on the order the nodes are processed the resulting may produce incorrect results. The following test case run with debug option -XX:+AlwaysIncrementalInline produces an incorrect result:

public class TestCapturedStores {

    int i1;
    int i2;

    TestCapturedStores(int i1, int i2) {
        this.i1 = i1;
        this.i2 = i2;
    }

    static int m1(int v) {
        return v;
    }

    static TestCapturedStores m() {
        TestCapturedStores obj = new TestCapturedStores(10, 100);
        int v1 = obj.i1;
        
        int v3 = m1(v1);
        int v2 = obj.i2;
        obj.i2 = v3;
        obj.i1 = v2;
        
        return obj;
    }

    static public void main(String[] args) {
        for (int i = 0; i < 100000; i++) {
            TestCapturedStores obj = m();
            if (obj.i1 != 100 || obj.i2 != 10) {
                System.out.println("Error " + obj.i1 + " " + obj.i2);
                throw new Error();
            }
        }
    }
}

This fails because:
- before inlining initialization stores are captured so that obj.i1=10 and obj.i2=100
- inlining of m1 puts store obj.i2 = v3 ahead of load int v2 = obj.i2 in the igvn worklist
- obj.i2 = v3 is captured by the initialization of obj so the captured stores are obj.i1=10 and obj.i2=10
- v2 = obj.i2 is processed but loads the newly stored value 10
- obj.i1 = v2 stores 10 to i1 and is captured. So the final two stores are obj.i1=10 and obj.i2=10

The logic that capture stores misses the v2 = obj.i2 load when obj.i2 = v3 is captured.

I don't think this can be reproduced easily without incremental inlining.
Comments
An other case.
19-02-2014

The bug can be reproduce without incremental inlining with this simple method: static int m(int i) { int j = 0; if (i > 0) { j = 1; } int[] arr = new int[10]; arr[0] = 1; arr[1] = 2; int v1 = arr[j]; arr[0] = 3; arr[1] = 4; return v1; } if i <= 0, it returns 3 instead of 1. If i > 0, it returns 4 instead of 2.
08-02-2013

The description includes an evaluation.
31-01-2013