Skip to content

Commit

Permalink
Showing 17 changed files with 226 additions and 76 deletions.
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ public Object execute(VirtualFrame frame) {
// TODO(CS): not sure we're closing over the correct state here

return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.LAMBDA,
method.getSharedMethodInfo(), method.getCallTarget(), method.getCallTarget(),
method.getSharedMethodInfo(), method.getCallTarget(), method.getCallTarget(), method.getCallTarget(),
method.getDeclarationFrame(), method.getDeclaringModule(), method, RubyArguments.getSelf(frame.getArguments()), null);
}

Original file line number Diff line number Diff line change
@@ -13,15 +13,12 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrument.KillException;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.UndefinedPlaceholder;
import org.jruby.truffle.runtime.core.*;

public class TraceNode extends RubyNode {
@@ -70,7 +67,7 @@ public void trace(VirtualFrame frame) {
traceFunc = context.getTraceManager().getTraceFunc();

if (traceFunc != null) {
callNode = insert(Truffle.getRuntime().createDirectCallNode(traceFunc.getCallTarget()));
callNode = insert(Truffle.getRuntime().createDirectCallNode(traceFunc.getCallTargetForBlocks()));
} else {
callNode = null;
}
Original file line number Diff line number Diff line change
@@ -2510,7 +2510,7 @@ public Object max(VirtualFrame frame, RubyArray array) {

final RubyProc block = new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.PROC,
maxBlock.getSharedMethodInfo(), maxBlock.getCallTarget(), maxBlock.getCallTarget(),
maximumClosureFrame.materialize(), null, null, array, null);
maxBlock.getCallTarget(), maximumClosureFrame.materialize(), null, null, array, null);

eachNode.call(frame, array, "each", block);

@@ -2629,7 +2629,7 @@ public Object min(VirtualFrame frame, RubyArray array) {

final RubyProc block = new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.PROC,
minBlock.getSharedMethodInfo(), minBlock.getCallTarget(), minBlock.getCallTarget(),
minimumClosureFrame.materialize(), null, null, array, null);
minBlock.getCallTarget(), minimumClosureFrame.materialize(), null, null, array, null);

eachNode.call(frame, array, "each", block);

Original file line number Diff line number Diff line change
@@ -1240,7 +1240,8 @@ public RubyProc proc(RubyProc block) {

return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.LAMBDA,
block.getSharedMethodInfo(), block.getCallTargetForMethods(), block.getCallTargetForMethods(),
block.getDeclarationFrame(), block.getDeclaringModule(), block.getMethod(), block.getSelfCapturedInScope(), block.getBlockCapturedInScope());
block.getCallTargetForMethods(), block.getDeclarationFrame(), block.getDeclaringModule(),
block.getMethod(), block.getSelfCapturedInScope(), block.getBlockCapturedInScope());
}
}

@@ -1513,8 +1514,9 @@ public RubyProc proc(RubyProc block) {
notDesignedForCompilation();

return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.PROC,
block.getSharedMethodInfo(), block.getCallTarget(), block.getCallTargetForMethods(), block.getDeclarationFrame(),
block.getDeclaringModule(), block.getMethod(), block.getSelfCapturedInScope(), block.getBlockCapturedInScope());
block.getSharedMethodInfo(), block.getCallTargetForProcs(), block.getCallTargetForProcs(),
block.getCallTargetForMethods(), block.getDeclarationFrame(), block.getDeclaringModule(),
block.getMethod(), block.getSelfCapturedInScope(), block.getBlockCapturedInScope());
}
}

