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: 8a20cf8851a7
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9505d0e517e0
Choose a head ref

Commits on Feb 15, 2015

  1. Copy the full SHA
    37a1eda View commit details
  2. Copy the full SHA
    8085764 View commit details

Commits on Feb 20, 2015

  1. Merge branch 'master' into truffle-kwargs

    Conflicts:
    	truffle/src/main/java/org/jruby/truffle/nodes/dispatch/UnresolvedDispatchNode.java
    	truffle/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
    chrisseaton committed Feb 20, 2015
    Copy the full SHA
    59f6b7b View commit details
  2. Copy the full SHA
    613810f View commit details

Commits on Feb 27, 2015

  1. Merge branch 'master' into truffle-kwargs

    Conflicts:
    	truffle/src/main/java/org/jruby/truffle/runtime/subsystems/SafepointManager.java
    chrisseaton committed Feb 27, 2015
    Copy the full SHA
    29ff529 View commit details

Commits on Mar 3, 2015

  1. Merge branch 'master' into truffle-kwargs

    Conflicts:
    	truffle/src/main/java/org/jruby/truffle/nodes/core/IONodes.java
    	truffle/src/main/java/org/jruby/truffle/nodes/dispatch/DispatchHeadNode.java
    	truffle/src/main/java/org/jruby/truffle/nodes/dispatch/DispatchNode.java
    	truffle/src/main/java/org/jruby/truffle/nodes/dispatch/UncachedDispatchNode.java
    	truffle/src/main/java/org/jruby/truffle/nodes/dispatch/UnresolvedDispatchNode.java
    chrisseaton committed Mar 3, 2015
    Copy the full SHA
    041619f View commit details

Commits on Mar 5, 2015

  1. Copy the full SHA
    25d21b2 View commit details

Commits on Mar 8, 2015

  1. Merge branch 'master' into truffle-kwargs

    Conflicts:
    	truffle/src/main/java/org/jruby/truffle/nodes/dispatch/DispatchNode.java
    	truffle/src/main/java/org/jruby/truffle/nodes/dispatch/UnresolvedDispatchNode.java
    chrisseaton committed Mar 8, 2015
    Copy the full SHA
    fb82903 View commit details

Commits on Mar 10, 2015

  1. Merge branch 'master' into truffle-kwargs

    Conflicts:
    	truffle/src/main/java/org/jruby/truffle/runtime/methods/Arity.java
    	truffle/src/main/java/org/jruby/truffle/translator/BodyTranslator.java
    chrisseaton committed Mar 10, 2015
    Copy the full SHA
    a8f49a0 View commit details

Commits on Mar 12, 2015

  1. Merge branch 'master' into truffle-kwargs

    Conflicts:
    	truffle/src/main/java/org/jruby/truffle/nodes/core/ArrayAllocationSite.java
    	truffle/src/main/java/org/jruby/truffle/runtime/subsystems/SafepointManager.java
    chrisseaton committed Mar 12, 2015
    Copy the full SHA
    0dbd174 View commit details

Commits on Mar 13, 2015

  1. Copy the full SHA
    2604aee View commit details

Commits on Mar 15, 2015

  1. Merge branch 'master' into truffle-kwargs

    Conflicts:
    	truffle/src/main/java/org/jruby/truffle/nodes/RubyCallNode.java
    chrisseaton committed Mar 15, 2015
    Copy the full SHA
    ae474b3 View commit details

Commits on Mar 17, 2015

  1. Copy the full SHA
    44060f3 View commit details

Commits on Mar 18, 2015

  1. Copy the full SHA
    2c15c8c View commit details

Commits on Mar 19, 2015

  1. Copy the full SHA
    8f2adb4 View commit details
  2. Copy the full SHA
    e4dac71 View commit details
  3. Copy the full SHA
    f9be3f6 View commit details
  4. [Truffle] Formatting.

    chrisseaton committed Mar 19, 2015
    Copy the full SHA
    8733dc5 View commit details
  5. Copy the full SHA
    1a8076d View commit details

Commits on Mar 20, 2015

  1. Copy the full SHA
    1f38216 View commit details
  2. Copy the full SHA
    d1dd8ab View commit details
  3. Copy the full SHA
    78024be View commit details
  4. Copy the full SHA
    9ecd3dd View commit details
  5. Copy the full SHA
    4728f23 View commit details

