FULL PRODUCT VERSION :
The code fails on the server compiler for 1.4.2, 1.5.0 and all the mustang builds I have, including
Java(TM) SE Runtime Environment (build 1.6.0-beta2-b85)
Java HotSpot(TM) Server VM (build 1.6.0-beta2-b85, mixed mode)
FULL OS VERSION :
SunOS eyas 5.9 Generic_118558-11 sun4u sparc SUNW,Sun-Fire-480R
SunOS noisy 5.10 Generic_118833-03 sun4u sparc SUNW,Sun-Fire-V490
Linux hoopoe 2.6.11.4-21.11-default #1 Thu Feb 2 20:54:26 UTC 2006 i686 i686 i386 GNU/Linux
Windows XP
This failure happens on every linux and Solaris version I've tried
A DESCRIPTION OF THE PROBLEM :
The attached code fails when run with the -server compiler. It fails on Solaris+sparc and linux+x86 for the 1.4.2, 1.5 and 1.6 server JVMs. The -client compiler runs the code fine.
The code fails immediately once the target function f() is compiled by HotSpot (I'm running with -XX:+PrintCompilation).
If I lower the CompileThreshold down to ~500, then the error no longer happens.
I'm guessing this is a loop unrolling problem.
The test case is a bit twisted; it was part of a much larger application which would fail intermitently because of this problem, but we were never able to reproduce the error.
THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No
THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
compile and run the test code with the server compiler
EXPECTED VERSUS ACTUAL BEHAVIOR :
The results I expect:
hoopoe$ jdk1.6.0/bin/java -client Loop
done...
The results I get with the server compiler
hoopoe$ jdk1.6.0/bin/java -server Loop
i=2
index=252
w.length=2
ol.length=253
nl.length=2
java.lang.ArrayIndexOutOfBoundsException: 2
at Loop.f(Loop.java:29)
at Loop.main(Loop.java:5)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
public class Loop {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 1000000; i++)
f();
System.out.println("done...");
}
// a fake function to always return 2, but to prevent the optimizer from knowing this...
private static int length() {
double x = Math.random();
if (x < 2)
return 2;
else
return 10;
}
private static void f() {
final int lag = 3;
double[] nl = new double[length()];
double[] ol = new double[253];
double[] w = new double[nl.length];
for(int i = 0; i < nl.length; i++) {
try {
if (i < lag)
w[i] = ol[ol.length - lag + i];
else
w[i] = nl[i-lag];
} catch (Exception e) {
// the index i is 2, eve though that shouldn't be possible
// because the array length of nl is always 2.
// we're failing on the indexing of w[2]
System.err.println("i="+i);
System.err.println("index="+(ol.length - lag + i));
System.err.println("w.length="+w.length);
System.err.println("ol.length="+ol.length);
System.err.println("nl.length="+nl.length);
e.printStackTrace();
System.exit(1);
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I can work around this by using the client compiler, which isn't acceptable on our large systems. The server compiler does give a nice performance boost.
I can also defeat the (loop-unrolling?) optimization by adding a check for
if (i >= nl.length)
throw new Exception();
which should never be taken.
So, even while I have a workaround in place, this has been a major problem for us. While the test case here is trivial, this is part of a big application which would fail in random ways because of this problem. In fact, we were never able to reproduce the problem until recently, and even then it would take hours of running each time to help isolate the problem.
I'm flagging this as a severe error (even though I have a workaround) because it is a severe error. Now that the -server compiler is the default on larger systems, it's important to not have these errors.