Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Inconsistency between MRI and JRuby with begin/rescue/else #733

Closed
maxsz opened this Issue · 7 comments

2 participants

@maxsz

Consider the following simple program:

def test?
    puts "test?"
rescue
    return true
else
    return false
end

def test_begin?
    begin
        puts "test_begin?"
    rescue
        return true
    else
        return false
    end
end

puts "failure" if test?
puts "failure" if test_begin?

Expected Output:

test?
test_begin?

Actual Output:

test?

This works on MRI, as expected:

$ rvm use jruby
Using /Users/szengel/.rvm/gems/jruby-1.7.3
$ ruby --version
jruby 1.7.3 (1.9.3p385) 2013-02-21 dac429b on Java HotSpot(TM) 64-Bit Server VM 1.6.0_45-b06-451-11M4406 [darwin-x86_64]
$ ruby test.rb
test?
$ rvm use 1.9.3
Using /Users/szengel/.rvm/gems/ruby-1.9.3-p392
$ ruby --version
ruby 1.9.3p385 (2013-02-06 revision 39114) [x86_64-darwin12.3.0]
$ ruby test.rb  
test?
test_begin?
@headius
Owner

Updated issue to make the test clearer.

@headius
Owner

So yeah, this is super wacky. It only appears to affect the JIT:

$ jruby bug.rb 
test?

$ jruby -X-C bug.rb 
test?
test_begin?

Adding additional logging shows that the "else" in "test?" does fire, but for whatever reason the script's execution seems to get no further. A message immediately after the call to "test?" does not output.

This only seems to affect "else" at method level, oddly enough. If both methods are modified to use "begin" form, everything runs as expected. So there's your workaround for the moment: use the begin...rescue...else form instead of the method-root form.

Will investigate.

@maxsz

In our rails app we actually have a very similar example that actually works with JIT, but when compiled AOT and then loading the class files using require __FILE__.sub(/.rb$/, '.class') (as warbler does it) it fails. The begin...rescue...else workaround causes no problems. Thanks.

@headius
Owner

Ah-ha...so maybe not JIT but just AOT. I'll try to confirm that.

@headius
Owner

Ok, confirmed...the AOT version does appear to be the only one failing.

Looking at the bytecode output, I can immediately see that the AOT version is using a lighter-weight form of exception-handling that doesn't set up a full Ruby context for execution. I suspect something isn't quite right with this logic, and while it's doing lightweight rescue logic it's still doing the heavier-weight return logic, which then bubbles all the way out of the script.

I should be able to find a fix. Worst case, I can simply use heavyweight exception-handling, but I'd like to ensure the lightweight version works.

@headius
Owner

Additional note: the AOT compile does not treat the "begin" form as a lightweight handler, so it does the slower version. That fits as well.

@headius
Owner

Yeah, as suspected, it's using heavyweight "return" logic that throws a ReturnJump exception, expecting it has to unroll through heavyweight "rescue" logic. I have a trivial fix I'm testing: https://gist.github.com/headius/413e3a9a393be89410fc

@headius headius closed this in ba4df82
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.