Commits on Mar 21, 2015

  1. Copy the full SHA
    3422bcb View commit details
  2. Copy the full SHA
    9505d0e View commit details
Showing with 488 additions and 43 deletions.
  1. +16 −0 core/src/main/java/org/jruby/ast/ArgsNode.java
  2. +1 −1 truffle/src/main/java/org/jruby/truffle/TruffleBridgeImpl.java
  3. +183 −1 truffle/src/main/java/org/jruby/truffle/nodes/RubyCallNode.java
  4. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/core/CoreMethodNodeManager.java
  5. +0 −2 truffle/src/main/java/org/jruby/truffle/nodes/core/IONodes.java
  6. +2 −2 truffle/src/main/java/org/jruby/truffle/nodes/core/ModuleNodes.java
  7. +12 −1 truffle/src/main/java/org/jruby/truffle/nodes/dispatch/CachedBoxedDispatchNode.java
  8. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/dispatch/CachedDispatchNode.java
  9. +4 −0 truffle/src/main/java/org/jruby/truffle/nodes/dispatch/DispatchNode.java
  10. +12 −0 truffle/src/main/java/org/jruby/truffle/nodes/literal/HashLiteralNode.java
  11. +24 −0 truffle/src/main/java/org/jruby/truffle/nodes/methods/MarkerNode.java
  12. +10 −1 truffle/src/main/java/org/jruby/truffle/nodes/methods/arguments/CheckArityNode.java
  13. +25 −0 truffle/src/main/java/org/jruby/truffle/nodes/methods/arguments/OptionalKeywordArgMissingNode.java
  14. +39 −14 truffle/src/main/java/org/jruby/truffle/nodes/methods/arguments/ReadKeywordArgumentNode.java
  15. +22 −1 truffle/src/main/java/org/jruby/truffle/nodes/methods/arguments/ReadKeywordRestArgumentNode.java
  16. +1 −1 truffle/src/main/java/org/jruby/truffle/nodes/methods/arguments/ReadOptionalArgumentNode.java
  17. +26 −0 truffle/src/main/java/org/jruby/truffle/nodes/methods/arguments/UnknownArgumentErrorNode.java
  18. +0 −2 truffle/src/main/java/org/jruby/truffle/nodes/respondto/RespondToNode.java
  19. +24 −4 truffle/src/main/java/org/jruby/truffle/runtime/RubyArguments.java
  20. +0 −2 truffle/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
  21. +61 −4 truffle/src/main/java/org/jruby/truffle/runtime/methods/Arity.java
  22. +10 −0 truffle/src/main/java/org/jruby/truffle/runtime/methods/SharedMethodInfo.java
  23. +11 −2 truffle/src/main/java/org/jruby/truffle/translator/LoadArgumentsTranslator.java
  24. +3 −3 truffle/src/main/java/org/jruby/truffle/translator/MethodTranslator.java
