diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java index 80b2d4eb141463eb588c35467f57271848a8d583..eadcc67c1691925fac1754d3f54317dbf876dcd6 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java @@ -48,6 +48,7 @@ import com.oracle.truffle.api.impl.FindContextNode; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; @@ -102,6 +103,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; import com.oracle.truffle.r.runtime.nodes.RNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; /** @@ -384,7 +386,7 @@ final class REngine implements Engine, Engine.Timings { for (int i = 0; i < exprs.getLength(); i++) { Object obj = RASTUtils.checkForRSymbol(exprs.getDataAt(i)); if (obj instanceof RLanguage) { - result = evalNode((RNode) ((RLanguage) obj).getRep(), envir, depth); + result = evalNode(((RLanguage) obj).getRep().asRSyntaxNode(), envir, depth); } else { result = obj; } @@ -394,7 +396,7 @@ final class REngine implements Engine, Engine.Timings { @Override public Object eval(RLanguage expr, REnvironment envir, int depth) { - return evalNode((RNode) expr.getRep(), envir, depth); + return evalNode(expr.getRep().asRSyntaxNode(), envir, depth); } @Override @@ -432,11 +434,11 @@ final class REngine implements Engine, Engine.Timings { return func.getTarget().call(rArgs); } - private Object evalNode(RNode exprRep, REnvironment envir, int depth) { + private Object evalNode(RSyntaxElement exprRep, REnvironment envir, int depth) { // we need to copy the node, otherwise it (and its children) will specialized to a specific // frame descriptor and will fail on subsequent re-executions - RNode n = (RNode) exprRep.deepCopy(); - RootCallTarget callTarget = doMakeCallTarget(n, EVAL_FUNCTION_NAME, false, false); + RSyntaxNode n = RContext.getASTBuilder().process(exprRep); + RootCallTarget callTarget = doMakeCallTarget(n.asRNode(), EVAL_FUNCTION_NAME, false, false); RCaller call = RArguments.getCall(envir.getFrame()); return evalTarget(callTarget, call, envir, depth); } @@ -484,6 +486,7 @@ final class REngine implements Engine, Engine.Timings { private final class AnonymousRootNode extends RootNode { private final ValueProfile frameTypeProfile = ValueProfile.createClassProfile(); + private final ConditionProfile isVirtualFrameProfile = ConditionProfile.createBinaryProfile(); private final String description; private final boolean printResult; @@ -499,10 +502,21 @@ final class REngine implements Engine, Engine.Timings { this.topLevel = topLevel; } + private VirtualFrame prepareFrame(VirtualFrame frame) { + VirtualFrame vf; + MaterializedFrame originalFrame = (MaterializedFrame) frameTypeProfile.profile(frame.getArguments()[0]); + if (isVirtualFrameProfile.profile(originalFrame instanceof VirtualFrame)) { + vf = (VirtualFrame) originalFrame; + } else { + vf = SubstituteVirtualFrame.create(originalFrame); + } + return vf; + } + @Override public Object execute(VirtualFrame frame) { assert frame.getArguments().length == 1; - VirtualFrame vf = SubstituteVirtualFrame.create((MaterializedFrame) frameTypeProfile.profile(frame.getArguments()[0])); + VirtualFrame vf = prepareFrame(frame); Object result = null; try { result = body.execute(vf); diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java index 590fdc5b8f241f2ab63c3b14aabe3d21965309d5..3387c39a9edb20d3fe757c41f8760495f60b4932 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java @@ -48,7 +48,6 @@ import com.oracle.truffle.r.nodes.control.IfNode; import com.oracle.truffle.r.nodes.control.ReplacementNode; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; -import com.oracle.truffle.r.nodes.function.GroupDispatchNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.runtime.Arguments; @@ -268,16 +267,14 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { private static RNode unwrapToRNode(Object objArg) { Object obj = objArg; + // obj is RSymbol or a primitive value. + // A symbol needs to be converted back to a ReadVariableNode if (obj instanceof RLanguage) { return (RNode) RASTUtils.unwrap(((RLanguage) obj).getRep()); + } else if (obj instanceof RSymbol) { + return ReadVariableNode.create(((RSymbol) obj).getName()); } else { - // obj is RSymbol or a primitive value. - // A symbol needs to be converted back to a ReadVariableNode - if (obj instanceof RSymbol) { - return ReadVariableNode.create(((RSymbol) obj).getName()); - } else { - return ConstantNode.create(obj); - } + return ConstantNode.create(obj); } } @@ -299,7 +296,8 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { @TruffleBoundary public RStringVector getNames(RLanguage rl) { RBaseNode node = rl.getRep(); - if (node instanceof RCallNode || node instanceof GroupDispatchNode) { + if (node instanceof RCallNode) { + RCallNode call = (RCallNode) node; /* * If the function or any argument has a name, then all arguments (and the function) are * given names, with unnamed arguments getting "". However, if no arguments have names, @@ -307,13 +305,12 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { */ boolean hasName = false; String functionName = ""; - RNode fnNode = RASTUtils.getFunctionNode(node); + RNode fnNode = call.getFunctionNode(); if (fnNode instanceof NamedRNode) { hasName = true; functionName = ((NamedRNode) fnNode).name; } - Arguments<RSyntaxNode> args = RASTUtils.findCallArguments(node); - ArgumentsSignature sig = args.getSignature(); + ArgumentsSignature sig = call.getSyntaxSignature(); if (!hasName) { for (int i = 0; i < sig.getLength(); i++) { if (sig.getName(i) != null) { @@ -342,7 +339,8 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { public void setNames(RLanguage rl, RStringVector names) { RNode node = (RNode) rl.getRep(); if (node instanceof RCallNode) { - Arguments<RSyntaxNode> args = RASTUtils.findCallArguments(node); + RCallNode call = (RCallNode) node; + Arguments<RSyntaxNode> args = call.getArguments(); ArgumentsSignature sig = args.getSignature(); String[] newNames = new String[sig.getLength()]; int argNamesLength = names.getLength() - 1; @@ -354,8 +352,6 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { } // copying is already handled by RShareable rl.setRep(RCallNode.createCall(RSyntaxNode.INTERNAL, ((RCallNode) node).getFunctionNode(), ArgumentsSignature.get(newNames), args.getArguments())); - } else if (node instanceof GroupDispatchNode) { - throw RError.nyi(null, "group dispatch names update"); } else { throw RInternalError.shouldNotReachHere(); } @@ -601,7 +597,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { String className = tag.getSimpleName(); switch (className) { case "CallTag": - return node instanceof RCallNode || node instanceof GroupDispatchNode; + return node instanceof RCallNode; case "StatementTag": { Node parent = ((RInstrumentableNode) node).unwrapParent(); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java index 8b323a7fdcc6a4628f197ac642032030265de0ec..682b91fa607cef84a868fd069418f2b0e9bef573 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java @@ -379,7 +379,7 @@ public class MethodsListDispatch { } RCallNode callNode = (RCallNode) matchedCall.getRep(); RNode f = ReadVariableNode.create(RRuntime.R_DOT_NEXT_METHOD); - ArgumentsSignature sig = callNode.getArguments().getSignature(); + ArgumentsSignature sig = callNode.getSyntaxSignature(); RSyntaxNode[] args = new RSyntaxNode[sig.getLength()]; for (int i = 0; i < args.length; i++) { args[i] = ReadVariableNode.create(sig.getName(i)); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java index 010d68a7e827fa350a899c70a8bfb3118c30bf2b..3e7d905c8275e80c958c998808ac306e8363502e 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java @@ -37,7 +37,7 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.RASTUtils; -import com.oracle.truffle.r.nodes.builtin.RPrecedenceBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode; @@ -52,6 +52,8 @@ import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.CastToVectorNode; import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen; +import com.oracle.truffle.r.nodes.unary.PrecedenceNode; +import com.oracle.truffle.r.nodes.unary.PrecedenceNodeGen; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RBuiltin; @@ -71,14 +73,34 @@ import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.ops.na.NACheck; -public abstract class Bind extends RPrecedenceBuiltinNode { +public abstract class Bind extends RBaseNode { + + protected enum BindType { + rbind, + cbind; + } + + protected static final int NO_PRECEDENCE = PrecedenceNode.NO_PRECEDENCE; + protected static final int RAW_PRECEDENCE = PrecedenceNode.RAW_PRECEDENCE; + protected static final int LOGICAL_PRECEDENCE = PrecedenceNode.LOGICAL_PRECEDENCE; + protected static final int INT_PRECEDENCE = PrecedenceNode.INT_PRECEDENCE; + protected static final int DOUBLE_PRECEDENCE = PrecedenceNode.DOUBLE_PRECEDENCE; + protected static final int COMPLEX_PRECEDENCE = PrecedenceNode.COMPLEX_PRECEDENCE; + protected static final int STRING_PRECEDENCE = PrecedenceNode.STRING_PRECEDENCE; + protected static final int LIST_PRECEDENCE = PrecedenceNode.LIST_PRECEDENCE; + protected static final int EXPRESSION_PRECEDENCE = PrecedenceNode.EXPRESSION_PRECEDENCE; + + public abstract Object execute(VirtualFrame frame, Object deparseLevelObj, Object[] args, RArgsValuesAndNames promiseArgs, int precedence); @Child private CastToVectorNode castVector; @Child private UseMethodInternalNode dcn; @Child private CastLogicalNode castLogical; + private final BindType type; + private final ConditionProfile nullNamesProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile emptyVectorProfile = ConditionProfile.createBinaryProfile(); private final BranchProfile nonNullNames = BranchProfile.create(); @@ -87,10 +109,19 @@ public abstract class Bind extends RPrecedenceBuiltinNode { protected final ValueProfile resultProfile = ValueProfile.createClassProfile(); protected final ValueProfile vectorProfile = ValueProfile.createClassProfile(); - protected String getBindType() { - // this method should be abstract but due to annotation processor problem it does not work - RInternalError.unimplemented("getBindType() method must be overridden in a subclass"); - return null; + @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create(); + + protected int precedence(RArgsValuesAndNames args) { + int precedence = -1; + Object[] array = args.getArguments(); + for (int i = 0; i < array.length; i++) { + precedence = Math.max(precedence, precedenceNode.executeInteger(array[i], RRuntime.LOGICAL_FALSE)); + } + return precedence; + } + + protected Bind(BindType type) { + this.type = type; } protected RAbstractVector castVector(Object value) { @@ -110,9 +141,8 @@ public abstract class Bind extends RPrecedenceBuiltinNode { } @SuppressWarnings("unused") - @Specialization(guards = "isNullPrecedence(args)") - protected RNull allNull(VirtualFrame frame, Object deparseLevelObj, RArgsValuesAndNames args) { - controlVisibility(); + @Specialization(guards = "precedence == NO_PRECEDENCE") + protected RNull allNull(VirtualFrame frame, Object deparseLevelObj, Object[] args, RArgsValuesAndNames promiseArgs, int precedence) { return RNull.instance; } @@ -120,35 +150,33 @@ public abstract class Bind extends RPrecedenceBuiltinNode { private static final RStringVector DATA_FRAME_CLASS = RDataFactory.createStringVectorFromScalar("data.frame"); - @Specialization(guards = {"args.getLength() > 1", "isDataFrame(args)"}) - protected Object allDataFrame(VirtualFrame frame, Object deparseLevel, RArgsValuesAndNames args) { + @Specialization(guards = {"args.length > 1", "isDataFrame(args)"}) + protected Object allDataFrame(VirtualFrame frame, Object deparseLevel, @SuppressWarnings("unused") Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) { if (dcn == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - dcn = insert(new UseMethodInternalNode(getBindType(), SIGNATURE, false)); + dcn = insert(new UseMethodInternalNode(type.toString(), SIGNATURE, false)); } try { - return dcn.execute(frame, DATA_FRAME_CLASS, new Object[]{deparseLevel, args}); + return dcn.execute(frame, DATA_FRAME_CLASS, new Object[]{deparseLevel, promiseArgs}); } catch (S3FunctionLookupNode.NoGenericMethodException e) { throw RInternalError.shouldNotReachHere(); } } - private Object bindInternal(VirtualFrame frame, Object deparseLevel, RArgsValuesAndNames args, CastNode castNode, boolean needsVectorCast) { - controlVisibility(); - Object[] array = args.getArguments(); - ArgumentsSignature signature = args.getSignature(); + private Object bindInternal(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, CastNode castNode, boolean needsVectorCast) { + ArgumentsSignature signature = promiseArgs.getSignature(); String[] vecNames = nullNamesProfile.profile(signature.getNonNullCount() == 0) ? null : new String[signature.getLength()]; - RAbstractVector[] vectors = new RAbstractVector[args.getLength()]; + RAbstractVector[] vectors = new RAbstractVector[args.length]; boolean complete = true; int ind = 0; naCheck.enable(true); - for (int i = 0; i < array.length; i++) { + for (int i = 0; i < args.length; i++) { if (vecNames != null) { nonNullNames.enter(); vecNames[ind] = signature.getName(i); naCheck.check(vecNames[ind]); } - Object result = castNode.execute(array[i]); + Object result = castNode.execute(args[i]); RAbstractVector vector; if (needsVectorCast) { vector = castVector(result); @@ -163,80 +191,48 @@ public abstract class Bind extends RPrecedenceBuiltinNode { ind++; } } - if (emptyVectorProfile.profile(ind < array.length)) { + if (emptyVectorProfile.profile(ind < args.length)) { if (vecNames != null) { nonNullNames.enter(); vecNames = Arrays.copyOf(vecNames, ind); } vectors = Arrays.copyOf(vectors, ind); } - return genericBind(frame, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel); + if (type == BindType.cbind) { + return genericCBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel); + } else { + return genericRBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel); + } } - @Specialization(guards = {"isIntegerPrecedence(args)", "args.getLength() > 1", "!isDataFrame(args)"}) - protected Object allInt(VirtualFrame frame, Object deparseLevel, RArgsValuesAndNames args, // + @Specialization(guards = {"precedence == INT_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"}) + protected Object allInt(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastIntegerNode cast) { - return bindInternal(frame, deparseLevel, args, cast, true); + return bindInternal(deparseLevel, args, promiseArgs, cast, true); } - @Specialization(guards = {"isDoublePrecedence( args)", "args.getLength() > 1", "!isDataFrame(args)"}) - protected Object allDouble(VirtualFrame frame, Object deparseLevel, RArgsValuesAndNames args, // + @Specialization(guards = {"precedence == DOUBLE_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"}) + protected Object allDouble(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastDoubleNode cast) { - return bindInternal(frame, deparseLevel, args, cast, true); + return bindInternal(deparseLevel, args, promiseArgs, cast, true); } - @Specialization(guards = {"isStringPrecedence( args)", "args.getLength() > 1", "!isDataFrame(args)"}) - protected Object allString(VirtualFrame frame, Object deparseLevel, RArgsValuesAndNames args, // + @Specialization(guards = {"precedence == STRING_PRECEDENCE", "args.length> 1", "!isDataFrame(args)"}) + protected Object allString(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastStringNode cast) { - return bindInternal(frame, deparseLevel, args, cast, true); + return bindInternal(deparseLevel, args, promiseArgs, cast, true); } - @Specialization(guards = {"isComplexPrecedence( args)", "args.getLength() > 1", "!isDataFrame(args)"}) - protected Object allComplex(VirtualFrame frame, Object deparseLevel, RArgsValuesAndNames args, // + @Specialization(guards = {"precedence == COMPLEX_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"}) + protected Object allComplex(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastComplexNode cast) { - return bindInternal(frame, deparseLevel, args, cast, true); + return bindInternal(deparseLevel, args, promiseArgs, cast, true); } - @Specialization(guards = {"isListPrecedence( args)", "args.getLength() > 1", "!isDataFrame(args)"}) - protected Object allList(VirtualFrame frame, Object deparseLevel, RArgsValuesAndNames args, // + @Specialization(guards = {"precedence == LIST_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"}) + protected Object allList(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastListNode cast) { - return bindInternal(frame, deparseLevel, args, cast, false); - } - - protected Object allOneElem(VirtualFrame frame, Object deparseLevelObj, RArgsValuesAndNames args, boolean cbind) { - RAbstractVector vec = castVector(args.getArgument(0)); - if (vec.isMatrix()) { - return vec; - } - int[] dims = getDimensions(vec, cbind); - // for cbind dimNamesA is names for the 1st dim and dimNamesB is names for 2nd dim; for - // rbind the other way around - Object dimNamesA = vec.getNames(attrProfiles) == null ? RNull.instance : vec.getNames(attrProfiles); - Object dimNamesB; - - ArgumentsSignature signature = args.getSignature(); - if (signature.getNonNullCount() == 0) { - int deparseLevel = deparseLevel(deparseLevelObj); - if (deparseLevel == 0) { - dimNamesB = RNull.instance; - } else { - // var arg is at the first position - as in the R bind call - RArgsValuesAndNames varArg = (RArgsValuesAndNames) RArguments.getArgument(frame, 0); - String deparsedName = deparseArgName(varArg, deparseLevel, 0); - dimNamesB = deparsedName == RRuntime.NAMES_ATTR_EMPTY_VALUE ? RNull.instance : RDataFactory.createStringVector(deparsedName); - } - } else { - String[] names = new String[signature.getLength()]; - for (int i = 0; i < names.length; i++) { - names[i] = signature.getName(i); - } - dimNamesB = RDataFactory.createStringVector(names, RDataFactory.COMPLETE_VECTOR); - } - - RVector res = (RVector) vec.copyWithNewDimensions(dims); - res.setDimNames(RDataFactory.createList(cbind ? new Object[]{dimNamesA, dimNamesB} : new Object[]{dimNamesB, dimNamesA})); - res.copyRegAttributesFrom(vec); - return res; + return bindInternal(deparseLevel, args, promiseArgs, cast, false); } /** @@ -273,18 +269,9 @@ public abstract class Bind extends RPrecedenceBuiltinNode { /** * Compute dimnames for columns (cbind) or rows (rbind) from names of vectors being combined or * by deparsing. - * - * @param frame - * @param vec - * @param argNames - * @param resDim - * @param oldInd - * @param vecInd - * @param deparseLevelObj - * @param dimNamesArray - * @return dimnames */ - protected int getDimResultNamesFromVectors(VirtualFrame frame, RAbstractVector vec, String[] argNames, int resDim, int oldInd, int vecInd, Object deparseLevelObj, String[] dimNamesArray, + protected int getDimResultNamesFromVectors(RArgsValuesAndNames promiseArgs, RAbstractVector vec, String[] argNames, int resDim, int oldInd, int vecInd, Object deparseLevelObj, + String[] dimNamesArray, int dimNamesInd) { int ind = oldInd; if (vec.isMatrix()) { @@ -311,8 +298,7 @@ public abstract class Bind extends RPrecedenceBuiltinNode { dimNamesArray[ind++] = RRuntime.NAMES_ATTR_EMPTY_VALUE; return -ind; } else { - RArgsValuesAndNames varArg = (RArgsValuesAndNames) RArguments.getArgument(frame, 0); - String deparsedName = deparseArgName(varArg, deparseLevel, vecInd); + String deparsedName = deparseArgName(promiseArgs, deparseLevel, vecInd); dimNamesArray[ind++] = deparsedName; return deparsedName == RRuntime.NAMES_ATTR_EMPTY_VALUE ? -ind : ind; } @@ -331,33 +317,25 @@ public abstract class Bind extends RPrecedenceBuiltinNode { } } - @SuppressWarnings("unused") - protected RVector genericBind(VirtualFrame frame, RAbstractVector[] vectors, boolean complete, String[] vacNames, boolean vecNamesComplete, Object deparseLevel) { - // this method should be abstract but due to annotation processor problem it does not work - RInternalError.unimplemented("genericBind() method must be overridden in a subclass"); - return null; - } - /** * * @param vectors vectors to be combined * @param res result dims * @param bindDims columns dim (cbind) or rows dim (rbind) - * @param cbind to be used for cbind function (true) or rbind function (false) * @return whether number of rows (cbind) or columns (rbind) in vectors is the same */ - protected static boolean getResultDimensions(RAbstractVector[] vectors, int[] res, int[] bindDims, boolean cbind) { - int srcDim1Ind = cbind ? 0 : 1; - int srcDim2Ind = cbind ? 1 : 0; + protected boolean getResultDimensions(RAbstractVector[] vectors, int[] res, int[] bindDims) { + int srcDim1Ind = type == BindType.cbind ? 0 : 1; + int srcDim2Ind = type == BindType.cbind ? 1 : 0; assert vectors.length > 0; - int[] dim = getDimensions(vectors[0], cbind); + int[] dim = getDimensions(vectors[0]); assert dim.length == 2; bindDims[0] = dim[srcDim2Ind]; res[srcDim1Ind] = dim[srcDim1Ind]; res[srcDim2Ind] = dim[srcDim2Ind]; boolean notEqualDims = false; for (int i = 1; i < vectors.length; i++) { - int[] dims = getDimensions(vectors[i], cbind); + int[] dims = getDimensions(vectors[i]); assert dims.length == 2; bindDims[i] = dims[srcDim2Ind]; if (dims[srcDim1Ind] != res[srcDim1Ind]) { @@ -380,10 +358,10 @@ public abstract class Bind extends RPrecedenceBuiltinNode { } } - protected static int[] getDimensions(RAbstractVector vector, boolean cbind) { + protected int[] getDimensions(RAbstractVector vector) { int[] dimensions = vector.getDimensions(); if (dimensions == null || dimensions.length != 2) { - return cbind ? new int[]{vector.getLength(), 1} : new int[]{1, vector.getLength()}; + return type == BindType.cbind ? new int[]{vector.getLength(), 1} : new int[]{1, vector.getLength()}; } else { assert dimensions.length == 2; return dimensions; @@ -391,9 +369,9 @@ public abstract class Bind extends RPrecedenceBuiltinNode { } @TruffleBoundary - protected static String deparseArgName(RArgsValuesAndNames varArg, int deparseLevel, int argInd) { - assert varArg.getLength() >= argInd; - Object argValue = varArg.getArgument(argInd); + protected static String deparseArgName(RArgsValuesAndNames promiseArgs, int deparseLevel, int argInd) { + assert promiseArgs.getLength() >= argInd; + Object argValue = promiseArgs.getArgument(argInd); if (argValue instanceof RPromise) { RPromise p = (RPromise) argValue; Object node = RASTUtils.createLanguageElement(RASTUtils.unwrap(p.getRep())); @@ -438,9 +416,9 @@ public abstract class Bind extends RPrecedenceBuiltinNode { } } - protected boolean isDataFrame(RArgsValuesAndNames args) { - for (int i = 0; i < args.getLength(); i++) { - if (inheritsCheck.execute(args.getArgument(i))) { + protected boolean isDataFrame(Object[] args) { + for (int i = 0; i < args.length; i++) { + if (inheritsCheck.execute(args[i])) { return true; } } @@ -449,151 +427,198 @@ public abstract class Bind extends RPrecedenceBuiltinNode { } @RBuiltin(name = "cbind", kind = INTERNAL, parameterNames = {"deparse.level", "..."}) - public abstract static class CbindInternal extends Bind { - private final BranchProfile everSeenNotEqualRows = BranchProfile.create(); + public abstract static class CbindInternal extends RBuiltinNode { - @Override - public String getBindType() { - return "cbind"; + @Child private Bind bind = BindNodeGen.create(BindType.cbind); + @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create(); + + private int precedence(Object[] args) { + int precedence = -1; + for (int i = 0; i < args.length; i++) { + precedence = Math.max(precedence, precedenceNode.executeInteger(args[i], RRuntime.LOGICAL_FALSE)); + } + return precedence; } - @Specialization(guards = {"!isNullPrecedence(args)", "args.getLength() == 1"}) - protected Object allOneElem(VirtualFrame frame, Object deparseLevelObj, RArgsValuesAndNames args) { + @Specialization + protected Object bind(VirtualFrame frame, Object deparseLevelObj, RArgsValuesAndNames args) { controlVisibility(); - return allOneElem(frame, deparseLevelObj, args, true); + return bind.execute(frame, deparseLevelObj, args.getArguments(), (RArgsValuesAndNames) RArguments.getArgument(frame, 0), precedence(args.getArguments())); } + } - @Override - public RVector genericBind(VirtualFrame frame, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, Object deparseLevel) { - - int[] resultDimensions = new int[2]; - int[] secondDims = new int[vectors.length]; - boolean notEqualRows = getResultDimensions(vectors, resultDimensions, secondDims, true); - RVector result = resultProfile.profile(vectors[0].createEmptySameType(resultDimensions[0] * resultDimensions[1], complete)); - - int ind = 0; - Object rowDimResultNames = RNull.instance; - String[] colDimNamesArray = new String[resultDimensions[1]]; - int colInd = 0; - boolean allColDimNamesNull = true; - for (int i = 0; i < vectors.length; i++) { - RAbstractVector vec = vectorProfile.profile(vectors[i]); - if (rowDimResultNames == RNull.instance) { - // get the first valid names value - rowDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[0], 0); - } + private final BranchProfile everSeenNotEqualRows = BranchProfile.create(); + private final BranchProfile everSeenNotEqualColumns = BranchProfile.create(); - // compute dimnames for the second dimension - int newColInd = getDimResultNamesFromVectors(frame, vec, vecNames, secondDims[i], colInd, i, deparseLevel, colDimNamesArray, 1); - if (newColInd < 0) { - colInd = -newColInd; - } else { - allColDimNamesNull = false; - colInd = newColInd; - } + @Specialization(guards = {"precedence != NO_PRECEDENCE", "args.length == 1"}) + protected Object allOneElem(Object deparseLevelObj, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) { + RAbstractVector vec = castVector(args[0]); + if (vec.isMatrix()) { + return vec; + } + int[] dims = getDimensions(vec); + // for cbind dimNamesA is names for the 1st dim and dimNamesB is names for 2nd dim; for + // rbind the other way around + Object dimNamesA = vec.getNames(attrProfiles) == null ? RNull.instance : vec.getNames(attrProfiles); + Object dimNamesB; - // compute result vector values - int vecLength = vec.getLength(); - for (int j = 0; j < vecLength; j++) { - result.transferElementSameType(ind++, vec, j); - } - if (notEqualRows) { - everSeenNotEqualRows.enter(); - if (vecLength < resultDimensions[0]) { - // re-use vector elements - int k = 0; - for (int j = 0; j < resultDimensions[0] - vecLength; j++, k = Utils.incMod(k, vecLength)) { - result.transferElementSameType(ind++, vectors[i], k); - } - - if (k != 0) { - RError.warning(this, RError.Message.ROWS_NOT_MULTIPLE, i + 1); - } + ArgumentsSignature signature = promiseArgs.getSignature(); + if (signature.getNonNullCount() == 0) { + int deparseLevel = deparseLevel(deparseLevelObj); + if (deparseLevel == 0) { + dimNamesB = RNull.instance; + } else { + // var arg is at the first position - as in the R bind call + String deparsedName = deparseArgName(promiseArgs, deparseLevel, 0); + dimNamesB = deparsedName == RRuntime.NAMES_ATTR_EMPTY_VALUE ? RNull.instance : RDataFactory.createStringVector(deparsedName); + } + } else { + String[] names = new String[signature.getLength()]; + for (int i = 0; i < names.length; i++) { + names[i] = signature.getName(i); + } + dimNamesB = RDataFactory.createStringVector(names, RDataFactory.COMPLETE_VECTOR); + } + + RVector res = (RVector) vec.copyWithNewDimensions(dims); + res.setDimNames(RDataFactory.createList(type == BindType.cbind ? new Object[]{dimNamesA, dimNamesB} : new Object[]{dimNamesB, dimNamesA})); + res.copyRegAttributesFrom(vec); + return res; + } + + public RVector genericCBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, Object deparseLevel) { + + int[] resultDimensions = new int[2]; + int[] secondDims = new int[vectors.length]; + boolean notEqualRows = getResultDimensions(vectors, resultDimensions, secondDims); + RVector result = resultProfile.profile(vectors[0].createEmptySameType(resultDimensions[0] * resultDimensions[1], complete)); + + int ind = 0; + Object rowDimResultNames = RNull.instance; + String[] colDimNamesArray = new String[resultDimensions[1]]; + int colInd = 0; + boolean allColDimNamesNull = true; + for (int i = 0; i < vectors.length; i++) { + RAbstractVector vec = vectorProfile.profile(vectors[i]); + if (rowDimResultNames == RNull.instance) { + // get the first valid names value + rowDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[0], 0); + } + + // compute dimnames for the second dimension + int newColInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, secondDims[i], colInd, i, deparseLevel, colDimNamesArray, 1); + if (newColInd < 0) { + colInd = -newColInd; + } else { + allColDimNamesNull = false; + colInd = newColInd; + } + + // compute result vector values + int vecLength = vec.getLength(); + for (int j = 0; j < vecLength; j++) { + result.transferElementSameType(ind++, vec, j); + } + if (notEqualRows) { + everSeenNotEqualRows.enter(); + if (vecLength < resultDimensions[0]) { + // re-use vector elements + int k = 0; + for (int j = 0; j < resultDimensions[0] - vecLength; j++, k = Utils.incMod(k, vecLength)) { + result.transferElementSameType(ind++, vectors[i], k); } - } + if (k != 0) { + RError.warning(this, RError.Message.ROWS_NOT_MULTIPLE, i + 1); + } + } } - Object colDimResultNames = allColDimNamesNull ? RNull.instance : RDataFactory.createStringVector(colDimNamesArray, vecNamesComplete); - result.setDimensions(resultDimensions); - result.setDimNames(RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames})); - return result; + } + Object colDimResultNames = allColDimNamesNull ? RNull.instance : RDataFactory.createStringVector(colDimNamesArray, vecNamesComplete); + result.setDimensions(resultDimensions); + result.setDimNames(RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames})); + return result; } @RBuiltin(name = "rbind", kind = INTERNAL, parameterNames = {"deparse.level", "..."}) - public abstract static class RbindInternal extends Bind { - private final BranchProfile everSeenNotEqualColumns = BranchProfile.create(); + public abstract static class RbindInternal extends RBuiltinNode { + + @Child private Bind bind = BindNodeGen.create(BindType.rbind); + @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create(); - @Override - public String getBindType() { - return "rbind"; + private int precedence(Object[] args) { + int precedence = -1; + for (int i = 0; i < args.length; i++) { + precedence = Math.max(precedence, precedenceNode.executeInteger(args[i], RRuntime.LOGICAL_FALSE)); + } + return precedence; } - @Specialization(guards = {"!isNullPrecedence(args)", "args.getLength() == 1"}) - protected Object allOneElem(VirtualFrame frame, Object deparseLevelObj, RArgsValuesAndNames args) { + @Specialization + protected Object bind(VirtualFrame frame, Object deparseLevelObj, RArgsValuesAndNames args) { controlVisibility(); - return allOneElem(frame, deparseLevelObj, args, false); + return bind.execute(frame, deparseLevelObj, args.getArguments(), (RArgsValuesAndNames) RArguments.getArgument(frame, 0), precedence(args.getArguments())); } + } - @Override - public RVector genericBind(VirtualFrame frame, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, Object deparseLevel) { - - int[] resultDimensions = new int[2]; - int[] firstDims = new int[vectors.length]; - boolean notEqualColumns = getResultDimensions(vectors, resultDimensions, firstDims, false); - RVector result = resultProfile.profile(vectors[0].createEmptySameType(resultDimensions[0] * resultDimensions[1], complete)); - - Object colDimResultNames = RNull.instance; - String[] rowDimNamesArray = new String[resultDimensions[0]]; - int rowInd = 0; - boolean allRowDimNamesNull = true; - int dstRowInd = 0; - for (int i = 0; i < vectors.length; i++) { - RAbstractVector vec = vectorProfile.profile(vectors[i]); - if (colDimResultNames == RNull.instance) { - // get the first valid names value - colDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[1], 1); - } + public RVector genericRBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, Object deparseLevel) { + + int[] resultDimensions = new int[2]; + int[] firstDims = new int[vectors.length]; + boolean notEqualColumns = getResultDimensions(vectors, resultDimensions, firstDims); + RVector result = resultProfile.profile(vectors[0].createEmptySameType(resultDimensions[0] * resultDimensions[1], complete)); + + Object colDimResultNames = RNull.instance; + String[] rowDimNamesArray = new String[resultDimensions[0]]; + int rowInd = 0; + boolean allRowDimNamesNull = true; + int dstRowInd = 0; + for (int i = 0; i < vectors.length; i++) { + RAbstractVector vec = vectorProfile.profile(vectors[i]); + if (colDimResultNames == RNull.instance) { + // get the first valid names value + colDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[1], 1); + } - // compute dimnames for the second dimension - int newRowInd = getDimResultNamesFromVectors(frame, vec, vecNames, firstDims[i], rowInd, i, deparseLevel, rowDimNamesArray, 0); - if (newRowInd < 0) { - rowInd = -newRowInd; - } else { - allRowDimNamesNull = false; - rowInd = newRowInd; - } + // compute dimnames for the second dimension + int newRowInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, firstDims[i], rowInd, i, deparseLevel, rowDimNamesArray, 0); + if (newRowInd < 0) { + rowInd = -newRowInd; + } else { + allRowDimNamesNull = false; + rowInd = newRowInd; + } - // compute result vector values - int vecLength = vec.getLength(); - int srcInd = 0; - int j = 0; - for (; j < vecLength / firstDims[i]; j++) { - for (int k = dstRowInd; k < dstRowInd + firstDims[i]; k++) { - result.transferElementSameType(j * resultDimensions[0] + k, vec, srcInd++); - } + // compute result vector values + int vecLength = vec.getLength(); + int srcInd = 0; + int j = 0; + for (; j < vecLength / firstDims[i]; j++) { + for (int k = dstRowInd; k < dstRowInd + firstDims[i]; k++) { + result.transferElementSameType(j * resultDimensions[0] + k, vec, srcInd++); } - if (notEqualColumns) { - everSeenNotEqualColumns.enter(); - if (j < resultDimensions[1]) { - // re-use vector elements - int k = 0; - for (; j < resultDimensions[1]; j++, k = Utils.incMod(k, vecLength % resultDimensions[1])) { - result.transferElementSameType(j * resultDimensions[0] + (dstRowInd + firstDims[i] - 1), vectors[i], k); - } - - if (k != 0) { - RError.warning(this, RError.Message.COLUMNS_NOT_MULTIPLE, i + 1); - } + } + if (notEqualColumns) { + everSeenNotEqualColumns.enter(); + if (j < resultDimensions[1]) { + // re-use vector elements + int k = 0; + for (; j < resultDimensions[1]; j++, k = Utils.incMod(k, vecLength % resultDimensions[1])) { + result.transferElementSameType(j * resultDimensions[0] + (dstRowInd + firstDims[i] - 1), vectors[i], k); } - } - dstRowInd += firstDims[i]; + if (k != 0) { + RError.warning(this, RError.Message.COLUMNS_NOT_MULTIPLE, i + 1); + } + } } - Object rowDimResultNames = allRowDimNamesNull ? RNull.instance : RDataFactory.createStringVector(rowDimNamesArray, vecNamesComplete); - result.setDimensions(resultDimensions); - result.setDimNames(RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames})); - return result; + dstRowInd += firstDims[i]; + } + Object rowDimResultNames = allRowDimNamesNull ? RNull.instance : RDataFactory.createStringVector(rowDimNamesArray, vecNamesComplete); + result.setDimensions(resultDimensions); + result.setDimNames(RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames})); + return result; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java index c3136361e36c15445c5d4912009641c6f641f233..f1828f586f2ec87bd74c3ae75c76ccec60e0ee65 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java @@ -25,48 +25,30 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.BranchProfile; -import com.oracle.truffle.r.nodes.CallInlineCacheNode; -import com.oracle.truffle.r.nodes.CallInlineCacheNodeGen; import com.oracle.truffle.r.nodes.RASTUtils; -import com.oracle.truffle.r.nodes.access.ConstantNode; +import com.oracle.truffle.r.nodes.access.FrameSlotNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen; -import com.oracle.truffle.r.nodes.function.ArgumentMatcher; -import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; -import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen; -import com.oracle.truffle.r.nodes.function.EvaluatedArguments; -import com.oracle.truffle.r.nodes.function.GroupDispatchNode; -import com.oracle.truffle.r.nodes.function.PromiseHelperNode; -import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode; -import com.oracle.truffle.r.nodes.function.RCallNode.RootCallNode; -import com.oracle.truffle.r.nodes.function.RCallerHelper; -import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode; -import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result; -import com.oracle.truffle.r.nodes.function.signature.GetCallerFrameNode; -import com.oracle.truffle.r.nodes.function.signature.RArgumentsNode; +import com.oracle.truffle.r.nodes.function.GetCallerFrameNode; +import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RBuiltin; -import com.oracle.truffle.r.runtime.RDispatch; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; -import com.oracle.truffle.r.runtime.data.RBuiltinDescriptor; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RMissing; -import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; @@ -79,26 +61,18 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode; @RBuiltin(name = "do.call", kind = INTERNAL, parameterNames = {"what", "args", "envir"}) public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNodeChildren { - @Child private CallInlineCacheNode callCache = CallInlineCacheNodeGen.create(); @Child private GetFunctions.Get getNode; - @Child private GroupDispatchNode groupDispatch; @Child private GetCallerFrameNode getCallerFrame; - @Child private PromiseHelperNode promiseHelper = new PromiseHelperNode(); - @CompilationFinal private boolean needsCallerFrame; - - @Child private S3FunctionLookupNode dispatchLookup; - @Child private PromiseCheckHelperNode hierarchyPromiseHelper; - @Child private ClassHierarchyNode classHierarchyNode; - @Child private RootCallNode internalDispatchCall; - - @Child private RArgumentsNode argsNode = RArgumentsNode.create(); - private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); private final BranchProfile errorProfile = BranchProfile.create(); private final BranchProfile containsRLanguageProfile = BranchProfile.create(); private final BranchProfile containsRSymbolProfile = BranchProfile.create(); + private final Object argsIdentifier = new Object(); + @Child private RCallNode call = RCallNode.createExplicitCall(argsIdentifier); + @Child private FrameSlotNode slot = FrameSlotNode.createTemp(argsIdentifier, true); + @Specialization protected Object doDoCall(VirtualFrame frame, Object what, RList argsAsList, REnvironment env) { /* @@ -155,85 +129,9 @@ public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNode } } } - - /* Step 3: Perform the actual evaluation, checking for builtin special cases. */ - return executeCall(frame, func, argValues, signature, callerFrame); - } - - /* This exists solely for forceAndCall builtin (R3.2.3) */ - @Specialization - protected Object doDoCall(VirtualFrame frame, RFunction func, RArgsValuesAndNames args, @SuppressWarnings("unused") RNull env) { - return executeCall(frame, func, args.getArguments(), args.getSignature(), null); - } - - private Object executeCall(VirtualFrame frame, RFunction funcArg, Object[] argValues, ArgumentsSignature signature, MaterializedFrame callerFrameArg) { - RFunction func = funcArg; - MaterializedFrame callerFrame = callerFrameArg; - RBuiltinDescriptor builtin = func.getRBuiltin(); - if (func.isBuiltin() && builtin.getDispatch() == RDispatch.INTERNAL_GENERIC) { - if (dispatchLookup == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - dispatchLookup = insert(S3FunctionLookupNode.create(true, false)); - classHierarchyNode = insert(ClassHierarchyNodeGen.create(true, true)); - hierarchyPromiseHelper = insert(new PromiseCheckHelperNode()); - } - RStringVector type = classHierarchyNode.execute(hierarchyPromiseHelper.checkEvaluate(frame, argValues[0])); - Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), null); - if (result != null) { - func = result.function; - } - } - if (func.isBuiltin() && builtin.getDispatch() != null && builtin.getDispatch().isGroupGeneric()) { - if (groupDispatch == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - /* This child is not being used in a syntax context so remove tags */ - groupDispatch = insert(GroupDispatchNode.create(builtin.getName(), null, func, getOriginalCall().getSourceSection())); - } - for (int i = 0; i < argValues.length; i++) { - Object arg = argValues[i]; - if (arg instanceof RPromise) { - argValues[i] = promiseHelper.evaluate(frame, (RPromise) arg); - } - } - return groupDispatch.executeDynamic(frame, new RArgsValuesAndNames(argValues, signature), builtin.getName().intern(), builtin.getDispatch(), func); - } - EvaluatedArguments evaledArgs = EvaluatedArguments.create(argValues, signature); - EvaluatedArguments reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(func, evaledArgs, this, false); - if (func.isBuiltin()) { - Object[] argArray = reorderedArgs.getArguments(); - for (int i = 0; i < argArray.length; i++) { - Object arg = argArray[i]; - if (builtin.evaluatesArg(i)) { - if (arg instanceof RPromise) { - argArray[i] = promiseHelper.evaluate(frame, (RPromise) arg); - } else if (arg instanceof RArgsValuesAndNames) { - Object[] varArgValues = ((RArgsValuesAndNames) arg).getArguments(); - for (int j = 0; j < varArgValues.length; j++) { - if (varArgValues[j] instanceof RPromise) { - varArgValues[j] = promiseHelper.evaluate(frame, (RPromise) varArgValues[j]); - } - } - } - } else { - if (!(arg instanceof RPromise) && arg != RMissing.instance && !(arg instanceof RArgsValuesAndNames)) { - callerFrame = getCallerFrame(frame, callerFrame); - argArray[i] = createArgPromise(callerFrame, ConstantNode.create(arg)); - } - } - } - } - if (!needsCallerFrame && func.containsDispatch()) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - needsCallerFrame = true; - } - callerFrame = needsCallerFrame ? getCallerFrame(frame, callerFrame) : null; - Object[] callArgs = argsNode.execute(func, new RCallerHelper.Representation(func, argValues), callerFrame, RArguments.getDepth(frame) + 1, - RArguments.getPromiseFrame(frame), - reorderedArgs.getArguments(), reorderedArgs.getSignature(), - null); - RArguments.setIsIrregular(callArgs, true); - return callCache.execute(frame, func.getTarget(), callArgs); - + FrameSlot frameSlot = slot.executeFrameSlot(frame); + frame.setObject(frameSlot, new RArgsValuesAndNames(argValues, signature)); + return call.execute(frame, func); } private MaterializedFrame getCallerFrame(VirtualFrame frame, MaterializedFrame callerFrame) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java index d6cc39970113f6710dc95d28f58cfa00b43e2a59..12ba9db3e2243e0fba60f880c019c10299616e8b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java @@ -47,9 +47,9 @@ import com.oracle.truffle.r.nodes.builtin.RList2EnvNode; import com.oracle.truffle.r.nodes.builtin.RList2EnvNodeGen; import com.oracle.truffle.r.nodes.builtin.base.EnvFunctionsFactory.CopyNodeGen; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; +import com.oracle.truffle.r.nodes.function.GetCallerFrameNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseDeoptimizeFrameNode; -import com.oracle.truffle.r.nodes.function.signature.GetCallerFrameNode; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RError; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java index 7d8fdb265ffa1463ea75894a9dff0e42056059de..f93bc9ca83a5e5ab2d4a9951eaf3da03d45dc2a1 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java @@ -28,22 +28,28 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.r.nodes.access.FrameSlotNode; import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; +import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPromise; @RBuiltin(name = "forceAndCall", kind = PRIMITIVE, parameterNames = {"n", "FUN", "..."}, nonEvalArgs = 2) public abstract class ForceAndCall extends RBuiltinNode { - @Child private DoCall doCallNode; + private final Object argsIdentifier = new Object(); + + @Child private RCallNode call = RCallNode.createExplicitCall(argsIdentifier); + @Child private FrameSlotNode slot = FrameSlotNode.createTemp(argsIdentifier, true); + @Child private PromiseHelperNode promiseHelper; protected PromiseHelperNode initPromiseHelper() { @@ -59,29 +65,22 @@ public abstract class ForceAndCall extends RBuiltinNode { casts.toInteger(0); } - private DoCall getDoCallNode() { - if (doCallNode == null) { - doCallNode = insert(DoCallNodeGen.create(null)); + @Specialization + protected Object forceAndCallBuiltin(VirtualFrame frame, int n, RFunction fun, RArgsValuesAndNames args) { + if (!fun.isBuiltin()) { + initPromiseHelper(); + RArgsValuesAndNames flattened = flatten(args); + // In GnuR there appears to be no error checks on n > args.length + int cnt = Math.min(flattened.getLength(), n); + for (int i = 0; i < cnt; i++) { + RPromise arg = (RPromise) args.getArgument(i); + initPromiseHelper().evaluate(frame, arg); + } } - return doCallNode; - } - @Specialization(guards = "isBuiltin(fun)") - protected Object forceAndCallBuiltin(VirtualFrame frame, @SuppressWarnings("unused") int n, RFunction fun, RArgsValuesAndNames args) { - return getDoCallNode().execute(frame, fun, args, RNull.instance); - } - - @Specialization(guards = "!isBuiltin(fun)") - protected Object forceAndCall(VirtualFrame frame, int n, RFunction fun, RArgsValuesAndNames args) { - initPromiseHelper(); - RArgsValuesAndNames flattened = flatten(args); - // In GnuR there appears to be no error checks on n > args.length - int cnt = Math.min(flattened.getLength(), n); - for (int i = 0; i < cnt; i++) { - RPromise arg = (RPromise) args.getArgument(i); - initPromiseHelper().evaluate(frame, arg); - } - return getDoCallNode().execute(frame, fun, flattened, RNull.instance); + FrameSlot frameSlot = slot.executeFrameSlot(frame); + frame.setObject(frameSlot, args); + return call.execute(frame, fun); } @TruffleBoundary diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java index 6692048fd2bec706d00e11fed9dc42404396b3b0..f69729837e082b5e82f1287bb909725f79ecfab1 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java @@ -47,16 +47,15 @@ import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.ArgumentMatcher; import com.oracle.truffle.r.nodes.function.CallArgumentsNode; -import com.oracle.truffle.r.nodes.function.GroupDispatchNode; -import com.oracle.truffle.r.nodes.function.MatchedArguments; import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseDeoptimizeFrameNode; import com.oracle.truffle.r.nodes.function.PromiseNode; import com.oracle.truffle.r.nodes.function.PromiseNode.VarArgNode; import com.oracle.truffle.r.nodes.function.PromiseNode.VarArgsPromiseNode; import com.oracle.truffle.r.nodes.function.RCallNode; -import com.oracle.truffle.r.nodes.function.UnrolledVariadicArguments; +import com.oracle.truffle.r.nodes.function.UnmatchedArguments; import com.oracle.truffle.r.nodes.function.signature.FrameDepthNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.HasSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RArguments.S3Args; import com.oracle.truffle.r.runtime.RBuiltin; @@ -260,10 +259,10 @@ public class FrameFunctions { */ RCallNode callNode = (RCallNode) RASTUtils.unwrap(call.getRep()); CallArgumentsNode callArgs = callNode.createArguments(null, false, false); - UnrolledVariadicArguments executeFlatten = callArgs.executeFlatten(cframe); - MatchedArguments matchedArgs = ArgumentMatcher.matchArguments(definition, executeFlatten, null, true); - ArgumentsSignature sig = matchedArgs.getSignature(); - RNode[] matchedArgNodes = matchedArgs.getArguments(); + ArgumentsSignature inputVarArgSignature = callArgs.containsVarArgsSymbol() ? CallArgumentsNode.getVarargsAndNames(cframe).getSignature() : null; + UnmatchedArguments executeFlatten = callArgs.unrollArguments(inputVarArgSignature); + RNode[] matchedArgNodes = ArgumentMatcher.matchArguments(definition, executeFlatten, null, true); + ArgumentsSignature sig = ((HasSignature) definition.getRootNode()).getSignature(); // expand any varargs ArrayList<RNode> nodes = new ArrayList<>(); ArrayList<String> names = new ArrayList<>(); @@ -406,7 +405,7 @@ public class FrameFunctions { if (callObj instanceof RLanguage) { RLanguage call = (RLanguage) callObj; RNode node = (RNode) RASTUtils.unwrap(call.getRep()); - if (node instanceof RCallNode || node instanceof GroupDispatchNode) { + if (node instanceof RCallNode) { return call; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java index d302e0459de0d2dc674180e6929bf20bcd547976..f69af929c49b70b59219713690c75394a39ceeac 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java @@ -41,11 +41,13 @@ import com.oracle.truffle.r.nodes.function.FormalArguments; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.RCallerHelper; import com.oracle.truffle.r.nodes.function.signature.RArgumentsNode; +import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RList; @@ -293,7 +295,8 @@ public class GetFunctions { } MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; FormalArguments formals = ((RRootNode) ifnFunc.getRootNode()).getFormalArguments(); - Object[] callArgs = argsNode.execute(ifnFunc, new RCallerHelper.Representation(ifnFunc, new Object[]{x}), callerFrame, RArguments.getDepth(frame) + 1, + RArgsValuesAndNames args = new RArgsValuesAndNames(new Object[]{x}, ArgumentsSignature.empty(1)); + Object[] callArgs = argsNode.execute(ifnFunc, new RCallerHelper.Representation(ifnFunc, args), callerFrame, RArguments.getDepth(frame) + 1, RArguments.getPromiseFrame(frame), new Object[]{x}, formals.getSignature(), null); return callCache.execute(frame, ifnFunc.getTarget(), callArgs); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Internal.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Internal.java index 5d49715dff6ec09ec62e8143229377e56aeeb2f1..ef3b28c279d6a831e30e80ec16fd847fc5f5ccb7 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Internal.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Internal.java @@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.RBuiltinKind.PRIMITIVE; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeCost; @@ -35,7 +34,6 @@ import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.RCallNode; -import com.oracle.truffle.r.nodes.function.RCallNode.LeafCallNode; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RBuiltinKind; import com.oracle.truffle.r.runtime.RError; @@ -66,8 +64,7 @@ public abstract class Internal extends RBuiltinNode { private final BranchProfile errorProfile = BranchProfile.create(); - @Child private LeafCallNode builtinCallNode; - @CompilationFinal private RFunction builtinFunction; + @Child private RNode builtinCallNode; @Specialization protected Object doInternal(@SuppressWarnings("unused") RMissing x) { @@ -101,10 +98,9 @@ public abstract class Internal extends RBuiltinNode { // .Internal function is validated CompilerDirectives.transferToInterpreterAndInvalidate(); - builtinCallNode = insert(RCallNode.createInternalCall(frame, callNode, function, name)); - builtinFunction = function; + builtinCallNode = insert(RCallNode.createInternalCall(callNode, function)); } - return builtinCallNode.execute(frame, builtinFunction, null); + return builtinCallNode.execute(frame); } private static boolean notImplemented(String name) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java index c1a5a755da1c6a80ffa7b4aea176e8b8b198e506..830ee2595ed20a68d9fdf3e9c74b04211d48acc8 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java @@ -13,40 +13,34 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.RootCallTarget; -import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.nodes.access.ConstantNode; import com.oracle.truffle.r.nodes.access.WriteVariableNode; import com.oracle.truffle.r.nodes.access.WriteVariableNode.Mode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; +import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; +import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; +import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNodeGen; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.base.LapplyNodeGen.LapplyInternalNodeGen; -import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode; -import com.oracle.truffle.r.nodes.function.PromiseNode; +import com.oracle.truffle.r.nodes.control.RLengthNode; +import com.oracle.truffle.r.nodes.control.RLengthNodeGen; import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.runtime.AnonymousFrameVariable; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RBuiltin; -import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RMissing; -import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.nodes.InternalRSyntaxNodeChildren; import com.oracle.truffle.r.runtime.nodes.RBaseNode; -import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; -import com.oracle.truffle.r.runtime.nodes.RNode; -import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; /** * The {@code lapply} builtin. {@code lapply} is an important implicit iterator in R. This @@ -64,13 +58,9 @@ public abstract class Lapply extends RBuiltinNode { @Child private LapplyInternalNode lapply = LapplyInternalNodeGen.create(); - @Child private PromiseCheckHelperNode promiseCheck; - @Specialization protected Object lapply(VirtualFrame frame, RAbstractVector vec, RFunction fun) { - RArgsValuesAndNames optionalArgs = (RArgsValuesAndNames) RArguments.getArgument(frame, 2); - // forceVarArgs(frame, optionalArgs); - Object[] result = lapply.execute(frame, vec, fun, optionalArgs); + Object[] result = lapply.execute(frame, vec, fun); // set here else it gets overridden by the iterator evaluation controlVisibility(); return RDataFactory.createList(result, vec.getNames(attrProfiles)); @@ -78,108 +68,41 @@ public abstract class Lapply extends RBuiltinNode { public abstract static class LapplyInternalNode extends RBaseNode implements InternalRSyntaxNodeChildren { - private static final String INDEX_NAME = AnonymousFrameVariable.create("LAPPLY_ITER_INDEX"); private static final String VECTOR_ELEMENT = AnonymousFrameVariable.create("LAPPLY_VEC_ELEM"); - @Child private Length lengthNode = LengthNodeGen.create(null); + @Child private RLengthNode lengthNode = RLengthNodeGen.create(); @Child private WriteVariableNode writeVectorElement = WriteVariableNode.createAnonymous(VECTOR_ELEMENT, null, Mode.REGULAR); - @Child private WriteVariableNode writeIndex = WriteVariableNode.createAnonymous(INDEX_NAME, null, Mode.REGULAR); - @Child private RNode indexedLoadNode = createIndexedLoad(); - - public abstract Object[] execute(VirtualFrame frame, Object vector, RFunction function, RArgsValuesAndNames additionalArguments); + @Child private ExtractVectorNode extractElementNode = ExtractVectorNodeGen.create(ElementAccessMode.SUBSCRIPT, false); + @Child private RCallNode callNode = createCallNode(); - private Object[] lApplyInternal(VirtualFrame frame, Object vector, RFunction function, RCallNode callNode) { + public abstract Object[] execute(VirtualFrame frame, Object vector, RFunction function); - int length = lengthNode.executeInt(frame, vector); + @Specialization + protected Object[] cachedLApply(VirtualFrame frame, Object vector, RFunction function) { + // TODO: R switches to double if x.getLength() is greater than 2^31-1 + int length = lengthNode.executeInteger(frame, vector); Object[] result = new Object[length]; for (int i = 1; i <= length; i++) { - writeIndex.execute(frame, i); - writeVectorElement.execute(frame, indexedLoadNode.execute(frame)); + writeVectorElement.execute(frame, extractElementNode.apply(frame, vector, new Object[]{i}, RRuntime.LOGICAL_TRUE, RRuntime.LOGICAL_TRUE)); result[i - 1] = callNode.execute(frame, function); } return result; } - @SuppressWarnings("unused") - @Specialization(limit = "5", guards = {"function.getTarget() == cachedTarget", "additionalArguments.getSignature() == cachedSignature"}) - protected Object[] cachedLApply(VirtualFrame frame, Object vector, RFunction function, RArgsValuesAndNames additionalArguments, // - @Cached("function.getTarget()") RootCallTarget cachedTarget, // - @Cached("additionalArguments.getSignature()") ArgumentsSignature cachedSignature, // - @Cached("createCallNode(additionalArguments)") RCallNode callNode) { - return lApplyInternal(frame, vector, function, callNode); - } - - @Specialization(contains = "cachedLApply") - protected Object[] genericLApply(VirtualFrame frame, Object vector, RFunction function, RArgsValuesAndNames additionalArguments) { - - // TODO: implement more efficiently (how much does it matter considering that there is - // cached version?); previous comment here implied that having RCallNode executing with - // an evaluated RArgsValuesAndNames would help - return lApplyInternal(frame, vector, function, createCallNode(additionalArguments)); - } - - private static RNode createIndexedLoad() { - RCodeBuilder<RSyntaxNode> builder = RContext.getASTBuilder(); - RSyntaxNode receiver = builder.lookup(RSyntaxNode.INTERNAL, "X", false); - RSyntaxNode index = builder.lookup(RSyntaxNode.INTERNAL, INDEX_NAME, false); - RSyntaxNode access = builder.lookup(RSyntaxNode.INTERNAL, "[[", true); - return builder.call(RSyntaxNode.INTERNAL, access, receiver, index).asRNode(); - } - /** * Creates the {@link RCallNode} for this target and {@code varArgs}. - * - * @param additionalArguments may be {@link RMissing#instance} to indicate empty "..."! */ - @TruffleBoundary - protected RCallNode createCallNode(RArgsValuesAndNames additionalArguments) { - /* TODO: R switches to double if x.getLength() is greater than 2^31-1 */ - - ReadVariableNode readVector = ReadVariableNode.create(VECTOR_ELEMENT); - - // The remaining parameters are passed from {@code ...}. The call node will take - // care of matching. - RSyntaxNode[] args; - String[] names; - if (additionalArguments.isEmpty()) { // == null || (varArgs.length() == 1 && - // varArgs.getValue(0) - // == RMissing.instance)) { - args = new RSyntaxNode[]{readVector}; - names = new String[]{null}; - } else { - // Insert expressions found inside "..." as arguments - args = new RSyntaxNode[additionalArguments.getLength() + 1]; - args[0] = readVector; - Object[] varArgsValues = additionalArguments.getArguments(); - for (int i = 0; i < additionalArguments.getLength(); i++) { - args[i + 1] = (RSyntaxNode) wrapVarArgValue(varArgsValues[i], i); - - } - names = new String[additionalArguments.getLength() + 1]; - names[0] = null; - for (int i = 0; i < additionalArguments.getLength(); i++) { - String name = additionalArguments.getSignature().getName(i); - if (name != null && !name.isEmpty()) { - // change "" to null - names[i + 1] = name; - } - } - } - ArgumentsSignature argsSig = ArgumentsSignature.get(names); - // Errors can be thrown from the modified call so a SourceSection is required - return RCallNode.createCall(createCallSourceSection(), null, argsSig, args); + protected RCallNode createCallNode() { + CompilerAsserts.neverPartOfCompilation(); + + ReadVariableNode readVector = ReadVariableNode.createSilent(VECTOR_ELEMENT, RType.Any); + ReadVariableNode readArgs = ReadVariableNode.createSilent(ArgumentsSignature.VARARG_NAME, RType.Any); + + return RCallNode.createCall(createCallSourceSection(), null, ArgumentsSignature.get(null, "..."), readVector, readArgs); } } static SourceSection createCallSourceSection() { return CALL_SOURCE.createSection("", 0, CALL_SOURCE.getLength()); } - - private static RNode wrapVarArgValue(Object varArgValue, int varArgIndex) { - if (varArgValue instanceof RPromise) { - return PromiseNode.createVarArg(varArgIndex); - } else { - return ConstantNode.create(varArgValue); - } - } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java index d22d7cc5de0037762f2fc70e726cb5d80155aa12..a90acdd3f05996d26b537da99104d3c44df84fc9 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java @@ -39,8 +39,8 @@ import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.base.MatchFunNodeGen.MatchFunInternalNodeGen; +import com.oracle.truffle.r.nodes.function.GetCallerFrameNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; -import com.oracle.truffle.r.nodes.function.signature.GetCallerFrameNode; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java index c8d3bee04b3018e0ad0081c02e1acf441bacd3b0..f7af4bdaca193ced16ae3d395051cf139ed7f589 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java @@ -43,12 +43,10 @@ import com.oracle.truffle.r.nodes.unary.CastLogicalNode; import com.oracle.truffle.r.nodes.unary.CastLogicalNodeGen; import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.CastStringNodeGen; -import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -132,14 +130,13 @@ public abstract class VApply extends RBuiltinNode { @Specialization protected Object vapply(VirtualFrame frame, RAbstractVector vec, RFunction fun, Object funValue, byte useNames) { - RArgsValuesAndNames optionalArgs = (RArgsValuesAndNames) RArguments.getArgument(frame, 3); - RVector result = delegateToLapply(frame, vec, fun, funValue, useNames, optionalArgs); + RVector result = delegateToLapply(frame, vec, fun, funValue, useNames); // set here else it gets overridden by the iterator evaluation controlVisibility(); return result; } - private RVector delegateToLapply(VirtualFrame frame, RAbstractVector vec, RFunction fun, Object funValueArg, byte useNames, RArgsValuesAndNames optionalArgs) { + private RVector delegateToLapply(VirtualFrame frame, RAbstractVector vec, RFunction fun, Object funValueArg, byte useNames) { /* * The implementation is complicated by the existence of scalar length 1 vectors (e.g. * Integer) and concrete length 1 vectors (e.g. RIntVector), as either form can occur in @@ -155,7 +152,7 @@ public abstract class VApply extends RBuiltinNode { int funValueVecLen = funValueVec.getLength(); RVector vecMat = vec.materialize(); - Object[] applyResult = doApply.execute(frame, vecMat, fun, optionalArgs); + Object[] applyResult = doApply.execute(frame, vecMat, fun); RVector result = null; boolean applyResultZeroLength = applyResult.length == 0; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java index 8e4fb77736917b561ad1bf6339037598e0993758..e0ccd70c7c8191564845a1475ac01db66182a6a7 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java @@ -91,7 +91,7 @@ final class ValuePrinters implements ValuePrinter<Object> { } else if (x instanceof REnvironment) { printer = EnvironmentPrinter.INSTANCE; } else { - RInternalError.shouldNotReachHere(); + RInternalError.shouldNotReachHere("unexpected type: " + (x == null ? "null" : x.getClass())); } } printer.print(x, printCtx); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java index 8bd5d1b65a89c763abe6ee2c33fde7567445e887..54d84b5f5407537fca68ece6be99ee43face700d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java @@ -44,7 +44,6 @@ import com.oracle.truffle.r.nodes.control.WhileNode; import com.oracle.truffle.r.nodes.function.FormalArguments; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; -import com.oracle.truffle.r.nodes.function.GroupDispatchNode; import com.oracle.truffle.r.nodes.function.PostProcessArgumentsNode; import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.nodes.function.SaveArgumentsNode; @@ -53,15 +52,13 @@ import com.oracle.truffle.r.nodes.unary.GetNonSharedNodeGen; import com.oracle.truffle.r.parser.tools.EvaluatedArgumentsVisitor; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.FastROptions; -import com.oracle.truffle.r.runtime.RDispatch; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.FastPathFactory; -import com.oracle.truffle.r.runtime.data.RBuiltinDescriptor; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.REmpty; +import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; @@ -133,11 +130,6 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> { return new NextNode(source); } } else if (args.size() == 1) { - // handle unary arithmetics, for the time being - RBuiltinDescriptor builtin = RContext.lookupBuiltinDescriptor(symbol); - if (builtin != null && builtin.getDispatch() == RDispatch.OPS_GROUP_GENERIC) { - return GroupDispatchNode.create(symbol, source, ArgumentsSignature.empty(1), args.get(0).value); - } switch (symbol) { case "repeat": return WhileNode.create(source, ConstantNode.create(RRuntime.LOGICAL_TRUE), args.get(0).value, true); @@ -145,11 +137,6 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> { return args.get(0).value; } } else if (args.size() == 2) { - // handle binary arithmetics, for the time being - RBuiltinDescriptor builtin = RContext.lookupBuiltinDescriptor(symbol); - if (builtin != null && builtin.getDispatch() == RDispatch.OPS_GROUP_GENERIC) { - return GroupDispatchNode.create(symbol, source, ArgumentsSignature.empty(2), args.get(0).value, args.get(1).value); - } switch (symbol) { case "while": return WhileNode.create(source, args.get(0).value, args.get(1).value, false); @@ -190,13 +177,6 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> { arg -> (arg.value == null && arg.name == null) ? ConstantNode.create(arg.source == null ? RSyntaxNode.SOURCE_UNAVAILABLE : arg.source, REmpty.instance) : arg.value).toArray( RSyntaxNode[]::new); - if (lhs instanceof RSyntaxLookup) { - String symbol = ((RSyntaxLookup) lhs).getIdentifier(); - RBuiltinDescriptor builtin = RContext.lookupBuiltinDescriptor(symbol); - if (builtin != null && builtin.getDispatch().isGroupGeneric()) { - return GroupDispatchNode.create(symbol, source, signature, nodes); - } - } return RCallNode.createCall(source, lhs.asRNode(), signature, nodes); } @@ -458,7 +438,7 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> { @Override public RSyntaxNode constant(SourceSection source, Object value) { assert value instanceof Byte || value instanceof Integer || value instanceof Double || value instanceof RComplex || value instanceof String || value instanceof RNull || - value instanceof REmpty || value instanceof RSymbol || value instanceof RAbstractVector : value.getClass(); + value instanceof REmpty || value instanceof RSymbol || value instanceof RAbstractVector || value instanceof RFunction : value.getClass(); if (value instanceof String && !RRuntime.isNA((String) value)) { return ConstantNode.create(source, ((String) value).intern()); } else { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java index bd7831a895ffe8d55b70a95654b9aed682441073..20e39ffd491a6b5d87a7874a30c066370e140772 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.nodes; -import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.VirtualFrame; @@ -34,15 +33,11 @@ import com.oracle.truffle.r.nodes.access.ConstantNode; import com.oracle.truffle.r.nodes.access.ReadVariadicComponentNode; import com.oracle.truffle.r.nodes.access.variables.NamedRNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; -import com.oracle.truffle.r.nodes.function.CallArgumentsNode; -import com.oracle.truffle.r.nodes.function.GroupDispatchNode; import com.oracle.truffle.r.nodes.function.PromiseNode.VarArgNode; import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.nodes.function.WrapArgumentBaseNode; import com.oracle.truffle.r.nodes.function.WrapArgumentNode; -import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -67,6 +62,7 @@ public class RASTUtils { * . */ public static <T extends RBaseNode> T cloneNode(T node) { + // TODO: use RASTBuilder here as well? return NodeUtil.cloneNode(node); } @@ -126,6 +122,9 @@ public class RASTUtils { return value; } else if (argNode instanceof ReadVariableNode) { return RASTUtils.createRSymbol(argNode); + } else if (argNode instanceof VarArgNode) { + VarArgNode varArgNode = (VarArgNode) argNode; + return RDataFactory.createSymbolInterned(varArgNode.getIdentifier()); } else { assert !(argNode instanceof VarArgNode); return RDataFactory.createLanguage((RNode) argNode); @@ -224,9 +223,6 @@ public class RASTUtils { return RCallNode.createCall(sourceSection, (ReadVariableNode) fn, signature, arguments); } else if (fn instanceof NamedRNode) { return RCallNode.createCall(RSyntaxNode.SOURCE_UNAVAILABLE, (NamedRNode) fn, signature, arguments); - } else if (fn instanceof GroupDispatchNode) { - GroupDispatchNode gdcn = (GroupDispatchNode) fn; - return GroupDispatchNode.create(gdcn.getGenericName(), gdcn.getCallSrc(), signature, arguments); } else if (fn instanceof RFunction) { RFunction rfn = (RFunction) fn; return RCallNode.createCall(sourceSection, ConstantNode.create(rfn), signature, arguments); @@ -240,55 +236,6 @@ public class RASTUtils { } } - /** - * Find the {@link CallArgumentsNode} that is the child of {@code node}. N.B. Does not copy. - */ - public static Arguments<RSyntaxNode> findCallArguments(Node node) { - if (node instanceof RCallNode) { - return ((RCallNode) node).getArguments(); - } else if (node instanceof GroupDispatchNode) { - return ((GroupDispatchNode) node).getArguments(); - } - throw RInternalError.shouldNotReachHere(); - } - - /** - * Returns the name (as an {@link RSymbol} of the function associated with an {@link RCallNode} - * or {@link GroupDispatchNode}. - */ - public static Object findFunctionName(RBaseNode node) { - CompilerAsserts.neverPartOfCompilation(); // for string interning - RNode child = (RNode) unwrap(getFunctionNode(node)); - if (child instanceof ConstantNode && ConstantNode.isFunction(child)) { - return ((ConstantNode) child).getValue(); - } else if (child instanceof ReadVariableNode) { - String name = ((ReadVariableNode) child).getIdentifier(); - assert name == name.intern(); - return RDataFactory.createSymbol(name); - } else if (child instanceof GroupDispatchNode) { - GroupDispatchNode groupDispatchNode = (GroupDispatchNode) child; - String gname = groupDispatchNode.getGenericName(); - return RDataFactory.createSymbolInterned(gname); - } else { - // TODO This should really fail in some way as (clearly) this is not a "name" - // some more complicated expression, just deparse it - return RDataFactory.createSymbolInterned(RDeparse.deparse(child)); - } - } - - /** - * Unifies {@link RCallNode} and {@link GroupDispatchNode} for accessing (likely) function name. - */ - public static RNode getFunctionNode(Node node) { - if (node instanceof RCallNode) { - return ((RCallNode) node).getFunctionNode(); - } else if (node instanceof GroupDispatchNode) { - return (RNode) node; - } - assert false; - return null; - } - @TruffleBoundary /** * The heart of the {@code substitute} function, where we look up the value of {@code name} in diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java index b71392f90ed51fe0dd42d83c02dad648e03a5295..ae23ed865a3cd740638ecaa3feda691e0bcc2cd3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java @@ -29,7 +29,6 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.VisibilityController; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; -import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RSymbol; @@ -46,10 +45,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax super(sourceSection); } - public static boolean isFunction(RNode node) { - return node instanceof ConstantObjectNode && ((ConstantObjectNode) node).value instanceof RFunction; - } - public static boolean isMissing(RNode node) { return node instanceof ConstantObjectNode && ((ConstantObjectNode) node).value == RMissing.instance; } @@ -198,16 +193,4 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax } } } - - public static Integer asIntConstant(RSyntaxNode argument, boolean castFromDouble) { - if (argument instanceof ConstantNode) { - Object value = ((ConstantNode) argument).getValue(); - if (value instanceof Integer) { - return (int) value; - } else if (castFromDouble && value instanceof Double) { - return (int) (double) value; - } - } - return null; - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java index 469e1f11006c8e8e69da4727cc240e876f48f2a7..274546d254248bd72cdbfac3d4569b65c5d4eea5 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java @@ -117,9 +117,9 @@ public abstract class RBuiltinNode extends RNode implements VisibilityController return Truffle.getRuntime().createCallTarget(root); } - static final RBuiltinNode inline(RBuiltinFactory factory, RNode[] args) { + public static final RBuiltinNode inline(RBuiltinDescriptor factory, RNode[] args) { // static number of arguments - return factory.getConstructor().apply(args); + return ((RBuiltinFactory) factory).getConstructor().apply(args); } protected final RBuiltin getRBuiltin() { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java index 12f2fcec908deb0fd01b40454efc78dffc0201f2..c502085a2ae82c892dde1e72786bd74617bcac96 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java @@ -31,7 +31,6 @@ import com.oracle.truffle.r.nodes.RRootNode; import com.oracle.truffle.r.nodes.function.FormalArguments; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; -import com.oracle.truffle.r.runtime.nodes.RNode; public final class RBuiltinRootNode extends RRootNode { @@ -76,10 +75,6 @@ public final class RBuiltinRootNode extends RRootNode { return factory.isAlwaysSplit(); } - public RBuiltinNode inline(RNode[] args) { - return RBuiltinNode.inline(factory, args); - } - @Override public String getSourceCode() { throw RInternalError.shouldNotReachHere(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java index 60c18c59803d2938eb30bfeec9880e070c842264..73dded63d284599fb6fdd1606af7dd5c288d10da 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java @@ -62,9 +62,8 @@ import com.oracle.truffle.r.runtime.nodes.RNode; * {@link FormalArguments} of a specific function, see * {@link #matchArguments(RFunction, UnmatchedArguments, RBaseNode, boolean)} . The other match * functions are used for special cases, where builtins make it necessary to re-match parameters, - * e.g.: {@link #matchArgumentsEvaluated(RFunction, EvaluatedArguments, RBaseNode, boolean)} for - * 'UseMethod' and {@link #matchArgumentsInlined(RFunction, UnmatchedArguments, RBaseNode)} for - * builtins which are implemented in Java. + * e.g.: {@link #matchArgumentsEvaluated(RFunction, RArgsValuesAndNames, RBaseNode, boolean)} for + * 'UseMethod'. * </p> * * <p> @@ -130,33 +129,13 @@ public class ArgumentMatcher { * @return A fresh {@link MatchedArguments} containing the arguments in correct order and * wrapped in {@link PromiseNode}s */ - public static MatchedArguments matchArguments(RFunction function, UnmatchedArguments suppliedArgs, RBaseNode callingNode, boolean noOpt) { - RNode[] wrappedArgs = matchNodes(function, suppliedArgs.getArguments(), suppliedArgs.getSignature(), callingNode, suppliedArgs, noOpt); - FormalArguments formals = ((RRootNode) function.getTarget().getRootNode()).getFormalArguments(); - return MatchedArguments.create(wrappedArgs, formals.getSignature()); + public static RNode[] matchArguments(RFunction function, UnmatchedArguments suppliedArgs, RBaseNode callingNode, boolean noOpt) { + return matchNodes(function, suppliedArgs.getArguments(), suppliedArgs.getSignature(), callingNode, suppliedArgs, noOpt); } - /** - * Match arguments supplied for a specific function call to the formal arguments and wraps them - * in special {@link PromiseNode}s. Used for calls to builtins which are built into FastR and - * thus are implemented in Java - * - * @param function The function which is to be called - * @param suppliedArgs The arguments supplied to the call - * @param callingNode The {@link Node} invoking the match - * @return A fresh {@link InlinedArguments} containing the arguments in correct order and - * wrapped in special {@link PromiseNode}s - */ - public static RNode[] matchArgumentsInlined(RFunction function, UnmatchedArguments suppliedArgs, RBaseNode callingNode) { - return matchNodes(function, suppliedArgs.getArguments(), suppliedArgs.getSignature(), callingNode, suppliedArgs, false); - } - - public static MatchPermutation matchArguments(ArgumentsSignature suppliedSignature, ArgumentsSignature formalSignature, RBaseNode callingNode, boolean forNextMethod, RBuiltinDescriptor builtin) { + public static MatchPermutation matchArguments(ArgumentsSignature supplied, ArgumentsSignature formal, RBaseNode callingNode, boolean forNextMethod, RBuiltinDescriptor builtin) { CompilerAsserts.neverPartOfCompilation(); - MatchPermutation match = permuteArguments(suppliedSignature, formalSignature, callingNode, forNextMethod, index -> { - throw RInternalError.unimplemented("S3Dispatch should not have arg length mismatch"); - }, index -> suppliedSignature.getName(index), builtin); - return match; + return permuteArguments(supplied, formal, callingNode, forNextMethod, index -> false, index -> supplied.getName(index) == null ? "" : supplied.getName(index), builtin); } public static ArgumentsSignature getFunctionSignature(RFunction function) { @@ -213,10 +192,10 @@ public class ArgumentMatcher { * @param callingNode The {@link Node} invoking the match * @param forNextMethod matching when evaluating NextMethod * - * @return A Fresh {@link EvaluatedArguments} containing the arguments rearranged and stuffed + * @return A Fresh {@link RArgsValuesAndNames} containing the arguments rearranged and stuffed * with default values (in the form of {@link RPromise}s where needed) */ - public static EvaluatedArguments matchArgumentsEvaluated(RFunction function, EvaluatedArguments evaluatedArgs, RBaseNode callingNode, boolean forNextMethod) { + public static RArgsValuesAndNames matchArgumentsEvaluated(RFunction function, RArgsValuesAndNames evaluatedArgs, RBaseNode callingNode, boolean forNextMethod) { RRootNode rootNode = (RRootNode) function.getTarget().getRootNode(); FormalArguments formals = rootNode.getFormalArguments(); MatchPermutation match = permuteArguments(evaluatedArgs.getSignature(), formals.getSignature(), callingNode, forNextMethod, index -> { @@ -248,7 +227,7 @@ public class ArgumentMatcher { evaledArgs[formalIndex] = evaluatedArgs.getArgument(suppliedIndex); } } - return new EvaluatedArguments(evaledArgs, formals.getSignature()); + return new RArgsValuesAndNames(evaledArgs, formals.getSignature()); } private static String getErrorForArgument(RNode[] suppliedArgs, ArgumentsSignature suppliedSignature, int index) { @@ -430,7 +409,7 @@ public class ArgumentMatcher { } } - static final class MatchPermutation { + public static final class MatchPermutation { public static final int UNMATCHED = -1; public static final int VARARGS = -2; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java index 2179fffe501dc67fc0263546c18b0e8731b2834c..a6b47df08fbe1e6680aceccc60eb82e8b5dbc14e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java @@ -22,10 +22,8 @@ */ package com.oracle.truffle.r.nodes.function; -import java.util.ArrayList; import java.util.Arrays; import java.util.IdentityHashMap; -import java.util.List; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; @@ -97,33 +95,20 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum * @param modeChangeForAll * @param args {@link #arguments}; new array gets created. Every {@link RNode} (except * <code>null</code>) gets wrapped into a {@link WrapArgumentNode}. + * @param varArgsSymbolIndicesArr * @return A fresh {@link CallArgumentsNode} */ - public static CallArgumentsNode create(boolean modeChange, boolean modeChangeForAll, RNode[] args, ArgumentsSignature signature) { + public static CallArgumentsNode create(boolean modeChange, boolean modeChangeForAll, RNode[] args, ArgumentsSignature signature, int[] varArgsSymbolIndicesArr) { // Prepare arguments: wrap in WrapArgumentNode RNode[] wrappedArgs = new RNode[args.length]; - List<Integer> varArgsSymbolIndices = new ArrayList<>(); for (int i = 0; i < wrappedArgs.length; i++) { RNode arg = args[i]; if (arg == null) { wrappedArgs[i] = null; } else { - if (arg instanceof ReadVariableNode) { - // Check for presence of "..." in the arguments - ReadVariableNode rvn = (ReadVariableNode) arg; - if (ArgumentsSignature.VARARG_NAME.equals(rvn.getIdentifier())) { - varArgsSymbolIndices.add(i); - } - } wrappedArgs[i] = WrapArgumentNode.create(arg, i == 0 || modeChangeForAll ? modeChange : true, i); } } - - // Setup and return - int[] varArgsSymbolIndicesArr = new int[varArgsSymbolIndices.size()]; - for (int i = 0; i < varArgsSymbolIndicesArr.length; i++) { - varArgsSymbolIndicesArr[i] = varArgsSymbolIndices.get(i); - } return new CallArgumentsNode(wrappedArgs, signature, varArgsSymbolIndicesArr); } @@ -140,10 +125,11 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum * This methods unrolls all "..." in the argument list. The result varies if the number of * arguments in the varargs or their names change. */ - public UnrolledVariadicArguments executeFlatten(Frame frame) { + public UnmatchedArguments unrollArguments(ArgumentsSignature varArgSignature) { CompilerAsserts.neverPartOfCompilation(); + assert containsVarArgsSymbol() == (varArgSignature != null); if (!containsVarArgsSymbol()) { - return UnrolledVariadicArguments.create(getArguments(), getSignature(), this); + return this; } else { RNode[] values = new RNode[arguments.length]; String[] newNames = new String[arguments.length]; @@ -152,19 +138,18 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum int index = 0; for (int i = 0; i < arguments.length; i++) { if (vargsSymbolsIndex < varArgsSymbolIndices.length && varArgsSymbolIndices[vargsSymbolsIndex] == i) { - RArgsValuesAndNames varArgInfo = getVarargsAndNames(frame); - if (varArgInfo.isEmpty()) { + if (varArgSignature.isEmpty()) { // An empty "..." vanishes values = Utils.resizeArray(values, values.length - 1); newNames = Utils.resizeArray(newNames, newNames.length - 1); continue; } - values = Utils.resizeArray(values, values.length + varArgInfo.getLength() - 1); - newNames = Utils.resizeArray(newNames, newNames.length + varArgInfo.getLength() - 1); - for (int j = 0; j < varArgInfo.getLength(); j++) { + values = Utils.resizeArray(values, values.length + varArgSignature.getLength() - 1); + newNames = Utils.resizeArray(newNames, newNames.length + varArgSignature.getLength() - 1); + for (int j = 0; j < varArgSignature.getLength(); j++) { values[index] = PromiseNode.createVarArg(j); - newNames[index] = varArgInfo.getSignature().getName(j); + newNames[index] = varArgSignature.getName(j); index++; } vargsSymbolsIndex++; @@ -174,18 +159,17 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum index++; } } - return UnrolledVariadicArguments.create(values, ArgumentsSignature.get(newNames), this); } } @ExplodeLoop - public RArgsValuesAndNames evaluateFlatten(VirtualFrame frame, RArgsValuesAndNames varArgInfo) { + public RArgsValuesAndNames evaluateFlatten(VirtualFrame frame, RArgsValuesAndNames varArgs) { int size = arguments.length; ArgumentsSignature resultSignature = null; String[] names = null; if (containsVarArgsSymbol()) { - size += (varArgInfo.getLength() - 1) * varArgsSymbolIndices.length; + size += (varArgs.getLength() - 1) * varArgsSymbolIndices.length; names = new String[size]; } else { resultSignature = signature; @@ -195,7 +179,7 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum int index = 0; for (int i = 0; i < arguments.length; i++) { if (vargsSymbolsIndex < varArgsSymbolIndices.length && varArgsSymbolIndices[vargsSymbolsIndex] == i) { - index = flattenVarArgs(frame, varArgInfo, names, values, index); + index = flattenVarArgs(frame, varArgs, names, values, index); vargsSymbolsIndex++; } else { values[index] = arguments[i] == null ? RMissing.instance : arguments[i].execute(frame); @@ -212,19 +196,17 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum } @ExplodeLoop - public Object[] evaluateFlattenObjects(VirtualFrame frame) { + public Object[] evaluateFlattenObjects(VirtualFrame frame, RArgsValuesAndNames varArgs) { int size = arguments.length; - RArgsValuesAndNames varArgInfo = null; if (containsVarArgsSymbol()) { - varArgInfo = getVarargsAndNames(frame); - size += (varArgInfo.getLength() - 1) * varArgsSymbolIndices.length; + size += (varArgs.getLength() - 1) * varArgsSymbolIndices.length; } Object[] values = new Object[size]; int vargsSymbolsIndex = 0; int index = 0; for (int i = 0; i < arguments.length; i++) { if (vargsSymbolsIndex < varArgsSymbolIndices.length && varArgsSymbolIndices[vargsSymbolsIndex] == i) { - index = flattenVarArgsObject(frame, varArgInfo, values, index); + index = flattenVarArgsObject(frame, varArgs, values, index); vargsSymbolsIndex++; } else { values[index] = arguments[i] == null ? RMissing.instance : arguments[i].execute(frame); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java index f5c513c67f84737f621acd6c4f892a0381f0fa8b..3aba0d373115b90028403ad2c73a024a95ef0698 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java @@ -24,7 +24,6 @@ import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.RRootNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; -import com.oracle.truffle.r.nodes.builtin.RBuiltinRootNode; import com.oracle.truffle.r.nodes.function.ArgumentMatcher.MatchPermutation; import com.oracle.truffle.r.nodes.function.signature.RArgumentsNode; import com.oracle.truffle.r.nodes.unary.CastNode; @@ -200,8 +199,7 @@ public abstract class CallMatcherNode extends RBaseNode { this.next = next; this.formals = ((RRootNode) cachedFunction.getRootNode()).getFormalArguments(); if (function.isBuiltin()) { - RBuiltinRootNode builtinRoot = RCallNode.findBuiltinRootNode(function.getTarget()); - this.builtin = builtinRoot.inline(null); + this.builtin = RBuiltinNode.inline(function.getRBuiltin(), null); this.builtinArgumentCasts = builtin.getCasts(); } else { this.call = Truffle.getRuntime().createDirectCallNode(function.getTarget()); @@ -218,7 +216,8 @@ public abstract class CallMatcherNode extends RBaseNode { Object[] reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(permutation, preparedArguments, formals); evaluatePromises(frame, cachedFunction, reorderedArgs, formals.getSignature().getVarArgIndex()); if (call != null) { - RCaller caller = functionName == null ? RCallerHelper.InvalidRepresentation.instance : new RCallerHelper.Representation(functionName, reorderedArgs); + RCaller caller = functionName == null ? RCallerHelper.InvalidRepresentation.instance + : new RCallerHelper.Representation(functionName, new RArgsValuesAndNames(reorderedArgs, ArgumentsSignature.empty(reorderedArgs.length))); Object[] arguments = prepareArguments(frame, reorderedArgs, formals.getSignature(), cachedFunction, dispatchArgs, caller); return call.call(frame, arguments); } else { @@ -297,10 +296,11 @@ public abstract class CallMatcherNode extends RBaseNode { @Override public Object execute(VirtualFrame frame, ArgumentsSignature suppliedSignature, Object[] suppliedArguments, RFunction function, String functionName, DispatchArgs dispatchArgs) { - EvaluatedArguments reorderedArgs = reorderArguments(suppliedArguments, function, suppliedSignature); + RArgsValuesAndNames reorderedArgs = reorderArguments(suppliedArguments, function, suppliedSignature); evaluatePromises(frame, function, reorderedArgs.getArguments(), reorderedArgs.getSignature().getVarArgIndex()); - RCaller caller = functionName == null ? RCallerHelper.InvalidRepresentation.instance : new RCallerHelper.Representation(functionName, reorderedArgs.getArguments()); + RCaller caller = functionName == null ? RCallerHelper.InvalidRepresentation.instance + : new RCallerHelper.Representation(functionName, new RArgsValuesAndNames(reorderedArgs.getArguments(), ArgumentsSignature.empty(reorderedArgs.getLength()))); Object[] arguments = prepareArguments(frame, reorderedArgs.getArguments(), reorderedArgs.getSignature(), function, dispatchArgs, caller); return call.call(frame, function.getTarget(), arguments); } @@ -317,7 +317,7 @@ public abstract class CallMatcherNode extends RBaseNode { } @TruffleBoundary - protected EvaluatedArguments reorderArguments(Object[] args, RFunction function, ArgumentsSignature paramSignature) { + protected RArgsValuesAndNames reorderArguments(Object[] args, RFunction function, ArgumentsSignature paramSignature) { assert paramSignature.getLength() == args.length; int argCount = args.length; @@ -362,10 +362,10 @@ public abstract class CallMatcherNode extends RBaseNode { } // ...and use them as 'supplied' arguments... - EvaluatedArguments evaledArgs = EvaluatedArguments.create(argValues, signature); + RArgsValuesAndNames evaledArgs = new RArgsValuesAndNames(argValues, signature); // ...to match them against the chosen function's formal arguments - EvaluatedArguments evaluated = ArgumentMatcher.matchArgumentsEvaluated(function, evaledArgs, this, forNextMethod); + RArgsValuesAndNames evaluated = ArgumentMatcher.matchArgumentsEvaluated(function, evaledArgs, this, forNextMethod); return evaluated; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java index ca6b156c7254d882a617aeadf605ffc8392466a7..69037c6399a16f843fe699d9e9199287543b6f78 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java @@ -74,6 +74,10 @@ public abstract class ClassHierarchyNode extends UnaryNode { this.withS4 = withS4; } + public static ClassHierarchyNode create() { + return ClassHierarchyNodeGen.create(false, false); + } + @Override public abstract RStringVector execute(Object arg); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/EvaluatedArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/EvaluatedArguments.java deleted file mode 100644 index 3d20ec3c550d744ad3cc213f5235c0606d719a6d..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/EvaluatedArguments.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.nodes.function; - -import com.oracle.truffle.r.runtime.Arguments; -import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RArguments; - -/** - * Simple container class for holding arguments which are ready to be pushed into {@link RArguments} - * (or are taken from there!). 'argument missing' is denoted by <code>null</code>. - */ -public class EvaluatedArguments extends Arguments<Object> { - - EvaluatedArguments(Object[] evaluatedArgs, ArgumentsSignature signature) { - super(evaluatedArgs, signature); - } - - public static EvaluatedArguments create(Object[] args, ArgumentsSignature signature) { - return new EvaluatedArguments(args, signature); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/GetCallerFrameNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java similarity index 91% rename from com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/GetCallerFrameNode.java rename to com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java index b41b824f8bf90adba7b3dc0e5b6740a4ba59f331..cbab2849930de3a423a0482124bb88ff15dfb08e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/GetCallerFrameNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.r.nodes.function.signature; +package com.oracle.truffle.r.nodes.function; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.Frame; @@ -30,7 +30,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.r.nodes.PromiseEvalFrameDebug; -import com.oracle.truffle.r.nodes.function.RCallNode.CallWithCallerFrame; +import com.oracle.truffle.r.nodes.function.signature.FrameDepthNode; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; @@ -54,8 +54,8 @@ public final class GetCallerFrameNode extends RBaseNode { if (frameDepthNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); RCaller call = RArguments.getCall(frame); - if (call != null && call.getSyntaxNode() instanceof CallWithCallerFrame) { - if (!((CallWithCallerFrame) call.getSyntaxNode()).setNeedsCallerFrame()) { + if (call instanceof RCallNode) { + if (!((RCallNode) call).setNeedsCallerFrame()) { reset = true; } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java deleted file mode 100644 index 1b104f9bc09a57223d60f70153be6608c6bc836c..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (c) 2014, Purdue University - * Copyright (c) 2015, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.nodes.function; - -import java.util.Arrays; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.UnexpectedResultException; -import com.oracle.truffle.api.profiles.ConditionProfile; -import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.nodes.RASTUtils; -import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; -import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.NoGenericMethodException; -import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result; -import com.oracle.truffle.r.runtime.Arguments; -import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RArguments.S3Args; -import com.oracle.truffle.r.runtime.RDispatch; -import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.RSerialize; -import com.oracle.truffle.r.runtime.RType; -import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.env.REnvironment; -import com.oracle.truffle.r.runtime.nodes.RNode; -import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode; -import com.oracle.truffle.r.runtime.nodes.RSyntaxCall; -import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; -import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup; -import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; - -public final class GroupDispatchNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxCall { - - @Child private CallArgumentsNode callArgsNode; - @Child private S3FunctionLookupNode functionLookupL; - @Child private S3FunctionLookupNode functionLookupR; - @Child private ClassHierarchyNode classHierarchyL; - @Child private ClassHierarchyNode classHierarchyR; - @Child private CallMatcherNode callMatcher = CallMatcherNode.create(false, true); - @Child private ReadVariableNode lookupVarArgs; - - private final String fixedGenericName; - private final RDispatch fixedDispatch; - private final RFunction fixedBuiltinFunction; - - private final ConditionProfile mismatchProfile = ConditionProfile.createBinaryProfile(); - - @CompilationFinal private boolean dynamicLookup; - private final ConditionProfile exactEqualsProfile = ConditionProfile.createBinaryProfile(); - - private GroupDispatchNode(SourceSection sourceSection, String genericName, CallArgumentsNode callArgNode, RFunction builtinFunction) { - super(sourceSection); - this.fixedGenericName = genericName.intern(); - this.fixedDispatch = builtinFunction.getRBuiltin().getDispatch(); - this.callArgsNode = callArgNode; - this.fixedBuiltinFunction = builtinFunction; - } - - public static GroupDispatchNode create(String genericName, SourceSection sourceSection, ArgumentsSignature signature, RSyntaxNode... arguments) { - CallArgumentsNode callArgNode = CallArgumentsNode.create(false, true, Arrays.copyOf(arguments, arguments.length, RNode[].class), signature); - GroupDispatchNode gdcn = new GroupDispatchNode(sourceSection, genericName, callArgNode, RContext.lookupBuiltin(genericName)); - return gdcn; - } - - public static GroupDispatchNode create(String genericName, CallArgumentsNode callArgNode, RFunction builtinFunction, SourceSection sourceSection) { - GroupDispatchNode gdcn = new GroupDispatchNode(sourceSection, genericName, callArgNode, builtinFunction); - return gdcn; - } - - public Arguments<RSyntaxNode> getArguments() { - return new Arguments<>(callArgsNode.getSyntaxArguments(), callArgsNode.getSignature()); - } - - public String getGenericName() { - return fixedGenericName; - } - - public SourceSection getCallSrc() { - return getSourceSection(); - } - - @Override - public void serializeImpl(RSerialize.State state) { - String name = getGenericName(); - state.setAsBuiltin(name); - RCallNode.serializeArguments(state, callArgsNode.getSyntaxArguments(), callArgsNode.signature, false); - } - - @Override - public RSyntaxNode substituteImpl(REnvironment env) { - // TODO substitute aDispatchNode - Arguments<RSyntaxNode> substituteArguments = RCallNode.substituteArguments(env, callArgsNode.getSyntaxArguments(), callArgsNode.signature); - return RASTUtils.createCall(this, false, substituteArguments.getSignature(), substituteArguments.getArguments()); - } - - @Override - public Object execute(VirtualFrame frame) { - RArgsValuesAndNames varArgs = null; - if (callArgsNode.containsVarArgsSymbol()) { - if (lookupVarArgs == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - lookupVarArgs = insert(ReadVariableNode.createSilent(ArgumentsSignature.VARARG_NAME, RType.Any)); - } - try { - varArgs = lookupVarArgs.executeRArgsValuesAndNames(frame); - } catch (UnexpectedResultException e) { - throw RInternalError.shouldNotReachHere(e, "'...' should always be represented by RArgsValuesAndNames"); - } - } - RArgsValuesAndNames argAndNames = callArgsNode.evaluateFlatten(frame, varArgs); - return executeInternal(frame, argAndNames, fixedGenericName, fixedDispatch, fixedBuiltinFunction); - } - - public Object executeDynamic(VirtualFrame frame, RArgsValuesAndNames argAndNames, String genericName, RDispatch dispatch, RFunction builtinFunction) { - if (!dynamicLookup) { - if (builtinFunction == fixedBuiltinFunction && (exactEqualsProfile.profile(fixedGenericName == genericName) || fixedGenericName.equals(genericName))) { - return executeInternal(frame, argAndNames, fixedGenericName, fixedDispatch, fixedBuiltinFunction); - } - CompilerDirectives.transferToInterpreterAndInvalidate(); - dynamicLookup = true; - } - return executeInternal(frame, argAndNames, genericName, dispatch, builtinFunction); - } - - private Object executeInternal(VirtualFrame frame, RArgsValuesAndNames argAndNames, String genericName, RDispatch dispatch, RFunction builtinFunction) { - assert dispatch.isGroupGeneric(); - Object[] evaluatedArgs = argAndNames.getArguments(); - - if (classHierarchyL == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - classHierarchyL = insert(ClassHierarchyNodeGen.create(false, true)); - } - RStringVector typeL = evaluatedArgs.length == 0 ? null : classHierarchyL.execute(evaluatedArgs[0]); - - Result resultL = null; - if (typeL != null) { - try { - if (functionLookupL == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - functionLookupL = insert(S3FunctionLookupNode.create(false, false)); - } - resultL = functionLookupL.execute(frame, genericName, typeL, dispatch.getGroupGenericName(), frame.materialize(), null); - } catch (NoGenericMethodException e) { - // fall-through - } - } - Result resultR = null; - if (dispatch == RDispatch.OPS_GROUP_GENERIC && argAndNames.getSignature().getLength() >= 2) { - if (classHierarchyR == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - classHierarchyR = insert(ClassHierarchyNodeGen.create(false, true)); - } - RStringVector typeR = classHierarchyR.execute(evaluatedArgs[1]); - if (typeR != null) { - try { - if (functionLookupR == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - functionLookupR = insert(S3FunctionLookupNode.create(false, false)); - } - resultR = functionLookupR.execute(frame, genericName, typeR, dispatch.getGroupGenericName(), frame.materialize(), null); - } catch (NoGenericMethodException e) { - // fall-through - } - } - } - - Result result; - RStringVector dotMethod; - if (resultL == null) { - if (resultR == null) { - result = null; - dotMethod = null; - } else { - result = resultR; - dotMethod = RDataFactory.createStringVector(new String[]{"", result.targetFunctionName}, true); - } - } else { - if (resultR == null) { - result = resultL; - dotMethod = RDataFactory.createStringVector(new String[]{result.targetFunctionName, ""}, true); - } else { - if (mismatchProfile.profile(resultL.function != resultR.function)) { - RError.warning(this, RError.Message.INCOMPATIBLE_METHODS, resultL.targetFunctionName, resultR.targetFunctionName, genericName); - result = null; - dotMethod = null; - } else { - result = resultL; - dotMethod = RDataFactory.createStringVector(new String[]{result.targetFunctionName, result.targetFunctionName}, true); - } - } - } - ArgumentsSignature signature = argAndNames.getSignature(); - S3Args s3Args; - RFunction function; - String functionName; - if (result == null) { - s3Args = null; - function = builtinFunction; - functionName = function.getName(); - } else { - s3Args = new S3Args(genericName, result.clazz, dotMethod, frame.materialize(), null, result.groupMatch ? dispatch.getGroupGenericName() : null); - function = result.function; - functionName = result.targetFunctionName; - } - if (function == null) { - CompilerDirectives.transferToInterpreter(); - throw RError.nyi(this, "missing builtin function '" + genericName + "'"); - } - return callMatcher.execute(frame, signature, evaluatedArgs, function, functionName, s3Args); - } - - @Override - public RSyntaxElement getSyntaxLHS() { - return RSyntaxLookup.createDummyLookup(null, fixedGenericName, true); - } - - @Override - public RSyntaxElement[] getSyntaxArguments() { - return callArgsNode.getSyntaxArguments(); - } - - @Override - public ArgumentsSignature getSyntaxSignature() { - return callArgsNode.getSignature(); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/MatchedArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/MatchedArguments.java index 9e248913f67f10c404ff3c20c33f9eae0296d190..fc5b9b5e975fc9b99616cf0475af00f804467b2f 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/MatchedArguments.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/MatchedArguments.java @@ -27,7 +27,6 @@ import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; -import com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.nodes.RNode; /** @@ -43,41 +42,10 @@ import com.oracle.truffle.r.runtime.nodes.RNode; */ public final class MatchedArguments extends Arguments<RNode> { - static final class MatchedArgumentsNode extends RBaseNode { - @Children private final RNode[] arguments; - private final ArgumentsSignature signature; - - private MatchedArgumentsNode(RNode[] arguments, ArgumentsSignature signature) { - this.arguments = arguments; - this.signature = signature; - } - - @ExplodeLoop - Object[] executeArray(VirtualFrame frame) { - Object[] result = new Object[arguments.length]; - for (int i = 0; i < arguments.length; i++) { - result[i] = arguments[i].execute(frame); - } - return result; - } - - public ArgumentsSignature getSignature() { - return signature; - } - - public RNode[] getArguments() { - return arguments; - } - } - private MatchedArguments(RNode[] arguments, ArgumentsSignature signature) { super(arguments, signature); } - MatchedArgumentsNode createNode() { - return new MatchedArgumentsNode(getArguments(), getSignature()); - } - /** * @return A fresh {@link MatchedArguments}; arguments may contain <code>null</code> iff there * is neither a supplied argument nor a default argument 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 d6e92ce33586dd86896418df7f3e82985033c69d..7117b9d93ec754301f8f7e949ca6323419441b4a 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 @@ -24,15 +24,18 @@ package com.oracle.truffle.r.nodes.function; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; -import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; @@ -41,26 +44,33 @@ 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.nodes.DirectCallNode; -import com.oracle.truffle.api.nodes.IndirectCallNode; +import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeCloneable; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.NodeUtil; import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.RRootNode; +import com.oracle.truffle.r.nodes.access.ConstantNode; import com.oracle.truffle.r.nodes.access.FrameSlotNode; +import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinRootNode; -import com.oracle.truffle.r.nodes.function.MatchedArguments.MatchedArgumentsNode; +import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode; +import com.oracle.truffle.r.nodes.function.RCallNodeGen.FunctionDispatchNodeGen; +import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.NoGenericMethodException; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result; +import com.oracle.truffle.r.nodes.function.call.PrepareArguments; import com.oracle.truffle.r.nodes.function.signature.RArgumentsNode; +import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; +import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; @@ -76,9 +86,13 @@ import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RBuiltinDescriptor; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RPromise; +import com.oracle.truffle.r.runtime.data.RPromise.OptType; +import com.oracle.truffle.r.runtime.data.RPromise.PromiseType; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -86,182 +100,108 @@ import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; import com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.nodes.RFastPathNode; import com.oracle.truffle.r.runtime.nodes.RNode; -import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxCall; import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant; import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; -/** - * This class denotes a call site to a function,e.g.: - * - * <pre> - * f(a, b, c) - * </pre> - * <p> - * To avoid repeated work on each call, {@link CachedCallNode} class together with - * {@link UninitializedCallNode} forms the basis for the polymorphic inline cache (PIC) used to - * cache argument nodes on the call site of a function call. - * </p> - * There are two problems we're facing which are the reason for the caching: - * <ol> - * <li>on some call sites the function may change between executions</li> - * <li>for call sites taking "..." as an argument the actual argument list passed into the function - * may change each call (note that this is totally independent of the problem which function is to - * be called)</li> - * </ol> - * <p> - * Problem 1 can be tackled by a the use of an {@link IndirectCallNode} instead of a - * {@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 TruffleBoundary}. - * <br/> - * 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(Frame)}) - 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 TruffleBoundary}. - * </p> - * 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 arbitrary - * - * UV = {@link UninitializedCallNode} with varargs, - * UVC = {@link UninitializedVarArgsCacheCallNode} with varargs, for varargs cache - * DV = {@link DispatchedVarArgsCallNode}: Function fixed, with cached varargs - * DGV = {@link DispatchedGenericVarArgsCallNode}: Function fixed, with arbitrary varargs (generic case) - * - * (RB = {@link RBuiltinNode}: individual functions that are builtins are represented by this node - * 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 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: - * | - * D-D-D-U - * - * no varargs, generic (if max depth is exceeded): - * | - * D-D-D-D-G - * - * varargs: - * | - * DV-DV-UV <- function call target identity level cache - * | - * DV - * | - * UVC <- varargs signature level cache - * - * varargs, max varargs depth exceeded: - * | - * DV-DV-UV - * | - * DV - * | - * DV - * | - * DV - * | - * DGV - * - * varargs, max function depth exceeded: - * | - * DV-DV-DV-DV-GV - * </pre> - * <p> - * In the diagrams above every horizontal connection "-" is in fact established by a separate node: - * {@link CachedCallNode}, which encapsulates the check for function call target identity. So the 1. - * example in fact looks like this: - * - * <pre> - * | - * C-C-C-U - * | | | - * D D D - * </pre> - * - * This is useful as it avoids repetition and allows child nodes to be more concise. It is also - * needed as there are {@link RCallNode} implementations that are not aware of caching, e.g. - * {@link RBuiltinNode}, which may be part of the cache. Note that varargs cache nodes ( - * {@link DispatchedVarArgsCallNode}, the nodes connected by "|") handle the check for varargs value - * identity by itself. - * </p> - * - * As the two problems of changing arguments and changing functions are totally independent as - * described above, it would be possible to use two totally separate caching infrastructures. The - * reason for the current choice is the expectation that R users will try to call same functions - * with the same arguments, and there will very rarely be the case that the same arguments get - * passed via "..." to the same functions. - * - */ -@NodeInfo(cost = NodeCost.NONE) -public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxCall, RCaller { - - private static final int FUNCTION_INLINE_CACHE_SIZE = 4; - private static final int VARARGS_INLINE_CACHE_SIZE = 4; +class ForcePromiseNode extends RNode { - @Child private RNode functionNode; + @Child private RNode valueNode; @Child private PromiseHelperNode promiseHelper; - @Child private RootCallNode call; - @Child private RootCallNode internalDispatchCall; - @Child private RNode dispatchArgument; - @Child private TemporarySlotNode dispatchTempSlot; - @Child private S3FunctionLookupNode dispatchLookup; - @Child private ClassHierarchyNode classHierarchyNode; - @Child private GroupDispatchNode groupDispatchNode; + private final BranchProfile nonPromiseProfile = BranchProfile.create(); - /** - * The {@link #arguments} field must be cloned by {@link NodeUtil#cloneNode(Node)}. - */ - private static class SyntaxArguments extends NodeCloneable { - private final RSyntaxNode[] v; + ForcePromiseNode(RNode valueNode) { + this.valueNode = valueNode; + } - SyntaxArguments(RSyntaxNode[] arguments) { - this.v = arguments; - } + public RNode getValueNode() { + return valueNode; + } - @Override - protected Object clone() { - SyntaxArguments sa = new SyntaxArguments(new RSyntaxNode[v.length]); - for (int i = 0; i < v.length; i++) { - if (v[i] != null) { - RSyntaxNode viClone = (RSyntaxNode) RASTUtils.cloneNode(v[i].asRNode()); - sa.v[i] = viClone; - } + @Override + public Object execute(VirtualFrame frame) { + Object value = valueNode.execute(frame); + if (value instanceof RPromise) { + if (promiseHelper == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + promiseHelper = insert(new PromiseHelperNode()); } - return sa; + return promiseHelper.evaluate(frame, (RPromise) value); + } else { + nonPromiseProfile.enter(); + return value; } } +} + +interface CallWithCallerFrame extends RCaller { + boolean setNeedsCallerFrame(); +} + +@NodeInfo(cost = NodeCost.NONE) +@NodeChild(value = "function", type = ForcePromiseNode.class) +public abstract class RCallNode extends RNode implements RSyntaxNode, RSyntaxCall, RCaller { + + // currently cannot be RSourceSectionNode because of TruffleDSL restrictions + + @CompilationFinal private SourceSection sourceSectionR; + + @Override + public final void setSourceSection(SourceSection sourceSection) { + assert sourceSection != null; + this.sourceSectionR = sourceSection; + } - private final SyntaxArguments arguments; + @Override + public final SourceSection getSourceSection() { + return sourceSectionR; + } + + public abstract Object execute(VirtualFrame frame, Object function); + + protected abstract ForcePromiseNode getFunction(); + + private final RSyntaxNode[] arguments; + private final int[] varArgIndexes; private final ArgumentsSignature signature; + @Child private ReadVariableNode lookupVarArgs; + protected final LocalReadVariableNode explicitArgs; + + // needed for INTERNAL_GENERIC calls: + @Child private FunctionDispatch internalDispatchCall; + + @CompilationFinal private boolean needsCallerFrame; + + boolean setNeedsCallerFrame() { + try { + return needsCallerFrame; + } finally { + needsCallerFrame = true; + } + } - private final ValueProfile builtinProfile = ValueProfile.createIdentityProfile(); - private final ConditionProfile implicitTypeProfile = ConditionProfile.createBinaryProfile(); - private final ConditionProfile resultIsBuiltinProfile = ConditionProfile.createBinaryProfile(); - private final ConditionProfile isPromiseProfile = ConditionProfile.createBinaryProfile(); - private final BranchProfile normalDispatchProfile = BranchProfile.create(); - private final BranchProfile errorProfile = BranchProfile.create(); - private final ConditionProfile isRFunctionProfile = ConditionProfile.createBinaryProfile(); + @Override + public RSyntaxNode getSyntaxNode() { + return this; + } - @Child private Node foreignCall; - @CompilationFinal private int foreignCallArgCount; - @Child private CallArgumentsNode foreignCallArguments; + protected RCaller createCaller(VirtualFrame frame, RFunction function) { + if (explicitArgs == null) { + return this; + } else { + return new RCallerHelper.Representation(function, (RArgsValuesAndNames) explicitArgs.execute(frame)); + } + } - private RCallNode(SourceSection sourceSection, RNode function, RSyntaxNode[] arguments, ArgumentsSignature signature) { - super(sourceSection); - this.functionNode = function; - this.arguments = new SyntaxArguments(arguments); + protected RCallNode(SourceSection sourceSection, RSyntaxNode[] arguments, ArgumentsSignature signature) { + assert sourceSection != null; + this.sourceSectionR = sourceSection; + this.arguments = arguments; + this.explicitArgs = null; + this.varArgIndexes = getVarArgIndexes(arguments); + this.lookupVarArgs = varArgIndexes.length == 0 ? null : ReadVariableNode.createSilent(ArgumentsSignature.VARARG_NAME, RType.Any); for (String name : signature) { if (name != null && name.isEmpty()) { @@ -275,172 +215,357 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, this.signature = signature; } - @Override - public RSyntaxNode getSyntaxNode() { - return this; + protected RCallNode(SourceSection sourceSection, Object explicitArgsIdentifier) { + assert sourceSection != null; + this.sourceSectionR = sourceSection; + this.arguments = null; + this.explicitArgs = LocalReadVariableNode.create(explicitArgsIdentifier, false); + this.varArgIndexes = null; + this.lookupVarArgs = null; + this.signature = null; + } + + public static int[] getVarArgIndexes(RSyntaxNode[] arguments) { + List<Integer> varArgsSymbolIndices = new ArrayList<>(); + for (int i = 0; i < arguments.length; i++) { + RSyntaxNode arg = arguments[i]; + if (arg instanceof RSyntaxLookup) { + RSyntaxLookup lookup = (RSyntaxLookup) arg; + // Check for presence of "..." in the arguments + if (ArgumentsSignature.VARARG_NAME.equals(lookup.getIdentifier())) { + varArgsSymbolIndices.add(i); + } + } + } + // Setup and return + int[] varArgsSymbolIndicesArr = new int[varArgsSymbolIndices.size()]; + for (int i = 0; i < varArgsSymbolIndicesArr.length; i++) { + varArgsSymbolIndicesArr[i] = varArgsSymbolIndices.get(i); + } + return varArgsSymbolIndicesArr; } public Arguments<RSyntaxNode> getArguments() { - return new Arguments<>(arguments.v, signature); + return new Arguments<>(arguments, signature); } - public int getArgumentCount() { - return arguments.v.length; + private RArgsValuesAndNames lookupVarArgs(VirtualFrame frame) { + if (explicitArgs != null) { + return (RArgsValuesAndNames) explicitArgs.execute(frame); + } + RArgsValuesAndNames varArgs; + if (lookupVarArgs == null) { + varArgs = null; + } else { + try { + varArgs = lookupVarArgs.executeRArgsValuesAndNames(frame); + } catch (UnexpectedResultException e) { + throw RError.error(RError.SHOW_CALLER, RError.Message.NO_DOT_DOT_DOT); + } + } + return varArgs; } - public RSyntaxNode getArgument(int index) { - return arguments.v[index]; + protected FunctionDispatch createUninitializedCall() { + return FunctionDispatchNodeGen.create(this, null, explicitArgs == null ? false : true); } - @Override - public Object execute(VirtualFrame frame) { - return execute(frame, executeFunctionNode(frame)); + protected FunctionDispatch createUninitializedExplicitCall() { + return FunctionDispatchNodeGen.create(this, null, true); } - @TruffleBoundary - private static String getMessage(Throwable e) { - return e.getMessage() != null ? e.getMessage() : e.toString(); + /** + * If there are no parameters, or the target function does not refer to a builtin, or the + * builtin has no special dispatching, then we know that we will just call the function with no + * special dispatch logic. + */ + protected boolean isDefaultDispatch(RFunction function) { + return (signature != null && signature.isEmpty()) || function.getRBuiltin() == null || function.getRBuiltin().getDispatch() == RDispatch.DEFAULT; } - @Override - public Node deepCopy() { - RCallNode copy = (RCallNode) super.deepCopy(); - // execution (frame) specific due to temp identifiers, so reset - copy.internalDispatchCall = null; - return copy; + @Specialization(guards = "isDefaultDispatch(function)") + public Object call(VirtualFrame frame, RFunction function, // + @Cached("createUninitializedCall()") FunctionDispatch call) { + return call.execute(frame, function, lookupVarArgs(frame), null); } - public Object execute(VirtualFrame frame, Object functionObject) { - RFunction function; - if (isRFunctionProfile.profile(functionObject instanceof RFunction)) { - function = (RFunction) functionObject; - // fall through - } else if (functionObject instanceof TruffleObject && !(functionObject instanceof RTypedValue)) { - if (foreignCallArguments == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - foreignCallArguments = insert(createArguments(null, true, true)); + protected RNode createDispatchArgument(int index) { + return new ForcePromiseNode(NodeUtil.cloneNode(arguments[index].asRNode())); + } + + /** + * If the target function refers to a builtin that requires internal generic dispatch and there + * are actual parameters to dispatch on, then we will do an internal generic dispatch on the + * first parameter. + */ + protected boolean isInternalGenericDispatch(RFunction function) { + if (signature != null && signature.isEmpty()) { + return false; + } + RBuiltinDescriptor builtin = function.getRBuiltin(); + return builtin != null && builtin.getDispatch() == RDispatch.INTERNAL_GENERIC; + } + + @Specialization(guards = {"explicitArgs == null", "isInternalGenericDispatch(function)"}) + public Object callInternalGeneric(VirtualFrame frame, RFunction function, // + @Cached("createDispatchArgument(0)") RNode dispatchArgument, // + @Cached("new()") TemporarySlotNode dispatchTempSlot, // + @Cached("create()") ClassHierarchyNode classHierarchyNode, // + @Cached("createWithError()") S3FunctionLookupNode dispatchLookup, // + @Cached("createIdentityProfile()") ValueProfile builtinProfile, // + @Cached("createBinaryProfile()") ConditionProfile implicitTypeProfile, // + @Cached("createBinaryProfile()") ConditionProfile resultIsBuiltinProfile) { + RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin()); + Object dispatchObject = dispatchArgument.execute(frame); + FrameSlot slot = dispatchTempSlot.initialize(frame, dispatchObject, () -> internalDispatchCall = null); + try { + RStringVector type = classHierarchyNode.execute(dispatchObject); + S3Args s3Args; + RFunction resultFunction; + if (implicitTypeProfile.profile(type != null)) { + Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), null); + if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) { + s3Args = null; + } else { + s3Args = new S3Args(result.generic, result.clazz, result.targetFunctionName, frame.materialize(), null, null); + } + resultFunction = result.function; + } else { + s3Args = null; + resultFunction = function; } - Object[] argumentsArray = foreignCallArguments.evaluateFlattenObjects(frame); - if (foreignCall == null || foreignCallArgCount != argumentsArray.length) { + if (internalDispatchCall == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - foreignCall = insert(Message.createExecute(argumentsArray.length).createNode()); - foreignCallArgCount = argumentsArray.length; + internalDispatchCall = insert(FunctionDispatchNodeGen.create(this, new Object[]{dispatchTempSlot.getIdentifier()}, false)); } - try { - return ForeignAccess.send(foreignCall, frame, (TruffleObject) functionObject, argumentsArray); - } catch (Throwable e) { - errorProfile.enter(); - throw RError.error(this, RError.Message.GENERIC, "Foreign function failed: " + getMessage(e)); + return internalDispatchCall.execute(frame, resultFunction, lookupVarArgs(frame), s3Args); + } finally { + dispatchTempSlot.cleanup(frame, slot); + } + } + + @Specialization(guards = {"explicitArgs != null", "isInternalGenericDispatch(function)"}) + public Object callInternalGenericExplicit(VirtualFrame frame, RFunction function, // + @Cached("create()") ClassHierarchyNode classHierarchyNode, // + @Cached("createWithError()") S3FunctionLookupNode dispatchLookup, // + @Cached("createIdentityProfile()") ValueProfile builtinProfile, // + @Cached("createBinaryProfile()") ConditionProfile implicitTypeProfile, // + @Cached("createBinaryProfile()") ConditionProfile resultIsBuiltinProfile, // + @Cached("createPromiseHelper()") PromiseCheckHelperNode promiseHelperNode, // + @Cached("createUninitializedExplicitCall()") FunctionDispatch call) { + RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin()); + RArgsValuesAndNames argAndNames = (RArgsValuesAndNames) explicitArgs.execute(frame); + + RStringVector type = argAndNames.isEmpty() ? null : classHierarchyNode.execute(promiseHelperNode.checkEvaluate(frame, argAndNames.getArgument(0))); + S3Args s3Args; + RFunction resultFunction; + if (implicitTypeProfile.profile(type != null)) { + Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), null); + if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) { + s3Args = null; + } else { + s3Args = new S3Args(result.generic, result.clazz, result.targetFunctionName, frame.materialize(), null, null); } + resultFunction = result.function; } else { - errorProfile.enter(); - throw RError.error(RError.SHOW_CALLER, RError.Message.APPLY_NON_FUNCTION); + s3Args = null; + resultFunction = function; } + return call.execute(frame, resultFunction, argAndNames, s3Args); + } - if (!signature.isEmpty() && function.getRBuiltin() != null) { - RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin()); - RDispatch dispatch = builtin.getDispatch(); - if (dispatch == RDispatch.DEFAULT) { - // fallthrough - } else if (dispatch == RDispatch.INTERNAL_GENERIC) { - if (internalDispatchCall == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - dispatchTempSlot = insert(new TemporarySlotNode()); - dispatchArgument = insert(RASTUtils.cloneNode(arguments.v[0].asRNode())); - dispatchLookup = insert(S3FunctionLookupNode.create(true, false)); - classHierarchyNode = insert(ClassHierarchyNodeGen.create(false, true)); - } - Object dispatchObject = dispatchArgument.execute(frame); - FrameSlot slot = dispatchTempSlot.initialize(frame, dispatchObject, identifier -> internalDispatchCall = insert(new UninitializedCallNode(this, identifier))); + protected CallArgumentsNode createArguments() { + return signature == null ? null : createArguments(null, false, false); + } + + protected ReadVariableNode createVarArgRead(CallArgumentsNode callArguments) { + return callArguments.containsVarArgsSymbol() ? ReadVariableNode.createSilent(ArgumentsSignature.VARARG_NAME, RType.Any) : null; + } + + protected boolean isGroupGenericDispatch(RFunction function) { + if (signature != null && signature.isEmpty()) { + return false; + } + RBuiltinDescriptor builtin = function.getRBuiltin(); + return builtin != null && builtin.getDispatch().isGroupGeneric(); + } + + protected PromiseCheckHelperNode createPromiseHelper() { + return new PromiseCheckHelperNode(); + } + + @Specialization(guards = "isGroupGenericDispatch(function)") + public Object callGroupGeneric(VirtualFrame frame, RFunction function, // + @Cached("createArguments()") CallArgumentsNode callArguments, // + @Cached("create()") ClassHierarchyNode classHierarchyNodeX, // + @Cached("createWithException()") S3FunctionLookupNode dispatchLookupX, // + @Cached("create()") ClassHierarchyNode classHierarchyNodeY, // + @Cached("createWithException()") S3FunctionLookupNode dispatchLookupY, // + @Cached("createIdentityProfile()") ValueProfile builtinProfile, // + @Cached("createBinaryProfile()") ConditionProfile implicitTypeProfileX, // + @Cached("createBinaryProfile()") ConditionProfile implicitTypeProfileY, // + @Cached("createBinaryProfile()") ConditionProfile mismatchProfile, // + @Cached("createBinaryProfile()") ConditionProfile resultIsBuiltinProfile, // + @Cached("createPromiseHelper()") PromiseCheckHelperNode promiseHelperNode, // + @Cached("createUninitializedExplicitCall()") FunctionDispatch call) { + + RArgsValuesAndNames argAndNames = explicitArgs != null ? (RArgsValuesAndNames) explicitArgs.execute(frame) : callArguments.evaluateFlatten(frame, lookupVarArgs(frame)); + + RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin()); + RDispatch dispatch = builtin.getDispatch(); + + RStringVector typeX = classHierarchyNodeX.execute(promiseHelperNode.checkEvaluate(frame, argAndNames.getArgument(0))); + Result resultX = null; + if (implicitTypeProfileX.profile(typeX != null)) { + try { + resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), null); + } catch (NoGenericMethodException e) { + // fall-through + } + } + Result resultY = null; + if (argAndNames.getLength() > 1 && dispatch == RDispatch.OPS_GROUP_GENERIC) { + RStringVector typeY = classHierarchyNodeY.execute(promiseHelperNode.checkEvaluate(frame, argAndNames.getArgument(1))); + if (implicitTypeProfileY.profile(typeY != null)) { try { - RStringVector type = classHierarchyNode.execute(dispatchObject); - S3Args s3Args; - RFunction resultFunction; - if (implicitTypeProfile.profile(type != null)) { - Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), null); - if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) { - s3Args = null; - } else { - s3Args = new S3Args(result.generic, result.clazz, result.targetFunctionName, frame.materialize(), null, null); - } - resultFunction = result.function; - } else { - s3Args = null; - resultFunction = function; - } - return internalDispatchCall.execute(frame, resultFunction, s3Args); - } finally { - dispatchTempSlot.cleanup(frame, slot); + resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), null); + } catch (NoGenericMethodException e) { + // fall-through } + } + } + + Result result; + RStringVector dotMethod; + if (resultX == null) { + if (resultY == null) { + result = null; + dotMethod = null; } else { - assert dispatch.isGroupGeneric(); + result = resultY; + dotMethod = RDataFactory.createStringVector(new String[]{"", result.targetFunctionName}, true); + } + } else { + if (resultY == null) { + result = resultX; + dotMethod = RDataFactory.createStringVector(new String[]{result.targetFunctionName, ""}, true); + } else { + if (mismatchProfile.profile(resultX.function != resultY.function)) { + RError.warning(this, RError.Message.INCOMPATIBLE_METHODS, resultX.targetFunctionName, resultY.targetFunctionName, dispatch.getGroupGenericName()); + result = null; + dotMethod = null; + } else { + result = resultX; + dotMethod = RDataFactory.createStringVector(new String[]{result.targetFunctionName, result.targetFunctionName}, true); + } } } - normalDispatchProfile.enter(); - if (call == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - call = insert(new UninitializedCallNode(this, null)); + S3Args s3Args; + RFunction resultFunction; + if (result == null) { + s3Args = null; + resultFunction = function; + } else { + if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) { + s3Args = null; + } else { + s3Args = new S3Args(builtin.getName(), result.clazz, dotMethod, frame.materialize(), null, result.groupMatch ? dispatch.getGroupGenericName() : null); + } + resultFunction = result.function; } - return call.execute(frame, function, null); + return call.execute(frame, resultFunction, argAndNames, s3Args); } - private Object executeFunctionNode(VirtualFrame frame) { - /** - * Expressions such as "pkg:::f" can result in (delayedAssign) promises that must be - * explicitly resolved. - */ - Object value = functionNode.execute(frame); - if (isPromiseProfile.profile(value instanceof RPromise)) { - if (promiseHelper == null) { + protected class ForeignCall extends Node { + + @Child private CallArgumentsNode arguments; + @Child private Node foreignCall; + @CompilationFinal private int foreignCallArgCount; + + private final BranchProfile errorProfile = BranchProfile.create(); + + public ForeignCall(CallArgumentsNode arguments) { + this.arguments = arguments; + } + + @SuppressWarnings("deprecation") + public Object execute(VirtualFrame frame, TruffleObject function) { + Object[] argumentsArray = explicitArgs != null ? ((RArgsValuesAndNames) explicitArgs.execute(frame)).getArguments() : arguments.evaluateFlattenObjects(frame, lookupVarArgs(frame)); + if (foreignCall == null || foreignCallArgCount != argumentsArray.length) { CompilerDirectives.transferToInterpreterAndInvalidate(); - promiseHelper = insert(new PromiseHelperNode()); + foreignCall = insert(Message.createExecute(argumentsArray.length).createNode()); + foreignCallArgCount = argumentsArray.length; + } + try { + return ForeignAccess.execute(foreignCall, frame, function, argumentsArray); + } catch (Throwable e) { + errorProfile.enter(); + throw RError.error(this, RError.Message.GENERIC, "Foreign function failed: " + e.getMessage() != null ? e.getMessage() : e.toString()); } - value = promiseHelper.evaluate(frame, (RPromise) value); } - return value; + } + + protected ForeignCall createForeignCall() { + return new ForeignCall(createArguments(null, true, true)); + } + + protected static boolean isRTypedValue(Object value) { + return value instanceof RTypedValue; + } + + @Specialization(guards = "!isRTypedValue(function)") + public Object call(VirtualFrame frame, TruffleObject function, // + @Cached("createForeignCall()") ForeignCall foreignCall) { + return foreignCall.execute(frame, function); + } + + @TruffleBoundary + @Fallback + public Object call(@SuppressWarnings("unused") Object function) { + throw RError.error(RError.SHOW_CALLER, RError.Message.APPLY_NON_FUNCTION); } public RNode getFunctionNode() { - if (functionNode != null) { + if (getFunction() != null) { // Only the very 1. RootCallNode on the top level contains the one-and-only function // node - return functionNode; + return getFunction().getValueNode(); } return getParentCallNode().getFunctionNode(); } - public CallArgumentsNode createArguments(Object dispatchTempIdentifier, boolean modeChange, boolean modeChangeAppliesToAll) { - RNode[] args = new RNode[arguments.v.length]; - for (int i = 0; i < arguments.v.length; i++) { - if (i == 0 && dispatchTempIdentifier != null) { - args[0] = new GetTempNode(dispatchTempIdentifier, arguments.v[0]); + public CallArgumentsNode createArguments(Object[] dispatchTempIdentifiers, boolean modeChange, boolean modeChangeAppliesToAll) { + RNode[] args = new RNode[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + if (dispatchTempIdentifiers != null && i < dispatchTempIdentifiers.length) { + args[i] = new GetTempNode(dispatchTempIdentifiers[i], arguments[i]); } else { - args[i] = arguments.v[i] == null ? null : RASTUtils.cloneNode(arguments.v[i].asRNode()); + args[i] = arguments[i] == null ? null : RASTUtils.cloneNode(arguments[i].asRNode()); } } - return CallArgumentsNode.create(modeChange, modeChangeAppliesToAll, args, signature); + return CallArgumentsNode.create(modeChange, modeChangeAppliesToAll, args, signature, varArgIndexes); } @Override public void serializeImpl(RSerialize.State state) { state.setAsLangType(); - state.serializeNodeSetCar(functionNode); - if (isColon(functionNode)) { + state.serializeNodeSetCar(getFunctionNode()); + if (isColon(getFunctionNode())) { // special case, have to translate Strings to Symbols state.openPairList(); - state.setCarAsSymbol(((ReadVariableNode) arguments.v[0]).getIdentifier()); + state.setCarAsSymbol(((ReadVariableNode) arguments[0]).getIdentifier()); state.openPairList(); - state.setCarAsSymbol(((ReadVariableNode) arguments.v[1]).getIdentifier()); + state.setCarAsSymbol(((ReadVariableNode) arguments[1]).getIdentifier()); state.linkPairList(2); state.setCdr(state.closePairList()); } else { - RSyntaxNode f = functionNode.asRSyntaxNode(); + RSyntaxNode f = getFunctionNode().asRSyntaxNode(); boolean infixFieldAccess = false; if (f instanceof RSyntaxLookup) { RSyntaxLookup lookup = (RSyntaxLookup) f; infixFieldAccess = "$".equals(lookup.getIdentifier()) || "@".equals(lookup.getIdentifier()); } - serializeArguments(state, arguments.v, signature, infixFieldAccess); + serializeArguments(state, arguments, signature, infixFieldAccess); } } @@ -490,7 +615,7 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, public RSyntaxNode substituteImpl(REnvironment env) { RNode functionSub = getFunctionNode().substitute(env).asRNode(); - Arguments<RSyntaxNode> argsSub = substituteArguments(env, arguments.v, signature); + Arguments<RSyntaxNode> argsSub = substituteArguments(env, arguments, signature); return RASTUtils.createCall(functionSub, false, argsSub.getSignature(), argsSub.getArguments()); } @@ -521,15 +646,45 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, * Creates a call to a resolved {@link RBuiltinKind#INTERNAL} that will be used to replace the * original call. * - * @param frame The frame to create the inlined builtins in - * @param internalCallArg the {@link UninitializedCallNode} corresponding to the argument to the - * {code .Internal}. + * @param internalCallArg the {@link RCallNode} corresponding to the argument to the {code + * .Internal}. * @param function the resolved {@link RFunction}. - * @param name The name of the function */ - public static LeafCallNode createInternalCall(VirtualFrame frame, RCallNode internalCallArg, RFunction function, String name) { + public static RNode createInternalCall(RCallNode internalCallArg, RFunction function) { CompilerAsserts.neverPartOfCompilation(); - return UninitializedCallNode.createCacheNode(frame, internalCallArg.createArguments(null, false, true), internalCallArg, function); + return new InternalNode(FunctionDispatchNodeGen.create(internalCallArg, null, false), function, internalCallArg.lookupVarArgs != null); + } + + @NodeInfo(cost = NodeCost.NONE) + private static final class InternalNode extends RNode { + @Child private FunctionDispatch rootCallNode; + @Child private ReadVariableNode lookupVarArgs; + private final RFunction function; + + InternalNode(FunctionDispatch rootCallNode, RFunction function, boolean needsVarArgLookup) { + this.rootCallNode = rootCallNode; + this.function = function; + this.lookupVarArgs = needsVarArgLookup ? ReadVariableNode.createSilent(ArgumentsSignature.VARARG_NAME, RType.Any) : null; + } + + private RArgsValuesAndNames lookupVarArgs(VirtualFrame frame) { + RArgsValuesAndNames varArgs; + if (lookupVarArgs == null) { + varArgs = null; + } else { + try { + varArgs = lookupVarArgs.executeRArgsValuesAndNames(frame); + } catch (UnexpectedResultException e) { + throw RError.error(RError.SHOW_CALLER, RError.Message.NO_DOT_DOT_DOT); + } + } + return varArgs; + } + + @Override + public Object execute(VirtualFrame frame) { + return rootCallNode.execute(frame, function, lookupVarArgs(frame), null); + } } /** @@ -539,11 +694,11 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, */ @TruffleBoundary public static RCallNode createCloneReplacingArgs(RCallNode call, RSyntaxNode... replacementArgs) { - RSyntaxNode[] args = new RSyntaxNode[call.arguments.v.length]; + RSyntaxNode[] args = new RSyntaxNode[call.arguments.length]; for (int i = 0; i < args.length; i++) { - args[i] = i < replacementArgs.length ? replacementArgs[i] : call.arguments.v[i]; + args[i] = i < replacementArgs.length ? replacementArgs[i] : call.arguments[i]; } - return new RCallNode(call.getSourceSection(), RASTUtils.cloneNode(call.functionNode), args, call.signature); + return RCallNodeGen.create(call.getSourceSection(), args, call.signature, new ForcePromiseNode(RASTUtils.cloneNode(call.getFunction()))); } /** @@ -551,13 +706,17 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, * {@code src == RSyntaxNode.EAGER_DEPARSE} we force a deparse. */ public static RCallNode createCall(SourceSection src, RNode function, ArgumentsSignature signature, RSyntaxNode... arguments) { - RCallNode call = new RCallNode(src, function, arguments, signature); + RCallNode call = RCallNodeGen.create(src, arguments, signature, new ForcePromiseNode(function)); if (src == RSyntaxNode.EAGER_DEPARSE) { RDeparse.ensureSourceSection(call); } return call; } + public static RCallNode createExplicitCall(Object explicitArgsIdentifier) { + return RCallNodeGen.create(RSyntaxNode.INTERNAL, explicitArgsIdentifier, null); + } + static RBuiltinRootNode findBuiltinRootNode(RootCallTarget callTarget) { RootNode root = callTarget.getRootNode(); if (root instanceof RBuiltinRootNode) { @@ -584,12 +743,6 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, return false; } - public abstract static class RootCallNode extends Node { - - public abstract Object execute(VirtualFrame frame, RFunction function, S3Args s3Args); - - } - private static final class GetTempNode extends RNode { @Child private FrameSlotNode slot; @@ -615,138 +768,83 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, } } - /** - * [U]/[UV] Forms the uninitialized end of the function PIC. - * - * @see RCallNode - */ - @NodeInfo(cost = NodeCost.UNINITIALIZED) - private static final class UninitializedCallNode extends RootCallNode { + public abstract static class FunctionDispatch extends Node { - private int depth; - private final RCallNode call; - private final Object dispatchTempIdentifier; + public abstract Object execute(VirtualFrame frame, RFunction function, Object varArgs, Object s3Args); - UninitializedCallNode(RCallNode call, Object dispatchTempIdentifier) { - this.call = call; - this.dispatchTempIdentifier = dispatchTempIdentifier; - this.depth = 0; - } + protected static final int CACHE_SIZE = 4; - @Override - public Object execute(VirtualFrame frame, RFunction function, S3Args s3Args) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - depth++; - RootCallNode next = depth < FUNCTION_INLINE_CACHE_SIZE ? this : new GenericCallNode(call.createArguments(dispatchTempIdentifier, true, true), call); - - RBuiltinDescriptor builtin = function.getRBuiltin(); - boolean modeChange = true; - if (builtin != null) { - modeChange = false; - } + private final RCallNode originalCall; + private final Object[] dispatchTempIdentifiers; + private final boolean explicitArgs; - LeafCallNode current = createCacheNode(frame, call.createArguments(dispatchTempIdentifier, modeChange, true), call, function); - RootCallNode cachedNode = new CachedCallNode(current, next, function); - this.replace(cachedNode); - return cachedNode.execute(frame, function, s3Args); + public FunctionDispatch(RCallNode originalCall, Object[] dispatchTempIdentifiers, boolean explicitArgs) { + this.originalCall = originalCall; + this.dispatchTempIdentifiers = dispatchTempIdentifiers; + this.explicitArgs = explicitArgs; } - private static LeafCallNode createCacheNode(VirtualFrame frame, CallArgumentsNode args, RCallNode creator, RFunction function) { - CompilerDirectives.transferToInterpreter(); - - LeafCallNode callNode = null; - // Check implementation: If written in Java, handle differently! + protected LeafCallNode createCacheNode(RFunction function) { + CompilerAsserts.neverPartOfCompilation(); + FormalArguments formals = ((RRootNode) function.getTarget().getRootNode()).getFormalArguments(); if (function.isBuiltin()) { - RootCallTarget callTarget = function.getTarget(); - RBuiltinRootNode root = findBuiltinRootNode(callTarget); - assert root != null; - - // We inline the given arguments here, as builtins are executed inside the same - // frame as they are called. - RNode[] inlinedArgs = ArgumentMatcher.matchArgumentsInlined(function, args, creator); - callNode = new BuiltinCallNode(root.inline(inlinedArgs), creator); + return new BuiltinCallNode(RBuiltinNode.inline(function.getRBuiltin(), null), function.getRBuiltin(), formals, originalCall); } else { - // Now we need to distinguish: Do supplied arguments vary between calls? - if (args.containsVarArgsSymbol()) { - VarArgsCacheCallNode nextNode = new UninitializedVarArgsCacheCallNode(args, creator); - ArgumentsSignature varArgsSignature = CallArgumentsNode.getVarargsAndNames(frame).getSignature(); - callNode = DispatchedVarArgsCallNode.create(frame, args, nextNode, creator, function, varArgsSignature); - } else { - MatchedArguments matchedArgs = ArgumentMatcher.matchArguments(function, args, creator, false); - callNode = new DispatchedCallNode(function, matchedArgs, creator); - } + return new DispatchedCallNode(function, formals.getSignature(), originalCall); } - - return callNode; } - } - - /** - * [C] Extracts the check for function call target identity away from the individual cache - * nodes. - * - * @see RCallNode - */ - private static final class CachedCallNode extends RootCallNode { - - @Child private RootCallNode nextNode; - @Child private LeafCallNode currentNode; - - private final CallTarget cachedCallTarget; - CachedCallNode(LeafCallNode current, RootCallNode next, RFunction cachedFunction) { - this.currentNode = current; - this.nextNode = next; - this.cachedCallTarget = cachedFunction.getTarget(); + protected PrepareArguments createArguments(RFunction function) { + if (explicitArgs) { + return PrepareArguments.createExplicit(function); + } else { + CallArgumentsNode args = originalCall.createArguments(dispatchTempIdentifiers, !function.isBuiltin(), true); + return PrepareArguments.create(function, args); + } } - @Override - public Object execute(VirtualFrame frame, RFunction f, S3Args s3Args) { - if (cachedCallTarget == f.getTarget()) { - return currentNode.execute(frame, f, s3Args); - } - return nextNode.execute(frame, f, s3Args); + @Specialization(limit = "CACHE_SIZE", guards = "function == cachedFunction") + protected Object dispatch(VirtualFrame frame, @SuppressWarnings("unused") RFunction function, Object varArgs, Object s3Args, // + @Cached("function") RFunction cachedFunction, // + @Cached("createCacheNode(cachedFunction)") LeafCallNode leafCall, // + @Cached("createArguments(cachedFunction)") PrepareArguments prepareArguments) { + Object[] orderedArguments = prepareArguments.execute(frame, (RArgsValuesAndNames) varArgs, originalCall); + return leafCall.execute(frame, cachedFunction, orderedArguments, (S3Args) s3Args); } - } - /** - * [GV] {@link RCallNode} in case there is no fixed {@link RFunction} AND varargs... - * - * @see RCallNode - */ - private static final class GenericCallNode extends RootCallNode { + /* + * Use a TruffleBoundaryNode to be able to switch child nodes without invalidating the whole + * method. + */ + protected final class GenericCall extends TruffleBoundaryNode { - @Child private IndirectCallNode indirectCall = Truffle.getRuntime().createIndirectCallNode(); - @Child private CallArgumentsNode arguments; + private RFunction cachedFunction; + @Child private LeafCallNode leafCall; + @Child private PrepareArguments prepareArguments; - private final RCallNode call; + @TruffleBoundary + public Object execute(MaterializedFrame materializedFrame, RFunction function, Object varArgs, Object s3Args) { + if (cachedFunction != function) { + leafCall = insert(createCacheNode(function)); + prepareArguments = insert(createArguments(function)); + } + VirtualFrame frame = SubstituteVirtualFrame.create(materializedFrame); + Object[] orderedArguments = prepareArguments.execute(frame, (RArgsValuesAndNames) varArgs, originalCall); + return leafCall.execute(frame, cachedFunction, orderedArguments, (S3Args) s3Args); + } + } - GenericCallNode(CallArgumentsNode arguments, RCallNode call) { - // here, it's safe to reuse the arguments - it's the final use - this.arguments = arguments; - this.call = call; + protected GenericCall createGenericCall() { + return new GenericCall(); } - @Override - public Object execute(VirtualFrame frame, RFunction currentFunction, S3Args s3Args) { - CompilerDirectives.transferToInterpreter(); - // Function and arguments may change every call: Flatt'n'Match on SlowPath! :-/ - UnrolledVariadicArguments argsValuesAndNames = arguments.executeFlatten(frame); - MatchedArguments matchedArgs = ArgumentMatcher.matchArguments(currentFunction, argsValuesAndNames, RError.ROOTNODE, true); - - Object[] argsObject = RArguments.create(currentFunction, call, null, RArguments.getDepth(frame) + 1, RArguments.getPromiseFrame(frame), matchedArgs.doExecuteArray(frame), - matchedArgs.getSignature(), s3Args); - return indirectCall.call(frame, currentFunction.getTarget(), argsObject); + @Specialization + protected Object dispatchFallback(VirtualFrame frame, RFunction function, Object varArgs, Object s3Args, // + @Cached("createGenericCall()") GenericCall generic) { + return generic.execute(frame.materialize(), function, varArgs, s3Args); } } - /** - * This is the counterpart of {@link RCallNode}: While that is the base class for all top-level - * nodes (C, G, U and GV), this is the base class for all nodes not on the top level of the PIC - * (and thus don't need all information, but can rely on their parents to have them). - * - * @see RCallNode - */ public abstract static class LeafCallNode extends RBaseNode { /** * The original {@link RSyntaxNode} this derives from. @@ -762,297 +860,162 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, return originalCall; } - public abstract Object execute(VirtualFrame frame, RFunction function, S3Args s3Args); + public abstract Object execute(VirtualFrame frame, RFunction function, Object[] orderedArguments, S3Args s3Args); } @NodeInfo(cost = NodeCost.NONE) private static final class BuiltinCallNode extends LeafCallNode { @Child private RBuiltinNode builtin; + @Child private PromiseCheckHelperNode promiseHelper; + @Children private final CastNode[] casts; - BuiltinCallNode(RBuiltinNode builtin, RCallNode originalCall) { - super(originalCall); - this.builtin = builtin; - } - - @Override - public Object execute(VirtualFrame frame, RFunction currentFunction, S3Args s3Args) { - return builtin.execute(frame); - } - } - - public interface CallWithCallerFrame { - boolean setNeedsCallerFrame(); - } - - /** - * [D] A {@link RCallNode} for calls to fixed {@link RFunction}s with fixed arguments (no - * varargs). - * - * @see RCallNode - */ - private static final class DispatchedCallNode extends LeafCallNode implements CallWithCallerFrame { - - @Child private DirectCallNode call; - @Child private MatchedArgumentsNode matchedArgs; - @Child private RArgumentsNode argsNode = RArgumentsNode.create(); - @Child private RFastPathNode fastPath; - - @CompilationFinal private boolean needsCallerFrame; - private final RootCallTarget callTarget; - @CompilationFinal private boolean needsSplitting; + private final BranchProfile emptyProfile = BranchProfile.create(); + private final BranchProfile varArgsProfile = BranchProfile.create(); + private final ConditionProfile wrapProfile = ConditionProfile.createBinaryProfile(); + private final FormalArguments formals; + private final RBuiltinDescriptor builtinDescriptor; - DispatchedCallNode(RFunction function, MatchedArguments matchedArgs, RCallNode originalCall) { + BuiltinCallNode(RBuiltinNode builtin, RBuiltinDescriptor builtinDescriptor, FormalArguments formalArguments, RCallNode originalCall) { super(originalCall); - this.matchedArgs = matchedArgs.createNode(); - this.needsCallerFrame = function.containsDispatch(); - this.needsSplitting = needsSplitting(function); - this.callTarget = function.getTarget(); + this.builtin = builtin; + this.builtinDescriptor = builtinDescriptor; + this.casts = builtin.getCasts(); + this.formals = formalArguments; + } + + @ExplodeLoop + public Object[] castArguments(VirtualFrame frame, Object[] args) { + int argCount = formals.getLength(); + Object[] result = new Object[argCount]; + for (int i = 0; i < argCount; i++) { + Object arg = args[i]; + if (arg == REmpty.instance) { + emptyProfile.enter(); + arg = formals.getInternalDefaultArgumentAt(i); + } + if (arg instanceof RArgsValuesAndNames) { + varArgsProfile.enter(); + RArgsValuesAndNames varArgs = (RArgsValuesAndNames) arg; + if (builtinDescriptor.evaluatesArg(i)) { + forcePromises(frame, varArgs); + } else { + wrapPromises(varArgs); + } + } else { + if (builtinDescriptor.evaluatesArg(i)) { + if (arg instanceof RPromise) { + if (promiseHelper == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + promiseHelper = insert(new PromiseCheckHelperNode()); + } + arg = promiseHelper.checkEvaluate(frame, arg); - this.fastPath = function.getFastPath() == null ? null : function.getFastPath().create(); - if (fastPath == null) { - this.call = Truffle.getRuntime().createDirectCallNode(function.getTarget()); + } + if (i < casts.length && casts[i] != null) { + assert builtinDescriptor.evaluatesArg(i); + arg = casts[i].execute(arg); + } + } else { + assert casts.length <= i || casts[i] == null : "no casts allowed on non-evaluated arguments"; + if (wrapProfile.profile(!(arg instanceof RPromise || arg instanceof RMissing))) { + arg = createPromise(arg); + } + } + } + result[i] = arg; } + return result; } - @Override - public Object execute(VirtualFrame frame, RFunction currentFunction, S3Args s3Args) { - if (fastPath != null) { - Object[] argValues = matchedArgs.executeArray(frame); - Object result = fastPath.execute(frame, argValues); - if (result != null) { - return result; + private void forcePromises(VirtualFrame frame, RArgsValuesAndNames varArgs) { + Object[] array = varArgs.getArguments(); + for (int i = 0; i < array.length; i++) { + if (promiseHelper == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + promiseHelper = insert(new PromiseCheckHelperNode()); } - CompilerDirectives.transferToInterpreterAndInvalidate(); - fastPath = null; - call = insert(Truffle.getRuntime().createDirectCallNode(callTarget)); - } - - if (needsSplitting) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - needsSplitting = false; - call.cloneCallTarget(); + array[i] = promiseHelper.checkEvaluate(frame, array[i]); } - MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; - - Object[] argsObject = argsNode.execute(currentFunction, originalCall, callerFrame, RArguments.getDepth(frame) + 1, RArguments.getPromiseFrame(frame), - matchedArgs.executeArray(frame), - matchedArgs.getSignature(), s3Args); - return call.call(frame, argsObject); } - @Override - public boolean setNeedsCallerFrame() { - try { - return needsCallerFrame; - } finally { - needsCallerFrame = true; + @TruffleBoundary + private static void wrapPromises(RArgsValuesAndNames varArgs) { + Object[] array = varArgs.getArguments(); + for (int i = 0; i < array.length; i++) { + Object arg = array[i]; + if (!(arg instanceof RPromise || arg instanceof RMissing)) { + array[i] = createPromise(arg); + } } } - } - - /* - * Varargs cache classes follow - */ - - /** - * Base class for the varargs cache [UVC] and [DV]. - * - * @see RCallNode - */ - private abstract static class VarArgsCacheCallNode extends LeafCallNode { - - @Child private ReadVariableNode lookupVarArgs = ReadVariableNode.createSilent(ArgumentsSignature.VARARG_NAME, RType.Any); - private VarArgsCacheCallNode(RCallNode originalCallNode) { - super(originalCallNode); + @TruffleBoundary + private static Object createPromise(Object arg) { + return RDataFactory.createPromise(PromiseType.NO_ARG, OptType.PROMISED, ConstantNode.create(arg), arg); } @Override - public final Object execute(VirtualFrame frame, RFunction function, S3Args s3Args) { - Object varArgs = lookupVarArgs.execute(frame); - if (varArgs == RNull.instance) { - varArgs = RArgsValuesAndNames.EMPTY; - } - if (varArgs == null || !(varArgs instanceof RArgsValuesAndNames)) { - CompilerDirectives.transferToInterpreter(); - RError.error(RError.SHOW_CALLER, RError.Message.NO_DOT_DOT_DOT); - } - return execute(frame, function, ((RArgsValuesAndNames) varArgs).getSignature(), s3Args); + public Object execute(VirtualFrame frame, RFunction currentFunction, Object[] orderedArguments, S3Args s3Args) { + return builtin.execute(frame, castArguments(frame, orderedArguments)); } - - protected abstract Object execute(VirtualFrame frame, RFunction function, ArgumentsSignature varArgsSignature, S3Args s3Args); } - /** - * [UVC] The uninitialized end of the varargs cache. - * - * @see RCallNode - */ - @NodeInfo(cost = NodeCost.UNINITIALIZED) - private static final class UninitializedVarArgsCacheCallNode extends VarArgsCacheCallNode { - @Child private CallArgumentsNode args; - private int depth = 1; // varargs cached is started with a [DV] DispatchedVarArgsCallNode - - UninitializedVarArgsCacheCallNode(CallArgumentsNode args, RCallNode creator) { - super(creator); - this.args = args; - } - - @Override - public Object execute(VirtualFrame frame, RFunction function, ArgumentsSignature varArgsSignature, S3Args s3Args) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - - // Extend cache - this.depth += 1; - CallArgumentsNode clonedArgs = RASTUtils.cloneNode(args); - VarArgsCacheCallNode next = createNextNode(function); - DispatchedVarArgsCallNode newCallNode = DispatchedVarArgsCallNode.create(frame, clonedArgs, next, this, function, varArgsSignature); - return replace(newCallNode).execute(frame, function, varArgsSignature, s3Args); - } - - private VarArgsCacheCallNode createNextNode(RFunction function) { - if (depth < VARARGS_INLINE_CACHE_SIZE) { - return this; - } else { - CallArgumentsNode clonedArgs = RASTUtils.cloneNode(args); - return new DispatchedGenericVarArgsCallNode(function, clonedArgs, originalCall); - } - } - } + private static final class DispatchedCallNode extends LeafCallNode { - /** - * [DV] A {@link RCallNode} for calls to cached {@link RFunction}s with cached varargs. - * - * @see RCallNode - */ - private static final class DispatchedVarArgsCallNode extends VarArgsCacheCallNode implements CallWithCallerFrame { @Child private DirectCallNode call; - @Child private CallArgumentsNode args; - @Child private VarArgsCacheCallNode next; - @Child private MatchedArgumentsNode matchedArgs; - @Child private RArgumentsNode argsNode = RArgumentsNode.create(); + @Child private RArgumentsNode argsNode; + @Child private RFastPathNode fastPath; - private final ArgumentsSignature cachedSignature; - @CompilationFinal private boolean needsCallerFrame; - @CompilationFinal private boolean needsSplitting; + private final ArgumentsSignature signature; + private final RFunction cachedFunction; - protected DispatchedVarArgsCallNode(CallArgumentsNode args, VarArgsCacheCallNode next, RFunction function, ArgumentsSignature varArgsSignature, MatchedArguments matchedArgs, - RCallNode originalCall) { + DispatchedCallNode(RFunction function, ArgumentsSignature signature, RCallNode originalCall) { super(originalCall); - this.call = Truffle.getRuntime().createDirectCallNode(function.getTarget()); - this.args = args; - this.next = next; - this.cachedSignature = varArgsSignature; - this.matchedArgs = matchedArgs.createNode(); - this.needsCallerFrame = function.containsDispatch(); - /* - * this is a simple heuristic - methods that need a caller frame should have call site - - * specific versions - */ - this.needsSplitting = needsSplitting(function); - } - - protected static DispatchedVarArgsCallNode create(VirtualFrame frame, CallArgumentsNode args, VarArgsCacheCallNode next, RBaseNode creator, RFunction function, - ArgumentsSignature varArgsSignature) { - UnrolledVariadicArguments unrolledArguments = args.executeFlatten(frame); - MatchedArguments matchedArgs = ArgumentMatcher.matchArguments(function, unrolledArguments, creator, false); - RCallNode originalCall; - if (creator instanceof LeafCallNode) { - originalCall = ((LeafCallNode) creator).originalCall; - } else if (creator instanceof RCallNode) { - originalCall = (RCallNode) creator; - } else { - throw RInternalError.shouldNotReachHere(); - } - return new DispatchedVarArgsCallNode(args, next, function, varArgsSignature, matchedArgs, originalCall); + this.cachedFunction = function; + this.signature = signature; + this.fastPath = function.getFastPath() == null ? null : function.getFastPath().create(); + originalCall.needsCallerFrame |= cachedFunction.containsDispatch(); } @Override - public Object execute(VirtualFrame frame, RFunction currentFunction, ArgumentsSignature varArgsSignature, S3Args s3Args) { - // If this is the root of the varargs sub-cache: The signature needs to be created - // once - - // If the signature does not match: delegate to next node! - if (cachedSignature != varArgsSignature) { - return next.execute(frame, currentFunction, varArgsSignature, s3Args); - } - - // Our cached function and matched arguments do match, simply execute! - - if (needsSplitting) { + public Object execute(VirtualFrame frame, RFunction currentFunction, Object[] orderedArguments, S3Args s3Args) { + if (fastPath != null) { + Object result = fastPath.execute(frame, orderedArguments); + if (result != null) { + return result; + } CompilerDirectives.transferToInterpreterAndInvalidate(); - needsSplitting = false; - call.cloneCallTarget(); - } - MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; - Object[] argsObject = argsNode.execute(currentFunction, originalCall, callerFrame, RArguments.getDepth(frame) + 1, RArguments.getPromiseFrame(frame), - matchedArgs.executeArray(frame), - matchedArgs.getSignature(), s3Args); - return call.call(frame, argsObject); - } - - @Override - public boolean setNeedsCallerFrame() { - try { - return needsCallerFrame; - } finally { - needsCallerFrame = true; + fastPath = null; } - } - } - /** - * [DGV] {@link RCallNode} in case there is a cached {@link RFunction} with cached varargs that - * exceeded the cache size {@link RCallNode#VARARGS_INLINE_CACHE_SIZE} . - * - * @see RCallNode - */ - private static final class DispatchedGenericVarArgsCallNode extends VarArgsCacheCallNode { - - @Child private DirectCallNode call; - @Child private CallArgumentsNode suppliedArgs; - - @CompilationFinal private boolean needsCallerFrame; - - DispatchedGenericVarArgsCallNode(RFunction function, CallArgumentsNode suppliedArgs, RCallNode originalCall) { - super(originalCall); - this.call = Truffle.getRuntime().createDirectCallNode(function.getTarget()); - this.suppliedArgs = suppliedArgs; - } - - @Override - protected Object execute(VirtualFrame frame, RFunction currentFunction, ArgumentsSignature varArgsSignature, S3Args s3Args) { - CompilerDirectives.transferToInterpreter(); - - // Arguments may change every call: Flatt'n'Match on SlowPath! :-/ - UnrolledVariadicArguments argsValuesAndNames = suppliedArgs.executeFlatten(frame); - MatchedArguments matchedArgs = ArgumentMatcher.matchArguments(currentFunction, argsValuesAndNames, this, true); - - if (!needsCallerFrame && currentFunction.containsDispatch()) { + if (argsNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - needsCallerFrame = true; + argsNode = insert(RArgumentsNode.create()); + call = insert(Truffle.getRuntime().createDirectCallNode(cachedFunction.getTarget())); + if (needsSplitting(cachedFunction)) { + call.cloneCallTarget(); + } } - MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; - Object[] argsObject = RArguments.create(currentFunction, originalCall, callerFrame, RArguments.getDepth(frame) + 1, RArguments.getPromiseFrame(frame), - matchedArgs.doExecuteArray(frame), - matchedArgs.getSignature(), s3Args); + MaterializedFrame callerFrame = CompilerDirectives.inInterpreter() || originalCall.needsCallerFrame ? frame.materialize() : null; + Object[] argsObject = argsNode.execute(cachedFunction, originalCall.createCaller(frame, cachedFunction), callerFrame, RArguments.getDepth(frame) + 1, RArguments.getPromiseFrame(frame), + orderedArguments, signature, s3Args); return call.call(frame, argsObject); } } @Override public RSyntaxElement getSyntaxLHS() { - return functionNode.asRSyntaxNode(); + return getFunction() == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : getFunctionNode().asRSyntaxNode(); } @Override public ArgumentsSignature getSyntaxSignature() { - return signature; + return signature == null ? ArgumentsSignature.empty(1) : signature; } @Override public RSyntaxElement[] getSyntaxArguments() { - return arguments.v; + return arguments == null ? new RSyntaxElement[]{RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "...", false)} : arguments; } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java index 31af3be0e2ae22903e0b1a0d8b4f162c4e5fdce0..5053315ec963a72c311b422b48fbad04a65bef63 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java @@ -47,10 +47,10 @@ public class RCallerHelper { public static final class Representation implements RCaller { private final Object func; - private final Object[] arguments; + private final RArgsValuesAndNames arguments; private RSyntaxNode syntaxNode = null; - public Representation(Object func, Object[] arguments) { + public Representation(Object func, RArgsValuesAndNames arguments) { this.func = func; this.arguments = arguments; } @@ -58,14 +58,14 @@ public class RCallerHelper { @Override public RSyntaxNode getSyntaxNode() { if (syntaxNode == null) { - RSyntaxNode[] syntaxArguments = new RSyntaxNode[arguments.length]; + RSyntaxNode[] syntaxArguments = new RSyntaxNode[arguments.getLength()]; int index = 0; // arguments are already ordered - once one is missing, all the remaining ones must // be // missing boolean missing = false; - for (int i = 0; i < arguments.length; i++) { - Object arg = arguments[i]; + for (int i = 0; i < arguments.getLength(); i++) { + Object arg = arguments.getArgument(i); if (arg instanceof RPromise) { assert !missing; RPromise p = (RPromise) arg; @@ -103,9 +103,6 @@ public class RCallerHelper { } } - // for some reason GNU R does not use argument names - hence empty signature even - // though - // an actual one is available syntaxNode = RASTUtils.createCall(func, true, ArgumentsSignature.empty(syntaxArguments.length), syntaxArguments); } return syntaxNode; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java index b3e8ffc21b48ecd2dc46afc2169fbc8949448ab8..342c1c1a3d049fbe6c8321862e5b57364d4d36d8 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java @@ -80,6 +80,14 @@ public abstract class S3FunctionLookupNode extends RBaseNode { return new UseMethodFunctionLookupUninitializedNode(throwsError, nextMethod); } + public static S3FunctionLookupNode createWithError() { + return new UseMethodFunctionLookupUninitializedNode(true, false); + } + + public static S3FunctionLookupNode createWithException() { + return new UseMethodFunctionLookupUninitializedNode(false, false); + } + @FunctionalInterface private interface LookupOperation { Object read(MaterializedFrame frame, String name, boolean inMethodsTable); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java index 3418749e522c45c5ca692713b441a6a619c5b949..56c0751202f6e38fef94f115bb4dcf895ce01efc 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java @@ -22,8 +22,6 @@ */ package com.oracle.truffle.r.nodes.function; -import java.util.function.Consumer; - import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotTypeException; @@ -34,16 +32,17 @@ import com.oracle.truffle.r.runtime.RInternalError; public final class TemporarySlotNode extends Node { - private static final Object[] defaultTempIdentifiers = new Object[]{new Object(), new Object(), new Object(), new Object()}; + private static final Object[] defaultTempIdentifiers = new Object[]{new Object(), new Object(), new Object(), new Object(), new Object(), new Object(), new Object(), new Object()}; @Child private FrameSlotNode tempSlot; private int tempIdentifier; + private Object identifier; - public FrameSlot initialize(VirtualFrame frame, Object value, Consumer<Object> initializer) { + public FrameSlot initialize(VirtualFrame frame, Object value, Runnable invalidate) { if (tempSlot == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - tempSlot = insert(FrameSlotNode.createInitialized(frame.getFrameDescriptor(), defaultTempIdentifiers[0], true)); - initializer.accept(defaultTempIdentifiers[0]); + tempSlot = insert(FrameSlotNode.createInitialized(frame.getFrameDescriptor(), identifier = defaultTempIdentifiers[0], true)); + invalidate.run(); } FrameSlot slot = tempSlot.executeFrameSlot(frame); try { @@ -52,9 +51,9 @@ public final class TemporarySlotNode extends Node { // keep the complete loop in the slow path do { tempIdentifier++; - Object identifier = tempIdentifier < defaultTempIdentifiers.length ? defaultTempIdentifiers[tempIdentifier] : new Object(); + identifier = tempIdentifier < defaultTempIdentifiers.length ? defaultTempIdentifiers[tempIdentifier] : new Object(); tempSlot.replace(FrameSlotNode.createInitialized(frame.getFrameDescriptor(), identifier, true)); - initializer.accept(identifier); + invalidate.run(); slot = tempSlot.executeFrameSlot(frame); } while (frame.isObject(slot) && frame.getObject(slot) != null); } @@ -69,4 +68,8 @@ public final class TemporarySlotNode extends Node { public void cleanup(VirtualFrame frame, FrameSlot slot) { frame.setObject(slot, null); } + + public Object getIdentifier() { + return identifier; + } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnmatchedArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnmatchedArguments.java index 2258928a55dbd78a81de7667db9c34b96bae5b2e..70829ff60866dce7e8d25982da5008160c738003 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnmatchedArguments.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnmatchedArguments.java @@ -28,7 +28,7 @@ import com.oracle.truffle.r.runtime.nodes.RNode; /** * An interface all arguments that are going to be matched need to implement. */ -interface UnmatchedArguments extends ClosureCache { +public interface UnmatchedArguments extends ClosureCache { /** * @return The arguments to be matched. Individual {@link RNode}s may be <code>null</code> to * denote "missingness"! diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnrolledVariadicArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnrolledVariadicArguments.java index d2c1eb5b5ff02cf479765929f7a2f76e0e430eb9..b671bfe682c05ca423bce40b3f645ee5f3e11f76 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnrolledVariadicArguments.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnrolledVariadicArguments.java @@ -24,7 +24,6 @@ package com.oracle.truffle.r.nodes.function; import java.util.IdentityHashMap; -import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.data.RPromise.Closure; @@ -32,7 +31,8 @@ import com.oracle.truffle.r.runtime.nodes.RNode; /** * This is a simple container class for arguments whose "..." have been unrolled and inserted into - * the original arguments, as it happens in {@link CallArgumentsNode#executeFlatten(Frame)}. + * the original arguments, as it happens in + * {@link CallArgumentsNode#unrollArguments(ArgumentsSignature)}. */ public final class UnrolledVariadicArguments extends Arguments<RNode> implements UnmatchedArguments { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java new file mode 100644 index 0000000000000000000000000000000000000000..2630a51f78a5d5e4a28cf2878fe0a7cdaaa1872c --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.function.call; + +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.Node; +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.UnmatchedArguments; +import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.nodes.RNode; + +/** + * This class provides the infrastructure to reorder the arguments based on R's argument matching + * rules. It implements two different paths: one for arguments provided as an + * {@link CallArgumentsNode}, i.e., unevaluated arguments, and another path for evaluated arguments. + */ +public abstract class PrepareArguments extends Node { + + private static final int CACHE_SIZE = 4; + + public abstract Object[] execute(VirtualFrame frame, RArgsValuesAndNames varArgs, RCallNode call); + + public static PrepareArguments create(RFunction function, CallArgumentsNode args) { + return new UninitializedPrepareArguments(function, args); + } + + public static PrepareArguments createExplicit(RFunction function) { + return new UninitializedExplicitPrepareArguments(function); + } + + private static final class UninitializedPrepareArguments extends PrepareArguments { + + private final RFunction function; + private final CallArgumentsNode sourceArguments; // not used as a node + private int depth = CACHE_SIZE; + + UninitializedPrepareArguments(RFunction function, CallArgumentsNode sourceArguments) { + this.function = function; + this.sourceArguments = sourceArguments; + } + + @Override + public Object[] execute(VirtualFrame frame, RArgsValuesAndNames varArgs, RCallNode call) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + PrepareArguments next; + if (depth-- > 0) { + next = new CachedPrepareArguments(this, function, call, sourceArguments, varArgs == null ? null : varArgs.getSignature()); + } else { + next = new GenericPrepareArguments(function, sourceArguments); + } + return replace(next).execute(frame, varArgs, call); + } + } + + private static final class CachedPrepareArguments extends PrepareArguments { + + @Child private PrepareArguments next; + @Children private final RNode[] matchedArguments; + private final ArgumentsSignature cachedVarArgSignature; + + CachedPrepareArguments(PrepareArguments next, RFunction function, RCallNode call, CallArgumentsNode args, ArgumentsSignature varArgSignature) { + this.next = next; + cachedVarArgSignature = varArgSignature; + matchedArguments = ArgumentMatcher.matchArguments(function, args.unrollArguments(varArgSignature), call, false); + } + + @Override + @ExplodeLoop + public Object[] execute(VirtualFrame frame, RArgsValuesAndNames varArgs, RCallNode call) { + assert (cachedVarArgSignature != null) == (varArgs != null); + if (cachedVarArgSignature == null || cachedVarArgSignature == varArgs.getSignature()) { + Object[] result = new Object[matchedArguments.length]; + for (int i = 0; i < matchedArguments.length; i++) { + result[i] = matchedArguments[i].execute(frame); + } + return result; + } + return next.execute(frame, varArgs, call); + } + } + + private static final class GenericPrepareArguments extends PrepareArguments { + + private final RFunction function; + private final CallArgumentsNode args; // not used as a node + + GenericPrepareArguments(RFunction function, CallArgumentsNode args) { + this.function = function; + this.args = args; + } + + @Override + public Object[] execute(VirtualFrame frame, RArgsValuesAndNames varArgs, RCallNode call) { + CompilerDirectives.transferToInterpreter(); + ArgumentsSignature varArgSignature = varArgs == null ? null : varArgs.getSignature(); + UnmatchedArguments argsValuesAndNames = args.unrollArguments(varArgSignature); + RNode[] matchedArgs = ArgumentMatcher.matchArguments(function, argsValuesAndNames, RError.ROOTNODE, true); + Object[] result = new Object[matchedArgs.length]; + for (int i = 0; i < matchedArgs.length; i++) { + result[i] = matchedArgs[i].execute(frame); + } + return result; + } + } + + private static final class UninitializedExplicitPrepareArguments extends PrepareArguments { + + private final RFunction function; + private int depth = CACHE_SIZE; + + UninitializedExplicitPrepareArguments(RFunction function) { + this.function = function; + } + + @Override + public Object[] execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, RCallNode call) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + PrepareArguments next; + if (depth-- > 0) { + next = new CachedExplicitPrepareArguments(this, function, call, explicitArgs == null ? null : explicitArgs.getSignature()); + } else { + next = new GenericExplicitPrepareArguments(function); + } + return replace(next).execute(frame, explicitArgs, call); + } + } + + 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, RFunction function, RCallNode call, ArgumentsSignature explicitArgSignature) { + this.next = next; + formals = ((RRootNode) function.getTarget().getRootNode()).getFormalArguments(); + permutation = ArgumentMatcher.matchArguments(explicitArgSignature, formals.getSignature(), call, false, function.getRBuiltin()); + cachedExplicitArgSignature = explicitArgSignature; + } + + @Override + public Object[] execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, RCallNode call) { + if (cachedExplicitArgSignature == explicitArgs.getSignature()) { + return ArgumentMatcher.matchArgumentsEvaluated(permutation, explicitArgs.getArguments(), formals); + } + return next.execute(frame, explicitArgs, call); + } + } + + private static final class GenericExplicitPrepareArguments extends PrepareArguments { + + private final RFunction function; + + GenericExplicitPrepareArguments(RFunction function) { + this.function = function; + } + + @Override + public Object[] execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, RCallNode call) { + CompilerDirectives.transferToInterpreter(); + // Function and arguments may change every call: Flatt'n'Match on SlowPath! :-/ + return ArgumentMatcher.matchArgumentsEvaluated(function, explicitArgs, RError.ROOTNODE, false).getArguments(); + } + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/EagerEvalHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/EagerEvalHelper.java index 0fe79bce163b58fcb88c4b303f7c59f484e94fec..2efb72901f8fec7b31d69558a44c0033c25d3b3a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/EagerEvalHelper.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/EagerEvalHelper.java @@ -27,13 +27,15 @@ import com.oracle.truffle.r.nodes.access.ConstantNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.function.ArgumentStatePush; import com.oracle.truffle.r.nodes.function.PromiseNode; -import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.nodes.RNode; -import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxCall; +import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant; +import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; +import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup; /** * Provides small helper function for eager evaluation of arguments for the use in @@ -81,17 +83,17 @@ public class EagerEvalHelper { if (!optConsts()) { return null; } - if (expr instanceof RCallNode) { - RCallNode call = (RCallNode) expr; - if (call.getFunctionNode() instanceof ReadVariableNode) { - String functionName = ((ReadVariableNode) call.getFunctionNode()).getIdentifier(); + if (expr instanceof RSyntaxCall) { + RSyntaxCall call = (RSyntaxCall) expr; + if (call.getSyntaxLHS() instanceof RSyntaxLookup) { + String functionName = ((RSyntaxLookup) call.getSyntaxLHS()).getIdentifier(); switch (functionName) { case "character": - if (call.getArgumentCount() == 0) { + if (call.getSyntaxArguments().length == 0) { return RDataFactory.createEmptyStringVector(); - } else if (call.getArgumentCount() == 1) { - RSyntaxNode argument = call.getArgument(0); - Integer value = ConstantNode.asIntConstant(argument, true); + } else if (call.getSyntaxArguments().length == 1) { + RSyntaxElement argument = call.getSyntaxArguments()[0]; + Integer value = RSyntaxConstant.asIntConstant(argument, true); if (value != null) { RStringVector vector = RDataFactory.createStringVector(value); ArgumentStatePush.transitionStateSlowPath(vector); @@ -101,8 +103,8 @@ public class EagerEvalHelper { break; } } - } else if (expr instanceof ConstantNode) { - return ((ConstantNode) expr).getValue(); + } else if (expr instanceof RSyntaxConstant) { + return ((RSyntaxConstant) expr).getValue(); } return null; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java index cfddfe74097a4c74a8d679bd809e96e0a7ee4181..e956c0faec14e3357cfe3b4e692b7e480a48ac40 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java @@ -484,10 +484,6 @@ public class RPromise implements RTypedValue { public RBaseNode getExpr() { return expr; } - - public Closure deepCopy() { - return new Closure((RBaseNode) expr.deepCopy()); - } } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxConstant.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxConstant.java index 6e8fabfb0db65285a65a4ace262d13d83fc101cb..40a233293549515696f76dcbe0af3ac8c319486c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxConstant.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxConstant.java @@ -53,4 +53,19 @@ public interface RSyntaxConstant extends RSyntaxElement { } }; } + + /** + * Helper function: extract an integer constant from an RSyntaxElement. + */ + static Integer asIntConstant(RSyntaxElement argument, boolean castFromDouble) { + if (argument instanceof RSyntaxConstant) { + Object value = ((RSyntaxConstant) argument).getValue(); + if (value instanceof Integer) { + return (int) value; + } else if (castFromDouble && value instanceof Double) { + return (int) (double) value; + } + } + return null; + } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index f69abc670f5a0ebde1f1721f5e483718c466ef67..122d0bf014cc61f7da2d7319a96d271020482015 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -52945,6 +52945,10 @@ Error in setwd(1) : character argument expected #{ setwd(character()) } Error in setwd(character()) : character argument expected +##com.oracle.truffle.r.test.functions.TestFunctions.testArgEvaluationOrder +#v <- 1; class(v) <- 'foo'; `-.foo` <- function(x,y,...) { cat('[-.foo]'); 1234 }; g <- function(...) { cat('[ing]'); ({cat('[-]'); `-`})(...) }; ({cat('[g]'); g})({cat('[x]'); v},{cat('[y]'); 3},{cat('[z]'); 5}) +[g][ing][-][x][y][z][-.foo][1] 1234 + ##com.oracle.truffle.r.test.functions.TestFunctions.testArgs #{ f<-function(x, row.names = NULL, optional = FALSE, ...) {print(optional); for (i in list(...)) {print(i)} }; f(c(7,42), row.names=NULL, nm="x") } [1] FALSE @@ -53255,6 +53259,10 @@ a ##com.oracle.truffle.r.test.functions.TestFunctions.testDots #f2 <- function(...) { f <- function() cat(...); f() }; f2() +##com.oracle.truffle.r.test.functions.TestFunctions.testDots +#{ `-.foo` <- function(...) 123; v <- 1; class(v) <- 'foo'; sapply(1,`-`,v); sapply(v,`-`,1); sapply(v,`-`,v) } +[1] 123 + ##com.oracle.truffle.r.test.functions.TestFunctions.testDots #{ asdf <- function(x,...) UseMethod("asdf",x); asdf.numeric <- function(x, ...) print(paste("num:", x, ...)); asdf(1) } [1] "num: 1" diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java index f5e7184962b27130766598232c77023bef39f779..5d0a4c7bf52c1e6c7748fb3f5a8a7ad7d5b0d177 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java @@ -217,6 +217,11 @@ public class TestFunctions extends TestBase { "e2 <- new.env(); e2n <- new.env(); assign(\"b\", \"isb\", e2n); assign(\"ex\", e2n, e2); ex1 <- c(\"a\"); ex2 <- c(\"b\"); f(e1, ex1); f(e2, ex2) == \"isb\""); } + @Test + public void testArgEvaluationOrder() { + assertEval("v <- 1; class(v) <- 'foo'; `-.foo` <- function(x,y,...) { cat('[-.foo]'); 1234 }; g <- function(...) { cat('[ing]'); ({cat('[-]'); `-`})(...) }; ({cat('[g]'); g})({cat('[x]'); v},{cat('[y]'); 3},{cat('[z]'); 5})"); + } + @Test public void testMatching() { assertEval("{ x<-function(foo,bar){foo*bar} ; x(f=10,2) }"); @@ -311,7 +316,7 @@ public class TestFunctions extends TestBase { assertEval("f2 <- function(...) { f <- function() cat(...); f() }; f2()"); assertEval("f2 <- function(...) { f <- function() cat(...); environment(f) <- globalenv(); f() }; f2()"); assertEval("f2 <- function(...) { f <- function() cat(...); f() }; f2(\"a\")"); - assertEval("f2 <- function(...) { f <- function() cat(...); assign(\"...\", NULL); f() }; f2(\"a\")"); + assertEval(Ignored.ImplementationError, "f2 <- function(...) { f <- function() cat(...); assign(\"...\", NULL); f() }; f2(\"a\")"); assertEval("f2 <- function(...) { f <- function() cat(...); assign(\"...\", \"asdf\"); f() }; f2(\"a\")"); assertEval("{ g <- function(a,b,x) { a + b * x } ; f <- function(...) { g(x=4, ..., 10) } ; f(b=1,a=2) }"); @@ -319,6 +324,8 @@ public class TestFunctions extends TestBase { assertEval("{ f <- function(a, barg, bextra, dummy) { a + barg } ; g <- function(...) { f(a=1, ..., xxx=2) } ; g(1) }"); assertEval("{ f <- function(a, barg, bextra, dummy) { a + barg } ; g <- function(...) { f(a=1, xxx=2, ...) } ; g(1) }"); + assertEval("{ `-.foo` <- function(...) 123; v <- 1; class(v) <- 'foo'; sapply(1,`-`,v); sapply(v,`-`,1); sapply(v,`-`,v) }"); + assertEval(Ignored.Unknown, "{ f <- function(...) { substitute(..1) } ; f(x+y) }"); assertEval(Ignored.Unknown, Output.ContainsError, "{ lapply(1:3, \"dummy\") }"); diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index db81248acc0e31a90b87084e44548dadc924e74a..39bdc1aaa7c197218691ebd726a6882c5860232d 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -171,7 +171,6 @@ com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode. com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java,gnu_r_gentleman_ihaka.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java,purdue.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java,purdue.copyright -com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java,purdue.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java,purdue.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodInternalNode.java,purdue.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java,gnu_r_gentleman_ihaka.copyright