Skip to content

Fixes #5517 (returns in unexpected place)#5527

Merged
enebo merged 11 commits intomasterfrom
gh5517
Dec 19, 2018
Merged

Fixes #5517 (returns in unexpected place)#5527
enebo merged 11 commits intomasterfrom
gh5517

Conversation

@enebo
Copy link
Member

@enebo enebo commented Dec 17, 2018

My main commit explains most of the details of what changed. See #5517 for more on what was broken.

An extra thing corrected here was that most returns within END blocks can be
statically determined so an LJE replaces the return during build time.  This
was a minor part of this but I mention it to get it out of the way.

The main fix was to change how we initiate a non-local return from a closure.
This commit changes from primarily walking a dynamic scope stack to walking
the static scope stack.   There are two reasons for this:

1. visibility to scopes which we do not add variables for
2. JITing may eliminate dynamic scopes

So the new mechanism uses getContainingReturnToScope.  As an added bonus
both checkForLJE and initiateNonLocalReturn use the same method now.  Before
the two methods were very very similar but one used IR and the other used
dynamic scope.

There is a tiny wrinkle to the new way but it does make sense.  static scope
is static but not all information we need is static.  We cannot know if a
closure will be a proc or a lambda.  So when we initiate a non-local return
so long as we are within closures we check dynamic scopes looking to see if
we are within a lambda (getContainingLambda).

My only wonderment of this whole commit is runInterpreter added a catch to
for IRReturnJump.  This is definitely ok to have here but I wonder if it
covers all paths into execution or not?  Is there another place where we should
add a catch?
@enebo enebo added this to the JRuby 9.2.6.0 milestone Dec 17, 2018
@enebo enebo requested review from headius and removed request for headius December 17, 2018 22:51
@enebo
Copy link
Member Author

enebo commented Dec 17, 2018

ok found some errors to fix with full spec run

…e to

research after this commit).

I could not originally reproduce this locally, but then I ran the tests
by doing ```jruby -S rake spec``` which ran core specs + other tests.  Our run
in CI does ```jruby spec/core_spec.rb``` which will compile the file
spec/core_spec.rb.

The issue found from this is CompileIRBlockBody seems to realize it has no
variables and that it then makes no dynamicScope.  I guard against no dynamic
scope now, but could this non-dynamicscope block end up being where we want
to return from?  I don't think so.  I have tried define_method and explicit
lambda and I see no failures....
… a better

way by using the IRScope.  This was what handBreakAndReturnsInLambda actually
wanted in the end and it allows JIT to not care about whether it will make a
dynamic scope or not...win win.
@enebo enebo requested a review from headius December 18, 2018 17:33
if (scope.isWithinEND()) {
// ENDs do not allow returns
addInstr(new ThrowExceptionInstr(IRException.RETURN_LocalJumpError));
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MRI doesn't appear to statically determine this, or else they just immediately bail out without propagating an exception. Probably doesn't matter that we actually raise? Maybe better?

[] ~/projects/jruby $ rvm ruby-2.5.3 do ruby -e 'END { begin; return; rescue Exception => e; p e; else; puts "not caught"; end }'
-e: unexpected return

[] ~/projects/jruby $ jruby -e 'END { begin; return; rescue Exception => e; p e; else; puts "not caught"; end }'
#<LocalJumpError: unexpected return>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah hmm. I did not consider the ability to catch. I do actually consider how we do it to be more correct but of course we emulate them...Even if we change this I would prefer to follow up on this in another PR/commit later. This is better than our escape crash. I also am not very concerned about this behavioral difference?

Copy link
Member

@headius headius Dec 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds fine to me.

public final Object returnValue;

private IRReturnJump(DynamicScope scopeToReturnFrom, Object rv) {
private IRReturnJump(IRScope returnScope, IRScope scopeToReturnFrom, Object rv) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming is a little weird here...these mean the same thing in my head.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returnScope is the scope where the return lives and scopeToReturnFrmo is where the return will exit from. I am happy to change those though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe sourceScope and targetScope, or returnScope and targetScope? Entirely up to you, it's a minor issue.

@enebo
Copy link
Member Author

enebo commented Dec 19, 2018

With these two reverts we pass all tests and one extra weird test I know fails...master also failed with exact same behavior. Plan after landing this is to re-land these IRScope vs using DynamicScope commits and fix the last weird bug I know about. The remaining issue known is about JITing the same define_method in a loop in the root scope.

@enebo enebo merged commit 5f56415 into master Dec 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants