From 19ac874c28abab1a43db423b658be134b5794de2 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 31 Jul 2024 11:48:35 -0500 Subject: [PATCH] Eliminate dynscope for leaf blocks with break/return 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. --- .../java/org/jruby/ir/builder/IRBuilder.java | 2 +- .../org/jruby/ir/instructions/BreakInstr.java | 2 +- .../jruby/ir/instructions/CheckForLJEInstr.java | 2 +- .../org/jruby/ir/runtime/IRRuntimeHelpers.java | 16 +++++++++------- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/jruby/ir/builder/IRBuilder.java b/core/src/main/java/org/jruby/ir/builder/IRBuilder.java index bf4a9d6db56..44877fe76f6 100644 --- a/core/src/main/java/org/jruby/ir/builder/IRBuilder.java +++ b/core/src/main/java/org/jruby/ir/builder/IRBuilder.java @@ -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); diff --git a/core/src/main/java/org/jruby/ir/instructions/BreakInstr.java b/core/src/main/java/org/jruby/ir/instructions/BreakInstr.java index d587640e113..40dc86b940b 100644 --- a/core/src/main/java/org/jruby/ir/instructions/BreakInstr.java +++ b/core/src/main/java/org/jruby/ir/instructions/BreakInstr.java @@ -47,7 +47,7 @@ public Operand getReturnValue() { @Override public boolean computeScopeFlags(IRScope scope, EnumSet flags) { scope.setHasBreakInstructions(); - flags.add(IRFlags.REQUIRES_DYNSCOPE); +// flags.add(IRFlags.REQUIRES_DYNSCOPE); return true; } diff --git a/core/src/main/java/org/jruby/ir/instructions/CheckForLJEInstr.java b/core/src/main/java/org/jruby/ir/instructions/CheckForLJEInstr.java index 01f29e61f9b..e84a68f886c 100644 --- a/core/src/main/java/org/jruby/ir/instructions/CheckForLJEInstr.java +++ b/core/src/main/java/org/jruby/ir/instructions/CheckForLJEInstr.java @@ -74,7 +74,7 @@ public void check(ThreadContext context, DynamicScope dynamicScope, Block block) @Override public boolean computeScopeFlags(IRScope scope, EnumSet flags) { super.computeScopeFlags(scope, flags); - flags.add(IRFlags.REQUIRES_DYNSCOPE); + //flags.add(IRFlags.REQUIRES_DYNSCOPE); return true; } } diff --git a/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java b/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java index b927ce2fc9d..e726ffe0609 100644 --- a/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java +++ b/core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java @@ -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); @@ -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. @@ -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?