16 changes: 16 additions & 0 deletions core/src/main/java/org/jruby/ast/ArgsNode.java
Original file line number Diff line number Diff line change
@@ -154,6 +154,18 @@ protected Arity calculateArity() {
public boolean hasKwargs() {
return hasKwargs;
}

public int countKeywords() {
if (hasKwargs) {
if (keywords == null) {
// Rest keyword argument
return 0;
}
return keywords.size();
} else {
return 0;
}
}

protected boolean hasMasgnArgs() {
if (preCount > 0) for (Node node : pre.childNodes()) {
@@ -254,6 +266,10 @@ public KeywordRestArgNode getKeyRest() {
return keyRest;
}

public boolean hasKeyRest() {
return keyRest != null;
}

public void checkArgCount(Ruby runtime, int argsLength) {
Arity.checkArgumentCount(runtime, argsLength, requiredArgsCount, maxArgsCount, hasKwargs);
}
Original file line number Diff line number Diff line change
@@ -164,7 +164,7 @@ public void init() {

@Override
public Object execute(final Object self, final org.jruby.ast.RootNode rootNode) {
return execute(TranslatorDriver.ParserContext.TOP_LEVEL, self, null, rootNode);
return execute(TranslatorDriver.ParserContext.TOP_LEVEL, self, null, rootNode);
}

public Object execute(final TranslatorDriver.ParserContext parserContext, final Object self, final MaterializedFrame parentFrame, final org.jruby.ast.RootNode rootNode) {
184 changes: 183 additions & 1 deletion truffle/src/main/java/org/jruby/truffle/nodes/RubyCallNode.java
Original file line number Diff line number Diff line change
@@ -13,28 +13,40 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.BranchProfile;
import org.jruby.truffle.nodes.cast.BooleanCastNode;
import org.jruby.truffle.nodes.cast.BooleanCastNodeFactory;
import org.jruby.truffle.nodes.cast.ProcOrNullNode;
import org.jruby.truffle.nodes.cast.ProcOrNullNodeFactory;
import org.jruby.truffle.nodes.dispatch.*;
import org.jruby.truffle.nodes.literal.HashLiteralNode;
import org.jruby.truffle.nodes.literal.ObjectLiteralNode;
import org.jruby.truffle.nodes.methods.MarkerNode;
import org.jruby.truffle.nodes.methods.arguments.OptionalKeywordArgMissingNode;
import org.jruby.truffle.nodes.methods.arguments.UnknownArgumentErrorNode;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.core.RubySymbol;
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.util.ArrayUtils;

import java.util.ArrayList;
import java.util.List;

public class RubyCallNode extends RubyNode {

private final String methodName;

@Child private RubyNode receiver;
@Child private ProcOrNullNode block;
@Children private final RubyNode[] arguments;
@Children private final RubyNode[] keywordOptimizedArguments;
@CompilerDirectives.CompilationFinal private int keywordOptimizedArgumentsLength;

private final boolean isSplatted;
private final boolean isVCall;
@@ -54,6 +66,8 @@ public class RubyCallNode extends RubyNode {

private final boolean ignoreVisibility;

@CompilerDirectives.CompilationFinal private boolean cannotOptimize;

public RubyCallNode(RubyContext context, SourceSection section, String methodName, RubyNode receiver, RubyNode block, boolean isSplatted, RubyNode... arguments) {
this(context, section, methodName, receiver, block, isSplatted, false, false, arguments);
}
@@ -84,12 +98,53 @@ public RubyCallNode(RubyContext context, SourceSection section, String methodNam
respondToMissingCast = BooleanCastNodeFactory.create(context, section, null);

this.ignoreVisibility = ignoreVisibility;

/*
* TODO CS 19-Mar-15 we currently can't swap an @Children array out
* so we just allocate a lot up-front. In a future version of Truffle
* @Children might not need to be final, which would fix this.
*/
keywordOptimizedArguments = new RubyNode[arguments.length + 32];
}

@Override
public Object execute(VirtualFrame frame) {
final Object receiverObject = receiver.execute(frame);
final Object[] argumentsObjects = executeArguments(frame);

final Object[] argumentsObjects;

if (dispatchHead.getFirstDispatchNode().couldOptimizeKeywordArguments() && !cannotOptimize) {
final CachedBoxedDispatchNode dispatchNode = (CachedBoxedDispatchNode) dispatchHead.getFirstDispatchNode();

if (keywordOptimizedArguments[0] == null) {
CompilerDirectives.transferToInterpreter();

System.err.println("optimizing for keyword arguments!");

final RubyNode[] optimized = expandedArgumentNodes(dispatchNode.getMethod(), arguments, isSplatted);

if (optimized == null || optimized.length > keywordOptimizedArguments.length) {
System.err.println("couldn't optimize :(");
cannotOptimize = true;
} else {
keywordOptimizedArgumentsLength = optimized.length;

for (int n = 0; n < keywordOptimizedArgumentsLength; n++) {
keywordOptimizedArguments[n] = insert(NodeUtil.cloneNode(optimized[n]));
}
}
}

if (dispatchNode.guard(methodName, receiverObject) && dispatchNode.getUnmodifiedAssumption().isValid()) {
argumentsObjects = executeKeywordOptimizedArguments(frame);
} else {
argumentsObjects = executeArguments(frame);
}

} else {
argumentsObjects = executeArguments(frame);
}

final RubyProc blockObject = executeBlock(frame);

return dispatchHead.call(frame, receiverObject, methodName, blockObject, argumentsObjects);
@@ -118,6 +173,21 @@ private Object[] executeArguments(VirtualFrame frame) {
}
}

@ExplodeLoop
private Object[] executeKeywordOptimizedArguments(VirtualFrame frame) {
final Object[] argumentsObjects = new Object[keywordOptimizedArgumentsLength];

for (int i = 0; i < keywordOptimizedArgumentsLength; i++) {
argumentsObjects[i] = keywordOptimizedArguments[i].execute(frame);
}

if (isSplatted) {
return splat(argumentsObjects[0]);
} else {
return argumentsObjects;
}
}

private Object[] splat(Object argument) {
// TODO(CS): what happens if isn't just one argument, or it isn't an Array?

@@ -165,6 +235,118 @@ private Object[] splat(Object argument) {
throw new UnsupportedOperationException();
}

public RubyNode[] expandedArgumentNodes(InternalMethod method, RubyNode[] argumentNodes, boolean isSplatted) {
final RubyNode[] result;

boolean shouldExpand = true;
if (method == null
|| method.getSharedMethodInfo().getArity().getKeywordArguments() == null) {
// no keyword arguments in method definition
shouldExpand = false;
} else if (argumentNodes.length != 0
&& !(argumentNodes[argumentNodes.length - 1] instanceof HashLiteralNode)) {
// last argument is not a Hash that could be expanded
shouldExpand = false;
} else if (method.getSharedMethodInfo().getArity() == null
|| method.getSharedMethodInfo().getArity().getRequired() >= argumentNodes.length) {
shouldExpand = false;
} else if (isSplatted
|| method.getSharedMethodInfo().getArity().allowsMore()) {
// TODO: make optimization work if splat arguments are involed
// the problem is that Markers and keyword args are used when
// reading splatted args
shouldExpand = false;
}

if (shouldExpand) {
List<String> kwargs = method.getSharedMethodInfo().getArity().getKeywordArguments();

int countArgNodes = argumentNodes.length + kwargs.size() + 1;
if (argumentNodes.length == 0) {
countArgNodes++;
}

result = new RubyNode[countArgNodes];
int i;

for (i = 0; i < argumentNodes.length - 1; ++i) {
result[i] = argumentNodes[i];
}

int firstMarker = i++;
result[firstMarker] = new MarkerNode(getContext(), null);

HashLiteralNode hashNode;
if (argumentNodes.length > 0) {
hashNode = (HashLiteralNode) argumentNodes[argumentNodes.length - 1];
} else {
hashNode = HashLiteralNode.create(getContext(), null,
new RubyNode[0]);
}

List<String> restKeywordLabels = new ArrayList<>();
for (int j = 0; j < hashNode.size(); j++) {
Object key = hashNode.getKey(j);
boolean keyIsSymbol = key instanceof ObjectLiteralNode &&
((ObjectLiteralNode) key).getObject() instanceof RubySymbol;

if (!keyIsSymbol) {
// cannot optimize case where keyword label is dynamic (not a fixed RubySymbol)
cannotOptimize = true;
return null;
}

final String label = ((ObjectLiteralNode) hashNode.getKey(j)).getObject().toString();
restKeywordLabels.add(label);
}

for (String kwarg : kwargs) {
result[i] = new OptionalKeywordArgMissingNode(getContext(), null);
for (int j = 0; j < hashNode.size(); j++) {
final String label = ((ObjectLiteralNode) hashNode.getKey(j)).getObject().toString();

if (label.equals(kwarg)) {
result[i] = hashNode.getValue(j);
restKeywordLabels.remove(label);
break;
}
}
i++;
}
result[i++] = new MarkerNode(getContext(), null);

if (restKeywordLabels.size() > 0
&& !method.getSharedMethodInfo().getArity().hasKeyRest()) {
result[firstMarker] = new UnknownArgumentErrorNode(getContext(), null, restKeywordLabels.get(0));
} else if (restKeywordLabels.size() > 0) {
i = 0;
RubyNode[] keyValues = new RubyNode[2 * restKeywordLabels
.size()];

for (String label : restKeywordLabels) {
for (int j = 0; j < hashNode.size(); j++) {
final String argLabel = ((ObjectLiteralNode) hashNode.getKey(j)).getObject().toString();

if (argLabel.equals(label)) {
keyValues[i++] = hashNode.getKey(j);
keyValues[i++] = hashNode.getValue(j);
}
}
}

HashLiteralNode restHash = HashLiteralNode.create(getContext(), null, keyValues);
result[firstMarker] = restHash;
}

}
else {
cannotOptimize = true;
result = null;
}

return result;
}

@Override
public Object isDefined(VirtualFrame frame) {
notDesignedForCompilation();
Original file line number Diff line number Diff line change
@@ -138,7 +138,7 @@ private static RubyRootNode makeGenericMethod(RubyContext context, MethodDetails
optional = methodDetails.getMethodAnnotation().optional();
}

final Arity arity = new Arity(required, optional, methodDetails.getMethodAnnotation().argumentsAsArray(), false);
final Arity arity = new Arity(required, optional, methodDetails.getMethodAnnotation().argumentsAsArray(), false, false, 0);

final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, null, arity, methodDetails.getIndicativeName(), false, null, true);

Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@
import com.oracle.truffle.api.dsl.CreateCast;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jcodings.specific.ASCIIEncoding;
@@ -24,7 +23,6 @@
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyFile;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.truffle.runtime.subsystems.ThreadManager;
import org.jruby.util.ByteList;
Original file line number Diff line number Diff line change
@@ -399,7 +399,7 @@ public RubyNilClass attrReader(RubyModule module, Object[] args) {
public static void attrReader(Node currentNode, RubyContext context, SourceSection sourceSection, RubyModule module, String name) {
CompilerDirectives.transferToInterpreter();

final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, new Arity(0, 0, false, false));
final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, new Arity(0, 0, false, false, false, 0));

final SelfNode self = new SelfNode(context, sourceSection);
final ReadInstanceVariableNode readInstanceVariable = new ReadInstanceVariableNode(context, sourceSection, "@" + name, self, false);
@@ -451,7 +451,7 @@ public RubyNilClass attrWriter(RubyModule module, Object[] args) {
public static void attrWriter(Node currentNode, RubyContext context, SourceSection sourceSection, RubyModule module, String name) {
CompilerDirectives.transferToInterpreter();

final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, new Arity(1, 0, false, false));
final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, new Arity(1, 0, false, false, false, 0));

final SelfNode self = new SelfNode(context, sourceSection);
final ReadPreArgumentNode readArgument = new ReadPreArgumentNode(context, sourceSection, 0, MissingArgumentBehaviour.RUNTIME_ERROR);
Original file line number Diff line number Diff line change
@@ -93,7 +93,7 @@ public CachedBoxedDispatchNode(
}

@Override
protected boolean guard(Object methodName, Object receiver) {
public boolean guard(Object methodName, Object receiver) {
return guardName(methodName) &&
(receiver instanceof RubyBasicObject) &&
((RubyBasicObject) receiver).getMetaClass() == expectedClass;
@@ -173,4 +173,15 @@ public String toString() {
method == null ? "null" : method.toString());
}

public boolean couldOptimizeKeywordArguments() {
return method.getSharedMethodInfo().getArity().getKeywordArguments() != null && next instanceof UnresolvedDispatchNode;
}

public InternalMethod getMethod() {
return method;
}

public Assumption getUnmodifiedAssumption() {
return unmodifiedAssumption;
}
}
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.truffle.runtime.core.RubySymbol;
import org.jruby.truffle.runtime.methods.InternalMethod;

public abstract class CachedDispatchNode extends DispatchNode {

@@ -89,5 +90,4 @@ protected RubySymbol getCachedNameAsSymbol() {
public boolean isIndirect() {
return indirect;
}

}
Original file line number Diff line number Diff line change
@@ -152,4 +152,8 @@ public DispatchAction getDispatchAction() {
return dispatchAction;
}

public boolean couldOptimizeKeywordArguments() {
return false;
}

}
Original file line number Diff line number Diff line change
@@ -41,6 +41,18 @@ protected HashLiteralNode(RubyContext context, SourceSection sourceSection, Ruby
freezeNode = DispatchHeadNodeFactory.createMethodCall(context);
}

public int size() {
return keyValues.length / 2;
}

public RubyNode getKey(int index) {
return keyValues[2 * index];
}

public RubyNode getValue(int index) {
return keyValues[2 * index + 1];
}

public static HashLiteralNode create(RubyContext context, SourceSection sourceSection, RubyNode[] keyValues) {
if (keyValues.length == 0) {
return new EmptyHashLiteralNode(context, sourceSection);
Loading