JDK-6910461 : Register allocator may insert spill code at wrong insertion index
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 6u15
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_10
  • CPU: sparc
  • Submitted: 2009-12-15
  • Updated: 2013-07-18
  • Resolved: 2012-03-07
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 Other
7u40Fixed 8Fixed hs24Fixed
Description
FULL PRODUCT VERSION :
java version "1.6.0_15"
Java(TM) SE Runtime Environment (build 1.6.0_15-b03-219)
Java HotSpot(TM) 64-Bit Server VM (build 14.1-b02-90, mixed mode)

FULL OS VERSION :
All platforms.

A DESCRIPTION OF THE PROBLEM :
When resolving exception edges after register allocation, the C1 register allocator may insert spill code at the wrong insertion position due to an off-by-one error.


THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Did not try

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See the file
src/share/vm/c1/c1_LinearScan.cpp @ 1840:

  if (move_resolver.has_mappings()) {
    // insert moves after first instruction
    move_resolver.set_insert_position(block->lir(), 1);
    move_resolver.resolve_and_append_moves();
  }

The constant 1 here is incorrect, since moves are inserted _after_ the specified index. Index 0 is always a label and the last index is always a branch. Usually the exception handler block has some instructions, but if it is empty the moves will be inserted after the branch (index 1) and cause an assertion failure later (in the move optimizer).



EXPECTED VERSUS ACTUAL BEHAVIOR :
The register allocator should insert moves at the correct position, but it does not. This may produce an assertion error later in the compiler, or may produce incorrect code that fails when catching the exception.
REPRODUCIBILITY :
This bug can be reproduced rarely.

---------- BEGIN SOURCE ----------
/*
 * @Harness: java
 * @Runs: 0 = 0; 1 = 2
 */
package jtt.except;

public class Except_Synchronized05 {

    Object field;

    public static int test(int arg) {
        Except_Synchronized05 obj = new Except_Synchronized05();
        int a = obj.bar(arg) != null ? 1 : 0;
        int b = obj.baz(arg) != null ? 1 : 0;
        return a + b;
    }

    public synchronized Object bar(int arg) {
        try {
            String f = foo1(arg);
            if (f == null) {
                field = new Object();
            }
        } catch (NullPointerException e) {
            // do nothing
        }
        return field;
    }

    public Object baz(int arg) {
        synchronized (this) {
            try {
                String f = foo1(arg);
                if (f == null) {
                    field = new Object();
                }
            } catch (NullPointerException e) {
                // do nothing
            }
            return field;
        }
    }

    private String foo1(int arg) {
        if (arg == 0) {
            throw null;
        }
        return null;
    }
}

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

CUSTOMER SUBMITTED WORKAROUND :
  Fix: change the constant 1 to constant 0 in the above mentioned code (repeated here):

src/share/vm/c1/c1_LinearScan.cpp @ 1840:

  if (move_resolver.has_mappings()) {
    // insert moves after first instruction
    move_resolver.set_insert_position(block->lir(), 0);
    move_resolver.resolve_and_append_moves();
  }

Comments
EVALUATION http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/b279f99d7143
22-03-2012

EVALUATION http://hg.openjdk.java.net/hsx/hotspot-comp/hotspot/rev/b279f99d7143
29-02-2012

EVALUATION see description.
27-02-2012