Skip to content

Commit

Permalink
Eliminate dynscope for leaf blocks with break/return
Browse files Browse the repository at this point in the history
This is a patch to eliminate the need to push a new DynamicScope
for leaf blocks that have non-local flow control (break or return)
by using the self block's binding's DynamicScope to find the
jump target.
  • Loading branch information
headius committed Jul 31, 2024
1 parent 025a424 commit 19ac874
Show file tree
Hide file tree
Showing 4 changed files with 12 additions and 10 deletions.
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/builder/IRBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ private void calculateClosureScopeFlags() {
}

private boolean computeNeedsDynamicScopeFlag() {
return scope.hasNonLocalReturns() ||
return //scope.hasNonLocalReturns() ||
scope.canCaptureCallersBinding() ||
scope.canReceiveNonlocalReturns() ||
flags.contains(BINDING_HAS_ESCAPED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public Operand getReturnValue() {
@Override
public boolean computeScopeFlags(IRScope scope, EnumSet<IRFlags> flags) {
scope.setHasBreakInstructions();
flags.add(IRFlags.REQUIRES_DYNSCOPE);
// flags.add(IRFlags.REQUIRES_DYNSCOPE);
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public void check(ThreadContext context, DynamicScope dynamicScope, Block block)
@Override
public boolean computeScopeFlags(IRScope scope, EnumSet<IRFlags> flags) {
super.computeScopeFlags(scope, flags);
flags.add(IRFlags.REQUIRES_DYNSCOPE);
//flags.add(IRFlags.REQUIRES_DYNSCOPE);
return true;
}
}
16 changes: 9 additions & 7 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public static boolean inProc(Block.Type blockType) {
public static void checkForLJE(ThreadContext context, DynamicScope currentScope, boolean definedWithinMethod, Block block) {
if (inLambda(block.type)) return; // break/return in lambda is unconditionally a return.

DynamicScope returnToScope = getContainingReturnToScope(currentScope);
DynamicScope returnToScope = getContainingReturnToScope(block.getBinding().getDynamicScope());

if (returnToScope == null || !context.scopeExistsOnCallStack(returnToScope)) {
throw IRException.RETURN_LocalJumpError.getException(context.runtime);
Expand Down Expand Up @@ -163,13 +163,14 @@ private static DynamicScope getContainingLambda(DynamicScope dynamicScope) {
public static IRubyObject initiateNonLocalReturn(DynamicScope currentScope, Block block, IRubyObject returnValue) {
if (block != null && inLambda(block.type)) throw new IRWrappedLambdaReturnValue(returnValue);

DynamicScope returnToScope = getContainingLambda(currentScope);
DynamicScope parentScope = block.getBinding().getDynamicScope();
DynamicScope returnToScope = getContainingLambda(parentScope);

if (returnToScope == null) returnToScope = getContainingReturnToScope(currentScope);
if (returnToScope == null) returnToScope = getContainingReturnToScope(parentScope);

assert returnToScope != null: "accidental return scope";

throw IRReturnJump.create(currentScope.getStaticScope(), returnToScope, returnValue);
throw IRReturnJump.create(block.getBody().getStaticScope(), returnToScope, returnValue);
}

// Finds static scope of where we want to *return* to.
Expand Down Expand Up @@ -217,16 +218,17 @@ public static IRubyObject initiateBreak(ThreadContext context, DynamicScope dynS
// paths so that ensures are run, frames/scopes are popped from runtime stacks, etc.
if (inLambda(block.type)) throw new IRWrappedLambdaReturnValue(breakValue, true);

IRScopeType scopeType = ensureScopeIsClosure(context, dynScope);
DynamicScope parentScope = block.getBinding().getDynamicScope();
// IRScopeType scopeType = ensureScopeIsClosure(context, parentScope);

DynamicScope parentScope = dynScope.getParentScope();
// DynamicScope parentScope = dynScope.getParentScope();

if (block.isEscaped()) {
throw Helpers.newLocalJumpErrorForBreak(context.runtime, breakValue);
}

// Raise a break jump so we can bubble back down the stack to the appropriate place to break from.
throw IRBreakJump.create(parentScope, breakValue, scopeType.isEval()); // weirdly evals are impld as closures...yes yes.
throw IRBreakJump.create(parentScope, breakValue, false);
}

// Are we within the scope where we want to return the value we are passing down the stack?
Expand Down

0 comments on commit 19ac874

Please sign in to comment.