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: e9e06aae1c3c
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8efce53e4047
Choose a head ref
  • 2 commits
  • 7 files changed
  • 1 contributor

Commits on Jan 5, 2015

  1. Copy the full SHA
    dd293d7 View commit details
  2. Copy the full SHA
    8efce53 View commit details
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.oracle.truffle.api.frame.MaterializedFrame;
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;
@@ -25,16 +26,25 @@
* Define a block. That is, store the definition of a block and when executed produce the executable
* object that results.
*/
public class BlockDefinitionNode extends MethodDefinitionNode {
public class BlockDefinitionNode extends RubyNode {

private final SharedMethodInfo sharedMethodInfo;

private final CallTarget callTarget;
private final CallTarget callTargetForMethods;

public BlockDefinitionNode(RubyContext context, SourceSection sourceSection, String name, SharedMethodInfo methodInfo,
boolean requiresDeclarationFrame, CallTarget callTarget, CallTarget callTargetForMethods, RubyRootNode rootNode) {
super(context, sourceSection, name, methodInfo, requiresDeclarationFrame, rootNode, false);
private final boolean requiresDeclarationFrame;

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

this.callTarget = callTarget;
this.callTargetForMethods = callTargetForMethods;

this.requiresDeclarationFrame = requiresDeclarationFrame;

}

@Override
Original file line number Diff line number Diff line change
@@ -31,22 +31,22 @@
*/
public class MethodDefinitionNode extends RubyNode {

protected final String name;
protected final SharedMethodInfo sharedMethodInfo;
private final String name;
private final SharedMethodInfo sharedMethodInfo;

protected final RubyRootNode rootNode;
private final CallTarget callTarget;

protected final boolean requiresDeclarationFrame;
private final boolean requiresDeclarationFrame;

protected final boolean ignoreLocalVisibility;
private final boolean ignoreLocalVisibility;

public MethodDefinitionNode(RubyContext context, SourceSection sourceSection, String name, SharedMethodInfo sharedMethodInfo,
boolean requiresDeclarationFrame, RubyRootNode rootNode, boolean ignoreLocalVisibility) {
boolean requiresDeclarationFrame, CallTarget callTarget, boolean ignoreLocalVisibility) {
super(context, sourceSection);
this.name = name;
this.sharedMethodInfo = sharedMethodInfo;
this.requiresDeclarationFrame = requiresDeclarationFrame;
this.rootNode = rootNode;
this.callTarget = callTarget;
this.ignoreLocalVisibility = ignoreLocalVisibility;
}

@@ -66,12 +66,7 @@ public RubyMethod executeMethod(VirtualFrame frame) {

public RubyMethod executeMethod(VirtualFrame frame, MaterializedFrame declarationFrame) {
notDesignedForCompilation();

Visibility visibility = getVisibility(frame);

final RubyRootNode rootNodeClone = NodeUtil.cloneNode(rootNode);
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNodeClone);

return new RubyMethod(sharedMethodInfo, name, null, visibility, false, callTarget, declarationFrame);
}

@@ -112,10 +107,6 @@ public String getName() {
return name;
}

public RubyRootNode getMethodRootNode() {
return rootNode;
}

public SharedMethodInfo getSharedMethodInfo() {
return sharedMethodInfo;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
/*
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
* 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.nodes.methods.arguments;
package org.jruby.truffle.translator;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeCost;
import com.oracle.truffle.api.nodes.NodeInfo;
@@ -21,29 +19,26 @@
@NodeInfo(cost = NodeCost.NONE)
public class BehaveAsBlockNode extends RubyNode {

private @CompilationFinal boolean behaveAsBlock;
@Child protected RubyNode asBlockNode;
@Child protected RubyNode asMethodNode;

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

@Override
public boolean executeBoolean(VirtualFrame frame) {
return behaveAsBlock;
this.asBlockNode = asBlockNode;
this.asMethodNode = asMethodNode;
}

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

public void setBehaveAsBlock(boolean behaveAsBlock) {
CompilerAsserts.neverPartOfCompilation();

this.behaveAsBlock = behaveAsBlock;
public RubyNode getAsBlockNode() {
return asBlockNode;
}

// No need to deoptimize, as we're only doing this during clone
public RubyNode getAsMethodNode() {
return asMethodNode;
}

}
Original file line number Diff line number Diff line change
@@ -1001,7 +1001,7 @@ protected RubyNode translateMethodDefinition(SourceSection sourceSection, RubyNo

final MethodTranslator methodCompiler = new MethodTranslator(currentNode, context, this, newEnvironment, false, parent == null, source);

final MethodDefinitionNode functionExprNode = methodCompiler.compileFunctionNode(sourceSection, methodName, argsNode, bodyNode, ignoreLocalVisiblity, sharedMethodInfo);
final MethodDefinitionNode functionExprNode = (MethodDefinitionNode) methodCompiler.compileFunctionNode(sourceSection, methodName, argsNode, bodyNode, ignoreLocalVisiblity, sharedMethodInfo);

/*
* In the top-level, methods are defined in the class of the main object. This is
@@ -2561,7 +2561,7 @@ public RubyNode visitLambdaNode(org.jruby.ast.LambdaNode node) {
throw new UnsupportedOperationException();
}

final MethodDefinitionNode definitionNode = methodCompiler.compileFunctionNode(translate(node.getPosition()), sharedMethodInfo.getName(), argsNode, node.getBodyNode(), false, sharedMethodInfo);
final RubyNode definitionNode = methodCompiler.compileFunctionNode(translate(node.getPosition()), sharedMethodInfo.getName(), argsNode, node.getBodyNode(), false, sharedMethodInfo);

return new LambdaNode(context, translate(node.getPosition()), definitionNode);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This
* Copyright (c) 2013, 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:
*
@@ -10,7 +10,6 @@
package org.jruby.truffle.translator;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.nodes.NodeUtil;
@@ -21,7 +20,6 @@
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.cast.ArrayCastNodeFactory;
import org.jruby.truffle.nodes.cast.BooleanCastNodeFactory;
import org.jruby.truffle.nodes.control.AndNode;
import org.jruby.truffle.nodes.control.IfNode;
import org.jruby.truffle.nodes.control.SequenceNode;
import org.jruby.truffle.nodes.literal.ObjectLiteralNode;
@@ -47,7 +45,7 @@ public MethodTranslator(RubyNode currentNode, RubyContext context, BodyTranslato
this.isTopLevel = isTopLevel;
}

public MethodDefinitionNode compileFunctionNode(SourceSection sourceSection, String methodName, ArgsNode argsNode, org.jruby.ast.Node bodyNode, boolean ignoreLocalVisiblity, SharedMethodInfo sharedMethodInfo) {
public RubyNode compileFunctionNode(SourceSection sourceSection, String methodName, ArgsNode argsNode, org.jruby.ast.Node bodyNode, boolean ignoreLocalVisiblity, SharedMethodInfo sharedMethodInfo) {
if (PRINT_PARSE_TREE_METHOD_NAMES.contains(methodName)) {
System.err.println(methodName);
System.err.println(sharedMethodInfo.getParseTree().toString(true, 0));
@@ -97,23 +95,23 @@ public MethodDefinitionNode compileFunctionNode(SourceSection sourceSection, Str
final RubyNode prelude;

if (isBlock) {
boolean shouldSwitch = true;
boolean shouldConsiderDestructuringArrayArg = true;

if (argsNode.getPreCount() == 0 && argsNode.getOptionalArgsCount() == 0 && argsNode.getPostCount() == 0 && argsNode.getRestArgNode() == null) {
shouldSwitch = false;
shouldConsiderDestructuringArrayArg = false;
}

if (argsNode.getPreCount() + argsNode.getPostCount() == 1 && argsNode.getOptionalArgsCount() == 0 && argsNode.getRestArgNode() == null) {
shouldSwitch = false;
shouldConsiderDestructuringArrayArg = false;
}

if (argsNode.getPreCount() == 0 && argsNode.getRestArgNode() != null) {
shouldSwitch = false;
shouldConsiderDestructuringArrayArg = false;
}

RubyNode preludeBuilder;

if (shouldSwitch) {
if (shouldConsiderDestructuringArrayArg) {
final RubyNode readArrayNode = new ReadPreArgumentNode(context, sourceSection, 0, MissingArgumentBehaviour.RUNTIME_ERROR);
final RubyNode castArrayNode = ArrayCastNodeFactory.create(context, sourceSection, readArrayNode);
final FrameSlot arraySlot = environment.declareVar(environment.allocateLocalTemp("destructure"));
@@ -123,22 +121,21 @@ public MethodDefinitionNode compileFunctionNode(SourceSection sourceSection, Str
destructureArgumentsTranslator.pushArraySlot(arraySlot);
final RubyNode newDestructureArguments = argsNode.accept(destructureArgumentsTranslator);

preludeBuilder = new IfNode(context, sourceSection,
BooleanCastNodeFactory.create(context, sourceSection,
new AndNode(context, sourceSection,
new BehaveAsBlockNode(context, sourceSection, true),
new ShouldDestructureNode(context, sourceSection, arity,
new RespondToNode(context, sourceSection, readArrayNode, "to_ary")))),
SequenceNode.sequence(context, sourceSection, writeArrayNode, newDestructureArguments),
loadArguments);
preludeBuilder =
new BehaveAsBlockNode(context, sourceSection,
new IfNode(context, sourceSection,
BooleanCastNodeFactory.create(context, sourceSection,
new ShouldDestructureNode(context, sourceSection, arity,
new RespondToNode(context, sourceSection, readArrayNode, "to_ary"))),
SequenceNode.sequence(context, sourceSection, writeArrayNode, newDestructureArguments),
NodeUtil.cloneNode(loadArguments)),
NodeUtil.cloneNode(loadArguments));
} else {
preludeBuilder = loadArguments;
}

prelude = SequenceNode.sequence(context, sourceSection,
new IfNode(context, sourceSection,
BooleanCastNodeFactory.create(context, sourceSection,
new BehaveAsBlockNode(context, sourceSection, true)),
new BehaveAsBlockNode(context, sourceSection,
new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getNilObject()),
new CheckArityNode(context, sourceSection, arityForCheck, parameterCollector.getKeywords(), argsNode.getKeyRest() != null)), preludeBuilder);
} else {
@@ -155,9 +152,6 @@ public MethodDefinitionNode compileFunctionNode(SourceSection sourceSection, Str

if (isBlock) {
body = new RedoableNode(context, sourceSection, body);
}

if (isBlock) {
body = new CatchReturnPlaceholderNode(context, sourceSection, body, environment.getReturnID());
} else {
body = new CatchReturnNode(context, sourceSection, body, environment.getReturnID());
@@ -188,33 +182,38 @@ public MethodDefinitionNode compileFunctionNode(SourceSection sourceSection, Str
}

if (isBlock) {
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
final CallTarget callTargetForMethods = withoutBlockDestructureSemantics(callTarget);

return new BlockDefinitionNode(context, sourceSection, methodName, environment.getSharedMethodInfo(), environment.needsDeclarationFrame(), callTarget, callTargetForMethods, rootNode);
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(), rootNode, ignoreLocalVisiblity);
return new MethodDefinitionNode(context, sourceSection, methodName, environment.getSharedMethodInfo(), environment.needsDeclarationFrame(), Truffle.getRuntime().createCallTarget(rootNode), ignoreLocalVisiblity);
}
}

private CallTarget withoutBlockDestructureSemantics(CallTarget callTarget) {
if (callTarget instanceof RootCallTarget && ((RootCallTarget) callTarget).getRootNode() instanceof RubyRootNode) {
final RubyRootNode newRootNode = ((RubyRootNode) ((RootCallTarget) callTarget).getRootNode()).cloneRubyRootNode();
private RubyRootNode withBlockDestructureSemantics(RubyRootNode rootNode) {
final RubyRootNode newRootNode = rootNode.cloneRubyRootNode();

for (BehaveAsBlockNode behaveAsBlockNode : NodeUtil.findAllNodeInstances(newRootNode, BehaveAsBlockNode.class)) {
behaveAsBlockNode.setBehaveAsBlock(false);
}
for (BehaveAsBlockNode behaveAsBlockNode : NodeUtil.findAllNodeInstances(newRootNode, BehaveAsBlockNode.class)) {
behaveAsBlockNode.replace(behaveAsBlockNode.getAsBlockNode());
}

final RubyRootNode newRootNodeWithCatchReturn = new RubyRootNode(
context,
newRootNode.getSourceSection(),
newRootNode.getFrameDescriptor(), newRootNode.getSharedMethodInfo(),
new CatchReturnNode(context, newRootNode.getSourceSection(), newRootNode.getBody(), getEnvironment().getReturnID()));
return newRootNode;
}

return Truffle.getRuntime().createCallTarget(newRootNodeWithCatchReturn);
} else {
throw new UnsupportedOperationException("Can't change the semantics of an opaque call target");
private RubyRootNode withoutBlockDestructureSemantics(RubyRootNode rootNode) {
final RubyRootNode newRootNode = rootNode.cloneRubyRootNode();

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

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

return newRootNodeWithCatchReturn;
}

private static Arity getArity(org.jruby.ast.ArgsNode argsNode) {
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.translator;

import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
@@ -62,7 +63,14 @@ public MethodDefinitionNode compileClassNode(SourceSection sourceSection, String

final RubyRootNode rootNode = new RubyRootNode(context, sourceSection, environment.getFrameDescriptor(), environment.getSharedMethodInfo(), body);

return new MethodDefinitionNode(context, sourceSection, environment.getSharedMethodInfo().getName(), environment.getSharedMethodInfo(), environment.needsDeclarationFrame(), rootNode, false);
return new MethodDefinitionNode(
context,
sourceSection,
environment.getSharedMethodInfo().getName(),
environment.getSharedMethodInfo(),
environment.needsDeclarationFrame(),
Truffle.getRuntime().createCallTarget(rootNode),
false);
}

@Override
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@ public static enum ParserContext {

private long nextReturnID = 0;

public MethodDefinitionNode parse(RubyContext context, org.jruby.ast.Node parseTree, org.jruby.ast.ArgsNode argsNode, org.jruby.ast.Node bodyNode, RubyNode currentNode) {
public RubyNode parse(RubyContext context, org.jruby.ast.Node parseTree, org.jruby.ast.ArgsNode argsNode, org.jruby.ast.Node bodyNode, RubyNode currentNode) {
final SourceSection sourceSection = null;

final LexicalScope lexicalScope = context.getRootLexicalScope(); // TODO(eregon): figure out how to get the lexical scope from JRuby