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 6837ec9a35d7193ad1bb68ade5755c93c88eee71..6c2f34cee14ff03ff4c37888c6de0e286e6b0296 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 @@ -97,7 +97,6 @@ import com.oracle.truffle.r.runtime.data.RLanguage; 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; import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; @@ -436,7 +435,7 @@ final class REngine implements Engine, Engine.Timings { @Override @TruffleBoundary - public Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, RStringVector names, Object... args) { + public Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, boolean evalPromises, ArgumentsSignature names, Object... args) { assert frame == null || caller != null; MaterializedFrame actualFrame = frame; if (actualFrame == null) { @@ -449,15 +448,17 @@ final class REngine implements Engine, Engine.Timings { } } RArgsValuesAndNames reorderedArgs = CallMatcherGenericNode.reorderArguments(args, func, - names == null ? ArgumentsSignature.empty(args.length) : ArgumentsSignature.get(names.getDataWithoutCopying()), RError.NO_CALLER); + names == null ? ArgumentsSignature.empty(args.length) : names, RError.NO_CALLER); Object[] newArgs = reorderedArgs.getArguments(); - for (int i = 0; i < newArgs.length; i++) { - Object arg = newArgs[i]; - if (arg instanceof RPromise) { - newArgs[i] = PromiseHelperNode.evaluateSlowPath(null, (RPromise) arg); + if (evalPromises) { + for (int i = 0; i < newArgs.length; i++) { + Object arg = newArgs[i]; + if (arg instanceof RPromise) { + newArgs[i] = PromiseHelperNode.evaluateSlowPath(null, (RPromise) arg); + } } } - return CallRFunctionNode.executeSlowpath(func, caller == null ? RArguments.getCall(actualFrame) : caller, actualFrame, newArgs, null); + return CallRFunctionNode.executeSlowpath(func, caller == null ? RArguments.getCall(actualFrame) : caller, actualFrame, newArgs, reorderedArgs.getSignature(), null); } private Object evalNode(RSyntaxElement exprRep, REnvironment envir, RCaller caller) { 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 7c242944350bfebdceda6e44619e119485e7d8c3..454eafb417159396083e0e72333299f393f513ff 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 @@ -367,7 +367,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { public Object callback(RFunction f, Object[] args) { boolean gd = RContext.getInstance().stateInstrumentation.setDebugGloballyDisabled(true); try { - return RContext.getEngine().evalFunction(f, null, null, null, args); + return RContext.getEngine().evalFunction(f, null, null, true, null, args); } catch (ReturnException ex) { // cannot throw return exceptions further up. return ex.getResult(); diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java index eaeeb329ea451ca404e91fe0c99f69592298e2e8..3d2a62fd7f04978fd81d4a64892f495e9a2200ce 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java @@ -99,7 +99,7 @@ public class JLineConsoleCompleter implements Completer { env.safePut("token", buffer.substring(start, cursor)); MaterializedFrame callingFrame = REnvironment.globalEnv().getFrame(); - RContext.getEngine().evalFunction(completeToken, callingFrame, RCaller.createInvalid(callingFrame), null, new Object[]{}); + RContext.getEngine().evalFunction(completeToken, callingFrame, RCaller.createInvalid(callingFrame), true, null, new Object[]{}); o = env.get("comps"); if (!(o instanceof RAbstractStringVector)) { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java index a2c92c4c538b61773a56f0198121a8525c4b4606..efd87be667163e281801070eb5c2804b37d73378 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java @@ -129,7 +129,7 @@ public final class GridContext { internalCode = RInternalCode.lookup(RContext.getInstance(), "grid", RInternalCode.loadSourceRelativeTo(LInitGrid.class, "fastrGrid.R")); } RFunction redrawAll = internalCode.lookupFunction(functionName); - return RContext.getEngine().evalFunction(redrawAll, REnvironment.baseEnv().getFrame(), RCaller.topLevel, null, args); + return RContext.getEngine().evalFunction(redrawAll, REnvironment.baseEnv().getFrame(), RCaller.topLevel, true, null, args); } private static final class DeviceAndState { 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 ec10b5b52c2799325428a28f97b2791f025321dd..ce6d340ec5cb2eb59e18ed0f4ad03e5748e25fc2 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 @@ -28,25 +28,43 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean; import static com.oracle.truffle.r.runtime.RVisibility.CUSTOM; import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; +import java.util.Arrays; + +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.FrameSlotKind; +import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; 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.access.ConstantNode; +import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.base.DoCallNodeGen.DoCallInternalNodeGen; import com.oracle.truffle.r.nodes.builtin.base.GetFunctions.Get; import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen; -import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode; +import com.oracle.truffle.r.nodes.function.RCallerHelper; import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode; +import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RArguments; +import com.oracle.truffle.r.runtime.RCaller; +import com.oracle.truffle.r.runtime.RDispatch; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor; import com.oracle.truffle.r.runtime.builtins.RBuiltinKind; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; @@ -58,24 +76,18 @@ import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RPromise.Closure; import com.oracle.truffle.r.runtime.data.RPromise.PromiseState; -import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; +import com.oracle.truffle.r.runtime.env.frame.RFrameSlot; import com.oracle.truffle.r.runtime.nodes.InternalRSyntaxNodeChildren; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; @RBuiltin(name = ".fastr.do.call", visibility = CUSTOM, kind = RBuiltinKind.INTERNAL, parameterNames = {"what", "args", "quote", "envir"}, behavior = COMPLEX) public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSyntaxNodeChildren { - @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); - - private final BranchProfile containsRLanguageProfile = BranchProfile.create(); - private final BranchProfile containsRSymbolProfile = BranchProfile.create(); - - @Child private RExplicitCallNode call = RExplicitCallNode.create(); - static { Casts casts = new Casts(DoCall.class); casts.arg("what").defaultError(Message.MUST_BE_STRING_OR_FUNCTION, "what").mustBe(instanceOf(RFunction.class).or(stringValue())); @@ -88,72 +100,180 @@ public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSynta return GetNodeGen.create(); } + // Note: quote tells us if symbols in args list should be interpreted as symbols (quote=TRUE) or + // they should be interpreted as read of given symbol from the given environment. + @Specialization protected Object doCall(VirtualFrame frame, RAbstractStringVector what, RList argsAsList, boolean quote, REnvironment env, + @Cached("create()") DoCallInternal internal, @Cached("createGet()") Get getNode) { if (what.getLength() != 1) { throw error(RError.Message.MUST_BE_STRING_OR_FUNCTION, "what"); } + // Note: if the function is in fact a promise, we are evaluating it here slightly earlier + // than GNU R. It should not a be a problem. RFunction func = (RFunction) getNode.execute(frame, what.getDataAt(0), env, RType.Function.getName(), true); - return doCall(frame, func, argsAsList, quote, env); + return doCall(frame, func, argsAsList, quote, env, internal); } @Specialization - protected Object doCall(VirtualFrame frame, RFunction func, RList argsAsList, boolean quote, REnvironment env) { - /* - * To re-create the illusion of a normal call, turn the values in argsAsList into promises. + protected Object doCall(VirtualFrame virtualFrame, RFunction func, RList argsAsList, boolean quote, REnvironment env, + @Cached("create()") DoCallInternal internal) { + return internal.execute(virtualFrame, func, argsAsList, quote, env); + } + + protected abstract static class DoCallInternal extends Node { + @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); + @Child private SetVisibilityNode setVisibilityNode = SetVisibilityNode.create(); + + public static DoCallInternal create() { + return DoCallInternalNodeGen.create(); + } + + public abstract Object execute(VirtualFrame virtualFrame, RFunction func, RList argsAsList, boolean quote, REnvironment env); + + protected final ArgumentsSignature getArgsNames(RList argsAsList) { + ArgumentsSignature signature = ArgumentsSignature.fromNamesAttribute(getNamesNode.getNames(argsAsList)); + return signature == null ? ArgumentsSignature.empty(argsAsList.getLength()) : signature; + } + + /** + * Fast version that works only for simple cases. It does not explicitly create the AST and + * evaluate it, but instead it directly implements what the execution of such AST would do. */ - Object[] argValues = argsAsList.getDataCopy(); - RStringVector n = getNamesNode.getNames(argsAsList); - ArgumentsSignature signature; - if (n == null) { - signature = ArgumentsSignature.empty(argValues.length); - } else { - String[] argNames = new String[argValues.length]; + @Specialization(guards = "isSimple(func, argsAsList)") + public Object doSimple(VirtualFrame virtualFrame, RFunction func, RList argsAsList, boolean quote, REnvironment env, + @Cached("create()") ShareObjectNode shareObjectNode, + @Cached("createBinaryProfile()") ConditionProfile quoteProfile, + @Cached("create()") BranchProfile containsRSymbolProfile, + @Cached("createClassProfile()") ValueProfile frameAccessProfile) { + Object[] argValuesData = argsAsList.getDataWithoutCopying(); + Object[] argValues = argValuesData; + MaterializedFrame envFrame = env.getFrame(frameAccessProfile).materialize(); + if (quoteProfile.profile(!quote)) { + argValues = Arrays.copyOf(argValuesData, argValuesData.length); + for (int i = 0; i < argValues.length; i++) { + Object arg = argValues[i]; + if (arg instanceof RSymbol) { + containsRSymbolProfile.enter(); + RSymbol symbol = (RSymbol) arg; + if (symbol.getName().isEmpty()) { + argValues[i] = REmpty.instance; + } else { + argValues[i] = createLookupPromise(envFrame, symbol); + } + } + } + } for (int i = 0; i < argValues.length; i++) { - String name = n.getDataAt(i); - argNames[i] = name == null ? null : name.isEmpty() ? null : name; + shareObjectNode.execute(argValues[i]); + } + ArgumentsSignature signature = getArgsNames(argsAsList); + RCaller caller = RCaller.create(virtualFrame, RCallerHelper.createFromArguments(func, new RArgsValuesAndNames(argValues, signature))); + try { + Object resultValue = RContext.getEngine().evalFunction(func, envFrame, caller, false, signature, argValues); + setVisibilityNode.execute(virtualFrame, getVisibility(envFrame)); + return resultValue; + } finally { + for (int i = 0; i < argValues.length; i++) { + ShareObjectNode.unshare(argValues[i]); + } } - signature = ArgumentsSignature.get(argNames); } - if (!quote) { + + protected static boolean isSimple(RFunction function, RList args) { + RBuiltinDescriptor builtin = function.getRBuiltin(); + if (builtin != null && builtin.getDispatch() != RDispatch.DEFAULT) { + CompilerDirectives.transferToInterpreter(); + return false; + } + for (int i = 0; i < args.getLength(); i++) { + if (args.getDataAt(i) instanceof RLanguage) { + CompilerDirectives.transferToInterpreter(); + // Note: language is tricky because of formulae, which are language that is + // really not meant to be evaluated again in a different frame than the one were + // the were evaluated for the first time. The solution should be to clone the + // language's rep and get its nodes in uninitilized state, but that does not + // work for some reason. + return false; + } + } + return true; + } + + @TruffleBoundary + private static RPromise createLookupPromise(MaterializedFrame callerFrame, RSymbol symbol) { + Closure closure = RPromise.Closure.create(RContext.getASTBuilder().lookup(RSyntaxNode.SOURCE_UNAVAILABLE, symbol.getName(), false).asRNode()); + return RDataFactory.createPromise(PromiseState.Supplied, closure, callerFrame); + } + + @TruffleBoundary + private boolean getVisibility(MaterializedFrame envFrame) { + FrameSlot envVisibilitySlot = FrameSlotChangeMonitor.findOrAddFrameSlot(envFrame.getFrameDescriptor(), RFrameSlot.Visibility, FrameSlotKind.Boolean); + if (envVisibilitySlot != null) { + try { + return envFrame.getBoolean(envVisibilitySlot); + } catch (FrameSlotTypeException e) { + throw RInternalError.shouldNotReachHere(); + } + } + return false; + } + + @Specialization(guards = "!isSimple(func, argsAsList)") + public Object doGeneric(VirtualFrame virtualFrame, RFunction func, RList argsAsList, boolean quote, REnvironment env) { + CallResult result = doCallGeneric(func, argsAsList.getDataWithoutCopying(), getArgsNames(argsAsList), quote, RArguments.getCall(virtualFrame), env); + setVisibilityNode.execute(virtualFrame, result.visibility); + return result.value; + } + + @TruffleBoundary + private CallResult doCallGeneric(RFunction function, Object[] argValues, ArgumentsSignature argsSignature, boolean quote, RCaller call, REnvironment env) { + RSyntaxNode[] argsConstants = new RSyntaxNode[argValues.length]; for (int i = 0; i < argValues.length; i++) { - Object arg = argValues[i]; - if (arg instanceof RLanguage) { - containsRLanguageProfile.enter(); - RLanguage lang = (RLanguage) arg; - argValues[i] = createRLanguagePromise(env.getFrame().materialize(), lang); - } else if (arg instanceof RSymbol) { - containsRSymbolProfile.enter(); - RSymbol symbol = (RSymbol) arg; - if (symbol.getName().isEmpty()) { - argValues[i] = REmpty.instance; + if (!quote && argValues[i] instanceof RLanguage) { + argsConstants[i] = ((RLanguage) argValues[i]).getRep().asRSyntaxNode(); + } else if (!quote && argValues[i] instanceof RSymbol) { + RSymbol symbol = (RSymbol) argValues[i]; + if (symbol.isMissing()) { + argsConstants[i] = ConstantNode.create(REmpty.instance); } else { - argValues[i] = createLookupPromise(env.getFrame().materialize(), symbol); + argsConstants[i] = ReadVariableNode.create(((RSymbol) argValues[i]).getName()); } + } else { + argsConstants[i] = ConstantNode.create(argValues[i]); } } - } - for (int i = 0; i < argValues.length; i++) { - ShareObjectNode.share(argValues[i]); - } - try { - return call.execute(frame, func, new RArgsValuesAndNames(argValues, signature)); - } finally { for (int i = 0; i < argValues.length; i++) { - ShareObjectNode.unshare(argValues[i]); + ShareObjectNode.share(argValues[i]); + } + RLanguage lang = RDataFactory.createLanguage(RASTUtils.createCall(ConstantNode.create(function), true, argsSignature, argsConstants).asRNode()); + try { + Object resultValue = RContext.getEngine().eval(lang, env, call); + MaterializedFrame envFrame = env.getFrame(); + FrameSlot envVisibilitySlot = FrameSlotChangeMonitor.findOrAddFrameSlot(envFrame.getFrameDescriptor(), RFrameSlot.Visibility, FrameSlotKind.Boolean); + boolean resultVisibility = false; + if (envVisibilitySlot != null) { + resultVisibility = envFrame.getBoolean(envVisibilitySlot); + } + return new CallResult(resultValue, resultVisibility); + } catch (FrameSlotTypeException e) { + throw RInternalError.shouldNotReachHere(); + } finally { + for (int i = 0; i < argValues.length; i++) { + ShareObjectNode.unshare(argValues[i]); + } } } - } - @TruffleBoundary - private static RPromise createLookupPromise(MaterializedFrame callerFrame, RSymbol symbol) { - Closure closure = RPromise.Closure.create(RContext.getASTBuilder().lookup(RSyntaxNode.SOURCE_UNAVAILABLE, symbol.getName(), false).asRNode()); - return RDataFactory.createPromise(PromiseState.Supplied, closure, callerFrame); - } + private static final class CallResult { + public final Object value; + public final boolean visibility; - @TruffleBoundary - private static RPromise createRLanguagePromise(MaterializedFrame callerFrame, RLanguage lang) { - return RDataFactory.createPromise(PromiseState.Supplied, RPromise.Closure.create(RASTUtils.cloneNode(lang.getRep())), callerFrame); + CallResult(Object value, boolean visibility) { + this.value = value; + this.visibility = visibility; + } + } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java index 873b10c3c1e1777b846da88ff8d5d53e37c9ea5f..3c217de32aa4b145a881ee4c6bf20e5f8a6d4a02 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java @@ -93,7 +93,7 @@ public class PrintFunctions { @Cached("createShowFunction(frame)") RFunction showFunction) { if (noOpt) { // S4 should only be called in case noOpt is true - RContext.getEngine().evalFunction(showFunction, null, null, null, o); + RContext.getEngine().evalFunction(showFunction, null, null, true, null, o); } else { printDefault(showFunction, digits, quote, naPrint, printGap, right, max, useSource, noOpt); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java index 0334382ddc1d606ea1bbd9dfb1ba213dda04c6cc..cdd90a090899456d7e339fbb92da3e3f5d0f06a8 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java @@ -97,7 +97,7 @@ public abstract class StandardGeneric extends RBuiltinNode.Arg2 { // and this slow path should not be executed again REnvironment methodsEnv = REnvironment.getRegisteredNamespace("methods"); RFunction currentFunction = ReadVariableNode.lookupFunction(".getMethodsTable", methodsEnv.getFrame(), true, true); - mtable = (REnvironment) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), null, def); + mtable = (REnvironment) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), true, null, def); } RList sigArgs = (RList) readSigARgs.execute(null, fnFrame); int sigLength = (int) castIntScalar.doCast(readSigLength.execute(null, fnFrame)); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java index 560b5fc442c9b3f045b699ee24fb4b268c34dd5e..083a7bcbe272cfe059e3f61900662e65c0c086fc 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java @@ -111,7 +111,7 @@ public abstract class UpdateSlot extends RBuiltinNode.Arg3 { checkSlotAssignFunction.getEnclosingFrame(), null); } else { // slow path - RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.createInvalid(frame), null, objClass, name, valClass); + RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.createInvalid(frame), true, null, objClass, name, valClass); } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java index abac7f57b85b22c01cf560bddb9d11ab29e4fe4f..a6f492fda37610985d91e463e67177c96dd1f5f5 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java @@ -67,6 +67,6 @@ public abstract class Xtfrm extends RBuiltinNode.Arg1 { env = REnvironment.createEnclosingEnvironments(frame.materialize()); } RFunction func = (RFunction) getNode.execute(frame, "xtfrm.default", env, RType.Function.getName(), true); - return RContext.getEngine().evalFunction(func, null, null, null, x); + return RContext.getEngine().evalFunction(func, null, null, true, null, x); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java index 2ff2c2bf36eaaf8fa1c1123cf8b40b2dec33b8e6..173799ff0b9808f9564f0908b66fd78ca324fc5c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java @@ -63,7 +63,7 @@ final class S4ObjectPrinter implements ValuePrinter<RS4Object> { static void printS4(PrintContext printCtx, Object o) { Frame frame = com.oracle.truffle.r.runtime.Utils.getActualCurrentFrame(); - RContext.getEngine().evalFunction(createShowFunction(frame), null, null, null, o); + RContext.getEngine().evalFunction(createShowFunction(frame), null, null, true, null, o); // The show function prints an additional new line character. The following attribute // instructs the ValuePrinter.println method not to print the new line since it was // already printed. diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java index 1d8fccff965444f3ffc3f9f100a442e4dfab6db3..61f7c1074d7076934b15812a134481813c0953eb 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java @@ -76,7 +76,7 @@ public abstract class AccessSlotNode extends RBaseNode { // TODO: any way to cache it or use a mechanism similar to overrides? REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods"); RFunction dataPart = getDataPartFunction(methodsNamespace); - return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), null, object); + return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), true, null, object); } else if (name == RRuntime.NAMES_ATTR_KEY && object instanceof RAbstractVector) { assert false; // RS4Object can never be a vector? return RNull.instance; @@ -126,7 +126,7 @@ public abstract class AccessSlotNode extends RBaseNode { // TODO: any way to cache it or use a mechanism similar to overrides? REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods"); RFunction dataPart = getDataPartFunction(methodsNamespace); - return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), null, object); + return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), true, null, object); } // this is really a fallback specialization but @Fallback does not work here (because of the diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java index 59d8ab2c49c12060a5c96d63205779293f1f01e2..f895c1d2bb2c1a2fbd0d82ebf19e56f2ca2022ec 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java @@ -59,7 +59,7 @@ public abstract class UpdateSlotNode extends RBaseNode { REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods"); Object f = methodsNamespace.findFunction(SET_DATA_PART); RFunction dataPart = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(SET_DATA_PART, f); - return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.createInvalid(null), null, object, prepareValue(value), RRuntime.LOGICAL_TRUE); + return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.createInvalid(null), true, null, object, prepareValue(value), RRuntime.LOGICAL_TRUE); } protected boolean isData(String name) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java index a6e270047ddfc99e8f2ab0d7170fb53245a143d2..5e88b23d2c8ba06309f6249d69c0fd12e26bd681 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java @@ -44,6 +44,7 @@ import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.ffi.ParseResult.ParseStatus; import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; +import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RCleanUp; @@ -204,7 +205,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { public Object R_do_MAKE_CLASS(Object clazz) { String name = "getClass"; RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name)); - return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), null, clazz); + return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), true, null, clazz); } @Override @@ -733,10 +734,11 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { RFunction f = (RFunction) l.car(); Object args = l.cdr(); if (args == RNull.instance) { - result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, null, new Object[0]); + result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, true, null, new Object[0]); } else { RList argsList = ((RPairList) args).toRList(); - result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, argsList.getNames(), + result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, true, + ArgumentsSignature.fromNamesAttribute(argsList.getNames()), argsList.getDataNonShared()); } } else { @@ -794,7 +796,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { @Override public int R_compute_identical(Object x, Object y, int flags) { RFunction indenticalBuiltin = RContext.lookupBuiltin("identical"); - Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))), + Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, true, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))), RRuntime.asLogical((!((flags & 2) == 0))), RRuntime.asLogical((!((flags & 4) == 0))), RRuntime.asLogical((!((flags & 8) == 0))), RRuntime.asLogical((!((flags & 16) == 0)))); return (int) res; } 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 1a6f9101103bbd7fd61b4af88d14b47a42edbf11..db25097a00b0d4d46095db9db9ec3ee1fc72274c 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 @@ -232,7 +232,6 @@ public class ArgumentMatcher { }, index -> evaluatedArgs.getSignature().getName(index), null); Object[] evaledArgs = new Object[match.resultPermutation.length]; - for (int formalIndex = 0; formalIndex < match.resultPermutation.length; formalIndex++) { int suppliedIndex = match.resultPermutation[formalIndex]; @@ -260,7 +259,7 @@ public class ArgumentMatcher { evaledArgs[formalIndex] = evaluatedArgs.getArgument(suppliedIndex); } } - return new RArgsValuesAndNames(evaledArgs, formals.getSignature()); + return new RArgsValuesAndNames(evaledArgs, match.resultSignature); } /** 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 dcaab1397e5254f321c47f018e8ef863c3b4a3dc..00a81a5535eb4c606c8de0f490e4841b5d119a3f 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 @@ -257,7 +257,7 @@ abstract class S4Class extends RBaseNode { // the assumption here is that the R function can only return either a String or // RStringVector s4Extends = (RStringVector) castToVector.doCast( - RContext.getEngine().evalFunction(sExtendsForS3Function, methodsEnv.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), null, classAttr)); + RContext.getEngine().evalFunction(sExtendsForS3Function, methodsEnv.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), true, null, classAttr)); RContext.getInstance().putS4Extends(classAttr, s4Extends); } return s4Extends; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java index 02a315c52e90c6df7363da15e1a207af7b8876c0..ee1b587d0e3ccb584dd31d81d7bd75f9d612986d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java @@ -65,8 +65,17 @@ public final class CallRFunctionNode extends Node { return callNode; } + public static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, DispatchArgs dispatchArgs) { + Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, suppliedSignature, function.getEnclosingFrame(), dispatchArgs); + return executeSlowpath(function, caller, callerFrame, callArgs); + } + public static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, DispatchArgs dispatchArgs) { Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, dispatchArgs); + return executeSlowpath(function, caller, callerFrame, callArgs); + } + + private static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] callArgs) { try { return function.getTarget().call(callArgs); } finally { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java index 9d4fdeb7f07be32e3bfa3d428564c36b170dcd6a..4098d1e5d501124ac77f8186066ce82ecb77dcb9 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java @@ -73,7 +73,7 @@ public abstract class DispatchGeneric extends RBaseNode { CompilerDirectives.transferToInterpreterAndInvalidate(); REnvironment methodsEnv = REnvironment.getRegisteredNamespace("methods"); RFunction currentFunction = ReadVariableNode.lookupFunction(".InheritForDispatch", methodsEnv.getFrame(), true, true); - method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), null, classes, fdef, mtable); + method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), true, null, classes, fdef, mtable); } method = loadMethod.executeRFunction(frame, method, fname); Object ret = executeMethod.executeObject(frame, method, fname); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java index 236289defb37f1353359c34e785f0b5b943282d6..3780418d1675fe83fe3101d4ad6bdc6a021b14fd 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java @@ -136,7 +136,7 @@ abstract class LoadMethod extends RBaseNode { loadMethodFunction.getEnclosingFrame(), null); } else { // slow path - ret = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), caller, null, fdef, fname, REnvironment.frameToEnvironment(frame.materialize())); + ret = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), caller, true, null, fdef, fname, REnvironment.frameToEnvironment(frame.materialize())); } } else { ret = fdef; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java index ca2ec69bbd8f5615607da8898b48296b20b6997d..ac69a5a14fd5a4ec37a529811733dbe1df51a437 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java @@ -30,6 +30,7 @@ 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.r.runtime.data.RStringVector; public final class ArgumentsSignature implements Iterable<String> { @@ -47,7 +48,7 @@ public final class ArgumentsSignature implements Iterable<String> { public static final int NO_VARARG = -1; @CompilationFinal(dimensions = 1) private static final ArgumentsSignature[] EMPTY_SIGNATURES = new ArgumentsSignature[32]; - public static final ArgumentsSignature INVALID_SIGNATURE = new ArgumentsSignature(new String[]{"<<invalid>>"}); + public static final ArgumentsSignature INVALID_SIGNATURE = new ArgumentsSignature(new String[]{"<<invalid>>"}, false); static { for (int i = 0; i < EMPTY_SIGNATURES.length; i++) { @@ -55,12 +56,8 @@ public final class ArgumentsSignature implements Iterable<String> { } } - @TruffleBoundary public static ArgumentsSignature get(String... names) { - assert names != null; - ArgumentsSignature newSignature = new ArgumentsSignature(names); - ArgumentsSignature oldSignature = signatures.putIfAbsent(newSignature, newSignature); - return oldSignature != null ? oldSignature : newSignature; + return get(names, false); } public static ArgumentsSignature empty(int length) { @@ -73,15 +70,41 @@ public final class ArgumentsSignature implements Iterable<String> { return get(new String[length]); } + /** + * Returns {@code null} if the the vector is {@code null}. Any empty string in the vector is + * converted to {@code null} value. + */ + public static ArgumentsSignature fromNamesAttribute(RStringVector names) { + return names == null ? null : get(names.getDataWithoutCopying(), true); + } + + @TruffleBoundary + private static ArgumentsSignature get(String[] names, boolean convertEmpty) { + assert names != null; + ArgumentsSignature newSignature = new ArgumentsSignature(names, convertEmpty); + ArgumentsSignature oldSignature = signatures.putIfAbsent(newSignature, newSignature); + return oldSignature != null ? oldSignature : newSignature; + } + @CompilationFinal(dimensions = 1) private final String[] names; @CompilationFinal(dimensions = 1) private final int[] varArgIndexes; @CompilationFinal(dimensions = 1) private final boolean[] isVarArg; private final int varArgIndex; private final int nonNullCount; - private ArgumentsSignature(String[] names) { - this.names = Arrays.stream(names).map(s -> s == null || s == UNMATCHED ? s : s.intern()).toArray(String[]::new); - this.nonNullCount = (int) Arrays.stream(names).filter(s -> s != null).count(); + private ArgumentsSignature(String[] names, boolean convertEmpty) { + this.names = new String[names.length]; + int nonNullCount = 0; + for (int i = 0; i < names.length; i++) { + String s = names[i]; + if (s == null || (s.isEmpty() && convertEmpty)) { + this.names[i] = null; + continue; + } + nonNullCount++; + this.names[i] = s == UNMATCHED ? s : s.intern(); + } + this.nonNullCount = nonNullCount; int index = NO_VARARG; int count = 0; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java index ac0af78b884cfab4b846dbdea61cac73915befec..6913a4f10243e621613dcd5c67915e5b532eb991 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java @@ -356,7 +356,7 @@ public class RErrorHandling { errorcallDfltWithCall(fromCall(call), Message.GENERIC, msg); } else { RFunction hf = (RFunction) h; - RContext.getEngine().evalFunction(hf, null, null, null, cond); + RContext.getEngine().evalFunction(hf, null, null, true, null, cond); } } else { throw gotoExitingHandler(cond, call, entry); @@ -524,7 +524,7 @@ public class RErrorHandling { evaluatedArgs[i] = RMissing.instance; } } - RContext.getEngine().evalFunction(errorFunction, null, null, null, evaluatedArgs); + RContext.getEngine().evalFunction(errorFunction, null, null, true, null, evaluatedArgs); } else if (errorExpr instanceof RLanguage || errorExpr instanceof RExpression) { if (errorExpr instanceof RLanguage) { RContext.getEngine().eval((RLanguage) errorExpr, materializedFrame); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java index 8ee00ebb4a460f4cff2111a5a39047dc91e2fa30..85b7cd674b25d9306ebe7c1bc94c08fd13183f2d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java @@ -466,7 +466,7 @@ public class RSerialize { // fast path through getRegisteredNamespace Object namespace = REnvironment.getRegisteredNamespace(s.getDataAt(0)); if (namespace == null) { - namespace = RContext.getEngine().evalFunction(contextState.getDotDotFindNamespace(), null, null, null, s, ""); + namespace = RContext.getEngine().evalFunction(contextState.getDotDotFindNamespace(), null, null, true, null, s, ""); } return checkResult(addReadRef(namespace)); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java index 6c7f7f692cc73dc2134594d4f5c71f4bc65dd99d..fe6fc77fa95752f8dea4d2fced40aa64930cd326 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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 @@ -28,13 +28,13 @@ import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RLanguage; -import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.nodes.RNode; @@ -171,8 +171,12 @@ public interface Engine { * namespace, but the current stack is not empty. So when {@code frame} is not {@code null} a * {@code caller} should be passed to maintain the call stack correctly. {@code names} string * vector describing (optional) argument names + * + * @param names signature of the given parameters, may be {@code null} in which case the empty + * signature of correct cardinality shall be used. + * @param evalPromises whether to evaluate promises in args array before calling the function. */ - Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, RStringVector names, Object... args); + Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, boolean evalPromises, ArgumentsSignature names, Object... args); /** * Checks for the existence of (startup/shutdown) function {@code name} and, if present, invokes diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/ActiveBinding.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/ActiveBinding.java index f44d5c5222baf7632708d894ec6e08fea8c74a7f..892566e5bf11b2a9067369e42ae9b843a4f01afd 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/ActiveBinding.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/ActiveBinding.java @@ -27,7 +27,6 @@ import java.util.Objects; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RTruffleObject; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -64,11 +63,11 @@ public class ActiveBinding implements RTruffleObject { } public Object writeValue(Object value) { - return RContext.getEngine().evalFunction(function, REnvironment.baseEnv().getFrame(), RCaller.createInvalid(null), null, value); + return RContext.getEngine().evalFunction(function, REnvironment.baseEnv().getFrame(), RCaller.createInvalid(null), true, null, value); } public Object readValue() { - return RContext.getEngine().evalFunction(function, REnvironment.baseEnv().getFrame(), RCaller.createInvalid(null), RDataFactory.createEmptyStringVector()); + return RContext.getEngine().evalFunction(function, REnvironment.baseEnv().getFrame(), RCaller.createInvalid(null), true, 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 a4a69155cacaecab5a2c1cd3f99735e0c92629e9..5c89154642282ef8112e8636bce9fda6e47c3a4a 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 @@ -22257,6 +22257,9 @@ Error in (function (x) : object 'foo' not found #{ do.call("+", list(quote(1), 2))} [1] 3 +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ do.call('+', list(data.frame(1), data.frame(2)), envir = new.env()); do.call('assign', list('a',2,new.env()), envir = new.env()); } + ##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# #{ do.call(quote, list(quote(1)))} [1] 1 @@ -22269,6 +22272,22 @@ x #{ do.call(quote, list(quote(x+1)))} x + 1 +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ e <- new.env(); assign('a', 42, e); a <- 1; foo <- function(x) force(x); do.call('foo', list(as.name('a')), envir=e); } +[1] 42 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ e <- new.env(); assign('a', 42, e); a <- 1; foo <- function(x) force(x); do.call('foo', list(as.name('a')), envir=e, quote=T); } +a + +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ e <- new.env(); assign('foo', 42, e); foo <- function(x) 1; do.call('foo', list(), envir=e); } +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ e <- new.env(); assign('foo', function() 42, e); foo <- function(x) 1; do.call('foo', list(), envir=e); } +[1] 42 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#Output.IgnoreErrorContext# #{ f <- function(x) x; do.call(f, list(quote(y + 1)))} Error in (function (x) : object 'y' not found @@ -22277,6 +22296,44 @@ Error in (function (x) : object 'y' not found #{ f <- function(x) x; do.call(f, list(quote(y)))} Error in (function (x) : object 'y' not found +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ foo <- function() ls(parent.frame()); bar <- function(a,b,c) do.call('foo', list()); bar(a=1,b=2,c=3); } +[1] "a" "b" "c" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ foo <- function() ls(parent.frame()); bar <- function(a,b,c) do.call('foo', list(), envir=globalenv()); bar(a=1,b=2,c=3) } +[1] "bar" "foo" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ foo <- function(a,b) list(a=a,b=b); e <- new.env(); assign('a', 2); assign('b', 3); a<-0; b<-1; do.call('foo', list(a,b), env=e); } +$a +[1] 0 + +$b +[1] 1 + + +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ foo <- function(a,b) list(a=a,b=b); e <- new.env(); assign('a', 2); assign('b', 3); a<-0; b<-1; do.call('foo', list(a=as.name('a'),as.name('b')), env=e) } +$a +[1] 0 + +$b +[1] 1 + + +##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# +#{ foo <- function(a,b,c) { cat('foo called.'); list(a=a,b=b,c=c); }; side <- function() { cat('side effect!'); 42 }; do.call('foo', list(parse(text='side()')[[1]], 0, 0)); } +foo called.side effect!$a +[1] 42 + +$b +[1] 0 + +$c +[1] 0 + + ##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall# #{ x<-list(c(1,2)); do.call("as.matrix", x) } [,1] diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_docall.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_docall.java index 73fbac9e68fd11f22099a70addf59940d87cd915..c0003b48744895d87218edb6e67044f4c97b3992 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_docall.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_docall.java @@ -4,7 +4,7 @@ * http://www.gnu.org/licenses/gpl-2.0.html * * Copyright (c) 2012-2014, Purdue University - * Copyright (c) 2013, 2016, Oracle and/or its affiliates + * Copyright (c) 2013, 2017, Oracle and/or its affiliates * * All rights reserved. */ @@ -31,5 +31,17 @@ public class TestBuiltin_docall extends TestBase { assertEval("v1 <- as.numeric_version('3.0.0'); v2 <- as.numeric_version('3.1.0'); do.call('<', list(quote(v1), quote(v2)))"); assertEval(Output.IgnoreErrorContext, "typeof(do.call(function(x) x, list(as.symbol('foo'))))"); assertEval("typeof(do.call(function(x) x, list(as.symbol('foo')), quote=TRUE))"); + + assertEval("{ foo <- function() ls(parent.frame()); bar <- function(a,b,c) do.call('foo', list()); bar(a=1,b=2,c=3); }"); + assertEval("{ foo <- function() ls(parent.frame()); bar <- function(a,b,c) do.call('foo', list(), envir=globalenv()); bar(a=1,b=2,c=3) }"); + assertEval("{ foo <- function(a,b) list(a=a,b=b); e <- new.env(); assign('a', 2); assign('b', 3); a<-0; b<-1; do.call('foo', list(a,b), env=e); }"); + assertEval("{ foo <- function(a,b) list(a=a,b=b); e <- new.env(); assign('a', 2); assign('b', 3); a<-0; b<-1; do.call('foo', list(a=as.name('a'),as.name('b')), env=e) }"); + assertEval("{ foo <- function(a,b,c) { cat('foo called.'); list(a=a,b=b,c=c); }; side <- function() { cat('side effect!'); 42 }; do.call('foo', list(parse(text='side()')[[1]], 0, 0)); }"); + + assertEval("{ e <- new.env(); assign('a', 42, e); a <- 1; foo <- function(x) force(x); do.call('foo', list(as.name('a')), envir=e); }"); + assertEval("{ e <- new.env(); assign('a', 42, e); a <- 1; foo <- function(x) force(x); do.call('foo', list(as.name('a')), envir=e, quote=T); }"); + assertEval("{ e <- new.env(); assign('foo', function() 42, e); foo <- function(x) 1; do.call('foo', list(), envir=e); }"); + assertEval("{ e <- new.env(); assign('foo', 42, e); foo <- function(x) 1; do.call('foo', list(), envir=e); }"); + assertEval("{ do.call('+', list(data.frame(1), data.frame(2)), envir = new.env()); do.call('assign', list('a',2,new.env()), envir = new.env()); }"); } }