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

Commits on Apr 5, 2016

  1. Copy the full SHA
    63bb793 View commit details
  2. Copy the full SHA
    e7d3c0e View commit details
  3. Copy the full SHA
    55469e9 View commit details
  4. Copy the full SHA
    24f9380 View commit details
Original file line number Diff line number Diff line change
@@ -74,11 +74,12 @@ public HelperNode(RubyContext context,
},
limit = "getCacheLimit()"
)
protected Object callProcCached(VirtualFrame frame,
DynamicObject proc,
Object[] arguments,
@Cached("proc") DynamicObject cachedProc,
@Cached("create(getProcCallTarget(cachedProc))") DirectCallNode callNode) {
protected Object callProcCached(
VirtualFrame frame,
DynamicObject proc,
Object[] arguments,
@Cached("proc") DynamicObject cachedProc,
@Cached("create(getProcCallTarget(cachedProc))") DirectCallNode callNode) {
return callNode.call(
frame,
RubyArguments.pack(
@@ -96,10 +97,11 @@ protected Object callProcCached(VirtualFrame frame,
guards = "isRubyProc(proc)",
contains = "callProcCached"
)
protected Object callProcUncached(VirtualFrame frame,
DynamicObject proc,
Object[] arguments,
@Cached("create()") IndirectCallNode callNode) {
protected Object callProcUncached(
VirtualFrame frame,
DynamicObject proc,
Object[] arguments,
@Cached("create()") IndirectCallNode callNode) {
return callNode.call(
frame,
getProcCallTarget(proc),
@@ -125,12 +127,13 @@ protected CallTarget getProcCallTarget(DynamicObject proc) {
},
limit = "getCacheLimit()"
)
protected Object callMethodCached(VirtualFrame frame,
DynamicObject method,
Object[] arguments,
@Cached("method") DynamicObject cachedMethod,
@Cached("getMethod(cachedMethod)") InternalMethod cachedInternalMethod,
@Cached("create(cachedInternalMethod.getCallTarget())") DirectCallNode callNode) {
protected Object callMethodCached(
VirtualFrame frame,
DynamicObject method,
Object[] arguments,
@Cached("method") DynamicObject cachedMethod,
@Cached("getMethod(cachedMethod)") InternalMethod cachedInternalMethod,
@Cached("create(cachedInternalMethod.getCallTarget())") DirectCallNode callNode) {
return callNode.call(
frame,
RubyArguments.pack(
@@ -148,10 +151,11 @@ protected Object callMethodCached(VirtualFrame frame,
guards = "isRubyMethod(method)",
contains = "callMethodCached"
)
protected Object callMethodUncached(VirtualFrame frame,
DynamicObject method,
Object[] arguments,
@Cached("create()") IndirectCallNode callNode) {
protected Object callMethodUncached(
VirtualFrame frame,
DynamicObject method,
Object[] arguments,
@Cached("create()") IndirectCallNode callNode) {
final InternalMethod internalMethod = getMethod(method);
return callNode.call(
frame,
103 changes: 56 additions & 47 deletions truffle/src/main/java/org/jruby/truffle/interop/ForeignReadNode.java
Original file line number Diff line number Diff line change
@@ -78,24 +78,26 @@ public StringCachingHelperNode(RubyContext context, SourceSection sourceSection)
},
limit = "getCacheLimit()"
)
public Object cacheStringAndForward(VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
@Cached("privatizeRope(label)") Rope cachedRope,
@Cached("ropeToString(cachedRope)") String cachedString,
@Cached("startsWithAt(cachedString)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object cacheStringAndForward(
VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
@Cached("privatizeRope(label)") Rope cachedRope,
@Cached("ropeToString(cachedRope)") String cachedString,
@Cached("startsWithAt(cachedString)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
return nextHelper.executeStringCachedHelper(frame, receiver, label, cachedString, cachedStartsWithAt);
}

@Specialization(
guards = "isRubyString(label)",
contains = "cacheStringAndForward"
)
public Object uncachedStringAndForward(VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object uncachedStringAndForward(
VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
final String labelString = objectToString(label);
return nextHelper.executeStringCachedHelper(frame, receiver, label, labelString, startsWithAt(labelString));
}
@@ -107,24 +109,26 @@ public Object uncachedStringAndForward(VirtualFrame frame,
},
limit = "getCacheLimit()"
)
public Object cacheSymbolAndForward(VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
@Cached("label") DynamicObject cachedLabel,
@Cached("objectToString(cachedLabel)") String cachedString,
@Cached("startsWithAt(cachedString)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object cacheSymbolAndForward(
VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
@Cached("label") DynamicObject cachedLabel,
@Cached("objectToString(cachedLabel)") String cachedString,
@Cached("startsWithAt(cachedString)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
return nextHelper.executeStringCachedHelper(frame, receiver, cachedLabel, cachedString, cachedStartsWithAt);
}

@Specialization(
guards = "isRubySymbol(label)",
contains = "cacheSymbolAndForward"
)
public Object uncachedSymbolAndForward(VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object uncachedSymbolAndForward(
VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
final String labelString = objectToString(label);
return nextHelper.executeStringCachedHelper(frame, receiver, label, labelString, startsWithAt(labelString));
}
@@ -133,20 +137,22 @@ public Object uncachedSymbolAndForward(VirtualFrame frame,
guards = "label == cachedLabel",
limit = "getCacheLimit()"
)
public Object cacheJavaStringAndForward(VirtualFrame frame,
DynamicObject receiver,
String label,
@Cached("label") String cachedLabel,
@Cached("startsWithAt(cachedLabel)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object cacheJavaStringAndForward(
VirtualFrame frame,
DynamicObject receiver,
String label,
@Cached("label") String cachedLabel,
@Cached("startsWithAt(cachedLabel)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
return nextHelper.executeStringCachedHelper(frame, receiver, cachedLabel, cachedLabel, cachedStartsWithAt);
}

@Specialization(contains = "cacheJavaStringAndForward")
public Object uncachedJavaStringAndForward(VirtualFrame frame,
DynamicObject receiver,
String label,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object uncachedJavaStringAndForward(
VirtualFrame frame,
DynamicObject receiver,
String label,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
return nextHelper.executeStringCachedHelper(frame, receiver, label, label, startsWithAt(label));
}

@@ -226,11 +232,12 @@ public abstract Object executeStringCachedHelper(VirtualFrame frame, DynamicObje
String stringLabel, boolean startsAt);

@Specialization(guards = "startsAt(startsAt)")
public Object readInstanceVariable(DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt,
@Cached("createReadObjectFieldNode(stringLabel)") ReadObjectFieldNode readObjectFieldNode) {
public Object readInstanceVariable(
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt,
@Cached("createReadObjectFieldNode(stringLabel)") ReadObjectFieldNode readObjectFieldNode) {
return readObjectFieldNode.execute(receiver);
}

@@ -248,11 +255,12 @@ protected ReadObjectFieldNode createReadObjectFieldNode(String label) {
"methodDefined(frame, receiver, stringLabel, getDefinedNode())"
}
)
public Object callMethod(VirtualFrame frame,
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt) {
public Object callMethod(
VirtualFrame frame,
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt) {
return getCallNode().call(frame, receiver, stringLabel, null);
}

@@ -263,11 +271,12 @@ public Object callMethod(VirtualFrame frame,
"methodDefined(frame, receiver, INDEX_METHOD_NAME, getIndexDefinedNode())"
}
)
public Object index(VirtualFrame frame,
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt) {
public Object index(
VirtualFrame frame,
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt) {
return getCallNode().call(frame, receiver, "[]", null, label);
}

125 changes: 67 additions & 58 deletions truffle/src/main/java/org/jruby/truffle/interop/ForeignWriteNode.java
Original file line number Diff line number Diff line change
@@ -79,26 +79,28 @@ public abstract Object executeStringCachingHelper(VirtualFrame frame, DynamicObj
},
limit = "getCacheLimit()"
)
public Object cacheStringAndForward(VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
Object value,
@Cached("privatizeRope(label)") Rope cachedRope,
@Cached("ropeToString(cachedRope)") String cachedString,
@Cached("startsWithAt(cachedString)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object cacheStringAndForward(
VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
Object value,
@Cached("privatizeRope(label)") Rope cachedRope,
@Cached("ropeToString(cachedRope)") String cachedString,
@Cached("startsWithAt(cachedString)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
return nextHelper.executeStringCachedHelper(frame, receiver, label, cachedString, cachedStartsWithAt, value);
}

@Specialization(
guards = "isRubyString(label)",
contains = "cacheStringAndForward"
)
public Object uncachedStringAndForward(VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
Object value,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object uncachedStringAndForward(
VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
Object value,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
final String labelString = objectToString(label);
return nextHelper.executeStringCachedHelper(frame, receiver, label, labelString,
startsWithAt(labelString), value);
@@ -111,14 +113,15 @@ public Object uncachedStringAndForward(VirtualFrame frame,
},
limit = "getCacheLimit()"
)
public Object cacheSymbolAndForward(VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
Object value,
@Cached("label") DynamicObject cachedLabel,
@Cached("objectToString(cachedLabel)") String cachedString,
@Cached("startsWithAt(cachedString)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object cacheSymbolAndForward(
VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
Object value,
@Cached("label") DynamicObject cachedLabel,
@Cached("objectToString(cachedLabel)") String cachedString,
@Cached("startsWithAt(cachedString)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
return nextHelper.executeStringCachedHelper(frame, receiver, cachedLabel, cachedString,
cachedStartsWithAt, value);
}
@@ -127,11 +130,12 @@ public Object cacheSymbolAndForward(VirtualFrame frame,
guards = "isRubySymbol(label)",
contains = "cacheSymbolAndForward"
)
public Object uncachedSymbolAndForward(VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
Object value,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object uncachedSymbolAndForward(
VirtualFrame frame,
DynamicObject receiver,
DynamicObject label,
Object value,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
final String labelString = objectToString(label);
return nextHelper.executeStringCachedHelper(frame, receiver, label, labelString,
startsWithAt(labelString), value);
@@ -141,23 +145,25 @@ public Object uncachedSymbolAndForward(VirtualFrame frame,
guards = "label == cachedLabel",
limit = "getCacheLimit()"
)
public Object cacheJavaStringAndForward(VirtualFrame frame,
DynamicObject receiver,
String label,
Object value,
@Cached("label") String cachedLabel,
@Cached("startsWithAt(cachedLabel)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object cacheJavaStringAndForward(
VirtualFrame frame,
DynamicObject receiver,
String label,
Object value,
@Cached("label") String cachedLabel,
@Cached("startsWithAt(cachedLabel)") boolean cachedStartsWithAt,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
return nextHelper.executeStringCachedHelper(frame, receiver, cachedLabel, cachedLabel,
cachedStartsWithAt, value);
}

@Specialization(contains = "cacheJavaStringAndForward")
public Object uncachedJavaStringAndForward(VirtualFrame frame,
DynamicObject receiver,
String label,
Object value,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
public Object uncachedJavaStringAndForward(
VirtualFrame frame,
DynamicObject receiver,
String label,
Object value,
@Cached("createNextHelper()") StringCachedHelperNode nextHelper) {
return nextHelper.executeStringCachedHelper(frame, receiver, label, label, startsWithAt(label), value);
}

@@ -209,12 +215,13 @@ public abstract Object executeStringCachedHelper(VirtualFrame frame, DynamicObje
String stringLabel, boolean startsAt, Object value);

@Specialization(guards = "startsAt(startsAt)")
public Object readInstanceVariable(DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt,
Object value,
@Cached("createWriteObjectFieldNode(stringLabel)") WriteObjectFieldNode writeObjectFieldNode) {
public Object readInstanceVariable(
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt,
Object value,
@Cached("createWriteObjectFieldNode(stringLabel)") WriteObjectFieldNode writeObjectFieldNode) {
writeObjectFieldNode.execute(receiver, value);
return value;
}
@@ -233,13 +240,14 @@ protected WriteObjectFieldNode createWriteObjectFieldNode(String label) {
"methodDefined(frame, receiver, writeMethodName, getDefinedNode())"
}
)
public Object callMethod(VirtualFrame frame,
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt,
Object value,
@Cached("createWriteMethodName(stringLabel)") String writeMethodName) {
public Object callMethod(
VirtualFrame frame,
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt,
Object value,
@Cached("createWriteMethodName(stringLabel)") String writeMethodName) {
return getCallNode().call(frame, receiver, writeMethodName, null, value);
}

@@ -254,13 +262,14 @@ protected String createWriteMethodName(String label) {
"methodDefined(frame, receiver, INDEX_METHOD_NAME, getIndexDefinedNode())"
}
)
public Object index(VirtualFrame frame,
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt,
Object value,
@Cached("createWriteMethodName(stringLabel)") String writeMethodName) {
public Object index(
VirtualFrame frame,
DynamicObject receiver,
Object label,
String stringLabel,
boolean startsAt,
Object value,
@Cached("createWriteMethodName(stringLabel)") String writeMethodName) {
return getCallNode().call(frame, receiver, "[]", null, label, value);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
/*
* Copyright (c) 2014, 2016 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.interop;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.interop.Message;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;

@NodeChildren({
@NodeChild("receiver"),
@NodeChild("args")
})
public abstract class OutgoingForeignCallNode extends RubyNode {

@Child private RubyToForeignNode megamorphicToForeignNode;

private final String name;

public OutgoingForeignCallNode(RubyContext context, SourceSection sourceSection, String name) {
super(context, sourceSection);
this.name = name;
}

public abstract Object executeCall(VirtualFrame frame, TruffleObject receiver, Object[] args);

@Specialization(
guards = "args.length == cachedArgsLength",
limit = "getCacheLimit()"
)
public Object callCached(
VirtualFrame frame,
TruffleObject receiver,
Object[] args,
@Cached("args.length") int cachedArgsLength,
@Cached("createHelperNode(cachedArgsLength)") OutgoingNode outgoingNode,
@Cached("createToForeignNodes(cachedArgsLength)") RubyToForeignNode[] toForeignNodes) {
return outgoingNode.executeCall(frame, receiver, argsToForeign(frame, toForeignNodes, args));
}

@Specialization(contains = "callCached")
public Object callUncached(
VirtualFrame frame,
TruffleObject receiver,
Object[] args) {
CompilerDirectives.bailout("can't compile megamorphic outgoing foreign calls");

if (megamorphicToForeignNode == null) {
megamorphicToForeignNode = insert(RubyToForeignNodeGen.create(getContext(), null, null));
}

final Object[] foreignArgs = new Object[args.length];

for (int n = 0; n < args.length; n++) {
foreignArgs[n] = megamorphicToForeignNode.executeConvert(frame, args[n]);
}

return createHelperNode(args.length).executeCall(frame, receiver, foreignArgs);
}

protected OutgoingNode createHelperNode(int argsLength) {
if (name.equals("[]") && argsLength == 1) {
return new IndexReadOutgoingNode();
} else if (name.equals("[]=") && argsLength == 2) {
return new IndexWriteOutgoingNode();
} else if (name.endsWith("=") && argsLength == 1) {
return new PropertyWriteOutgoingNode(name.substring(0, name.length() - 1));
} else if (name.equals("call")) {
return new CallOutgoingNode(argsLength);
} else if (name.equals("nil?") && argsLength == 0) {
return new IsNilOutgoingNode();
} else {
return new InvokeOutgoingNode(name, argsLength);
}
}

protected RubyToForeignNode[] createToForeignNodes(int argsLength) {
final RubyToForeignNode[] toForeignNodes = new RubyToForeignNode[argsLength];

for (int n = 0; n < argsLength; n++) {
toForeignNodes[n] = RubyToForeignNodeGen.create(getContext(), null, null);
}

return toForeignNodes;
}

@ExplodeLoop
protected Object[] argsToForeign(VirtualFrame frame, RubyToForeignNode[] toForeignNodes, Object[] args) {
assert toForeignNodes.length == args.length;

final Object[] foreignArgs = new Object[args.length];

for (int n = 0; n < args.length; n++) {
foreignArgs[n] = toForeignNodes[n].executeConvert(frame, args[n]);
}

return foreignArgs;
}

protected int getCacheLimit() {
return getContext().getOptions().INTEROP_EXECUTE_CACHE;
}

protected abstract class OutgoingNode extends Node {

private final BranchProfile exceptionProfile = BranchProfile.create();

public abstract Object executeCall(VirtualFrame frame, TruffleObject receiver, Object[] args);

protected void exceptionProfile() {
exceptionProfile.enter();
}

}

protected class IndexReadOutgoingNode extends OutgoingNode {

@Child private Node node;

public IndexReadOutgoingNode() {
node = Message.READ.createNode();
}

@Override
public Object executeCall(VirtualFrame frame, TruffleObject receiver, Object[] args) {
assert args.length == 1;

try {
return ForeignAccess.sendRead(node, frame, receiver, args[0]);
} catch (UnknownIdentifierException | UnsupportedMessageException e) {
exceptionProfile();
throw new RuntimeException(e);
}
}

}

protected class IndexWriteOutgoingNode extends OutgoingNode {

@Child private Node node;

public IndexWriteOutgoingNode() {
node = Message.WRITE.createNode();
}

@Override
public Object executeCall(VirtualFrame frame, TruffleObject receiver, Object[] args) {
assert args.length == 2;

try {
return ForeignAccess.sendWrite(node, frame, receiver, args[0], args[1]);
} catch (UnknownIdentifierException | UnsupportedMessageException | UnsupportedTypeException e) {
exceptionProfile();
throw new RuntimeException(e);
}
}

}

protected class PropertyWriteOutgoingNode extends OutgoingNode {

private final String name;

@Child private Node node;

public PropertyWriteOutgoingNode(String name) {
this.name = name;
node = Message.WRITE.createNode();
}

@Override
public Object executeCall(VirtualFrame frame, TruffleObject receiver, Object[] args) {
assert args.length == 1;

try {
return ForeignAccess.sendWrite(node, frame, receiver, name, args[0]);
} catch (UnknownIdentifierException | UnsupportedMessageException | UnsupportedTypeException e) {
exceptionProfile();
throw new RuntimeException(e);
}
}

}

protected class CallOutgoingNode extends OutgoingNode {

private final int argsLength;

@Child private Node node;

public CallOutgoingNode(int argsLength) {
this.argsLength = argsLength;
node = Message.createExecute(argsLength).createNode();
}

@Override
public Object executeCall(VirtualFrame frame, TruffleObject receiver, Object[] args) {
assert args.length == argsLength;

try {
return ForeignAccess.sendExecute(node, frame, receiver, args);
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
exceptionProfile();
throw new RuntimeException(e);
}
}

}

protected class IsNilOutgoingNode extends OutgoingNode {

@Child private Node node;

public IsNilOutgoingNode() {
node = Message.IS_NULL.createNode();
}

@Override
public Object executeCall(VirtualFrame frame, TruffleObject receiver, Object[] args) {
assert args.length == 0;

return ForeignAccess.sendIsNull(node, frame, receiver);
}

}

protected class InvokeOutgoingNode extends OutgoingNode {

private final String name;
private final int argsLength;

@Child private Node node;

public InvokeOutgoingNode(String name, int argsLength) {
this.name = name;
this.argsLength = argsLength;
node = Message.createInvoke(argsLength).createNode();
}

@Override
public Object executeCall(VirtualFrame frame, TruffleObject receiver, Object[] args) {
assert args.length == argsLength;

try {
return ForeignAccess.sendInvoke(node, frame, receiver, name, args);
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException | UnknownIdentifierException e) {
exceptionProfile();
throw new RuntimeException(e);
}
}

}


}
Original file line number Diff line number Diff line change
@@ -76,7 +76,7 @@ public ExecuteNode(RubyContext context, SourceSection sourceSection) {

@Specialization(
guards = "args.length == cachedArgsLength",
limit = "10"
limit = "getCacheLimit()"
)
public Object executeForeignCached(
VirtualFrame frame,
@@ -113,6 +113,10 @@ protected Node createExecuteNode(int argsLength) {
return Message.createExecute(argsLength).createNode();
}

protected int getCacheLimit() {
return getContext().getOptions().INTEROP_EXECUTE_CACHE;
}

}

@CoreMethod(unsafeNeedsAudit = true, names = "invoke", isModuleFunction = true, needsSelf = false, required = 2, rest = true)
Original file line number Diff line number Diff line change
@@ -9,75 +9,28 @@
*/
package org.jruby.truffle.language.dispatch;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.interop.Message;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.interop.RubyToForeignNode;
import org.jruby.truffle.interop.RubyToForeignNodeGen;
import org.jruby.truffle.language.RubyNode;

import java.util.Arrays;
import org.jruby.truffle.interop.OutgoingForeignCallNode;
import org.jruby.truffle.interop.OutgoingForeignCallNodeGen;

public final class CachedForeignDispatchNode extends CachedDispatchNode {

private final String name;
private final String nameForMessage;
private final int arity;

@Child private Node directArrayRead;
@Child private Node directArrayWrite;
@Child private Node directField;
@Child private Node directCall;
@Child private Node nullCheck;
@Child private Node access;
@Child private PrepareArguments prepareArguments;

@Child private OutgoingForeignCallNode outgoingForeignCallNode;

public CachedForeignDispatchNode(RubyContext context, DispatchNode next, Object cachedName, int arity) {
public CachedForeignDispatchNode(RubyContext context, DispatchNode next, Object cachedName) {
super(context, cachedName, next, DispatchAction.CALL_METHOD);

this.name = cachedName.toString();
this.arity = arity;
if (name.endsWith("=") && arity == 1) {
this.nameForMessage = name.substring(0, name.length() - 1);
} else {
this.nameForMessage = name;
}
initializeNodes(context, arity);
}

private void initializeNodes(RubyContext context, int arity) {
if (name.equals("[]")) {
directArrayRead = Message.READ.createNode();
} else if (name.equals("[]=")) {
directArrayWrite = Message.WRITE.createNode();
} else if (name.endsWith("=") && arity == 1) {
directField = Message.WRITE.createNode();
} else if (name.equals("call")) {
directCall = Message.createExecute(arity).createNode();
} else if (name.equals("nil?")) {
nullCheck = Message.IS_NULL.createNode();
} else {
access = Message.createInvoke(arity).createNode();
}
prepareArguments = new PrepareArguments(context, getSourceSection(), arity);
name = cachedName.toString();
outgoingForeignCallNode = OutgoingForeignCallNodeGen.create(context, null, name, null, null);
}

@Override
protected boolean guard(Object methodName, Object receiver) {
// TODO CS 8-Mar-15 not sure what the guards are supposed to be here
return true;
return guardName(methodName) && (receiver instanceof TruffleObject);
}

@Override
@@ -87,83 +40,11 @@ public Object executeDispatch(
Object methodName,
DynamicObject blockObject,
Object[] argumentsObjects) {
if (receiverObject instanceof TruffleObject) {
return doDispatch(frame, (TruffleObject) receiverObject, argumentsObjects);
} else {
return next.executeDispatch(
frame,
receiverObject,
methodName,
blockObject,
argumentsObjects);
}
return doDispatch(frame, (TruffleObject) receiverObject, argumentsObjects);
}


private Object doDispatch(VirtualFrame frame, TruffleObject receiverObject, Object[] arguments) {
if (arguments.length != arity) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException();
}

try {
if (directArrayRead != null) {
Object[] args = prepareArguments.convertArguments(frame, arguments, 0);
return ForeignAccess.sendRead(directArrayRead, frame, receiverObject, args[0]);
} else if (directArrayWrite != null) {
Object[] args = prepareArguments.convertArguments(frame, arguments, 0);
return ForeignAccess.sendWrite(directArrayWrite, frame, receiverObject, args[0], args[1]);
} else if (directField != null) {
Object[] args = prepareArguments.convertArguments(frame, arguments, 1);
args[0] = nameForMessage;
return ForeignAccess.sendWrite(directField, frame, receiverObject, args[0], args[1]);
} else if (directCall != null) {
Object[] args;
args = prepareArguments.convertArguments(frame, arguments, 0);
return ForeignAccess.sendExecute(directCall, frame, receiverObject, args);
} else if (nullCheck != null) {
return ForeignAccess.sendIsNull(nullCheck, frame, receiverObject);
} else if (access != null) {
Object[] args = prepareArguments.convertArguments(frame, arguments, 1);
args[0] = name;
return ForeignAccess.sendInvoke(access, frame, receiverObject, name, Arrays.copyOfRange(args, 1, args.length - 1));
} else {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException();
}
} catch (ArityException | UnsupportedMessageException | UnsupportedTypeException | UnknownIdentifierException e) {
CompilerDirectives.transferToInterpreter();
throw new RuntimeException(e);
}
return outgoingForeignCallNode.executeCall(frame, receiverObject, arguments);
}

private static class PrepareArguments extends RubyNode {

@Children private final RubyToForeignNode[] converters;
private final int arity;

public PrepareArguments(RubyContext context, SourceSection sourceSection, int arity) {
super(context, sourceSection);
this.converters = new RubyToForeignNode[arity];
this.arity = arity;
for (int i = 0; i < arity; i++) {
this.converters[i] = RubyToForeignNodeGen.create(context, sourceSection, null);
}
}

@ExplodeLoop
public Object[] convertArguments(VirtualFrame frame, Object[] arguments, int offset) {
Object[] result = new Object[arity + offset];
for (int i = 0; i < arity; i++) {
result[i + offset] = converters[i].executeConvert(frame, arguments[i]);
}
return result;
}

@Override
public Object execute(VirtualFrame frame) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException();
}
}
}
Original file line number Diff line number Diff line change
@@ -85,7 +85,7 @@ public DispatchNode call() throws Exception {
} else {
depth++;
if (RubyGuards.isForeignObject(receiverObject)) {
newDispathNode = createForeign(argumentsObjects, first, methodName);
newDispathNode = new CachedForeignDispatchNode(getContext(), first, methodName);
} else if (RubyGuards.isRubyBasicObject(receiverObject)) {
newDispathNode = doDynamicObject(frame, first, receiverObject, methodName, argumentsObjects);
} else {
@@ -101,10 +101,6 @@ public DispatchNode call() throws Exception {
return dispatch.executeDispatch(frame, receiverObject, methodName, blockObject, argumentsObjects);
}

private DispatchNode createForeign(Object[] argumentsObjects, DispatchNode first, Object methodName) {
return new CachedForeignDispatchNode(getContext(), first, methodName, argumentsObjects.length);
}

private DispatchNode doUnboxedObject(
VirtualFrame frame,
DispatchNode first,