JDK-6851282 : JIT miscompilation results in null entry in array when using CompressedOops
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 6u10,6u14
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: linux,solaris_10,windows_2003
  • CPU: x86,sparc
  • Submitted: 2009-06-15
  • Updated: 2011-03-09
  • Resolved: 2011-03-08
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 7 Other
7Fixed hs16Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b16, mixed mode)

java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b59)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b03, mixed mode)


FULL OS VERSION :
Linux mac 2.6.29.4-162.fc11.x86_64 #1 SMP Mon May 25 16:51:30 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
When executing the included program, the array will contain null fields after the server JIT recompiles some of the methods even though that should be impossible.

This only happens with -XX:+UseCompressedOops. I tested with JDK6u14 and the latest JDK7 snapshot (b59)

THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the included program with JDK6u14 -server -XX:+UseCompressedOops

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected results: nothing gets printed to the console

Actual results: The word "bug" is printed a few times.

Note that the problem does not occur if -XX:+UseCompressedOops is not used.
REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package test;

import java.util.ArrayList;
import java.util.List;


public class Hs {
  void foo(A a, A[] as) {
    for (A a1 : as) {
      B[] filtered = a.c(a1);
      for (B b : filtered)
        if (b == null) {
          System.out.println("bug");
        }
    }
  }
  
  public static void main(String[] args) {
    List<A> as = new ArrayList<A>();
    for (int i = 0; i < 5000; i++) {
      List<B> bs = new ArrayList<B>();
      for (int j = i; j < i + 1000; j++)
        bs.add(new B(j));
      as.add(new A(bs.toArray(new B[0])));
    }
    new Hs().foo(as.get(0), as.subList(1, as.size()).toArray(new A[0]));
  }
}

class A {
  final B[] bs;
  
  public A(B[] bs) {
    this.bs = bs;
  }
  
  final B[] c(final A a) {
    return new BoxedArray<B>(bs).filter(new Function<B, Boolean>() {
      public Boolean apply(B arg) {
        for (B b : a.bs) {
          if (b.d == arg.d)
            return true;
        }
        return false;
      }
    });
  }
}

class BoxedArray<T> {
  
  private final T[] array;
  
  BoxedArray(T[] array) {
    this.array = array;
  }
  
  public T[] filter(Function<T, Boolean> function) {
    boolean[] include = new boolean[array.length];
    int len = 0;
    int i = 0;
    while (i < array.length) {
      if (function.apply(array[i])) {
        include[i] = true;
        len += 1;
      }
      i += 1;
    }
    T[] result = (T[]) java.lang.reflect.Array.newInstance(array.getClass().getComponentType(), len);
    len = 0;
    i = 0;
    while (len < result.length) {
      if (include[i]) {
        result[len] = array[i];
        len += 1;
      }
      i += 1;
    }
    return result;
  }
}

interface Function<T, R> {
  R apply(T arg);
}

class B {
  final int d;
  public B(int d) {
    this.d = d;
  }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Remove -XX:+UseCompressedOops switch.

Comments
EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-gc/hotspot/rev/64219d2a6493
27-07-2009

EVALUATION PhiNode::Ideal() has optimization which pushes DecodeN node down through Phi. But it may set incorrect type (TOP) for new Phi node when it use DecodeN's input on dead path.
17-07-2009

PUBLIC COMMENTS Problem: PhiNode::Ideal() has optimization which pushes DecodeN node down through Phi. But it may set incorrect type (TOP) for new Phi node when it use DecodeN's input on dead path. Solution: Get type for new Phi from non dead path.
17-07-2009

SUGGESTED FIX Get type for new Phi from non dead path.
17-07-2009

EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-comp/hotspot/rev/64219d2a6493
17-07-2009