United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6916644 C2 compiler crash on x86
JDK-6916644 : C2 compiler crash on x86

Details
Type:
Bug
Submit Date:
2010-01-13
Status:
Resolved
Updated Date:
2010-05-24
Project Name:
JDK
Resolved Date:
2010-02-24
Component:
hotspot
OS:
linux_redhat_4.0,solaris_2.5.1
Sub-Component:
compiler
CPU:
x86,sparc
Priority:
P2
Resolution:
Fixed
Affected Versions:
6u14,6u17
Fixed Versions:
6u18-rev (b09)

Related Reports
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:
Relates:

Sub Tasks

Description
OS:Enterprise Linux Enterprise Linux AS release 4 (October Update 7)

vm_info: Java HotSpot(TM) Server VM (14.3-b01) for linux-x86 JRE (1.6.0_17-b04),
 built on Oct 11 2009 01:01:36 by "java_re" with gcc 3.2.1-7a (J2SE release)

Getting C2 crash with Server VM only (Client VM does not crash).  Always crashes in this method:

Current CompileTask:
C2:3144  !   com.bea.wli.monitoring.statistics.collection.BucketWindow.getAggreg
atedValueUntil(JLcom/bea/wli/monitoring/statistics/NonQualifiedValue;)V (229 byt
es)

It always fails with this method.  Customer has looked at the code and can't see any reason why it would fail.  They tested with the Client VM and report that it succeeds.

They can avoid the crash by excluding the method from compilation, but that's not a solution for them.  -XX:+PrintCompilation verifies the failing method.  This is easily reproducible at their site, but so far no test case available.

See the Attachments for hs_err logs (3 from 6u14 and 1 from 6u17) and the BucketWindow class that contains the failing method.

                                    

Comments
EVALUATION

The use of an expand rule involving a match with a load triggered some previously unexercised code in the adlc which screwed up the edges when generating the node.  I suspect it's from a time when what the comment says was true but it's clear not true now.  The memory edge is inserted irrespective of type of memory op.  The fix is simply to remove the logic:

diff -r cf0685d550f1 src/share/vm/adlc/output_c.cpp
--- a/src/share/vm/adlc/output_c.cpp    Wed Jan 20 22:10:33 2010 -0800
+++ b/src/share/vm/adlc/output_c.cpp    Fri Jan 22 11:16:27 2010 -0800
@@ -1546,17 +1546,6 @@ void ArchDesc::defineExpand(FILE *fp, In
     // Build a mapping from operand index to input edges
     fprintf(fp,"  unsigned idx0 = oper_input_base();\n");

-    // The order in which inputs are added to a node is very
-    // strange.  Store nodes get a memory input before Expand is
-    // called and all other nodes get it afterwards so
-    // oper_input_base is wrong during expansion.  This code adjusts
-    // is so that expansion will work correctly.
-    bool missing_memory_edge = node->_matrule->needs_ideal_memory_edge(_globalNames) &&
-                               node->is_ideal_store() == Form::none;
-    if (missing_memory_edge) {
-      fprintf(fp,"  idx0--; // Adjust base because memory edge hasn't been inserted yet\n");
-    }
-
     for( i = 0; i < node->num_opnds(); i++ ) {
       fprintf(fp,"  unsigned idx%d = idx%d + num%d;\n",
               i+1,i,i);
@@ -1611,10 +1600,9 @@ void ArchDesc::defineExpand(FILE *fp, In
         int node_mem_op = node->memory_operand(_globalNames);
         assert( node_mem_op != InstructForm::NO_MEMORY_OPERAND,
                 "expand rule member needs memory but top-level inst doesn't have any" );
-        if (!missing_memory_edge) {
-          // Copy memory edge
-          fprintf(fp,"  n%d->add_req(_in[1]);\t// Add memory edge\n", cnt);
-        }
+
+        // Copy memory edge
+        fprintf(fp,"  n%d->add_req(_in[1]);\t// Add memory edge\n", cnt);
       }

       // Iterate over the new instruction's operands

The crash resulted for an object being cast to an unrelated type and then performing a virtual dispatch on it.  This rule seem to be the only place where this has ever been exercised in our system.
                                     
2010-01-22
EVALUATION

Actually I'm incorrect about where the code came from.  It was introduced as part of the compressed oops work.  It doesn't appear to trigger at all these days so I'm not sure what problem it thinks is happening.  I'll have to investigate this more.  An alternate fix that it completely safe is to stop using the expand rule.

diff -r cf0685d550f1 src/cpu/x86/vm/x86_32.ad
--- a/src/cpu/x86/vm/x86_32.ad  Wed Jan 20 22:10:33 2010 -0800
+++ b/src/cpu/x86/vm/x86_32.ad  Fri Jan 22 11:24:41 2010 -0800
@@ -7841,9 +7841,10 @@ instruct cmovI_memUCF(cmpOpUCF cop, eFla
   predicate(VM_Version::supports_cmov() );
   match(Set dst (CMoveI (Binary cop cr) (Binary dst (LoadI src))));
   ins_cost(250);
-  expand %{
-    cmovI_memU(cop, cr, dst, src);
-  %}
+  format %{ "CMOV$cop $dst,$src" %}
+  opcode(0x0F,0x40);
+  ins_encode( enc_cmov(cop), RegMem( dst, src ) );
+  ins_pipe( pipe_cmov_mem );
 %}

 // Conditional move
                                     
2010-01-22
EVALUATION

The problem is that the code to deal with a potentially missing memory edge isn't completely correct.  Sometimes loads will already have their memory edge connected and sometimes it won't.  It depends on what the full match tree looks like.  If the tree starts with a store then any loads in the tree will have their memory edge connected otherwise they won't.  The simplest fix is to pass the mem into expand so it can tell whether to handle the memory edge or not.
                                     
2010-01-22
EVALUATION

ChangeSet=http://hg.openjdk.java.net/jdk7/hotspot-comp/hotspot/rev/844a9d73ec22,ChangeRequest=6916644
                                     
2010-01-30



Hardware and Software, Engineered to Work Together