Skip to content

Commit

Permalink
Showing 4 changed files with 37 additions and 41 deletions.
4 changes: 4 additions & 0 deletions core/src/main/java/org/jruby/ir/IRScopeType.java
Original file line number Diff line number Diff line change
@@ -12,6 +12,10 @@ public static IRScopeType fromOrdinal(int ordinal) {
return VALUES[ordinal];
}

public boolean isEval() {
return this == EVAL_SCRIPT;
}

public boolean isMethodType() {
return this == INSTANCE_METHOD || this == CLASS_METHOD;
}
18 changes: 10 additions & 8 deletions core/src/main/java/org/jruby/ir/runtime/IRBreakJump.java
Original file line number Diff line number Diff line change
@@ -3,22 +3,24 @@
import org.jruby.exceptions.Unrescuable;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.cli.Options;

public class IRBreakJump extends IRJump implements Unrescuable {
public DynamicScope scopeToReturnTo;
public IRubyObject breakValue;
public boolean caughtByLambda;
public final DynamicScope scopeToReturnTo;
public final IRubyObject breakValue;
public boolean breakInEval;

private IRBreakJump(DynamicScope scopeToReturnTo, IRubyObject rv) {
private IRBreakJump(DynamicScope scopeToReturnTo, IRubyObject rv, boolean breakInEval) {
this.scopeToReturnTo = scopeToReturnTo;
this.breakValue = rv;
this.caughtByLambda = false;
this.breakInEval = false;
this.breakInEval = breakInEval;
}

@Deprecated
public static IRBreakJump create(DynamicScope scopeToReturnTo, IRubyObject rv) {
return new IRBreakJump(scopeToReturnTo, rv);
return new IRBreakJump(scopeToReturnTo, rv, false);
}

public static IRBreakJump create(DynamicScope scopeToReturnTo, IRubyObject rv, boolean breakInEval) {
return new IRBreakJump(scopeToReturnTo, rv, breakInEval);
}
}
55 changes: 23 additions & 32 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -157,7 +157,7 @@ public static IRubyObject handleNonlocalReturn(StaticScope scope, DynamicScope d
} else {
IRReturnJump rj = (IRReturnJump)rjExc;

// If we are in the method scope we are supposed to return from, stop propagating.
// If we are in the method scope we are supposed to return from, stop p<ropagating.
if (rj.methodToReturnFrom == dynScope) {
if (isDebug()) System.out.println("---> Non-local Return reached target in scope: " + dynScope + " matching dynscope? " + (rj.methodToReturnFrom == dynScope));
return (IRubyObject) rj.returnValue;
@@ -168,30 +168,26 @@ public static IRubyObject handleNonlocalReturn(StaticScope scope, DynamicScope d
}
}

// Is the current dynamicScope we pass in representing a closure (or eval which is impld internally as closure)?
private static IRScopeType ensureScopeIsClosure(ThreadContext context, DynamicScope dynamicScope) {
IRScopeType scopeType = dynamicScope.getStaticScope().getScopeType();

// Error -- breaks can only be initiated in closures
if (!scopeType.isClosureType()) throw IRException.BREAK_LocalJumpError.getException(context.runtime);

return scopeType;
}

// FIXME: When we recompile lambdas we can eliminate this binary code path and we can emit as a NONLOCALRETURN directly.
public static IRubyObject initiateBreak(ThreadContext context, DynamicScope dynScope, IRubyObject breakValue, Block.Type blockType) throws RuntimeException {
if (inLambda(blockType)) {
// Wrap the return value in an exception object
// and push it through the break exception paths so
// that ensures are run, frames/scopes are popped
// from runtime stacks, etc.
throw new IRWrappedLambdaReturnValue(breakValue);
} else {
StaticScope scope = dynScope.getStaticScope();
IRScopeType scopeType = scope.getScopeType();
if (!scopeType.isClosureType()) {
// Error -- breaks can only be initiated in closures
throw IRException.BREAK_LocalJumpError.getException(context.runtime);
}
// Wrap the return value in an exception object and push it through the break exception
// paths so that ensures are run, frames/scopes are popped from runtime stacks, etc.
if (inLambda(blockType)) throw new IRWrappedLambdaReturnValue(breakValue);

IRBreakJump bj = IRBreakJump.create(dynScope.getParentScope(), breakValue);
if (scopeType == IRScopeType.EVAL_SCRIPT) {
// If we are in an eval, record it so we can account for it
bj.breakInEval = true;
}
IRScopeType scopeType = ensureScopeIsClosure(context, dynScope);

// Start the process of breaking through the intermediate scopes
throw bj;
}
// Raise a break jump so we can bubble back down the stack to the appropriate place to break from.
throw IRBreakJump.create(dynScope.getParentScope(), breakValue, scopeType.isEval()); // weirdly evals are impld as closures...yes yes.
}

// Are we within the scope where we want to return the value we are passing down the stack?
@@ -240,16 +236,11 @@ public static IRubyObject handlePropagatedBreak(ThreadContext context, DynamicSc

IRBreakJump bj = (IRBreakJump)bjExc;
if (bj.breakInEval) {
// If the break was in an eval, we pretend as if it was in the containing scope
StaticScope scope = dynScope.getStaticScope();
IRScopeType scopeType = scope.getScopeType();
if (!scopeType.isClosureType()) {
// Error -- breaks can only be initiated in closures
throw IRException.BREAK_LocalJumpError.getException(context.runtime);
} else {
bj.breakInEval = false;
throw bj;
}
// If the break was in an eval, we pretend as if it was in the containing scope.
ensureScopeIsClosure(context, dynScope);

bj.breakInEval = false;
throw bj;
} else if (bj.scopeToReturnTo == dynScope) {
// Done!! Hurray!
if (isDebug()) System.out.println("---> Break reached target in scope: " + dynScope);
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@

import org.jruby.exceptions.Unrescuable;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.cli.Options;

// This class is just a thin wrapper around a return value
// from nonlocal-return and break instructions.

0 comments on commit e6358f6

Please sign in to comment.