break within a block throws LocalJumpError in JRuby but succeeds in MRI Ruby #4369

Closed
amarkowitz opened this Issue Dec 8, 2016 · 6 comments

Projects

None yet

5 participants

@amarkowitz

Environment

user_name@ ~/dev/scripts$ jruby --version
jruby 9.1.5.0 (2.3.1) 2016-09-07 036ce39 Java HotSpot(TM) 64-Bit Server VM 25.112-b16 on 1.8.0_112-b16 +jit [darwin-x86_64]
user_name@ ~/dev/scripts$ uname -a
Darwin MACHINE_NAME 16.1.0 Darwin Kernel Version 16.1.0: Wed Oct 19 20:31:56 PDT 2016; root:xnu-3789.21.4~4/RELEASE_X86_64 x86_64

Test Code

def lambda_calls_block
  lambda { yield }.call
end

f = nil
lambda_calls_block do
  f = 'a'
  break
end

puts f

Expected Behavior

I expect the above code to print a to the console.

Actual Behavior

MRI Ruby 2.3.0

user_name@ ~/dev/scripts$ rvm use ruby-2.3.0
Using /Users/user/.rvm/gems/ruby-2.3.0
user_name@ ~/dev/scripts$ ruby break_probs.rb 
a

JRuby behavior in 9.1.6.0, 9.1.5.0 and 1.7.19 is to throw a LocalJumpError:

user_name@ ~/dev/scripts$ rvm use jruby-9.1.6.0
Using /Users/user/.rvm/gems/jruby-9.1.6.0
user_name@ ~/dev/scripts$ ruby break_probs.rb 
LocalJumpError: unexpected break
  block in lambda_calls_block at break_probs.rb:2
           lambda_calls_block at break_probs.rb:2
                       <main> at break_probs.rb:6
user_name@ ~/dev/scripts$ rvm use jruby-9.1.5.0
Using /Users/user/.rvm/gems/jruby-9.1.5.0
user_name@ ~/dev/scripts$ ruby break_probs.rb 
LocalJumpError: unexpected break
  block in lambda_calls_block at break_probs.rb:2
           lambda_calls_block at break_probs.rb:2
                       <main> at break_probs.rb:6
user_name@ ~/dev/scripts$ rvm use jruby-1.7.19
Using /Users/user/.rvm/gems/jruby-1.7.19
user_name@ ~/dev/scripts$ ruby break_probs.rb 
LocalJumpError: unexpected break
                call at org/jruby/RubyProc.java:271
  lambda_calls_block at break_probs.rb:2
              (root) at break_probs.rb:6
@headius
Member
headius commented Dec 8, 2016

I'm surprised this works on MRI. I was under the impression that break can never escape a lambda body.

Confirmed on master:

[] ~/projects/jruby $ ruby23 -e "def foo; lambda { yield }.call; end; foo { break }"

[] ~/projects/jruby $ jruby -e "def foo; lambda { yield }.call; end; foo { break }"
LocalJumpError: unexpected break
...

Note that it works fine if you change the lambda to a proc. I suspect we're just preventing all non-local flow control from escaping a proper lambda.

This may be an IR thing or just a Proc thing.

cc @subbuss @enebo

@headius
Member
headius commented Dec 8, 2016

This works correctly in JRuby 1.7.25.

@deangelo-llooker
deangelo-llooker commented Dec 8, 2016 edited

The commit that was possibly regressed was between 1.7.19 and 1.7.20.

$ rvm use jruby-1.7.20
Using /home/miked/.rvm/gems/jruby-1.7.20
$ ruby -v
jruby 1.7.20 (1.9.3p551) 2015-05-04 3086e6a on Java HotSpot(TM) 64-Bit Server VM 1.8.0_112-b15 +jit [linux-amd64]
$ ruby -e "def foo; lambda { yield }.call; end; foo { break }"

$ rvm use jruby-1.7.19
Using /home/miked/.rvm/gems/jruby-1.7.19
$ ruby -v
jruby 1.7.19 (1.9.3p551) 2015-01-29 20786bd on Java HotSpot(TM) 64-Bit Server VM 1.8.0_112-b15 +jit [linux-amd64]
$ ruby -e "def foo; lambda { yield }.call; end; foo { break }"
LocalJumpError: unexpected break
    call at org/jruby/RubyProc.java:271
     foo at -e:1
  (root) at -e:1
@deangelo-llooker

I think this is the commit that originally fixed it, but then the code was refactored for 9k. e61b737

@subbuss
Contributor
subbuss commented Dec 13, 2016

https://github.com/jruby/jruby/blob/9dfb9556fd5d2fe3b939d93bd190ec3afa09761f/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java#L205-L207 has logic that always triggers a LocalJumpError for non-local breaks (which a break from a yield is considered) in a lambda. Maybe this logic is stale? I cannot keep this straight anymore since it has been a long time, but are there scenarios where breaks in lambdas trigger a local jump error?

@enebo
Member
enebo commented Dec 13, 2016

I cannot find any case where lambda cannot contain a break. If someone can chime in on an error case it would be great.

@headius headius added this to the JRuby 9.1.7.0 milestone Jan 6, 2017
@enebo enebo closed this Jan 10, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment