JDK-8043354 : OptimizePtrCompare too aggressive when allocations are present
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7u4,8-pool,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2014-05-16
  • Updated: 2014-10-15
  • Resolved: 2014-05-21
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 JDK 8 JDK 9
7u76Fixed 8u20Fixed 9 b15Fixed
Description
OptimizePtrCompare is overaggressive in converting comparisons to not-equal.

It appears that this is a result of is_return_allocated() in bcEscapeAnalyzer being not conservative enough.

The program below fails with "-XX:CompileOnly=.visitAndPop".  Passes with "-XX:-OptimizePtrCompare".

Forthcoming contribution with proposed fix.



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

public class TestMarkChecker {

  static TestMarkChecker dummy;

  class Marker {
  }

  List<Marker> markerList = new ArrayList<>();

  // Suppress compilation of this method, it must be processed
  // by the bytecode escape analyzer.

  // Make a new marker and put it on the List
  Marker getMarker() {
    // result escapes through markerList
    final Marker result = new Marker();
    markerList.add(result);
    return result;
  }

  void visit(int depth) {
    // Make a new marker
    getMarker();

    // Call visitAndPop every once in a while
    // Cap the depth of our recursive visits
    if (depth % 10 == 2) {
      visitAndPop(depth + 1);
    } else if (depth < 15) {
      visit(depth + 1);
    }
  }

   void visitAndPop(int depth) {
    // Random dummy allocation to force EscapeAnalysis to process this method
    dummy = new TestMarkChecker();

    // Make a new marker
    Marker marker = getMarker();

    visit(depth + 1);

    // Walk and pop the marker list up to the current marker
    boolean found = false;
    for (int i = markerList.size() - 1; i >= 0; i--) {
      Marker removed = markerList.remove(i);

      // In the failure, EA mistakenly converts this comparison to false
      if (removed == marker) {
        found = true;
        break;
      }
    }

    if (!found) {
      throw new RuntimeException("test fails");
    }
  }


  public static void main(String args[]) {
    TestMarkChecker tc = new TestMarkChecker();

    // Warmup and run enough times
    for (int i = 0; i < 20000; i++) {
      tc.visit(0);
    }
  }
}