Skip to content
Snippets Groups Projects
Commit 583590f8 authored by Lukas Stadler's avatar Lukas Stadler
Browse files

thread safety in PrepareArguments (use DSL)

parent 62c56773
No related branches found
No related tags found
No related merge requests found
......@@ -23,15 +23,23 @@
package com.oracle.truffle.r.nodes.function.call;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.dsl.TypeSystemReference;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
import com.oracle.truffle.r.nodes.RRootNode;
import com.oracle.truffle.r.nodes.function.ArgumentMatcher;
import com.oracle.truffle.r.nodes.function.ArgumentMatcher.MatchPermutation;
import com.oracle.truffle.r.nodes.function.CallArgumentsNode;
import com.oracle.truffle.r.nodes.function.FormalArguments;
import com.oracle.truffle.r.nodes.function.RCallNode;
import com.oracle.truffle.r.nodes.function.call.PrepareArgumentsFactory.PrepareArgumentsDefaultNodeGen;
import com.oracle.truffle.r.nodes.function.call.PrepareArgumentsFactory.PrepareArgumentsExplicitNodeGen;
import com.oracle.truffle.r.runtime.Arguments;
import com.oracle.truffle.r.runtime.ArgumentsSignature;
import com.oracle.truffle.r.runtime.RArguments.S3DefaultArguments;
......@@ -44,171 +52,111 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
* rules. It implements two different paths: one for arguments provided as an
* {@link CallArgumentsNode}, i.e., unevaluated arguments, and another path for evaluated arguments.
*/
@TypeSystemReference(EmptyTypeSystemFlatLayout.class)
public abstract class PrepareArguments extends Node {
private static final int CACHE_SIZE = 4;
protected static final int CACHE_SIZE = 8;
/**
* Returns the argument values and corresponding signature. The signature represents the
* original call signature reordered in the same way as the arguments. For s3DefaultArguments
* motivation see {@link RCallNode#callGroupGeneric}.
*/
public abstract RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call);
abstract static class PrepareArgumentsDefault extends PrepareArguments {
public static PrepareArguments create(RRootNode target, CallArgumentsNode args, boolean noOpt) {
return new UninitializedPrepareArguments(target, args, noOpt);
}
protected final RRootNode target;
protected final CallArgumentsNode sourceArguments; // not used as a node
protected final boolean noOpt;
public static PrepareArguments createExplicit(RRootNode target) {
return new UninitializedExplicitPrepareArguments(target);
}
static final class ArgumentsAndSignature extends Node {
@Children private final RNode[] matchedArguments;
private final ArgumentsSignature matchedSuppliedSignature;
@ExplodeLoop
private static RArgsValuesAndNames executeArgs(RNode[] arguments, ArgumentsSignature suppliedSignature, VirtualFrame frame) {
Object[] result = new Object[arguments.length];
for (int i = 0; i < arguments.length; i++) {
result[i] = arguments[i].execute(frame);
protected ArgumentsAndSignature(RNode[] matchedArguments, ArgumentsSignature matchedSuppliedSignature) {
this.matchedArguments = matchedArguments;
this.matchedSuppliedSignature = matchedSuppliedSignature;
}
}
return new RArgsValuesAndNames(result, suppliedSignature);
}
private static RArgsValuesAndNames executeArgs(Arguments<RNode> matched, VirtualFrame frame) {
return executeArgs(matched.getArguments(), matched.getSignature(), frame);
}
private static final class UninitializedPrepareArguments extends PrepareArguments {
private final RRootNode target;
private final CallArgumentsNode sourceArguments; // not used as a node
private final boolean noOpt;
private int depth = CACHE_SIZE;
protected static ArgumentsSignature getSignatureOrNull(RArgsValuesAndNames args) {
return args == null ? null : args.getSignature();
}
UninitializedPrepareArguments(RRootNode target, CallArgumentsNode sourceArguments, boolean noOpt) {
protected PrepareArgumentsDefault(RRootNode target, CallArgumentsNode sourceArguments, boolean noOpt) {
this.target = target;
this.sourceArguments = sourceArguments;
this.noOpt = noOpt;
}
@Override
public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
CompilerDirectives.transferToInterpreterAndInvalidate();
PrepareArguments next;
if (depth-- > 0) {
next = new CachedPrepareArguments(this, target, call, sourceArguments, varArgs == null ? null : varArgs.getSignature(), s3DefaultArguments, noOpt);
} else {
next = new GenericPrepareArguments(target, sourceArguments);
}
return replace(next).execute(frame, varArgs, s3DefaultArguments, call);
}
}
private static final class CachedPrepareArguments extends PrepareArguments {
@Child private PrepareArguments next;
@Children private final RNode[] matchedArguments;
private final ArgumentsSignature matchedSuppliedSignature;
private final ArgumentsSignature cachedVarArgSignature;
private final Object cachedS3DefaultArguments;
CachedPrepareArguments(PrepareArguments next, RRootNode target, RCallNode call, CallArgumentsNode args, ArgumentsSignature varArgSignature, S3DefaultArguments s3DefaultArguments,
boolean noOpt) {
this.next = next;
cachedVarArgSignature = varArgSignature;
Arguments<RNode> matched = ArgumentMatcher.matchArguments(target, args, varArgSignature, s3DefaultArguments, call, noOpt);
this.matchedArguments = matched.getArguments();
this.matchedSuppliedSignature = matched.getSignature();
this.cachedS3DefaultArguments = s3DefaultArguments;
protected ArgumentsAndSignature createArguments(RCallNode call, ArgumentsSignature varArgSignature, S3DefaultArguments s3DefaultArguments) {
Arguments<RNode> matched = ArgumentMatcher.matchArguments(target, sourceArguments, varArgSignature, s3DefaultArguments, call, noOpt);
return new ArgumentsAndSignature(matched.getArguments(), matched.getSignature());
}
@Override
@ExplodeLoop
public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
assert (cachedVarArgSignature != null) == (varArgs != null);
if ((cachedVarArgSignature == null || cachedVarArgSignature == varArgs.getSignature()) && cachedS3DefaultArguments == s3DefaultArguments) {
return executeArgs(matchedArguments, matchedSuppliedSignature, frame);
private static RArgsValuesAndNames executeArgs(RNode[] arguments, ArgumentsSignature suppliedSignature, VirtualFrame frame) {
Object[] result = new Object[arguments.length];
for (int i = 0; i < arguments.length; i++) {
result[i] = arguments[i].execute(frame);
}
return next.execute(frame, varArgs, s3DefaultArguments, call);
return new RArgsValuesAndNames(result, suppliedSignature);
}
}
private static final class GenericPrepareArguments extends PrepareArguments {
private final RRootNode target;
private final CallArgumentsNode args; // not used as a node
GenericPrepareArguments(RRootNode target, CallArgumentsNode args) {
this.target = target;
this.args = args;
@Specialization(limit = "CACHE_SIZE", guards = {"cachedVarArgSignature == null || cachedVarArgSignature == varArgs.getSignature()", "cachedS3DefaultArguments == s3DefaultArguments"})
public RArgsValuesAndNames prepare(VirtualFrame frame, RArgsValuesAndNames varArgs, @SuppressWarnings("unused") S3DefaultArguments s3DefaultArguments,
@SuppressWarnings("unused") RCallNode call,
@Cached("getSignatureOrNull(varArgs)") ArgumentsSignature cachedVarArgSignature,
@Cached("createArguments(call, cachedVarArgSignature, s3DefaultArguments)") ArgumentsAndSignature arguments,
@SuppressWarnings("unused") @Cached("s3DefaultArguments") S3DefaultArguments cachedS3DefaultArguments) {
assert (cachedVarArgSignature != null) == (varArgs != null);
return executeArgs(arguments.matchedArguments, arguments.matchedSuppliedSignature, frame);
}
@Override
public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
@Fallback
public RArgsValuesAndNames prepareGeneric(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call) {
CompilerDirectives.transferToInterpreter();
ArgumentsSignature varArgSignature = varArgs == null ? null : varArgs.getSignature();
Arguments<RNode> matchedArgs = ArgumentMatcher.matchArguments(target, args, varArgSignature, s3DefaultArguments, RError.ROOTNODE, true);
return executeArgs(matchedArgs, frame);
Arguments<RNode> matchedArgs = ArgumentMatcher.matchArguments(target, sourceArguments, varArgSignature, s3DefaultArguments, RError.ROOTNODE, true);
return executeArgs(matchedArgs.getArguments(), matchedArgs.getSignature(), frame);
}
}
private static final class UninitializedExplicitPrepareArguments extends PrepareArguments {
abstract static class PrepareArgumentsExplicit extends PrepareArguments {
private final RRootNode target;
private int depth = CACHE_SIZE;
protected final RRootNode target;
private final FormalArguments formals;
UninitializedExplicitPrepareArguments(RRootNode target) {
protected PrepareArgumentsExplicit(RRootNode target) {
this.target = target;
this.formals = target.getFormalArguments();
}
@Override
public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
CompilerDirectives.transferToInterpreterAndInvalidate();
PrepareArguments next;
if (depth-- > 0) {
next = new CachedExplicitPrepareArguments(this, target, call, explicitArgs == null ? null : explicitArgs.getSignature());
} else {
next = new GenericExplicitPrepareArguments(target);
}
return replace(next).execute(frame, explicitArgs, s3DefaultArguments, call);
protected MatchPermutation createArguments(RCallNode call, ArgumentsSignature explicitArgSignature) {
return ArgumentMatcher.matchArguments(explicitArgSignature, formals.getSignature(), call, target.getBuiltin());
}
}
private static final class CachedExplicitPrepareArguments extends PrepareArguments {
@Child private PrepareArguments next;
private final MatchPermutation permutation;
private final ArgumentsSignature cachedExplicitArgSignature;
private final FormalArguments formals;
CachedExplicitPrepareArguments(PrepareArguments next, RRootNode target, RCallNode call, ArgumentsSignature explicitArgSignature) {
this.next = next;
formals = target.getFormalArguments();
permutation = ArgumentMatcher.matchArguments(explicitArgSignature, formals.getSignature(), call, target.getBuiltin());
cachedExplicitArgSignature = explicitArgSignature;
@Specialization(limit = "CACHE_SIZE", guards = {"cachedExplicitArgSignature == explicitArgs.getSignature()"})
public RArgsValuesAndNames prepare(RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call,
@SuppressWarnings("unused") @Cached("explicitArgs.getSignature()") ArgumentsSignature cachedExplicitArgSignature,
@Cached("createArguments(call, cachedExplicitArgSignature)") MatchPermutation permutation) {
return ArgumentMatcher.matchArgumentsEvaluated(permutation, explicitArgs.getArguments(), s3DefaultArguments, formals);
}
@Override
public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
if (cachedExplicitArgSignature == explicitArgs.getSignature()) {
return ArgumentMatcher.matchArgumentsEvaluated(permutation, explicitArgs.getArguments(), s3DefaultArguments, formals);
}
return next.execute(frame, explicitArgs, s3DefaultArguments, call);
@Fallback
@TruffleBoundary
public RArgsValuesAndNames prepareGeneric(RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call) {
// Function and arguments may change every call: Flatt'n'Match on SlowPath! :-/
return ArgumentMatcher.matchArgumentsEvaluated(target, explicitArgs, s3DefaultArguments, RError.ROOTNODE);
}
}
private static final class GenericExplicitPrepareArguments extends PrepareArguments {
private final RRootNode target;
/**
* Returns the argument values and corresponding signature. The signature represents the
* original call signature reordered in the same way as the arguments. For s3DefaultArguments
* motivation see {@link RCallNode#callGroupGeneric}.
*/
public abstract RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call);
GenericExplicitPrepareArguments(RRootNode target) {
this.target = target;
}
public static PrepareArguments create(RRootNode target, CallArgumentsNode args, boolean noOpt) {
return PrepareArgumentsDefaultNodeGen.create(target, args, noOpt);
}
@Override
public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
CompilerDirectives.transferToInterpreter();
// Function and arguments may change every call: Flatt'n'Match on SlowPath! :-/
return ArgumentMatcher.matchArgumentsEvaluated(target, explicitArgs, s3DefaultArguments, RError.ROOTNODE);
}
public static PrepareArguments createExplicit(RRootNode target) {
return PrepareArgumentsExplicitNodeGen.create(target);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment