Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: f50b49513a1a
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 18e602d21224
Choose a head ref
  • 5 commits
  • 10 files changed
  • 1 contributor

Commits on May 29, 2015

  1. Copy the full SHA
    c69b44e View commit details
  2. Copy the full SHA
    96f3e87 View commit details
  3. Copy the full SHA
    2e67fd9 View commit details
  4. Copy the full SHA
    e2b9dae View commit details
  5. [Truffle] Rename BlockID to BreakID.

    * So it makes sense to use them as well for while/until loops.
    eregon committed May 29, 2015
    4
    Copy the full SHA
    18e602d View commit details
8 changes: 8 additions & 0 deletions spec/ruby/language/break_spec.rb
Original file line number Diff line number Diff line change
@@ -16,6 +16,14 @@
@program.break_value
ScratchPad.recorded.should == [:a, :aa, :b, :break, :d]
end

describe "yielded inside a while" do
it "breaks out of the block" do
value = @program.break_in_block_in_while
ScratchPad.recorded.should == [:aa, :break]
value.should == :value
end
end
end

describe "The break statement in a captured block" do
19 changes: 19 additions & 0 deletions spec/ruby/language/fixtures/break.rb
Original file line number Diff line number Diff line change
@@ -109,6 +109,25 @@ def break_in_yielding_method
def method(v)
yield v
end

def invoke_yield_in_while
looping = true
while looping
note :aa
yield
note :bb
looping = false
end
note :should_not_reach_here
end

def break_in_block_in_while
invoke_yield_in_while do
note :break
break :value
note :c
end
end
end

class Lambda < Driver
Original file line number Diff line number Diff line change
@@ -14,23 +14,23 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.BreakException;
import org.jruby.truffle.translator.TranslatorEnvironment.BlockID;
import org.jruby.truffle.translator.TranslatorEnvironment.BreakID;

