JDK-6544557 : C2:opto/chaitin.cpp,1455 "No dead instructions after post-alloc"
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 1.4.2_12
  • Priority: P2
  • Status: Closed
  • Resolution: Won't Fix
  • OS: generic
  • CPU: generic
  • Submitted: 2007-04-10
  • Updated: 2011-02-16
  • Resolved: 2007-05-03
Related Reports
Relates :  
Description
We hit the following assert while running an api JCK:
api/java_util/logging/Logger/index.html#LogpLSSSO

 ...
 # To suppress the following error report, specify this argument  # after
-XX: or in .hotspotrc:  SuppressErrorAt=/chaitin.cpp:1455]
 #
 # An unexpected error has been detected by HotSpot Virtual Machine:
 #
 #  Internal Error
 (/CLO/Components/JAVA_HOTSPOT/Src/src/share/vm/opto/chaitin.cpp, 1455),
pid=29347, tid=12  #  # Java VM: Java HotSpot(TM) Server VM (1.5.0.04
jinteg:06.08.06-10:33
 IA64 debug mixed mode)
 #
 # Error: assert(n->outcnt() != 0 || C->top() == n || n->is_Proj(),"No  dead
instructions after post-alloc")  # An error report file with more
information is saved as hs_err_pid29347.log  ...

This is an intermittent issue and it fails once in 200 runs.

Analysis:
We hit this issue while compiling
"sun.security.provider.PolicyParser.parseExtDirs".

Block B326 has a dead node,
 
  B326: # B4 <- N2288  Freq: 1.4808e-05  StartOffset: 0xffffffff,
 EndOffset: 0xffffffff
  2486   Region  ===  2486  1631  [[ 2486  2048  1683 ]]
  1683   CreateException ===  2486  681  [[ 1653 ]]
 java/lang/Throwable:NotNullOop: java/lang/Throwable:NotNull *
  2731   loadI   === _  683  693  [[ 2729 ]]
  2730   loadP   === _  683  684  [[ 2728  2728  2725 ]] char
 [int+]:exact*
  2729   lShiftI_reg_imm === _  2731  [[ 2728 ]] #1
  2728   addP_reg_reg    === _  2730  2730  2729  [[ 2725 ]]
  2725   addP_reg_imm14  === _  2730  2728  [[ 2723 ]] #12
  2723   prefetch_read   === _  681  2725  [[]]  <======  dead
 instruction
  2048   branch  ===  2486  [[ 3 ]]

 This dead node is suppose to be removed in post_allocate_copy_removal
(actually in yank_if_dead() ) method
 
 
The first two input arguments to yank_if_dead() method are

old: 2723   prefetch_read   === _  681  2725  [[]]
current_block:
B326: # B4 <- N2288  Freq: 1.4808e-05  StartOffset: 0xffffffff,
 EndOffset: 0xffffffff
  2486   Region  ===  2486  1631  [[ 2486  2048  1683 ]]
  1683   CreateException ===  2486  681  [[ 1653 ]]
 java/lang/Throwable:NotNull *  Oop:java/lang/Throwable:NotNull *
  2731   loadI   === _  683  693  [[ 2729 ]]
  2730   loadP   === _  683  684  [[ 2728  2728  2725 ]] char
 [int+]:exact*
  2729   lShiftI_reg_imm === _  2731  [[ 2728 ]] #1
  2728   addP_reg_reg    === _  2730  2730  2729  [[ 2725 ]]
  2725   addP_reg_imm14  === _  2730  2728  [[ 2723 ]] #12
  2723   prefetch_read   === _  681  2725  [[]]  <==========  dead
 instruction
  2048   branch  ===  2486  [[ 3 ]]


old (preferch_read) node has three node inputs.
 in(1) =  681    MachProj        ===  640  [[ 638  2723  1643  1683
 2714]] #1
 in(2) =  2725   addP_reg_imm14  === _  2730  2728  [[ 2723 ]] #12
 in(3) = 0x0

Even though we have three input nodes to this node, As per "yank_if_dead()"
method source code, it considers only the first input and the rest of the
nodes are not considered.

     77      Node *tmp = old->req() > 1 ? old->in(1) : NULL;
     78      old->disconnect_inputs(NULL);


