diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java index 4b7541fc27c25c991b992bb6459c7bacc6f0ac75..6639d3a732bc9a5f88e6ff59a5d98c606f8f73ee 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java @@ -59,20 +59,20 @@ import com.oracle.truffle.r.runtime.data.*; * {@link DirectCallNode} which is not as performant as the latter but has no further disadvantages. * But as the function changed its formal parameters changed, too, so a re-match has to be done as * well, which involves the creation of nodes and thus must happen on the {@link SlowPath}.<br/> - * Problem 2 however is not that easy, too: It is solved by reading the values associated with "..." - * (which are Promises) and wrapping them in newly created {@link RNode}s. These nodes get inserted - * into the arguments list ({@link CallArgumentsNode#executeFlatten(VirtualFrame)}) - which needs to + * Problem 2 is not that easy, too: It is solved by reading the values associated with "..." (which + * are Promises) and wrapping them in newly created {@link RNode}s. These nodes get inserted into + * the arguments list ({@link CallArgumentsNode#executeFlatten(VirtualFrame)}) - which needs to be * be matched against the formal parameters again, as theses arguments may carry names as well which * may have an impact on argument order. As matching involves node creation, it has to happen on the * {@link SlowPath}. * </p> - * To cache those node creations, two interwoven PICs are implemented. The cache is constructed - * using the following classes: + * To avoid repeated node creations as much as possible by caching two interwoven PICs are + * implemented. The caches are constructed using the following classes: * * <pre> * U = {@link UninitializedCallNode}: Forms the uninitialized end of the function PIC * D = {@link DispatchedCallNode}: Function fixed, no varargs - * G = {@link GenericCallNode}: Function fixed, no varargs (generic case) + * G = {@link GenericCallNode}: Function arbitrary, no varargs (generic case) * * UV = {@link UninitializedCallNode} with varargs, * UVC = {@link UninitializedVarArgsCacheCallNode} with varargs, for varargs cache @@ -81,12 +81,12 @@ import com.oracle.truffle.r.runtime.data.*; * GV = {@link GenericVarArgsCallNode}: Function arbitrary, with arbitrary varargs (generic case) * * (RB = {@link RBuiltinNode}: individual functions that are builtins are represented by this node - * which is not aware of caching) + * which is not aware of caching). Due to {@link CachedCallNode} (see below) this is transparent to + * the cache and just behaves like a D/DGV) * </pre> * - * As the function's identity is the primary id for this cache and as the property - * "takes varargs as argument" is static for each call site, we effectively end up with two separate - * cache structures. Some examples of each are depicted below: + * As the property "takes varargs as argument" is static for each call site, we effectively end up + * with two separate cache structures. Some examples of each are depicted below: * * <pre> * non varargs, max depth: @@ -95,23 +95,31 @@ import com.oracle.truffle.r.runtime.data.*; * * no varargs, generic (if max depth is exceeded): * | - * G + * D-D-D-D-G * * varargs: * | - * DV-DV-UV + * DV-DV-UV <- function identity level cache * | * DV * | - * UVC + * UVC <- varargs signature level cache * * varargs, max varargs depth exceeded: * | - * DV-DGV-UV + * DV-DV-UV + * | + * DV + * | + * DV + * | + * DV + * | + * DGV * * varargs, max function depth exceeded: * | - * GV + * DV-DV-DV-DV-GV * </pre> * <p> * In the diagrams above every horizontal connection "-" is in fact established by a separate node: @@ -142,8 +150,6 @@ public abstract class RCallNode extends RNode { private static final int FUNCTION_INLINE_CACHE_SIZE = 4; private static final int VARARGS_INLINE_CACHE_SIZE = 4; - private static final String GENERIC_VARARGS_WARNING = "Warning: RCallNode varargs generic case!"; - private static final String GENERIC_FUNCTION_WARNING = "Warning: RCallNode function generic case!"; protected RCallNode() { } @@ -264,7 +270,7 @@ public abstract class RCallNode extends RNode { } /** - * [C] + * [C] Extracts the check for function identity away from the individual cache nodes * * @see RCallNode */ @@ -307,7 +313,7 @@ public abstract class RCallNode extends RNode { } /** - * [U]/[UV] + * [U]/[UV] Forms the uninitialized end of the function PIC * * @see RCallNode */ @@ -347,20 +353,24 @@ public abstract class RCallNode extends RNode { private RCallNode specialize(VirtualFrame frame, RFunction function) { CompilerAsserts.neverPartOfCompilation(); - if (depth < FUNCTION_INLINE_CACHE_SIZE) { - final RCallNode current = createCacheNode(frame, function); - final RootCallNode cachedNode = new CachedCallNode(this.functionNode, current, new UninitializedCallNode(this), function); - current.onCreate(); - this.replace(cachedNode); - return cachedNode; + RCallNode current = createCacheNode(frame, function); + RootCallNode next = createNextNode(); + RootCallNode cachedNode = new CachedCallNode(this.functionNode, current, next, function); + next.onCreate(); + current.onCreate(); + this.replace(cachedNode); + return cachedNode; + } + + @SlowPath + protected RootCallNode createNextNode() { + if (depth + 1 < FUNCTION_INLINE_CACHE_SIZE) { + return new UninitializedCallNode(this); } else { - RootCallNode topMost = (RootCallNode) getTopNode(); // 2 possible cases: G (Multiple functions, no varargs) or GV (Multiple function // arbitrary varargs) - RCallNode generic = args.containsVarArgsSymbol() ? new GenericVarArgsCallNode(topMost.functionNode, args) : new GenericCallNode(topMost.functionNode, args); - generic = topMost.replace(generic, GENERIC_FUNCTION_WARNING); - generic.onCreate(); - return generic; + CallArgumentsNode clonedArgs = getClonedArgs(); + return args.containsVarArgsSymbol() ? new GenericVarArgsCallNode(functionNode, clonedArgs) : new GenericCallNode(functionNode, clonedArgs); } } @@ -401,14 +411,6 @@ public abstract class RCallNode extends RNode { return callNode; } - protected Node getTopNode() { - Node parentNode = this; - for (int i = 0; i < depth; i++) { - parentNode = parentNode.getParent(); - } - return parentNode; - } - public CallArgumentsNode getClonedArgs() { return NodeUtil.cloneNode(args); } @@ -514,29 +516,26 @@ public abstract class RCallNode extends RNode { return specializeAndExecute(frame, function, varArgsSignature); } + @SlowPath private Object specializeAndExecute(VirtualFrame frame, RFunction function, VarArgsSignature varArgsSignature) { CompilerAsserts.neverPartOfCompilation(); - if (depth < VARARGS_INLINE_CACHE_SIZE) { - // Extend cache - this.depth += 1; - CallArgumentsNode clonedArgs = NodeUtil.cloneNode(args); - DispatchedVarArgsCallNode newCallNode = DispatchedVarArgsCallNode.create(frame, clonedArgs, this, getSourceSection(), function, varArgsSignature, false); - return replace(newCallNode).execute(frame, function, varArgsSignature); - } else { - // Add stable generic case - DispatchedGenericVarArgsCallNode dgv = new DispatchedGenericVarArgsCallNode(function, args); - RCallNode topMostVarargsCache = getTopMost(); - return topMostVarargsCache.replace(dgv, GENERIC_VARARGS_WARNING).execute(frame, function); - } + // Extend cache + this.depth += 1; + CallArgumentsNode clonedArgs = NodeUtil.cloneNode(args); + VarArgsCacheCallNode next = createNextNode(function); + DispatchedVarArgsCallNode newCallNode = DispatchedVarArgsCallNode.create(frame, clonedArgs, next, getSourceSection(), function, varArgsSignature, false); + return replace(newCallNode).execute(frame, function, varArgsSignature); } - private RCallNode getTopMost() { - Node parent = this; - for (int i = 0; i < depth; i--) { - parent = parent.getParent(); + @SlowPath + private VarArgsCacheCallNode createNextNode(RFunction function) { + if (depth < VARARGS_INLINE_CACHE_SIZE) { + return this; + } else { + CallArgumentsNode clonedArgs = NodeUtil.cloneNode(args); + return new DispatchedGenericVarArgsCallNode(function, clonedArgs); } - return (RCallNode) parent; } } @@ -612,7 +611,7 @@ public abstract class RCallNode extends RNode { * * @see RCallNode */ - private static final class DispatchedGenericVarArgsCallNode extends RCallNode { + private static final class DispatchedGenericVarArgsCallNode extends VarArgsCacheCallNode { @Child private DirectCallNode call; @Child private CallArgumentsNode suppliedArgs; @@ -627,7 +626,7 @@ public abstract class RCallNode extends RNode { @Override @SlowPath - public Object execute(VirtualFrame frame, RFunction currentFunction) { + protected Object execute(VirtualFrame frame, RFunction currentFunction, VarArgsSignature varArgsSignature) { CompilerAsserts.neverPartOfCompilation(); assert function == currentFunction;