Original file line number Diff line number Diff line change
@@ -113,8 +113,10 @@ public InitializeNode(InitializeNode prev) {

@Specialization
public RubyNilClass initialize(RubyProc proc, RubyProc block) {
proc.initialize(block.getSharedMethodInfo(), block.getCallTargetForMethods(), block.getCallTargetForMethods(),
block.getDeclarationFrame(), block.getDeclaringModule(), block.getMethod(), block.getSelfCapturedInScope(), block.getBlockCapturedInScope());
proc.initialize(block.getSharedMethodInfo(), block.getCallTargetForProcs(),
block.getCallTargetForProcs(), block.getCallTargetForMethods(), block.getDeclarationFrame(),
block.getDeclaringModule(), block.getMethod(), block.getSelfCapturedInScope(),
block.getBlockCapturedInScope());

return getContext().getCoreLibrary().getNilObject();
}
Original file line number Diff line number Diff line change
@@ -14,7 +14,6 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyModule;
@@ -30,17 +29,23 @@ public class BlockDefinitionNode extends RubyNode {

private final SharedMethodInfo sharedMethodInfo;

private final CallTarget callTarget;
// TODO(CS, 10-Jan-15) having three call targets isn't ideal, but they all have different semantics, and we don't
// want to move logic into the call site

private final CallTarget callTargetForBlocks;
private final CallTarget callTargetForProcs;
private final CallTarget callTargetForMethods;

private final boolean requiresDeclarationFrame;

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

this.callTarget = callTarget;
this.callTargetForBlocks = callTargetForBlocks;
this.callTargetForProcs = callTargetForProcs;
this.callTargetForMethods = callTargetForMethods;

this.requiresDeclarationFrame = requiresDeclarationFrame;
@@ -68,7 +73,8 @@ public Object execute(VirtualFrame frame) {
}

return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.PROC, sharedMethodInfo,
callTarget, callTargetForMethods, declarationFrame, declaringModule, RubyArguments.getMethod(frame.getArguments()), RubyArguments.getSelf(frame.getArguments()),
callTargetForBlocks, callTargetForProcs, callTargetForMethods, declarationFrame, declaringModule,
RubyArguments.getMethod(frame.getArguments()), RubyArguments.getSelf(frame.getArguments()),
RubyArguments.getBlock(frame.getArguments()));
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.methods;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.BranchProfile;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.BreakException;
import org.jruby.truffle.runtime.control.RaiseException;

public class CatchBreakAsProcErrorNode extends RubyNode {

@Child private RubyNode body;

public CatchBreakAsProcErrorNode(RubyContext context, SourceSection sourceSection, RubyNode body) {
super(context, sourceSection);
this.body = body;
}

@Override
public Object execute(VirtualFrame frame) {
try {
return body.execute(frame);
} catch (BreakException e) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().loadError("break from proc-closure", this));
}
}

}
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ public class CachedYieldDispatchNode extends YieldDispatchNode {
public CachedYieldDispatchNode(RubyContext context, RubyProc block, YieldDispatchNode next) {
super(context);

callNode = Truffle.getRuntime().createDirectCallNode(block.getCallTarget());
callNode = Truffle.getRuntime().createDirectCallNode(block.getCallTargetForBlocks());
insert(callNode);

if (Options.TRUFFLE_INLINER_ALWAYS_CLONE_YIELD.load() && callNode.isCallTargetCloningAllowed()) {
@@ -44,7 +44,7 @@ public CachedYieldDispatchNode(RubyContext context, RubyProc block, YieldDispatc

@Override
public Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects) {
if (block.getCallTarget() != callNode.getCallTarget()) {
if (block.getCallTargetForBlocks() != callNode.getCallTarget()) {
return next.dispatch(frame, block, argumentsObjects);
}

@@ -53,7 +53,7 @@ public Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObj

@Override
public Object dispatchWithModifiedBlock(VirtualFrame frame, RubyProc block, RubyProc modifiedBlock, Object[] argumentsObjects) {
if (block.getCallTarget() != callNode.getCallTarget()) {
if (block.getCallTargetForBlocks() != callNode.getCallTarget()) {
return next.dispatch(frame, block, argumentsObjects);
}

@@ -62,7 +62,7 @@ public Object dispatchWithModifiedBlock(VirtualFrame frame, RubyProc block, Ruby

@Override
public Object dispatchWithModifiedSelf(VirtualFrame frame, RubyProc block, Object self, Object... argumentsObjects) {
if (block.getCallTarget() != callNode.getCallTarget()) {
if (block.getCallTargetForBlocks() != callNode.getCallTarget()) {
return next.dispatchWithModifiedSelf(frame, block, self, argumentsObjects);
}

Original file line number Diff line number Diff line change
@@ -30,17 +30,17 @@ public GeneralYieldDispatchNode(RubyContext context) {

@Override
public Object dispatch(VirtualFrame frame, RubyProc block, Object[] argumentsObjects) {
return callNode.call(frame, block.getCallTarget(), RubyArguments.pack(block, block.getDeclarationFrame(), block.getSelfCapturedInScope(), block.getBlockCapturedInScope(), argumentsObjects));
return callNode.call(frame, block.getCallTargetForBlocks(), RubyArguments.pack(block, block.getDeclarationFrame(), block.getSelfCapturedInScope(), block.getBlockCapturedInScope(), argumentsObjects));
}

@Override
public Object dispatchWithModifiedBlock(VirtualFrame frame, RubyProc block, RubyProc modifiedBlock, Object[] argumentsObjects) {
return callNode.call(frame, block.getCallTarget(), RubyArguments.pack(block, block.getDeclarationFrame(), block.getSelfCapturedInScope(), modifiedBlock, argumentsObjects));
return callNode.call(frame, block.getCallTargetForBlocks(), RubyArguments.pack(block, block.getDeclarationFrame(), block.getSelfCapturedInScope(), modifiedBlock, argumentsObjects));
}

@Override
public Object dispatchWithModifiedSelf(VirtualFrame frame, RubyProc block, Object self, Object... argumentsObjects) {
return callNode.call(frame, block.getCallTarget(), RubyArguments.pack(block, block.getDeclarationFrame(), self, block.getBlockCapturedInScope(), argumentsObjects));
return callNode.call(frame, block.getCallTargetForBlocks(), RubyArguments.pack(block, block.getDeclarationFrame(), self, block.getBlockCapturedInScope(), argumentsObjects));
}

}
36 changes: 24 additions & 12 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyProc.java
Original file line number Diff line number Diff line change
@@ -29,13 +29,15 @@ public class RubyProc extends RubyBasicObject implements MethodLike {
public static final boolean PROC_BINDING = Options.TRUFFLE_PROC_BINDING.load();

public static enum Type {
PROC, LAMBDA
BLOCK, PROC, LAMBDA
}

private final Type type;
@CompilationFinal private SharedMethodInfo sharedMethodInfo;
/** Call target for procs, which have special arguments destructuring */
@CompilationFinal private CallTarget callTarget;
/** Call target for blocks, which have special arguments destructuring */
@CompilationFinal private CallTarget callTargetForBlocks;
/** Call target for actual Proc arguments, which handle break differently */
@CompilationFinal private CallTarget callTargetForProcs;
/** Call target for lambdas and methods, which have strict arguments destructuring */
@CompilationFinal private CallTarget callTargetForMethods;
@CompilationFinal private MaterializedFrame declarationFrame;
@@ -49,16 +51,20 @@ public RubyProc(RubyClass procClass, Type type) {
this.type = type;
}

public RubyProc(RubyClass procClass, Type type, SharedMethodInfo sharedMethodInfo, CallTarget callTarget,
CallTarget callTargetForMethods, MaterializedFrame declarationFrame, RubyModule declaringModule, MethodLike method, Object self, RubyProc block) {
public RubyProc(RubyClass procClass, Type type, SharedMethodInfo sharedMethodInfo, CallTarget callTargetForBlocks,
CallTarget callTargetForProcs, CallTarget callTargetForMethods, MaterializedFrame declarationFrame,
RubyModule declaringModule, MethodLike method, Object self, RubyProc block) {
this(procClass, type);
initialize(sharedMethodInfo, callTarget, callTargetForMethods, declarationFrame, declaringModule, method, self, block);
initialize(sharedMethodInfo, callTargetForBlocks, callTargetForProcs, callTargetForMethods, declarationFrame,
declaringModule, method, self, block);
}

public void initialize(SharedMethodInfo sharedMethodInfo, CallTarget callTarget, CallTarget callTargetForMethods,
MaterializedFrame declarationFrame, RubyModule declaringModule, MethodLike method, Object self, RubyProc block) {
public void initialize(SharedMethodInfo sharedMethodInfo, CallTarget callTargetForBlocks, CallTarget callTargetForProcs,
CallTarget callTargetForMethods, MaterializedFrame declarationFrame, RubyModule declaringModule,
MethodLike method, Object self, RubyProc block) {
this.sharedMethodInfo = sharedMethodInfo;
this.callTarget = callTarget;
this.callTargetForBlocks = callTargetForBlocks;
this.callTargetForProcs = callTargetForProcs;
this.callTargetForMethods = callTargetForMethods;
this.declarationFrame = declarationFrame;
this.declaringModule = declaringModule;
@@ -69,8 +75,10 @@ public void initialize(SharedMethodInfo sharedMethodInfo, CallTarget callTarget,

public CallTarget getCallTargetForType() {
switch (type) {
case BLOCK:
return callTargetForBlocks;
case PROC:
return callTarget;
return callTargetForProcs;
case LAMBDA:
return callTargetForMethods;
}
@@ -94,8 +102,12 @@ public SharedMethodInfo getSharedMethodInfo() {
return sharedMethodInfo;
}

public CallTarget getCallTarget() {
return callTarget;
public CallTarget getCallTargetForBlocks() {
return callTargetForBlocks;
}

public CallTarget getCallTargetForProcs() {
return callTargetForProcs;
}

public CallTarget getCallTargetForMethods() {
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ public RubyProc toProc(SourceSection sourceSection, final RubyNode currentNode)
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);

return new RubyProc(context.getCoreLibrary().getProcClass(), RubyProc.Type.PROC, sharedMethodInfo, callTarget,
callTarget, null, null, null, getContext().getCoreLibrary().getNilObject(), null);
callTarget, callTarget, null, null, null, getContext().getCoreLibrary().getNilObject(), null);
}

public org.jruby.RubySymbol getJRubySymbol() {
Original file line number Diff line number Diff line change
@@ -19,26 +19,26 @@
@NodeInfo(cost = NodeCost.NONE)
public class BehaveAsBlockNode extends RubyNode {

@Child private RubyNode asBlockNode;
@Child private RubyNode asMethodNode;
@Child private RubyNode asBlock;
@Child private RubyNode notAsBlock;

public BehaveAsBlockNode(RubyContext context, SourceSection sourceSection, RubyNode asBlockNode, RubyNode asMethodNode) {
public BehaveAsBlockNode(RubyContext context, SourceSection sourceSection, RubyNode asBlock, RubyNode notAsBlock) {
super(context, sourceSection);
this.asBlockNode = asBlockNode;
this.asMethodNode = asMethodNode;
this.asBlock = asBlock;
this.notAsBlock = notAsBlock;
}

@Override
public Object execute(VirtualFrame frame) {
throw new UnsupportedOperationException();
}

public RubyNode getAsBlockNode() {
return asBlockNode;
public RubyNode getAsBlock() {
return asBlock;
}

public RubyNode getAsMethodNode() {
return asMethodNode;
public RubyNode getNotAsBlock() {
return notAsBlock;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2014, 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.translator;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;

@NodeInfo(cost = NodeCost.NONE)
public class BehaveAsProcNode extends RubyNode {

@Child private RubyNode asProc;
@Child private RubyNode notAsProc;

public BehaveAsProcNode(RubyContext context, SourceSection sourceSection, RubyNode asProc, RubyNode notAsProc) {
super(context, sourceSection);
this.asProc = asProc;
this.notAsProc = notAsProc;
}

@Override
public Object execute(VirtualFrame frame) {
throw new UnsupportedOperationException();
}

public RubyNode getAsProc() {
return asProc;
}

public RubyNode getNotAsProc() {
return notAsProc;
}

}
Original file line number Diff line number Diff line change
@@ -52,6 +52,7 @@
import org.jruby.truffle.nodes.yield.YieldNode;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.methods.SharedMethodInfo;
import org.jruby.util.KeyValuePair;
@@ -73,6 +74,7 @@ public class BodyTranslator extends Translator {
public boolean translatingForStatement = false;
public boolean useClassVariablesAsIfInClass = false;
private boolean translatingNextExpression = false;
private boolean translatingWhile = false;
private String currentCallMethodName = null;

private boolean privately = false;
@@ -325,6 +327,13 @@ 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);
}

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

RubyNode resultNode;
@@ -2461,7 +2470,15 @@ public RubyNode visitWhileNode(org.jruby.ast.WhileNode node) {

final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition);

RubyNode body = node.getBodyNode().accept(this);
translatingWhile = true;

final RubyNode body;

try {
body = node.getBodyNode().accept(this);
} finally {
translatingWhile = false;
}

if (node.evaluateAtStart()) {
return WhileNode.createWhile(context, sourceSection, conditionCast, body);
Original file line number Diff line number Diff line change
@@ -153,18 +153,20 @@ public RubyNode compileFunctionNode(SourceSection sourceSection, String methodNa
if (isBlock) {
body = new RedoableNode(context, sourceSection, body);
body = new CatchReturnPlaceholderNode(context, sourceSection, body, environment.getReturnID());

body = new BehaveAsProcNode(context, sourceSection,
new CatchBreakAsProcErrorNode(context, sourceSection, body),
NodeUtil.cloneNode(body));
} else {
body = new CatchBreakAsReturnNode(context, sourceSection, body);
body = new CatchReturnNode(context, sourceSection, body, environment.getReturnID());
}

body = new CatchNextNode(context, sourceSection, body);
body = new CatchRetryAsErrorNode(context, sourceSection, body);

if (isBlock && isTopLevel) {
body = new CatchBreakAsReturnNode(context, sourceSection, body);
}

if (!isBlock) {
// TODO(CS, 10-Jan-15) why do we only translate exceptions in methods and not blocks?
body = new ExceptionTranslatingNode(context, sourceSection, body);
}

@@ -182,38 +184,56 @@ public RubyNode compileFunctionNode(SourceSection sourceSection, String methodNa
}

if (isBlock) {
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(withBlockDestructureSemantics(rootNode));
final CallTarget callTargetForMethods = Truffle.getRuntime().createCallTarget(withoutBlockDestructureSemantics(rootNode));
return new BlockDefinitionNode(context, sourceSection, environment.getSharedMethodInfo(), environment.needsDeclarationFrame(), callTarget, callTargetForMethods);
} else {
return new MethodDefinitionNode(context, sourceSection, methodName, environment.getSharedMethodInfo(), environment.needsDeclarationFrame(), Truffle.getRuntime().createCallTarget(rootNode));
}
}
final RubyRootNode newRootNodeForBlocks = rootNode.cloneRubyRootNode();

private RubyRootNode withBlockDestructureSemantics(RubyRootNode rootNode) {
final RubyRootNode newRootNode = rootNode.cloneRubyRootNode();
for (BehaveAsBlockNode behaveAsBlockNode : NodeUtil.findAllNodeInstances(newRootNodeForBlocks, BehaveAsBlockNode.class)) {
behaveAsBlockNode.replace(behaveAsBlockNode.getAsBlock());
}

for (BehaveAsBlockNode behaveAsBlockNode : NodeUtil.findAllNodeInstances(newRootNode, BehaveAsBlockNode.class)) {
behaveAsBlockNode.replace(behaveAsBlockNode.getAsBlockNode());
}
for (BehaveAsProcNode behaveAsProcNode : NodeUtil.findAllNodeInstances(newRootNodeForBlocks, BehaveAsProcNode.class)) {
behaveAsProcNode.replace(behaveAsProcNode.getNotAsProc());
}

return newRootNode;
}
final RubyRootNode newRootNodeForProcs = rootNode.cloneRubyRootNode();

private RubyRootNode withoutBlockDestructureSemantics(RubyRootNode rootNode) {
final RubyRootNode newRootNode = rootNode.cloneRubyRootNode();
for (BehaveAsBlockNode behaveAsBlockNode : NodeUtil.findAllNodeInstances(newRootNodeForProcs, BehaveAsBlockNode.class)) {
behaveAsBlockNode.replace(behaveAsBlockNode.getAsBlock());
}

for (BehaveAsBlockNode behaveAsBlockNode : NodeUtil.findAllNodeInstances(newRootNode, BehaveAsBlockNode.class)) {
behaveAsBlockNode.replace(behaveAsBlockNode.getAsMethodNode());
}
for (BehaveAsProcNode behaveAsProcNode : NodeUtil.findAllNodeInstances(newRootNodeForProcs, BehaveAsProcNode.class)) {
behaveAsProcNode.replace(behaveAsProcNode.getAsProc());
}

final CallTarget callTargetAsProc = Truffle.getRuntime().createCallTarget(newRootNodeForProcs);

final CallTarget callTargetAsBlock = Truffle.getRuntime().createCallTarget(newRootNodeForBlocks);

final RubyRootNode newRootNodeForMethods = rootNode.cloneRubyRootNode();

for (BehaveAsBlockNode behaveAsBlockNode : NodeUtil.findAllNodeInstances(newRootNodeForMethods, BehaveAsBlockNode.class)) {
behaveAsBlockNode.replace(behaveAsBlockNode.getNotAsBlock());
}

for (BehaveAsProcNode behaveAsProcNode : NodeUtil.findAllNodeInstances(newRootNodeForMethods, BehaveAsProcNode.class)) {
behaveAsProcNode.replace(behaveAsProcNode.getNotAsProc());
}

final RubyRootNode newRootNodeWithCatchReturn = new RubyRootNode(
context,
newRootNode.getSourceSection(),
newRootNode.getFrameDescriptor(), newRootNode.getSharedMethodInfo(),
new CatchReturnNode(context, newRootNode.getSourceSection(), newRootNode.getBody(), getEnvironment().getReturnID()));
final RubyRootNode newRootNodeWithCatchReturn = new RubyRootNode(
context,
newRootNodeForMethods.getSourceSection(),
newRootNodeForMethods.getFrameDescriptor(), newRootNodeForMethods.getSharedMethodInfo(),
new CatchBreakAsReturnNode(context, sourceSection,
new CatchReturnNode(context, newRootNodeForMethods.getSourceSection(),
newRootNodeForMethods.getBody(), getEnvironment().getReturnID())));

return newRootNodeWithCatchReturn;
final CallTarget callTargetAsMethod = Truffle.getRuntime().createCallTarget(newRootNodeWithCatchReturn);

return new BlockDefinitionNode(context, sourceSection, environment.getSharedMethodInfo(),
environment.needsDeclarationFrame(), callTargetAsBlock, callTargetAsProc, callTargetAsMethod);
} else {
return new MethodDefinitionNode(context, sourceSection, methodName, environment.getSharedMethodInfo(),
environment.needsDeclarationFrame(), Truffle.getRuntime().createCallTarget(rootNode));
}
}

private static Arity getArity(org.jruby.ast.ArgsNode argsNode) {
4 changes: 4 additions & 0 deletions core/src/main/ruby/jruby/truffle/core/shims.rb
Original file line number Diff line number Diff line change
@@ -66,3 +66,7 @@ def self.last_match(n = nil)
end
end
end

def define_method(name, &block)
Kernel.define_method(name, &block)
end
6 changes: 6 additions & 0 deletions spec/truffle/tags/language/break_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fails:The break statement in a captured block when the invocation of the scope creating the block is still active raises a LocalJumpError when invoking the block from the scope creating the block
fails:The break statement in a captured block when the invocation of the scope creating the block is still active raises a LocalJumpError when invoking the block from a method
fails:The break statement in a captured block when the invocation of the scope creating the block is still active raises a LocalJumpError when yielding to the block
fails:The break statement in a captured block from a scope that has returned raises a LocalJumpError when calling the block from a method
fails:The break statement in a captured block from a scope that has returned raises a LocalJumpError when yielding to the block
fails:Executing break from within a block returns from the original invoking method even in case of chained calls

0 comments on commit 6428162

Please sign in to comment.