From cd0b46063a1f96037a743e95e679a9620d4dce82 Mon Sep 17 00:00:00 2001 From: Lukas Stadler <lukas.stadler@oracle.com> Date: Mon, 26 Sep 2016 15:19:33 +0200 Subject: [PATCH] add "special" hooks for frequently used primitive functions --- .../r/nodes/builtin/RBuiltinPackage.java | 6 +- .../r/nodes/builtin/base/BasePackage.java | 3 +- .../r/nodes/builtin/base/InfixFunctions.java | 59 +++++ .../oracle/truffle/r/nodes/RASTBuilder.java | 3 +- .../r/nodes/builtin/RBuiltinFactory.java | 4 +- .../truffle/r/nodes/function/RCallNode.java | 39 +++- .../r/nodes/function/RCallSpecialNode.java | 209 ++++++++++++++++++ .../runtime/builtins/RBuiltinDescriptor.java | 11 +- 8 files changed, 321 insertions(+), 13 deletions(-) create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java index 874e70cffb..25bc201bae 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java @@ -156,12 +156,16 @@ public abstract class RBuiltinPackage { } protected void add(Class<?> builtinClass, Function<RNode[], RBuiltinNode> constructor) { + add(builtinClass, constructor, null); + } + + protected void add(Class<?> builtinClass, Function<RNode[], RBuiltinNode> constructor, Function<RNode[], RNode> specialCall) { RBuiltin annotation = builtinClass.getAnnotation(RBuiltin.class); String[] parameterNames = annotation.parameterNames(); parameterNames = Arrays.stream(parameterNames).map(n -> n.isEmpty() ? null : n).toArray(String[]::new); ArgumentsSignature signature = ArgumentsSignature.get(parameterNames); putBuiltin(new RBuiltinFactory(annotation.name(), builtinClass, annotation.visibility(), annotation.aliases(), annotation.kind(), signature, annotation.nonEvalArgs(), annotation.splitCaller(), - annotation.alwaysSplit(), annotation.dispatch(), constructor, annotation.behavior())); + annotation.alwaysSplit(), annotation.dispatch(), constructor, annotation.behavior(), specialCall)); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 13fcd60a65..32661bc40b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -33,6 +33,7 @@ import com.oracle.truffle.r.nodes.binary.BinaryBooleanScalarNodeGen; import com.oracle.truffle.r.nodes.binary.ColonNode; import com.oracle.truffle.r.nodes.binary.ColonNodeGen; import com.oracle.truffle.r.nodes.builtin.RBuiltinPackage; +import com.oracle.truffle.r.nodes.builtin.base.InfixFunctions.AccessArraySubscriptSpecialBuiltin; import com.oracle.truffle.r.nodes.builtin.base.fastpaths.AssignFastPathNodeGen; import com.oracle.truffle.r.nodes.builtin.base.fastpaths.ExistsFastPathNodeGen; import com.oracle.truffle.r.nodes.builtin.base.fastpaths.GetFastPathNodeGen; @@ -386,7 +387,7 @@ public class BasePackage extends RBuiltinPackage { add(IConv.class, IConvNodeGen::create); add(Identical.class, Identical::create); add(NumericalFunctions.Im.class, NumericalFunctionsFactory.ImNodeGen::create); - add(InfixFunctions.AccessArraySubscriptBuiltin.class, InfixFunctionsFactory.AccessArraySubscriptBuiltinNodeGen::create); + add(InfixFunctions.AccessArraySubscriptBuiltin.class, InfixFunctionsFactory.AccessArraySubscriptBuiltinNodeGen::create, AccessArraySubscriptSpecialBuiltin::create); add(InfixFunctions.AccessArraySubscriptDefaultBuiltin.class, InfixFunctionsFactory.AccessArraySubscriptBuiltinNodeGen::create); add(InfixFunctions.AccessArraySubsetBuiltin.class, InfixFunctionsFactory.AccessArraySubsetBuiltinNodeGen::create); add(InfixFunctions.AccessArraySubsetDefaultBuiltin.class, InfixFunctionsFactory.AccessArraySubsetBuiltinNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InfixFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InfixFunctions.java index a22697f278..c067d06eb4 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InfixFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InfixFunctions.java @@ -45,9 +45,13 @@ import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode; import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.base.InfixFunctionsFactory.AccessArraySubscriptSpecialBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.base.InfixFunctionsFactory.PromiseEvaluatorNodeGen; +import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; +import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.RCallNode; +import com.oracle.truffle.r.nodes.function.RCallSpecialNode; import com.oracle.truffle.r.nodes.unary.CastListNode; import com.oracle.truffle.r.nodes.unary.CastListNodeGen; import com.oracle.truffle.r.runtime.RDeparse; @@ -66,6 +70,8 @@ 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.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; @@ -182,6 +188,59 @@ public class InfixFunctions { } + @NodeChild(value = "arguments", type = RNode[].class) + public abstract static class AccessArraySubscriptSpecialBuiltin extends RNode { + + @Child private ClassHierarchyNode classHierarchy = ClassHierarchyNodeGen.create(false, false); + + public static RNode create(RNode[] arguments) { + return arguments.length == 2 ? AccessArraySubscriptSpecialBuiltinNodeGen.create(arguments) : null; + } + + protected boolean simpleVector(RAbstractVector vector) { + return classHierarchy.execute(vector) == null; + } + + protected static boolean inIntRange(RAbstractVector vector, int index) { + return index >= 1 && index <= vector.getLength(); + } + + protected static boolean inDoubleRange(RAbstractVector vector, double index) { + return index >= 1 && index <= vector.getLength(); + } + + private static int toInt(double index) { + int i = (int) index; + return i == 0 ? 1 : i - 1; + } + + @Specialization(guards = {"simpleVector(vector)", "inIntRange(vector, index)"}) + protected static int access(RAbstractIntVector vector, int index) { + return vector.getDataAt(index - 1); + } + + @Specialization(guards = {"simpleVector(vector)", "inIntRange(vector, index)"}) + protected static double access(RAbstractDoubleVector vector, int index) { + return vector.getDataAt(index - 1); + } + + @Specialization(guards = {"simpleVector(vector)", "inDoubleRange(vector, index)"}) + protected static int access(RAbstractIntVector vector, double index) { + return vector.getDataAt(toInt(index)); + } + + @Specialization(guards = {"simpleVector(vector)", "inDoubleRange(vector, index)"}) + protected static double access(RAbstractDoubleVector vector, double index) { + return vector.getDataAt(toInt(index)); + } + + @SuppressWarnings("unused") + @Fallback + protected static Object access(Object vector, Object index) { + throw RCallSpecialNode.fullCallNeeded(); + } + } + @RBuiltin(name = "[[", kind = PRIMITIVE, parameterNames = {"", "...", "exact", "drop"}, dispatch = INTERNAL_GENERIC, behavior = PURE) public abstract static class AccessArraySubscriptBuiltin extends AccessArrayBuiltin { 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 7cc0b1120e..09a98a59ec 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 @@ -47,6 +47,7 @@ import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; import com.oracle.truffle.r.nodes.function.PostProcessArgumentsNode; import com.oracle.truffle.r.nodes.function.RCallNode; +import com.oracle.truffle.r.nodes.function.RCallSpecialNode; import com.oracle.truffle.r.nodes.function.SaveArgumentsNode; import com.oracle.truffle.r.nodes.function.WrapDefaultArgumentNode; import com.oracle.truffle.r.nodes.unary.GetNonSharedNodeGen; @@ -145,7 +146,7 @@ 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); - return RCallNode.createCall(source, lhs.asRNode(), signature, nodes); + return RCallSpecialNode.createCall(source, lhs.asRNode(), signature, nodes); } private RSyntaxNode createReplacement(SourceSection source, String operator, boolean isSuper, RSyntaxNode replacementLhs, RSyntaxNode replacementRhs) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinFactory.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinFactory.java index 2b0cce3072..399eb5a38b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinFactory.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinFactory.java @@ -38,8 +38,8 @@ public final class RBuiltinFactory extends RBuiltinDescriptor { private final Function<RNode[], RBuiltinNode> constructor; RBuiltinFactory(String name, Class<?> builtinNodeClass, RVisibility visibility, String[] aliases, RBuiltinKind kind, ArgumentsSignature signature, int[] nonEvalArgs, boolean splitCaller, - boolean alwaysSplit, RDispatch dispatch, Function<RNode[], RBuiltinNode> constructor, RBehavior behavior) { - super(name, builtinNodeClass, visibility, aliases, kind, signature, nonEvalArgs, splitCaller, alwaysSplit, dispatch, behavior); + boolean alwaysSplit, RDispatch dispatch, Function<RNode[], RBuiltinNode> constructor, RBehavior behavior, Function<RNode[], RNode> specialCall) { + super(name, builtinNodeClass, visibility, aliases, kind, signature, nonEvalArgs, splitCaller, alwaysSplit, dispatch, behavior, specialCall); this.constructor = constructor; } 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 52c81b0097..07816e35c6 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 @@ -67,6 +67,7 @@ import com.oracle.truffle.r.nodes.function.call.CallRFunctionNode; import com.oracle.truffle.r.nodes.function.call.PrepareArguments; import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; +import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; @@ -615,9 +616,13 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS @Override public void serializeImpl(RSerialize.State state) { + serializeImpl(state, getFunctionNode(), arguments, signature); + } + + public static void serializeImpl(RSerialize.State state, RNode functionNode, RSyntaxNode[] arguments, ArgumentsSignature signature) { state.setAsLangType(); - state.serializeNodeSetCar(getFunctionNode()); - if (isColon(getFunctionNode())) { + state.serializeNodeSetCar(functionNode); + if (isColon(functionNode)) { // special case, have to translate Identifier names to Symbols RSyntaxNode arg0 = arguments[0]; RSyntaxNode arg1 = arguments[1]; @@ -636,7 +641,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS state.linkPairList(2); state.setCdr(state.closePairList()); } else { - RSyntaxNode f = getFunctionNode().asRSyntaxNode(); + RSyntaxNode f = functionNode.asRSyntaxNode(); boolean infixFieldAccess = false; if (f instanceof RSyntaxLookup) { RSyntaxLookup lookup = (RSyntaxLookup) f; @@ -1014,13 +1019,33 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS return result; } + private final VectorLengthProfile varArgProfile = VectorLengthProfile.create(); + private void forcePromises(VirtualFrame frame, RArgsValuesAndNames varArgs) { + if (varArgsPromiseHelper == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + varArgsPromiseHelper = insert(new PromiseCheckHelperNode()); + } + varArgProfile.profile(varArgs.getLength()); + int cachedLength = varArgProfile.getCachedLength(); + if (cachedLength >= 0) { + forcePromisesUnrolled(frame, varArgs, cachedLength); + } else { + forcePromisesDynamic(frame, varArgs); + } + } + + @ExplodeLoop + private void forcePromisesUnrolled(VirtualFrame frame, RArgsValuesAndNames varArgs, int length) { + Object[] array = varArgs.getArguments(); + for (int i = 0; i < length; i++) { + array[i] = varArgsPromiseHelper.checkEvaluate(frame, array[i]); + } + } + + private void forcePromisesDynamic(VirtualFrame frame, RArgsValuesAndNames varArgs) { Object[] array = varArgs.getArguments(); for (int i = 0; i < array.length; i++) { - if (varArgsPromiseHelper == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - varArgsPromiseHelper = insert(new PromiseCheckHelperNode()); - } array[i] = varArgsPromiseHelper.checkEvaluate(frame, array[i]); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java new file mode 100644 index 0000000000..7ac75d8171 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java @@ -0,0 +1,209 @@ +/* + * 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; + +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.profiles.ConditionProfile; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode; +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.RSerialize.State; +import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RPromise; +import com.oracle.truffle.r.runtime.nodes.RNode; +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; + +final class PeekLocalVariableNode extends RNode { + + @Child private LocalReadVariableNode read; + + private final ConditionProfile isPromiseProfile = ConditionProfile.createBinaryProfile(); + + PeekLocalVariableNode(String name) { + this.read = LocalReadVariableNode.create(name, false); + } + + @Override + public Object execute(VirtualFrame frame) { + Object value = read.execute(frame); + if (value == null) { + throw RCallSpecialNode.fullCallNeeded(); + } + if (isPromiseProfile.profile(value instanceof RPromise)) { + RPromise promise = (RPromise) value; + if (!promise.isEvaluated()) { + throw RCallSpecialNode.fullCallNeeded(); + } + return promise.getValue(); + } + return value; + } +} + +public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode, RSyntaxCall { + + public static final RuntimeException FULL_CALL_NEEDED = new FullCallNeededException(); + + // currently cannot be RSourceSectionNode because of TruffleDSL restrictions + + @CompilationFinal private SourceSection sourceSectionR; + + @Override + public void setSourceSection(SourceSection sourceSection) { + assert sourceSection != null; + this.sourceSectionR = sourceSection; + } + + @Override + public SourceSection getSourceSection() { + return sourceSectionR; + } + + @SuppressWarnings("serial") + private static class FullCallNeededException extends RuntimeException { + @Override + public synchronized Throwable fillInStackTrace() { + return null; + } + } + + public static RuntimeException fullCallNeeded() { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw FULL_CALL_NEEDED; + } + + @Child private ForcePromiseNode functionNode; + @Child private RNode special; + + private final RSyntaxNode[] arguments; + private final ArgumentsSignature signature; + private final RFunction expectedFunction; + + private RCallSpecialNode(SourceSection sourceSection, RNode functionNode, RFunction expectedFunction, RSyntaxNode[] arguments, ArgumentsSignature signature, RNode special) { + this.sourceSectionR = sourceSection; + this.expectedFunction = expectedFunction; + this.special = special; + this.functionNode = new ForcePromiseNode(functionNode); + this.arguments = arguments; + this.signature = signature; + } + + public static RSyntaxNode createCall(SourceSection sourceSection, RNode functionNode, ArgumentsSignature signature, RSyntaxNode[] arguments) { + RCallSpecialNode special = tryCreate(sourceSection, functionNode, signature, arguments); + if (special != null) { + if (sourceSection == RSyntaxNode.EAGER_DEPARSE) { + RDeparse.ensureSourceSection(special); + } + return special; + } else { + return RCallNode.createCall(sourceSection, functionNode, signature, arguments); + } + } + + private static RCallSpecialNode tryCreate(SourceSection sourceSection, RNode functionNode, ArgumentsSignature signature, RSyntaxNode[] arguments) { + if (signature.getNonNullCount() > 0) { + // complex signature -> bail out + return null; + } + RSyntaxNode syntaxFunction = functionNode.asRSyntaxNode(); + if (!(syntaxFunction instanceof RSyntaxLookup)) { + // LHS is not a simple lookup -> bail out + return null; + } + for (RSyntaxNode argument : arguments) { + if (!(argument instanceof RSyntaxLookup)) { + // argument is not a simple lookup -> bail out + return null; + } + } + String name = ((RSyntaxLookup) syntaxFunction).getIdentifier(); + RBuiltinDescriptor builtinDescriptor = RContext.lookupBuiltinDescriptor(name); + if (builtinDescriptor == null || builtinDescriptor.getSpecialCall() == null) { + // no builtin or no special call definition -> bail out + return null; + } + RNode[] localArguments = new RNode[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + localArguments[i] = new PeekLocalVariableNode(((RSyntaxLookup) arguments[i]).getIdentifier()); + } + RNode special = builtinDescriptor.getSpecialCall().apply(localArguments); + if (special == null) { + // the factory refused to create a special call -> bail out + return null; + } + RFunction expectedFunction = RContext.lookupBuiltin(name); + RInternalError.guarantee(expectedFunction != null); + + return new RCallSpecialNode(sourceSection, functionNode, expectedFunction, arguments, signature, special); + } + + @Override + public Object execute(VirtualFrame frame, Object function) { + try { + if (function != expectedFunction) { + // the actual function differs from the expected function + throw RCallSpecialNode.fullCallNeeded(); + } + return special.execute(frame); + } catch (FullCallNeededException e) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + RCallNode call = RCallNode.createCall(sourceSectionR, functionNode == null ? null : functionNode.getValueNode(), signature, arguments); + return replace(call).execute(frame, function); + } + } + + @Override + public Object execute(VirtualFrame frame) { + return execute(frame, functionNode.execute(frame)); + } + + @Override + public void serializeImpl(State state) { + RCallNode.serializeImpl(state, functionNode.getValueNode(), arguments, signature); + } + + @Override + public RSyntaxElement getSyntaxLHS() { + ForcePromiseNode func = functionNode; + return func == null || func.getValueNode() == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : func.getValueNode().asRSyntaxNode(); + } + + @Override + public ArgumentsSignature getSyntaxSignature() { + return signature == null ? ArgumentsSignature.empty(1) : signature; + } + + @Override + public RSyntaxElement[] getSyntaxArguments() { + return arguments == null ? new RSyntaxElement[]{RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "...", false)} : arguments; + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/builtins/RBuiltinDescriptor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/builtins/RBuiltinDescriptor.java index 9581723641..c48d1283be 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/builtins/RBuiltinDescriptor.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/builtins/RBuiltinDescriptor.java @@ -23,12 +23,15 @@ package com.oracle.truffle.r.runtime.builtins; import java.util.Arrays; +import java.util.function.Function; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.PrimitiveMethodsInfo; import com.oracle.truffle.r.runtime.RDispatch; import com.oracle.truffle.r.runtime.RVisibility; +import com.oracle.truffle.r.runtime.nodes.RNode; public abstract class RBuiltinDescriptor { @@ -45,12 +48,14 @@ public abstract class RBuiltinDescriptor { private final boolean alwaysSplit; private final RDispatch dispatch; private final RBehavior behavior; + private final Function<RNode[], RNode> specialCall; private final int primitiveMethodIndex; @CompilationFinal private final boolean[] evaluatesArgument; public RBuiltinDescriptor(String name, Class<?> builtinNodeClass, RVisibility visibility, String[] aliases, RBuiltinKind kind, ArgumentsSignature signature, int[] nonEvalArgs, boolean splitCaller, - boolean alwaysSplit, RDispatch dispatch, RBehavior behavior) { + boolean alwaysSplit, RDispatch dispatch, RBehavior behavior, Function<RNode[], RNode> specialCall) { + this.specialCall = specialCall; this.name = name.intern(); this.builtinNodeClass = builtinNodeClass; this.visibility = visibility; @@ -131,4 +136,8 @@ public abstract class RBuiltinDescriptor { public RBehavior getBehavior() { return behavior; } + + public Function<RNode[], RNode> getSpecialCall() { + return specialCall; + } } -- GitLab