JDK-6758445 : loop heads that are exception entry points can crash during count_edges/mark_loops
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: hs10
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_9
  • CPU: sparc
  • Submitted: 2008-10-10
  • Updated: 2011-03-07
  • Resolved: 2011-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 6 JDK 7 Other
6u12Fixed 7Fixed hs11Fixed
Ok, I've just attached the files...too complicated to find somewhere to put them..

test.class is the class "ruby.test". jruby.jar is JRuby's jar. Run with:

java -client -cp jruby.jar:. ruby.test

(assuming you put the test.class in ./ruby)

It should crash under any version of JDK 6 client compiler.

I've also attached the Ruby source. If you want to just run it directly, and JRuby will compile it before run, do it like this:

java -jar jruby.jar org.jruby.Main test.rb

- Charlie
$ok = true

def getc
 if $ok
   $ok = false
   $ok = true

def gets
 c = getc or return
 l = ""
   l.concat c unless c == "\r"
   break if c == "\n"
 end while c = getc

loop { gets }

EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-comp/hotspot/rev/334969144810

SUGGESTED FIX diff --git a/src/share/vm/c1/c1_IR.cpp b/src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp +++ b/src/share/vm/c1/c1_IR.cpp @@ -574,12 +574,23 @@ void ComputeLinearScanOrder::count_edges TRACE_LINEAR_SCAN(3, tty->print_cr("backward branch")); assert(is_visited(cur), "block must be visisted when block is active"); assert(parent != NULL, "must have parent"); - assert(parent->number_of_sux() == 1, "loop end blocks must have one successor (critical edges are split)"); cur->set(BlockBegin::linear_scan_loop_header_flag); cur->set(BlockBegin::backward_branch_target_flag); parent->set(BlockBegin::linear_scan_loop_end_flag); + + // When a loop header is also the start of an exception handler, then the backward branch is + // an exception edge. Because such edges are usually critical edges which cannot be split, the + // loop must be excluded here from processing. + if (cur->is_set(BlockBegin::exception_entry_flag)) { + // Make sure that dominators are correct in this weird situation + _iterative_dominators = true; + return; + } + assert(parent->number_of_sux() == 1 && parent->sux_at(0) == cur, + "loop end blocks must have one successor (critical edges are split)"); + _loop_end_blocks.append(parent); return; }

EVALUATION So I'm looking at this crash and I'm seeing asserts that are unhappy about some loop structures that are being formed with exception handlers. I think it's a throw of a BreakJump that goes to a handler which jumps into a loop. I'm guessing that the problem is that it's producing a control structure you couldn't make from normal Java source. In Java it would/might require multiple separate exception ranges. I think it's something like this: try if (something) throw BreakJump loop: ..... catch (BreakJump bj) goto loop You'd have to build a structure like that in java source very differently and I think we'd handle that correctly but I don't think we've seen anything structured like this before. We can probably fix this but you might want to think about a workaround given how long it takes for releases to make it into users hands. I'll look into a fix for it. How do I get a version of the class file that was generated? The test.class you sent me appeared to be corrupted in some way. *** (#1 of 1): [ UNSAVED ] ###@###.###