public class BreakNode extends RubyNode {

private final BlockID blockID;
private final BreakID breakID;

@Child private RubyNode child;

public BreakNode(RubyContext context, SourceSection sourceSection, BlockID blockID, RubyNode child) {
public BreakNode(RubyContext context, SourceSection sourceSection, BreakID breakID, RubyNode child) {
super(context, sourceSection);
this.blockID = blockID;
this.breakID = breakID;
this.child = child;
}

@Override
public Object execute(VirtualFrame frame) {
throw new BreakException(blockID, child.execute(frame));
throw new BreakException(breakID, child.execute(frame));
}

}
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.methods.SharedMethodInfo;
import org.jruby.truffle.translator.TranslatorEnvironment.BlockID;
import org.jruby.truffle.translator.TranslatorEnvironment.BreakID;

/**
* Create a RubyProc to pass as a block to the called method.
@@ -37,11 +37,11 @@ public class BlockDefinitionNode extends RubyNode {
private final CallTarget callTargetForMethods;

private final boolean requiresDeclarationFrame;
private final BlockID blockID;
private final BreakID breakID;

public BlockDefinitionNode(RubyContext context, SourceSection sourceSection, SharedMethodInfo sharedMethodInfo,
boolean requiresDeclarationFrame, CallTarget callTargetForBlocks,
CallTarget callTargetForProcs, CallTarget callTargetForMethods, BlockID blockID) {
CallTarget callTargetForProcs, CallTarget callTargetForMethods, BreakID breakID) {
super(context, sourceSection);
this.sharedMethodInfo = sharedMethodInfo;

@@ -50,11 +50,11 @@ public BlockDefinitionNode(RubyContext context, SourceSection sourceSection, Sha
this.callTargetForMethods = callTargetForMethods;

this.requiresDeclarationFrame = requiresDeclarationFrame;
this.blockID = blockID;
this.breakID = breakID;
}

public BlockID getBlockID() {
return blockID;
public BreakID getBreakID() {
return breakID;
}

@Override
Original file line number Diff line number Diff line change
@@ -16,24 +16,25 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.BreakException;
import org.jruby.truffle.translator.TranslatorEnvironment.BlockID;
import org.jruby.truffle.translator.TranslatorEnvironment.BreakID;

/**
* Catch a {@code break} jump in a block at the top level and handle it as a return.
* Catch a {@code break} from a call with a block containing a break
* or inside a while/until loop.
*/
public class CatchBreakFromCallNode extends RubyNode {
public class CatchBreakNode extends RubyNode {

@Child private RubyNode body;

private final BlockID blockID;
private final BreakID breakID;

private final BranchProfile breakProfile = BranchProfile.create();
private final ConditionProfile matchingBreakProfile = ConditionProfile.createCountingProfile();

public CatchBreakFromCallNode(RubyContext context, SourceSection sourceSection, RubyNode body, BlockID blockID) {
public CatchBreakNode(RubyContext context, SourceSection sourceSection, RubyNode body, BreakID breakID) {
super(context, sourceSection);
this.body = body;
this.blockID = blockID;
this.breakID = breakID;
}

@Override
@@ -43,7 +44,7 @@ public Object execute(VirtualFrame frame) {
} catch (BreakException e) {
breakProfile.enter();

if (matchingBreakProfile.profile(e.getBlockID() == blockID)) {
if (matchingBreakProfile.profile(e.getBreakID() == breakID)) {
return e.getResult();
} else {
throw e;
Original file line number Diff line number Diff line change
@@ -10,23 +10,23 @@
package org.jruby.truffle.runtime.control;

import com.oracle.truffle.api.nodes.ControlFlowException;
import org.jruby.truffle.translator.TranslatorEnvironment.BlockID;
import org.jruby.truffle.translator.TranslatorEnvironment.BreakID;

/**
* Controls a break from a control structure or method.
*/
public final class BreakException extends ControlFlowException {

private final BlockID blockID;
private final BreakID breakID;
private final Object result;

public BreakException(BlockID blockID, Object result) {
this.blockID = blockID;
public BreakException(BreakID breakID, Object result) {
this.breakID = breakID;
this.result = result;
}

public BlockID getBlockID() {
return blockID;
public BreakID getBreakID() {
return breakID;
}

public Object getResult() {
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;

import org.jcodings.specific.ASCIIEncoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
@@ -77,6 +78,7 @@
import org.jruby.truffle.runtime.methods.Arity;
import org.jruby.truffle.runtime.methods.SharedMethodInfo;
import org.jruby.truffle.runtime.array.ArrayUtils;
import org.jruby.truffle.translator.TranslatorEnvironment.BreakID;
import org.jruby.util.ByteList;
import org.jruby.util.KeyValuePair;
import org.jruby.util.StringSupport;
@@ -367,12 +369,7 @@ public RubyNode visitBlockNode(org.jruby.ast.BlockNode node) {

@Override
public RubyNode visitBreakNode(org.jruby.ast.BreakNode node) {
if (!(environment.isBlock() || translatingWhile)) {
// TODO(CS 10-Jan-15): must raise a proper exception rather, but not sure if it should be a JRuby exception or a Truffle one
System.err.printf("%s:%d: Invalid break%n", node.getPosition().getFile(), node.getPosition().getLine() + 1);
System.err.printf("%s: compile error (SyntaxError)%n", node.getPosition().getFile());
System.exit(1);
}
assert environment.isBlock() || translatingWhile : "The parser did not see an invalid break";

final SourceSection sourceSection = translate(node.getPosition());

@@ -390,7 +387,7 @@ public RubyNode visitBreakNode(org.jruby.ast.BreakNode node) {
resultNode = node.getValueNode().accept(this);
}

return new BreakNode(context, sourceSection, environment.getBlockID(), resultNode);
return new BreakNode(context, sourceSection, environment.getBreakID(), resultNode);
}

@Override
@@ -616,7 +613,7 @@ public RubyNode visitCallNodeExtraArgument(CallNode node, RubyNode extraArgument

if (argumentsAndBlock.getBlock() instanceof BlockDefinitionNode) { // if we have a literal block, break breaks out of this call site
BlockDefinitionNode blockDef = (BlockDefinitionNode) argumentsAndBlock.getBlock();
translated = new CatchBreakFromCallNode(context, sourceSection, translated, blockDef.getBlockID());
translated = new CatchBreakNode(context, sourceSection, translated, blockDef.getBreakID());
}

// return instrumenter.instrumentAsCall(translated, node.getName());
@@ -1717,7 +1714,7 @@ public RubyNode visitIterNode(org.jruby.ast.IterNode node) {

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(
context, environment, environment.getParseEnvironment(), environment.getReturnID(), hasOwnScope, false,
sharedMethodInfo, environment.getNamedMethodName(), true, environment.getParseEnvironment().allocateBlockID());
sharedMethodInfo, environment.getNamedMethodName(), true, environment.getParseEnvironment().allocateBreakID());
final MethodTranslator methodCompiler = new MethodTranslator(currentNode, context, this, newEnvironment, true, source, argsNode);
methodCompiler.translatingForStatement = translatingForStatement;

@@ -2731,8 +2728,12 @@ private RubyNode visitWhileNode(org.jruby.ast.WhileNode node, boolean conditionI
}

final RubyNode body;
final BreakID whileBreakID = environment.getParseEnvironment().allocateBreakID();

final boolean oldTranslatingWhile = translatingWhile;
translatingWhile = true;
BreakID oldBreakID = environment.getBreakID();
environment.setBreakIDForWhile(whileBreakID);
try {
if (node.getBodyNode().isNil()) {
body = new DefinedWrapperNode(context, sourceSection,
@@ -2742,6 +2743,7 @@ private RubyNode visitWhileNode(org.jruby.ast.WhileNode node, boolean conditionI
body = node.getBodyNode().accept(this);
}
} finally {
environment.setBreakIDForWhile(oldBreakID);
translatingWhile = oldTranslatingWhile;
}

@@ -2753,7 +2755,7 @@ private RubyNode visitWhileNode(org.jruby.ast.WhileNode node, boolean conditionI
loop = WhileNode.createDoWhile(context, sourceSection, condition, body);
}

return new CatchBreakFromCallNode(context, sourceSection, loop, environment.getBlockID());
return new CatchBreakNode(context, sourceSection, loop, whileBreakID);
}

@Override
@@ -2847,7 +2849,7 @@ public RubyNode visitLambdaNode(org.jruby.ast.LambdaNode node) {

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(
context, environment, environment.getParseEnvironment(), environment.getReturnID(), false, false,
sharedMethodInfo, sharedMethodInfo.getName(), true, environment.getParseEnvironment().allocateBlockID());
sharedMethodInfo, sharedMethodInfo.getName(), true, environment.getParseEnvironment().allocateBreakID());
final MethodTranslator methodCompiler = new MethodTranslator(currentNode, context, this, newEnvironment, false, source, argsNode);

final RubyNode definitionNode = methodCompiler.compileFunctionNode(translate(node.getPosition()), sharedMethodInfo.getName(), node.getBodyNode(), sharedMethodInfo);
Original file line number Diff line number Diff line change
@@ -243,7 +243,7 @@ public RubyNode compileFunctionNode(SourceSection sourceSection, String methodNa
final CallTarget callTargetAsMethod = Truffle.getRuntime().createCallTarget(newRootNodeWithCatchReturn);

return new BlockDefinitionNode(context, sourceSection, environment.getSharedMethodInfo(),
environment.needsDeclarationFrame(), callTargetAsBlock, callTargetAsProc, callTargetAsMethod, environment.getBlockID());
environment.needsDeclarationFrame(), callTargetAsBlock, callTargetAsProc, callTargetAsMethod, environment.getBreakID());
} else {
return new MethodDefinitionNode(context, sourceSection, methodName, environment.getSharedMethodInfo(),
environment.needsDeclarationFrame(), Truffle.getRuntime().createCallTarget(rootNode));
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@

import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.translator.TranslatorEnvironment.BlockID;
import org.jruby.truffle.translator.TranslatorEnvironment.BreakID;

/**
* Translator environment, unique per parse/translation.
@@ -48,8 +48,8 @@ public long allocateReturnID() {
return allocated;
}

public BlockID allocateBlockID() {
return new BlockID();
public BreakID allocateBreakID() {
return new BreakID();
}

}
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@

public class TranslatorEnvironment {

public static class BlockID {
public static class BreakID {
};

private final RubyContext context;
@@ -38,7 +38,7 @@ public static class BlockID {

private final long returnID;
private final boolean isBlock;
private final BlockID blockID;
private BreakID breakID;

private final boolean ownScopeForAssignments;
private final boolean neverAssignInParentScope;
@@ -56,7 +56,7 @@ public static class BlockID {

public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, ParseEnvironment parseEnvironment,
long returnID, boolean ownScopeForAssignments, boolean neverAssignInParentScope,
SharedMethodInfo sharedMethodInfo, String namedMethodName, boolean isBlock, BlockID blockID,
SharedMethodInfo sharedMethodInfo, String namedMethodName, boolean isBlock, BreakID breakID,
FrameDescriptor frameDescriptor) {
this.context = context;
this.parent = parent;
@@ -67,15 +67,14 @@ public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent,
this.neverAssignInParentScope = neverAssignInParentScope;
this.sharedMethodInfo = sharedMethodInfo;
this.namedMethodName = namedMethodName;
assert isBlock == (blockID != null);
this.isBlock = isBlock;
this.blockID = blockID;
this.breakID = breakID;
}

public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, ParseEnvironment parseEnvironment,
long returnID, boolean ownScopeForAssignments, boolean neverAssignInParentScope,
SharedMethodInfo methodIdentifier, String namedMethodName, boolean isBlock, BlockID blockID) {
this(context, parent, parseEnvironment, returnID, ownScopeForAssignments, neverAssignInParentScope, methodIdentifier, namedMethodName, isBlock, blockID,
SharedMethodInfo methodIdentifier, String namedMethodName, boolean isBlock, BreakID breakID) {
this(context, parent, parseEnvironment, returnID, ownScopeForAssignments, neverAssignInParentScope, methodIdentifier, namedMethodName, isBlock, breakID,
new FrameDescriptor(context.getCoreLibrary().getNilObject()));
}

@@ -221,7 +220,12 @@ public boolean isBlock() {
return isBlock;
}

public BlockID getBlockID() {
return blockID;
public BreakID getBreakID() {
return breakID;
}

public void setBreakIDForWhile(BreakID breakID) {
this.breakID = breakID;
}

}