Skip to content

Commit

Permalink
Showing 3 changed files with 99 additions and 30 deletions.
3 changes: 2 additions & 1 deletion core/src/main/java/org/jruby/util/cli/Options.java
Original file line number Diff line number Diff line change
@@ -260,7 +260,8 @@ public class Options {
public static final Option<Integer> TRUFFLE_ENCODING_COMPATIBLE_QUERY_CACHE = integer(TRUFFLE, "truffle.encoding_compatible_query.cache", TRUFFLE_DEFAULT_CACHE.load(), "Encoding.compatible? cache size.");
public static final Option<Integer> TRUFFLE_THREAD_CACHE = integer(TRUFFLE, "truffle.thread.cache", TRUFFLE_DEFAULT_CACHE.load(), "Cache size of operations that depend on a particular thread.");
public static final Option<Integer> TRUFFLE_ROPE_CLASS_CACHE = integer(TRUFFLE, "truffle.rope_class.cache", 6, "Cache size for rope operations that depend on a concrete rope implementation to avoid virtual calls.");
public static final Option<Integer> TRUFFLE_INTEROP_CONVERT_CACHE = integer(TRUFFLE, "truffle.interop_convert.cache", TRUFFLE_DEFAULT_CACHE.load(), "Cache size for converting values for interop.");
public static final Option<Integer> TRUFFLE_INTEROP_CONVERT_CACHE = integer(TRUFFLE, "truffle.interop.convert.cache", TRUFFLE_DEFAULT_CACHE.load(), "Cache size for converting values for interop.");
public static final Option<Integer> TRUFFLE_INTEROP_EXECUTE_CACHE = integer(TRUFFLE, "truffle.interop.execute.cache", TRUFFLE_DEFAULT_CACHE.load(), "Cache size for interop EXECUTE messages.");

public static final Option<Boolean> TRUFFLE_CLONE_DEFAULT = bool(TRUFFLE, "truffle.clone.default", true, "Default option for cloning.");
public static final Option<Boolean> TRUFFLE_INLINE_DEFAULT = bool(TRUFFLE, "truffle.inline.default", true, "Default option for inlining.");
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
@@ -40,7 +39,7 @@ public final class ForeignExecuteNode extends ForeignExecuteBaseNode {

@Override
public Object access(VirtualFrame frame, DynamicObject object, Object[] arguments) {
return getHelperNode().executeExecute(frame, object, arguments);
return getHelperNode().executeCall(frame, object, arguments);
}

private HelperNode getHelperNode() {
@@ -60,54 +59,121 @@ private HelperNode getHelperNode() {
})
protected static abstract class HelperNode extends RubyNode {

@Child private IndirectCallNode callNode;

public HelperNode(RubyContext context,
SourceSection sourceSection) {
super(context, sourceSection);
callNode = Truffle.getRuntime().createIndirectCallNode();
}

public abstract Object executeExecute(VirtualFrame frame, Object receiver, Object[] arguments);
public abstract Object executeCall(VirtualFrame frame, Object receiver, Object[] arguments);

@Specialization(
guards = {
"isRubyProc(proc)",
"proc == cachedProc"
},
limit = "getCacheLimit()"
)
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(
Layouts.PROC.getDeclarationFrame(cachedProc),
null,
Layouts.PROC.getMethod(cachedProc),
DeclarationContext.METHOD,
null,
Layouts.PROC.getSelf(cachedProc),
null,
arguments));
}

This comment has been minimized.

Copy link
@eregon

eregon Apr 4, 2016

Member

Looks like this should reuse CallBlockNode.


@Specialization(guards = {"isRubyProc(proc)", "proc == cachedProc"})
protected Object doCallProc(VirtualFrame frame,
DynamicObject proc,
Object[] arguments,
@Cached("proc") DynamicObject cachedProc,
@Cached("create(getCallTarget(cachedProc))") DirectCallNode callNode) {
return callNode.call(frame, RubyArguments.pack(Layouts.PROC.getDeclarationFrame(cachedProc), null, Layouts.PROC.getMethod(cachedProc), DeclarationContext.METHOD, null, Layouts.PROC.getSelf(cachedProc), null, arguments));
@Specialization(
guards = "isRubyProc(proc)",
contains = "callProcCached"
)
protected Object callProcUncached(VirtualFrame frame,
DynamicObject proc,
Object[] arguments,
@Cached("create()") IndirectCallNode callNode) {
return callNode.call(
frame,
getProcCallTarget(proc),
RubyArguments.pack(
Layouts.PROC.getDeclarationFrame(proc),
null,
Layouts.PROC.getMethod(proc),
DeclarationContext.METHOD,
null,
Layouts.PROC.getSelf(proc),
null,
arguments));
}

@Specialization(guards = "isRubyProc(proc)")
protected Object doCallProc(VirtualFrame frame, DynamicObject proc, Object[] arguments) {
return callNode.call(frame, Layouts.PROC.getCallTargetForType(proc), RubyArguments.pack(Layouts.PROC.getDeclarationFrame(proc), null, Layouts.PROC.getMethod(proc), DeclarationContext.METHOD, null, Layouts.PROC.getSelf(proc), null, arguments));
protected CallTarget getProcCallTarget(DynamicObject proc) {
return Layouts.PROC.getCallTargetForType(proc);
}

@Specialization(guards = {"isRubyMethod(method)", "method == cachedMethod"})
protected Object doCall(VirtualFrame frame,
@Specialization(
guards = {
"isRubyMethod(method)",
"method == cachedMethod"
},
limit = "getCacheLimit()"
)
protected Object callMethodCached(VirtualFrame frame,
DynamicObject method,
Object[] arguments,
@Cached("method") DynamicObject cachedMethod,
@Cached("getMethod(cachedMethod)") InternalMethod internalMethod,
@Cached("create(getMethod(cachedMethod).getCallTarget())") DirectCallNode callNode) {
return callNode.call(frame, RubyArguments.pack(null, null, internalMethod, DeclarationContext.METHOD, null, Layouts.METHOD.getReceiver(cachedMethod), null, arguments));
}

@Specialization(guards = "isRubyMethod(method)")
protected Object doCall(VirtualFrame frame, DynamicObject method, Object[] arguments) {
final InternalMethod internalMethod = Layouts.METHOD.getMethod(method);
return callNode.call(frame, internalMethod.getCallTarget(), RubyArguments.pack(null, null, internalMethod, DeclarationContext.METHOD, null, Layouts.METHOD.getReceiver(method), null, arguments));
@Cached("getMethod(cachedMethod)") InternalMethod cachedInternalMethod,
@Cached("create(cachedInternalMethod.getCallTarget())") DirectCallNode callNode) {
return callNode.call(
frame,
RubyArguments.pack(
null,
null,
cachedInternalMethod,
DeclarationContext.METHOD,
null,
Layouts.METHOD.getReceiver(cachedMethod),
null,
arguments));

This comment has been minimized.

Copy link
@eregon

eregon Apr 4, 2016

Member

And this CallMethodNode.

This comment has been minimized.

Copy link
@chrisseaton

chrisseaton Apr 4, 2016

Author Contributor

Yes I got a bit confused about what node could call both this and the case above. I'll take a look again.

This comment has been minimized.

Copy link
@eregon

eregon Apr 4, 2016

Member

I guess it makes sense to have the same kind of interop semantics with bound Methods and blocks (Proc). But it's probably simpler to separate for the implementation of EXECUTE and such.

This comment has been minimized.

Copy link
@chrisseaton

chrisseaton Apr 4, 2016

Author Contributor

Yes, and unbound methods should be runnable if you do an INVOKE somehow I think. But at the moment I'm just understanding, documenting (https://github.com/jruby/jruby/wiki/JRuby-and-Truffle-Interop) and tidying up our current interop semantics. Then I'll go back and think about modifying it.

}

protected CallTarget getCallTarget(DynamicObject proc) {
return Layouts.PROC.getCallTargetForType(proc);
@Specialization(
guards = "isRubyMethod(method)",
contains = "callMethodCached"
)
protected Object callMethodUncached(VirtualFrame frame,
DynamicObject method,
Object[] arguments,
@Cached("create()") IndirectCallNode callNode) {
final InternalMethod internalMethod = getMethod(method);
return callNode.call(
frame,
internalMethod.getCallTarget(),
RubyArguments.pack(
null,
null,
internalMethod,
DeclarationContext.METHOD,
null,
Layouts.METHOD.getReceiver(method),
null,
arguments));
}

protected InternalMethod getMethod(DynamicObject method) {
return Layouts.METHOD.getMethod(method);
}

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

}

}
2 changes: 2 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/language/Options.java
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@
import static org.jruby.util.cli.Options.TRUFFLE_INSTANCE_VARIABLE_CACHE;
import static org.jruby.util.cli.Options.TRUFFLE_INSTRUMENTATION_SERVER_PORT;
import static org.jruby.util.cli.Options.TRUFFLE_INTEROP_CONVERT_CACHE;
import static org.jruby.util.cli.Options.TRUFFLE_INTEROP_EXECUTE_CACHE;
import static org.jruby.util.cli.Options.TRUFFLE_IS_A_CACHE;
import static org.jruby.util.cli.Options.TRUFFLE_METHODMISSING_ALWAYS_CLONE;
import static org.jruby.util.cli.Options.TRUFFLE_METHODMISSING_ALWAYS_INLINE;
@@ -111,6 +112,7 @@ public class Options {
public final int THREAD_CACHE = TRUFFLE_THREAD_CACHE.load();
public final int ROPE_CLASS_CACHE = TRUFFLE_ROPE_CLASS_CACHE.load();
public final int INTEROP_CONVERT_CACHE = TRUFFLE_INTEROP_CONVERT_CACHE.load();
public final int INTEROP_EXECUTE_CACHE = TRUFFLE_INTEROP_EXECUTE_CACHE.load();

// Cloning and inlining

0 comments on commit 33c0e45

Please sign in to comment.