JDK-8065618 : C2 RA incorrectly removes kill projections
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7u80,8u40,9
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2014-11-21
  • Updated: 2015-06-03
  • Resolved: 2014-11-22
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.
7u80Fixed 8u40Fixed 9 b42Fixed
Related Reports
Relates :  
I found this problem while working on one of my projects.
Some nodes have SCMemProj projection node to keep them alive even when their result is not used because they have memory side effect.
For example, EncodeISOArrayNode and loadstore nodes like CompareAndSwapPNode.
Such node's code may kill some registers and flags when it is executed:

instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len,
                          regD tmp1, regD tmp2, regD tmp3, regD tmp4,
                          rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{
  match(Set result (EncodeISOArray src (Binary dst len)));
  effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr);

  format %{ "Encode array $src,$dst,$len -> $result    // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %}
  ins_encode %{
    __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register,
                        $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister,
                        $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register);

To keep such nodes alive when their result is not used there is RA code in PhaseChaitin::add_input_to_liveout() which does that by putting node's LiveRange on liveout list when it has SCMemProj projection.

Unfortunately SCMemProj node could be placed in a block before kill MachProj nodes and will be process in add_input_to_liveout() too late. When kill MachProj are processed their def node looks like dead and these nodes are removed from graph. As result killed register is not marked as killed anymore and it could be used after instructions which kills/modifies it. For example in EncodeISOArray case its dst value could be used after it.

These code existed forever. I think we did not hit it before because it was used only for loadstore nodes before which may have only kill flags MachProj projection. And EncodeISOArray was added very recently.
noreg-hard: I was not able to write test with existing VM code. encodeISOArray() method can't be called directly - it is part of sun.nio.cs.ISO_8859_1$Encoder::encode() which calls it in a loop. There is enough code after encodeISOArray() call in encode() method which prevents using the same register after encode().