United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4903383 Incorrect ordering of loads/stores of same memory loc with -XX:-OptoScheduling
JDK-4903383 : Incorrect ordering of loads/stores of same memory loc with -XX:-OptoScheduling

Details
Type:
Bug
Submit Date:
2003-08-08
Status:
Resolved
Updated Date:
2003-11-25
Project Name:
JDK
Resolved Date:
2003-09-05
Component:
hotspot
OS:
solaris_2.6
Sub-Component:
compiler
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
5.0
Fixed Versions:
1.4.1_07 (07)

Related Reports
Backport:
Backport:

Sub Tasks

Description
This test case shows what looks like a problem with memory aliasing
handling in the server compiler.  Only one method is compiled.


class Test {
  private int pos;
  private int charBufSize;
  private char[] charBuf = new char[8];

  // Only compile this method to see the failure.
  private void fill() throws Exception {
    int preloopPos = pos;  // pos == 1
    for (int i = 0; i < charBufSize - pos; i++)
      charBuf[i] = charBuf[i + pos];
    int postloopPos = pos;
    charBufSize = charBufSize - pos;
    pos = 0;
    int n = read(charBuf, charBufSize, charBuf.length - charBufSize);
    if (postloopPos != preloopPos) {
      // Should never reach here, but we do.
      throw new Exception("Pre loop " + preloopPos +
                          " Post loop " + postloopPos);
    }
    if (n > 0) {
      charBufSize += n;
    }
  }

  // This should not be inlined into fill().  What it does is irrelevant.
  private int read(char[] buf, int x, int y) {
    for (int i = 0; i != y; ++i)
      buf[i + x] = 'Z';
    return y;
  }

  public static void main(String[] args) {
    Test test = new Test();
    try {
      test.pos = 1;  // set pos != 0
      test.charBufSize = 2;
      test.fill();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}


Run the test like this on Solaris/SPARC:

% java_g -server -version
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Server VM (build 1.4.1_01-b01-debug, mixed mode)
% java_g -server -XX:-OptoScheduling -Xcomp -XX:CompileOnly=Test.fill -XX:-Inline -XX:+PrintCompilation Test
VM option '-OptoScheduling'
VM option 'CompileOnly=Test.fill'
VM option '-Inline'
VM option '+PrintCompilation'
  1   b   Test::fill (156 bytes)
java.lang.Exception: Pre loop 1 Post loop 0
        at Test.fill(Test.java:20)
        at Test.main(Test.java:39)


The code that throws the exception should never be reached!  This test
fails with 1.4.1_01, 1.4.2 fcs, and 1.5.0 build 13.  It does not fail
with 1.4.0_03.  The test also fails on Linux/x86.


In the PrintOptoAssembly output for fill() the bad code can be seen in
this block:

    1dc   B18: #    B40 B19 <- B17 B13  Freq: 0.000599997
    1dc     STW    #0,[R_I0 + #12]              # pos = 0
    1e0     LDUW   [R_I0 + #8],R_O1 ! ptr
    1e4     LDUW   [R_I0 + #16],R_L1
    1e8     LDUW   [R_I0 + #12],R_L5            # postloopPos = pos
    1ec     SUB    R_L1,R_L5,R_O2
    1f0     STW    R_O2,[R_I0 + #16]
    1f4     BReq   R_O1,B40  P=0.000001 C=-1.000000

In the source code the assignment "postloopPos = pos" is before the
assignment "pos = 0".  But in the generated code the store to "pos" is
first!  This causes the failure.

The load and store of "pos" occur in the correct order when
OptoScheduling is enabled.  It looks like the compiler is not
recognizing that the load and store refer to the same memory location.
So during scheduling it can switch the order of the load and store.
But scheduling should never move a load/store past a store to the same
memory location.

                                    

Comments
SUGGESTED FIX

In 1.4.1 code base, loopopts.cpp line 61..64:

          // Else x is a new node we are keeping
          // We do not need register_new_node_with_optimizer
          // because set_type has already been called.
!         _igvn._worklist.push(n);
---
          // Else x is a new node we are keeping
          // We do not need register_new_node_with_optimizer
          // because set_type has already been called.
!         _igvn._worklist.push(x);

----- -----
                                     
2004-06-11
EVALUATION

Loop optimizations/split_if must preserve anti-dependence edges.
###@###.### 2003-08-08
-----
###@###.### 2003-08-14

The loop optimizations and split_if preserved the structure of the code 
but did not put all necessary nodes onto the iGVN worklist.  This resulted 
in not reaching an optimization fix-point.  In specific, a load and store 
used the same memory state before loop opts.  Since only the Store's clone 
was put onto the worklist during loop optimization, only the Store's memory 
input was updated.
-----
                                     
2004-06-11
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
1.4.1_07
1.4.2_04
generic
tiger

FIXED IN:
1.4.1_07
1.4.2_04
tiger

INTEGRATED IN:
1.4.1_07
1.4.2_04
tiger
tiger-b17
tiger-b18


                                     
2004-06-14



Hardware and Software, Engineered to Work Together