After remving "prefetch_read" and disconnecting inputs to this  node,
current_block looks like this
 
 B326: # B4 <- N2288  Freq: 1.4808e-05  StartOffset: 0xffffffff,
 EndOffset: 0xffffffff
  2486   Region  ===  2486  1631  [[ 2486  2048  1683 ]]
  1683   CreateException ===  2486  681  [[ 1653 ]]
 java/lang/Throwable:NotNull *  Oop:java/lang/Throwable:NotNull *
  2731   loadI   === _  683  693  [[ 2729 ]]
  2730   loadP   === _  683  684  [[ 2728  2728  2725 ]] char
 [int+]:exact*
  2729   lShiftI_reg_imm === _  2731  [[ 2728 ]] #1
  2728   addP_reg_reg    === _  2730  2730  2729  [[ 2725 ]]
  2725   addP_reg_imm14 === _  2730  2728  [[]] #12
  2048   branch  ===  2486  [[ 3 ]]


in(1) , which is not part of the current_block  looks like this
 681    MachProj        ===  640  [[ 638  2714  1643  1683 ]] #1

So we still have a dead node (addP_reg_imm14) in B326.


The same problem can be reproduced while compiling "java.io.File::toURI".
workaround:  This issue can be resolved by recursively deleting all dead
input nodes to the current dead node.

Here is the modified source code for yank_if_dead method


> >  if (old->outcnt() == 0 && old != C->top()) {
> >     Block *oldb = _cfg._bbs[old->_idx];
> >     if(oldb) {
> >       oldb->find_remove(old);
> >       // Count 1 if deleting an instruction from the current block
> >       if( oldb == current_block ) blk_adjust++;
> >       _cfg._bbs.map(old->_idx,NULL);
> >       OptoReg::Name old_reg = lrgs(n2lidx(old)).reg();
> >       if( regnd && (*regnd)[old_reg]==old ) { // Instruction is currently
available?
> >         value->map(old_reg,NULL);  // Yank from value/regnd maps
> >         regnd->map(old_reg,NULL);  // This register's value is now unknown
> >       }
> >       // Deletion of a dead node may result in few more dead nodes.
> >       // So it is mandatory to check whether all inputs to the current
> >       // dead node are valid nodes after deleting the current dead node.
> >       Node_List *ins_list;
> >       ins_list = new Node_List();
> >       for ( int i =0; i< old->req(); i++ )
> >         ins_list->push( old->in(i));
> >       old->disconnect_inputs(NULL);
> > 
> >       for ( int j=0; jsize(); j++ ) {
> >         Node *tmp = ins_list->pop();
> >         if ( tmp)
> >           blk_adjust += yank_if_dead ( tmp, current_block, value, regnd);
> >       }
> >     }
> >   }

Comments
EVALUATION This bug is specific to using -XX:+OptoScheduling on platforms where kill projections are likely to be generated. It is has been fixed for release 7 under the bug 6525524. The customer is satisfied with that fix, as shown in the suggested fix section, and is not asking for a backport. Closing this bug as will-not-fix.
03-05-2007

SUGGESTED FIX This relevant fix from 6525524 should be applied to catch_call_cleanup() in lcm.cpp. The last loop in that function now looks like this: // If the successor blocks have a CreateEx node, move it back to the top for(uint i4 = 0; i4 < _num_succs; i4++ ) { Block *sb = _succs[i4]; uint new_cnt = end - beg; // Remove any newly created, but dead, nodes. for( uint j = new_cnt; j > 0; j-- ) { Node *n = sb->_nodes[j]; if (n->outcnt() == 0 && (!n->is_Proj() || n->as_Proj()->in(0)->outcnt() == 1) ){ n->disconnect_inputs(NULL); sb->_nodes.remove(j); new_cnt--; } } // If any newly created nodes remain, move the CreateEx node to the top if (new_cnt > 0) { Node *cex = sb->_nodes[1+new_cnt]; if( cex->is_Mach() && cex->as_Mach()->ideal_Opcode() == Op_CreateEx ) { sb->_nodes.remove(1+new_cnt); sb->_nodes.insert(1,cex); } } }
03-05-2007