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 3877ee3ed298131c8b17a8f571954206be9a0cbe..f52c8e64823a2448a5245895889ef20965acb89f 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 @@ -332,7 +332,7 @@ public final class REngine implements RContext.Engine { } catch (UnsupportedSpecializationException use) { ConsoleHandler ch = singleton.context.getConsoleHandler(); ch.println("Unsupported specialization in node " + use.getNode().getClass().getSimpleName() + " - supplied values: " + - Arrays.asList(use.getSuppliedValues()).stream().map(v -> v.getClass().getSimpleName()).collect(Collectors.toList())); + Arrays.asList(use.getSuppliedValues()).stream().map(v -> v == null ? "null" : v.getClass().getSimpleName()).collect(Collectors.toList())); throw use; } catch (DebugExitException | BrowserQuitException e) { throw e; @@ -453,10 +453,10 @@ public final class REngine implements RContext.Engine { if (loadBase) { Object printMethod = REnvironment.globalEnv().findFunction("print"); RFunction function = (RFunction) (printMethod instanceof RPromise ? PromiseHelperNode.evaluateSlowPath(null, (RPromise) printMethod) : printMethod); - function.getTarget().call(RArguments.create(function, null, 1, new Object[]{resultValue, RMissing.instance})); + function.getTarget().call(RArguments.create(function, null, REnvironment.baseEnv().getFrame(), 1, new Object[]{resultValue, RMissing.instance})); } else { // we only have the .Internal print.default method available - getPrintInternal().getTarget().call(RArguments.create(printInternal, null, 1, new Object[]{resultValue})); + getPrintInternal().getTarget().call(RArguments.create(printInternal, null, REnvironment.baseEnv().getFrame(), 1, new Object[]{resultValue})); } } } @@ -491,7 +491,7 @@ public final class REngine implements RContext.Engine { private static void reportImplementationError(Throwable e) { ByteArrayOutputStream out = new ByteArrayOutputStream(); e.printStackTrace(new PrintStream(out)); - singleton.context.getConsoleHandler().printErrorln(RRuntime.toString(out)); + singleton.context.getConsoleHandler().printErrorln(out.toString()); // R suicide, unless, e.g., we are running units tests. // We don't call quit as the system is broken. if (singleton.crashOnFatalError) { diff --git a/com.oracle.truffle.r.native/library/fastr/src/R/fastr.R b/com.oracle.truffle.r.native/library/fastr/src/R/fastr.R index 484f91baf83a6b5a7f7b4b93a40ee55990c21257..6d20654b777ab456b7b11687cbc56422bec513e6 100644 --- a/com.oracle.truffle.r.native/library/fastr/src/R/fastr.R +++ b/com.oracle.truffle.r.native/library/fastr/src/R/fastr.R @@ -25,9 +25,9 @@ fastr.createcc <- function(func) .FastR(.NAME="createcc", func) fastr.getcc <- function(func) .FastR(.NAME="getcc", func) -fastr.compile <- function(func, background=TRUE) .FastR(.NAME="getcc", func, background) +fastr.compile <- function(func, background=TRUE) .FastR(.NAME="compile", func, background) -fastr.dumptrees <- function(func, igvDump=FALSE, verbose=FALSE) .FastR(.NAME="getcc", func, igvDump, verbose) +fastr.dumptrees <- function(func, igvDump=FALSE, verbose=FALSE) .FastR(.NAME="dumptrees", func, igvDump, verbose) fastr.source <- function(func) .FastR(.NAME="source", func) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java index 0ebe26709dbca92cbf48e2c30ad3d8ac9da5e8e2..e18239d4f012f1beb39b6c06eb5433f133f594c2 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java @@ -70,7 +70,7 @@ public abstract class Args extends RBuiltinNode { FunctionBodyNode newBody = new FunctionBodyNode(SaveArgumentsNode.NO_ARGS, nullBody); String newDesc = "args(" + rootNode.getDescription() + ")"; FunctionDefinitionNode newNode = new FunctionDefinitionNode(null, rootNode.getFrameDescriptor(), newBody, formals, newDesc, false); - return RDataFactory.createFunction(newDesc, Truffle.getRuntime().createCallTarget(newNode), REnvironment.globalEnv().getFrame()); + return RDataFactory.createFunction(newDesc, Truffle.getRuntime().createCallTarget(newNode), REnvironment.globalEnv().getFrame(), false); } @Fallback 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 fe03675beebd301941d5861c38095c8635e4b475..b2b8e8783a8b6fbf17479c8e7630f746e7e5ce6f 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,6 +25,7 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.RBuiltinKind.*; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.r.nodes.*; @@ -44,24 +45,16 @@ public abstract class DoCall extends RBuiltinNode { @Child private GetFunctions.Get getNode; @Child private PromiseHelperNode promiseHelper = new PromiseHelperNode(); + @CompilationFinal private boolean needsCallerFrame; @Specialization(guards = "lengthOne") protected Object doDoCall(VirtualFrame frame, RAbstractStringVector fname, RList argsAsList, REnvironment env) { - /* - * TODO this is only necessary to find builtins that are (currently) not available via the - * standard lookup; it's very dangerous if it happens to find a .Internal, as that cannot be - * called directly with the same semantics! - */ - RFunction func = RContext.getEngine().lookupBuiltin(fname.getDataAt(0)); - if (func == null || func.getRBuiltin().kind() == RBuiltinKind.INTERNAL) { - if (getNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getNode = insert(GetFactory.create(new RNode[4], this.getBuiltin(), getSuppliedArgsNames())); - } - func = (RFunction) getNode.execute(frame, fname, env, RType.Function.getName(), RRuntime.LOGICAL_TRUE); + if (getNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getNode = insert(GetFactory.create(new RNode[4], this.getBuiltin(), getSuppliedArgsNames())); } - Object result = doDoCall(frame, func, argsAsList, env); - return result; + RFunction func = (RFunction) getNode.execute(frame, fname, env, RType.Function.getName(), RRuntime.LOGICAL_TRUE); + return doDoCall(frame, func, argsAsList, env); } @Specialization() @@ -71,7 +64,12 @@ public abstract class DoCall extends RBuiltinNode { String[] argNames = n == null ? null : n.getDataNonShared(); EvaluatedArguments evaledArgs = EvaluatedArguments.create(argValues, argNames); EvaluatedArguments reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(frame, func, evaledArgs, getEncapsulatingSourceSection(), promiseHelper, false); - Object[] callArgs = RArguments.create(func, callCache.getSourceSection(), RArguments.getDepth(frame) + 1, reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); + if (!needsCallerFrame && func.containsDispatch()) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + needsCallerFrame = true; + } + MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; + Object[] callArgs = RArguments.create(func, callCache.getSourceSection(), callerFrame, RArguments.getDepth(frame) + 1, reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); RArguments.setIsIrregular(callArgs, true); return callCache.execute(frame, func.getTarget(), callArgs); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java index ac4967a715f770025acf01712c9d5532441d67ad..9bb359813bab260b78ccd41e20e5ac55de0f5bf1 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java @@ -14,7 +14,8 @@ package com.oracle.truffle.r.nodes.builtin.base; import java.io.*; import com.oracle.truffle.api.*; -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.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.utilities.*; @@ -464,7 +465,7 @@ public class ForeignFunctions { @SuppressWarnings("unused") @Specialization(guards = "isFlushconsole") - protected RNull flushConsole(RList f, Object[] args, RMissing packageName) { + protected RNull flushConsole(RList f, RArgsValuesAndNames args, RMissing packageName) { return RNull.instance; } @@ -516,7 +517,7 @@ public class ForeignFunctions { @SuppressWarnings("unused") @Specialization(guards = "isMakeQuartzDefault") - protected byte makeQuartzDefault(RList f, Object[] args, RMissing packageName) { + protected byte makeQuartzDefault(RList f, RArgsValuesAndNames args, RMissing packageName) { return RRuntime.LOGICAL_FALSE; } 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 68d89050d8e351a33c0fdd2879faa00a5115976a..8db0007c768b5b2785efb18d291d86fccdcb9807 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 @@ -24,6 +24,8 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.RBuiltinKind.*; +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.utilities.*; @@ -127,6 +129,8 @@ public class GetFunctions { @Child private CallInlineCacheNode callCache = CallInlineCacheNode.create(3); + @CompilationFinal private boolean needsCallerFrame; + @SuppressWarnings("unused") public static boolean isInherits(RStringVector xv, REnvironment envir, RAbstractStringVector mode, RList ifNotFound, byte inherits) { return inherits == RRuntime.LOGICAL_TRUE; @@ -238,7 +242,12 @@ public class GetFunctions { } private Object call(VirtualFrame frame, RFunction ifnFunc, String x) { - Object[] callArgs = RArguments.create(ifnFunc, callCache.getSourceSection(), RArguments.getDepth(frame) + 1, new Object[]{x}, new String[0]); + if (!needsCallerFrame && ifnFunc.containsDispatch()) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + needsCallerFrame = true; + } + MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; + Object[] callArgs = RArguments.create(ifnFunc, callCache.getSourceSection(), callerFrame, RArguments.getDepth(frame) + 1, new Object[]{x}, new String[0]); return callCache.execute(frame, ifnFunc.getTarget(), callArgs); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java index da19ceebcb840ca1e1a1355343bbf716264cc715..028ba4684436b8848d81dc9a152c3390c2f20f58 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java @@ -202,7 +202,7 @@ public class HiddenInternalFunctions { RSerialize.CallHook callHook = new RSerialize.CallHook() { public Object eval(Object arg) { - Object[] callArgs = RArguments.create(envhook, callCache.getSourceSection(), RArguments.getDepth(frame) + 1, new Object[]{arg}, new String[0]); + Object[] callArgs = RArguments.create(envhook, callCache.getSourceSection(), null, RArguments.getDepth(frame) + 1, new Object[]{arg}, new String[0]); // TODO this cast is problematic return callCache.execute((VirtualFrame) frame, envhook.getTarget(), callArgs); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java index 66712b3ecc38d8c7544921da6a5b172c1ecf5fc4..11d1904d5ac854487edfdeafb332a4c0af598663 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -49,7 +49,7 @@ public abstract class Recall extends RBuiltinNode { } // Use arguments in "..." as arguments for RECALL call - Object[] argsObject = RArguments.create(function, callCache.getSourceSection(), RArguments.getDepth(frame) + 1, args.getValues()); + Object[] argsObject = RArguments.create(function, callCache.getSourceSection(), null, RArguments.getDepth(frame) + 1, args.getValues()); return callCache.execute(frame, function.getTarget(), argsObject); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java index 56d80f9a72ae799720cf8ad50035befc83f62334..dec2c924c1dc9c46625ddcc70abdd96504226256 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java @@ -24,7 +24,7 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.RBuiltinKind.*; -import java.util.*; +import java.util.function.*; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.utilities.*; @@ -34,14 +34,12 @@ import com.oracle.truffle.r.nodes.unary.*; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.*; import com.oracle.truffle.r.runtime.data.model.*; -import com.oracle.truffle.r.runtime.ops.na.*; @RBuiltin(name = "rep.int", kind = INTERNAL, parameterNames = {"x", "times"}) public abstract class RepeatInternal extends RBuiltinNode { - private final ConditionProfile timesOne = ConditionProfile.createBinaryProfile(); + private final ConditionProfile timesOneProfile = ConditionProfile.createBinaryProfile(); private final BranchProfile errorProfile = BranchProfile.create(); - private final NACheck naCheck = NACheck.create(); @CreateCast("arguments") protected RNode[] castStatusArgument(RNode[] arguments) { @@ -50,144 +48,80 @@ public abstract class RepeatInternal extends RBuiltinNode { return arguments; } - @Specialization - protected RDoubleVector repInt(double value, int times) { - controlVisibility(); - double[] array = new double[times]; - Arrays.fill(array, value); - naCheck.enable(value); - return RDataFactory.createDoubleVector(array, !naCheck.check(value)); + @FunctionalInterface + private interface ArrayUpdateFunction<ValueT, ArrayT> { + void update(ArrayT array, int pos, ValueT value, int index); } - @Specialization - protected RRawVector repInt(RRaw value, int times) { - controlVisibility(); - byte[] array = new byte[times]; - Arrays.fill(array, value.getValue()); - return RDataFactory.createRawVector(array); + @FunctionalInterface + private interface CreateResultFunction<ResultT, ArrayT> { + ResultT create(ArrayT array, boolean complete); } - @Specialization - protected RIntVector repInt(RIntSequence value, int times) { + private <ValueT extends RAbstractVector, ResultT extends ValueT, ArrayT> ResultT repInt(ValueT value, RAbstractIntVector times, IntFunction<ArrayT> arrayConstructor, + ArrayUpdateFunction<ValueT, ArrayT> arrayUpdate, CreateResultFunction<ResultT, ArrayT> createResult) { controlVisibility(); - int oldLength = value.getLength(); - int length = oldLength * times; - int[] array = new int[length]; - for (int i = 0; i < times; i++) { - for (int j = 0; j < oldLength; ++j) { - array[i * oldLength + j] = value.getDataAt(j); + ArrayT result; + int timesLength = times.getLength(); + int valueLength = value.getLength(); + if (timesOneProfile.profile(timesLength == 1)) { + int timesValue = times.getDataAt(0); + int count = timesValue * valueLength; + result = arrayConstructor.apply(count); + int pos = 0; + for (int i = 0; i < timesValue; i++) { + for (int j = 0; j < valueLength; j++) { + arrayUpdate.update(result, pos++, value, j); + } } - } - return RDataFactory.createIntVector(array, value.isComplete()); - } - - @Specialization - protected RDoubleVector repInt(RDoubleVector value, int times) { - controlVisibility(); - int oldLength = value.getLength(); - int length = value.getLength() * times; - double[] array = new double[length]; - for (int i = 0; i < times; i++) { - for (int j = 0; j < oldLength; ++j) { - array[i * oldLength + j] = value.getDataAt(j); + } else if (timesLength == valueLength) { + int count = 0; + for (int i = 0; i < timesLength; i++) { + int data = times.getDataAt(i); + if (data < 0) { + errorProfile.enter(); + RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_VALUE, "times"); + } + count += data; } - } - return RDataFactory.createDoubleVector(array, value.isComplete()); - } - - @Specialization(guards = "isTimesValid") - protected RDoubleVector repInt(RAbstractDoubleVector value, RIntVector times) { - controlVisibility(); - List<Double> result = new ArrayList<>(); - for (int i = 0; i < value.getLength(); i++) { - for (int j = 0; j < times.getDataAt(i); ++j) { - result.add(value.getDataAt(i)); + result = arrayConstructor.apply(count); + int pos = 0; + for (int i = 0; i < valueLength; i++) { + int num = times.getDataAt(i); + for (int j = 0; j < num; j++) { + arrayUpdate.update(result, pos++, value, i); + } } + } else { + errorProfile.enter(); + throw RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_VALUE, "times"); } - double[] ans = new double[result.size()]; - for (int i = 0; i < ans.length; ++i) { - ans[i] = result.get(i); - } - return RDataFactory.createDoubleVector(ans, value.isComplete()); + return createResult.create(result, value.isComplete()); } - @Specialization(guards = "isTimesValid") - protected RIntVector repInt(RAbstractIntVector value, RIntVector times) { - controlVisibility(); - List<Integer> result = new ArrayList<>(); - for (int i = 0; i < value.getLength(); i++) { - for (int j = 0; j < times.getDataAt(i); ++j) { - result.add(value.getDataAt(i)); - } - } - int[] ans = new int[result.size()]; - for (int i = 0; i < ans.length; ++i) { - ans[i] = result.get(i); - } - return RDataFactory.createIntVector(ans, value.isComplete()); + @Specialization + protected RDoubleVector repInt(RAbstractDoubleVector value, RAbstractIntVector times) { + return repInt(value, times, double[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createDoubleVector); } @Specialization - protected RIntVector repInt(int value, int times) { - controlVisibility(); - int[] array = new int[times]; - Arrays.fill(array, value); - naCheck.enable(value); - return RDataFactory.createIntVector(array, !naCheck.check(value)); + protected RIntVector repInt(RAbstractIntVector value, RAbstractIntVector times) { + return repInt(value, times, int[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createIntVector); } @Specialization - protected RLogicalVector repInt(byte value, int times) { - controlVisibility(); - byte[] array = new byte[times]; - Arrays.fill(array, value); - naCheck.enable(value); - return RDataFactory.createLogicalVector(array, !naCheck.check(value)); + protected RLogicalVector repInt(RAbstractLogicalVector value, RAbstractIntVector times) { + return repInt(value, times, byte[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createLogicalVector); } @Specialization - protected RStringVector repInt(String value, int times) { - controlVisibility(); - String[] array = new String[times]; - Arrays.fill(array, value); - naCheck.enable(value); - return RDataFactory.createStringVector(array, !naCheck.check(value)); + protected RStringVector repInt(RAbstractStringVector value, RAbstractIntVector times) { + return repInt(value, times, String[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createStringVector); } @Specialization - protected RStringVector repInt(RStringVector value, RIntVector timesVec) { - controlVisibility(); - int valueLength = value.getLength(); - int times = timesVec.getLength(); - if (!(times == 1 || times == valueLength)) { - errorProfile.enter(); - throw RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_TIMES_ARG); - } - String[] array; - if (timesOne.profile(times == 1)) { - int length = value.getLength() * times; - array = new String[length]; - for (int i = 0; i < times; i++) { - for (int j = 0; j < valueLength; ++j) { - array[i * valueLength + j] = value.getDataAt(j); - } - } - } else { - int length = 0; - for (int k = 0; k < times; k++) { - length = length + timesVec.getDataAt(k); - } - array = new String[length]; - int arrayIndex = 0; - for (int i = 0; i < valueLength; i++) { - String s = value.getDataAt(i); - int timesLen = timesVec.getDataAt(i); - for (int k = 0; k < timesLen; k++) { - array[arrayIndex++] = s; - } - } - } - return RDataFactory.createStringVector(array, value.isComplete()); + protected RRawVector repInt(RAbstractRawVector value, RAbstractIntVector times) { + return repInt(value, times, byte[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index).getValue(), (array, complete) -> RDataFactory.createRawVector(array)); } @Specialization @@ -203,12 +137,4 @@ public abstract class RepeatInternal extends RBuiltinNode { } return RDataFactory.createList(array); } - - protected boolean isTimesValid(RAbstractVector value, RIntVector times) { - if (value.getLength() != times.getLength()) { - errorProfile.enter(); - throw RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_VALUE, "times"); - } - return true; - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java index 6fcd6023411e6847f2eacd4b22d5a99356914b81..9ad69a27f9f2b6e16ffa1f71171db2372f41a639 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java @@ -145,6 +145,7 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> { String[] argumentNames = new String[argumentsList.size()]; RNode[] defaultValues = new RNode[argumentsList.size()]; SaveArgumentsNode saveArguments; + AccessArgumentNode[] argAccessNodes = new AccessArgumentNode[argumentsList.size()]; if (!argumentsList.isEmpty()) { RNode[] init = new RNode[argumentsList.size()]; int index = 0; @@ -159,7 +160,9 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> { } // Create an initialization statement - init[index] = WriteVariableNode.create(arg.getName(), AccessArgumentNode.create(index), true, false); + AccessArgumentNode accessArg = AccessArgumentNode.create(index); + argAccessNodes[index] = accessArg; + init[index] = WriteVariableNode.create(arg.getName(), accessArg, true, false); // Store formal arguments argumentNames[index] = arg.getName(); @@ -178,6 +181,9 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> { statements.assignSourceSection(astBody.getSource()); } FormalArguments formals = FormalArguments.create(argumentNames, defaultValues); + for (AccessArgumentNode access : argAccessNodes) { + access.setFormals(formals); + } FrameDescriptor descriptor = new FrameDescriptor(); FrameSlotChangeMonitor.initializeFrameDescriptor(descriptor, false); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java index e131aa90a8a475298e3c6f0cca487f1c67ba2375..92e8cbc2b0f00df907c2cdf100ac1354caf087f6 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java @@ -82,12 +82,12 @@ public abstract class AccessArgumentNode extends RNode { defaultArgCanBeOptimized = prev.defaultArgCanBeOptimized; } - @Override - protected void onAdopt() { - formals = ((RRootNode) getRootNode()).getFormalArguments(); + public void setFormals(FormalArguments formals) { + CompilerAsserts.neverPartOfCompilation(); + assert this.formals == null; + this.formals = formals; hasDefaultArg = formals.getDefaultArg(getIndex()) != null; isVarArgIndex = formals.getVarArgIndex() == getIndex(); - super.onAdopt(); } /** @@ -136,27 +136,27 @@ public abstract class AccessArgumentNode extends RNode { return argMissing; } - @Specialization(guards = {"hasDefaultArg", "canBeOptimized"}) - public Object doArgumentEagerDefaultArg(VirtualFrame frame, RMissing argMissing) { - // Insert default value - checkPromiseFactory(); - if (!checkInsertOptDefaultArg()) { - // Default arg cannot be optimized: Rewrite to default and assure that we don't take - // this path again - CompilerDirectives.transferToInterpreterAndInvalidate(); - defaultArgCanBeOptimized = false; - return doArgumentDefaultArg(frame, argMissing); - } - Object result = optDefaultArgNode.execute(frame); - RArguments.setArgument(frame, index, result); // Update RArguments for S3 dispatch to work - return result; - } - - @Specialization(guards = {"hasDefaultArg", "!canBeOptimized"}) + @Specialization(guards = {"hasDefaultArg"}) public Object doArgumentDefaultArg(VirtualFrame frame, @SuppressWarnings("unused") RMissing argMissing) { + Object result; + if (canBeOptimized()) { + // Insert default value + checkPromiseFactory(); + if (checkInsertOptDefaultArg()) { + result = optDefaultArgNode.execute(frame); + // Update RArguments for S3 dispatch to work + RArguments.setArgument(frame, index, result); + return result; + } else { + // Default arg cannot be optimized: Rewrite to default and assure that we don't take + // this path again + CompilerDirectives.transferToInterpreterAndInvalidate(); + defaultArgCanBeOptimized = false; + } + } // Insert default value checkPromiseFactory(); - RPromise result = factory.createPromise(frame.materialize()); + result = factory.createPromise(frame.materialize()); RArguments.setArgument(frame, index, result); // Update RArguments for S3 dispatch to work return result; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/PositionsArrayNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/PositionsArrayNode.java index 803b5ddbcb41523e701ce88d4ff3a41ee8a2fc8d..654172afed95502e642e942a453976c006e6312d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/PositionsArrayNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/PositionsArrayNode.java @@ -83,19 +83,24 @@ public class PositionsArrayNode extends RNode { } @ExplodeLoop - public Object executeEvalNoVarArg(VirtualFrame frame, Object vector, Object exact) { - int length = conversionAdapter.getLength(); + public static Object[] explodeLoopNoVarArg(VirtualFrame frame, PositionsArrayNodeAdapter positionsAdapter, int length) { Object[] evaluatedElements = new Object[length]; for (int i = 0; i < length; i++) { evaluatedElements[i] = positionsAdapter.executePos(frame, i); } - executeEvalInternal(frame, vector, exact, evaluatedElements); + return evaluatedElements; + } + + public Object executeEvalNoVarArg(VirtualFrame frame, Object vector, Object exact) { + int length = conversionAdapter.getLength(); + Object[] evaluatedElements = explodeLoopNoVarArg(frame, positionsAdapter, length); + length = conversionAdapter.getLength(); // could have changed + executeEvalInternal(frame, vector, exact, evaluatedElements, length); return conversionAdapter.getLength() == 1 ? evaluatedElements[0] : evaluatedElements; } @ExplodeLoop - public Object executeEvalVarArg(VirtualFrame frame, Object vector, Object exact) { - int length = conversionAdapter.getLength(); + public static Object[] explodeLoopVarArg(VirtualFrame frame, PositionsArrayNodeAdapter positionsAdapter, int length, PromiseHelperNode promiseHelper) { Object[] evaluatedElements = new Object[length]; int ind = 0; for (int i = 0; i < length; i++) { @@ -108,17 +113,24 @@ public class PositionsArrayNode extends RNode { evaluatedElements[ind++] = p; } } + return evaluatedElements; + } + + public Object executeEvalVarArg(VirtualFrame frame, Object vector, Object exact) { + int length = conversionAdapter.getLength(); + Object[] evaluatedElements = explodeLoopVarArg(frame, positionsAdapter, length, promiseHelper); if (evaluatedElements.length != conversionAdapter.getLength()) { CompilerDirectives.transferToInterpreterAndInvalidate(); - this.conversionAdapter = new PositionsArrayConversionNodeMultiDimAdapter(this.conversionAdapter.isSubset(), evaluatedElements.length); + this.conversionAdapter = insert(new PositionsArrayConversionNodeMultiDimAdapter(this.conversionAdapter.isSubset(), evaluatedElements.length)); } - executeEvalInternal(frame, vector, exact, evaluatedElements); + length = conversionAdapter.getLength(); // could have changed + executeEvalInternal(frame, vector, exact, evaluatedElements, length); return conversionAdapter.getLength() == 1 ? evaluatedElements[0] : evaluatedElements; } @ExplodeLoop - public void executeEvalInternal(VirtualFrame frame, Object vector, Object exact, Object[] evaluatedElements) { - for (int i = 0; i < evaluatedElements.length; i++) { + public void executeEvalInternal(VirtualFrame frame, Object vector, Object exact, Object[] evaluatedElements, int length) { + for (int i = 0; i < length; i++) { Object convertedOperator = conversionAdapter.executeConvert(frame, vector, evaluatedElements[i], exact, i); evaluatedElements[i] = conversionAdapter.executeArg(frame, vector, convertedOperator, i); if (conversionAdapter.multiDimOperatorConverters != null) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/PositionsArrayNodeValue.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/PositionsArrayNodeValue.java index 1607f44952d56e9dcad746bc5b7657fd8111151e..7634ee3fc9539e30f87fa39ec85007c73464304a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/PositionsArrayNodeValue.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/PositionsArrayNodeValue.java @@ -31,7 +31,6 @@ import com.oracle.truffle.r.nodes.access.array.read.*; import com.oracle.truffle.r.nodes.function.*; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.RDeparse.*; -import com.oracle.truffle.r.runtime.data.*; public class PositionsArrayNodeValue extends RNode { @@ -62,41 +61,29 @@ public class PositionsArrayNodeValue extends RNode { } } + @ExplodeLoop public Object executeEvalNoVarArg(VirtualFrame frame, Object vector, Object value) { int length = conversionAdapter.getLength(); - Object[] evaluatedElements = new Object[length]; - for (int i = 0; i < length; i++) { - evaluatedElements[i] = positionsAdapter.executePos(frame, i); - } - executeEvalInternal(frame, vector, value, evaluatedElements); + Object[] evaluatedElements = PositionsArrayNode.explodeLoopNoVarArg(frame, positionsAdapter, length); + executeEvalInternal(frame, vector, value, evaluatedElements, length); return conversionAdapter.getLength() == 1 ? evaluatedElements[0] : evaluatedElements; } public Object executeEvalVarArg(VirtualFrame frame, Object vector, Object value) { int length = conversionAdapter.getLength(); - Object[] evaluatedElements = new Object[length]; - int ind = 0; - for (int i = 0; i < length; i++) { - Object p = positionsAdapter.executePos(frame, i); - if (p instanceof RArgsValuesAndNames) { - RArgsValuesAndNames varArg = (RArgsValuesAndNames) p; - evaluatedElements = PositionsArrayNode.expandVarArg(frame, varArg, ind, evaluatedElements, promiseHelper); - ind += varArg.length(); - } else { - evaluatedElements[ind++] = p; - } - } + Object[] evaluatedElements = PositionsArrayNode.explodeLoopVarArg(frame, positionsAdapter, length, promiseHelper); if (evaluatedElements.length != conversionAdapter.getLength()) { CompilerDirectives.transferToInterpreterAndInvalidate(); - this.conversionAdapter = new PositionsArrayConversionValueNodeMultiDimAdapter(this.conversionAdapter.isSubset(), evaluatedElements.length); + this.conversionAdapter = insert(new PositionsArrayConversionValueNodeMultiDimAdapter(this.conversionAdapter.isSubset(), evaluatedElements.length)); } - executeEvalInternal(frame, vector, value, evaluatedElements); + length = conversionAdapter.getLength(); // could have changed + executeEvalInternal(frame, vector, value, evaluatedElements, length); return conversionAdapter.getLength() == 1 ? evaluatedElements[0] : evaluatedElements; } @ExplodeLoop - public void executeEvalInternal(VirtualFrame frame, Object vector, Object value, Object[] evaluatedElements) { - for (int i = 0; i < conversionAdapter.getLength(); i++) { + public void executeEvalInternal(VirtualFrame frame, Object vector, Object value, Object[] evaluatedElements, int length) { + for (int i = 0; i < length; i++) { Object convertedOperator = conversionAdapter.executeConvert(frame, vector, evaluatedElements[i], RRuntime.LOGICAL_TRUE, i); evaluatedElements[i] = conversionAdapter.executeArg(frame, vector, convertedOperator, i); if (conversionAdapter.multiDimOperatorConverters != 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 66d3f418dd892221d10c9fce2fec058785919f98..4ecc1657b7c6dd97167918f9d708e8eb1ce0d736 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 @@ -160,7 +160,7 @@ public abstract class RBuiltinNode extends LeafCallNode implements VisibilityCon static RootCallTarget createArgumentsCallTarget(RBuiltinFactory builtin) { // Create function initialization RNode[] argAccessNodes = createAccessArgumentsNodes(builtin); - RBuiltinNode node = createNode(builtin, argAccessNodes, null); + RBuiltinNode node = createNode(builtin, argAccessNodes.clone(), null); // Create formal arguments // TODO We only call getParameterNames to support overrides @@ -176,6 +176,9 @@ public abstract class RBuiltinNode extends LeafCallNode implements VisibilityCon names[i] = nameObj.isEmpty() ? null : nameObj; } FormalArguments formals = FormalArguments.create(names, node.getParameterValues()); + for (RNode access : argAccessNodes) { + ((AccessArgumentNode) access).setFormals(formals); + } // Setup FrameDescriptor frameDescriptor = new FrameDescriptor(); 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 70029ab22c30ced7d50231e8c078232cf74a8058..076b6beed317e6807051643b2fc9832a25a73454 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 @@ -23,9 +23,9 @@ package com.oracle.truffle.r.nodes.function; import java.util.*; +import java.util.function.*; import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; @@ -98,8 +98,8 @@ import com.oracle.truffle.r.runtime.data.RPromise.RPromiseFactory; * * f <- function(...) g(...); g <- function(a,b) { a - b }; f(b=1,2) * - * Consequently, "non-executed" ... arguments are represented as {@link VarArgsNode}-s (inheriting - * from {@link RNode}) and "executed" .. arguments are represented as a language level value of type + * Consequently, "non-executed" ... arguments are represented as VarArgsNodes (inheriting from + * {@link RNode}) and "executed" .. arguments are represented as a language level value of type * {@link RArgsValuesAndNames}, which can be passes directly in the {@link RArguments} object and * whose type is understood by the language's builtins (both representations are name-preserving). * </p> @@ -121,8 +121,8 @@ public class ArgumentMatcher { * ClosureCache, boolean) */ public static MatchedArguments matchArguments(RFunction function, UnmatchedArguments suppliedArgs, SourceSection callSrc, SourceSection argsSrc, boolean noOpt) { - FormalArguments formals = ((RRootNode) function.getTarget().getRootNode()).getFormalArguments(); RNode[] wrappedArgs = matchNodes(function, suppliedArgs.getArguments(), suppliedArgs.getNames(), callSrc, argsSrc, false, suppliedArgs, noOpt); + FormalArguments formals = ((RRootNode) function.getTarget().getRootNode()).getFormalArguments(); return MatchedArguments.create(wrappedArgs, formals.getNames()); } @@ -164,8 +164,35 @@ public class ArgumentMatcher { boolean forNextMethod) { RRootNode rootNode = (RRootNode) function.getTarget().getRootNode(); FormalArguments formals = rootNode.getFormalArguments(); - Object[] evaledArgs = permuteArguments(function, evaluatedArgs.getEvaluatedArgs(), evaluatedArgs.getNames(), formals, new VarArgsAsObjectArrayFactory(), new ObjectArrayFactory(), callSrc, - null, forNextMethod); + MatchPermutation match = permuteArguments(function, evaluatedArgs.getNames(), formals, callSrc, null, forNextMethod, index -> { + throw Utils.nyi("S3Dispatch should not have arg length mismatch"); + }, index -> evaluatedArgs.getNames()[index]); + + Object[] evaledArgs = new Object[match.resultPermutation.length]; + + for (int formalIndex = 0; formalIndex < match.resultPermutation.length; formalIndex++) { + int suppliedIndex = match.resultPermutation[formalIndex]; + + // Has varargs? Unfold! + if (suppliedIndex == VARARGS) { + int varArgsLen = match.varargsPermutation.length; + Object[] newVarArgs = new Object[varArgsLen]; + boolean nonNull = false; + for (int i = 0; i < varArgsLen; i++) { + newVarArgs[i] = evaluatedArgs.arguments[match.varargsPermutation[i]]; + nonNull |= newVarArgs[i] != null; + } + if (nonNull) { + evaledArgs[formalIndex] = new RArgsValuesAndNames(newVarArgs, match.varargsNames); + } else { + evaledArgs[formalIndex] = RArgsValuesAndNames.EMPTY; + } + } else if (suppliedIndex == UNMATCHED) { + // nothing to do... (resArgs[formalIndex] == null) + } else { + evaledArgs[formalIndex] = evaluatedArgs.arguments[suppliedIndex]; + } + } // Replace RMissing with default value! RNode[] defaultArgs = formals.getDefaultArgs(); @@ -219,8 +246,6 @@ public class ArgumentMatcher { * * @return A list of {@link RNode}s which consist of the given arguments in the correct order * and wrapped into the proper {@link PromiseNode}s - * @see #permuteArguments(RFunction, Object[], String[], FormalArguments, VarArgsFactory, - * ArrayFactory, SourceSection, SourceSection, boolean) */ private static RNode[] matchNodes(RFunction function, RNode[] suppliedArgs, String[] suppliedNames, SourceSection callSrc, SourceSection argsSrc, boolean isForInlinedBuiltin, ClosureCache closureCache, boolean noOpt) { @@ -229,272 +254,259 @@ public class ArgumentMatcher { FormalArguments formals = ((RRootNode) function.getTarget().getRootNode()).getFormalArguments(); // Rearrange arguments - RNode[] resultArgs = permuteArguments(function, suppliedArgs, suppliedNames, formals, new VarArgsAsObjectArrayNodeFactory(), new RNodeArrayFactory(), callSrc, argsSrc, false); + MatchPermutation match = permuteArguments(function, suppliedNames, formals, callSrc, argsSrc, false, index -> ArgumentsTrait.isVarArg(RMissingHelper.unwrapName(suppliedArgs[index])), + index -> suppliedArgs[index].getSourceSection().getCode()); + + RNode[] defaultArgs = formals.getDefaultArgs(); + RNode[] resArgs = new RNode[match.resultPermutation.length]; + + /** + * Walks a list of given arguments ({@link RNode}s) and wraps them in {@link PromiseNode}s + * individually by using promiseWrapper (unfolds varargs, too!) if necessary. + * + * @param function The function which is to be called + * @param arguments The arguments passed to the function call, already in correct order + * @param formals The {@link FormalArguments} for the given function + * @param promiseWrapper The {@link PromiseWrapper} implementation which handles the + * wrapping of individual arguments + * @param closureCache The {@link ClosureCache} for the supplied arguments + * @return A list of {@link RNode} wrapped in {@link PromiseNode}s + */ + + // Check whether this is a builtin + RootNode rootNode = function.getTarget().getRootNode(); + RBuiltinRootNode builtinRootNode = rootNode instanceof RBuiltinRootNode ? (RBuiltinRootNode) rootNode : null; + + // int logicalIndex = 0; As our builtin's 'evalsArgs' is meant for FastR arguments (which + // take "..." as one), we don't need a logicalIndex + for (int formalIndex = 0; formalIndex < match.resultPermutation.length; formalIndex++) { + int suppliedIndex = match.resultPermutation[formalIndex]; - PromiseWrapper wrapper = isForInlinedBuiltin ? new BuiltinInitPromiseWrapper(noOpt) : new DefaultPromiseWrapper(noOpt); - return wrapInPromises(function, resultArgs, formals, wrapper, closureCache, callSrc); + // Has varargs? Unfold! + if (suppliedIndex == VARARGS) { + int varArgsLen = match.varargsPermutation.length; + String[] newNames = match.varargsNames; + RNode[] newVarArgs = new RNode[varArgsLen]; + int index = 0; + for (int i = 0; i < varArgsLen; i++) { + RNode varArg = suppliedArgs[match.varargsPermutation[i]]; + if (varArg == null) { + if (newNames[i] == null) { + // Skip all missing values (important for detection of emtpy "...", + // which consequently collapse + continue; + } else { + // But do not skip parameters ala "[...], builtins =, [...]" + varArg = ConstantNode.create(RMissing.instance); + } + } + newNames[index] = newNames[i]; + newVarArgs[index] = varArg; + index++; + } + + // "Delete and shrink": Shrink only if necessary + int newLength = index; + if (newLength == 0) { + // Corner case: "f <- function(...) g(...); g <- function(...)" + // Insert correct "missing"! + resArgs[formalIndex] = wrap(formals, builtinRootNode, closureCache, null, null, formalIndex, isForInlinedBuiltin, noOpt); + continue; + } + if (newNames.length > newLength) { + newNames = Arrays.copyOf(newNames, newLength); + newVarArgs = Arrays.copyOf(newVarArgs, newLength); + } + + EvalPolicy evalPolicy = getEvalPolicy(builtinRootNode, formalIndex); + resArgs[formalIndex] = PromiseNode.createVarArgs(null, evalPolicy, newVarArgs, newNames, closureCache, callSrc); + } else { + RNode defaultArg = formalIndex < defaultArgs.length ? defaultArgs[formalIndex] : null; + RNode suppliedArg = suppliedIndex == UNMATCHED ? null : suppliedArgs[suppliedIndex]; + resArgs[formalIndex] = wrap(formals, builtinRootNode, closureCache, suppliedArg, defaultArg, formalIndex, isForInlinedBuiltin, noOpt); + } + } + return resArgs; + } + + private static final class MatchPermutation { + private final int[] resultPermutation; + private final int[] varargsPermutation; + private final String[] varargsNames; + + public MatchPermutation(int[] resultPermutation, int[] varargsPermutation, String[] varargsNames) { + this.resultPermutation = resultPermutation; + this.varargsPermutation = varargsPermutation; + this.varargsNames = varargsNames; + } } + private static final int UNMATCHED = -1; + private static final int VARARGS = -2; + /** * /** This method does the heavy lifting of re-arranging arguments by their names and position, * also handling varargs. * * @param function The function which should be called - * @param suppliedArgs The arguments given to this function call * @param suppliedNames The names the arguments might have * @param formals The {@link FormalArguments} this function has - * @param listFactory An abstraction for the creation of list of different types - * @param arrFactory An abstraction for the generic creation of type safe arrays * @param callSrc The source of the function call currently executed * @param argsSrc The source code encapsulating the arguments, for debugging purposes * @param forNextMethod matching when evaluating NextMethod * - * @param <T> The type of the given arguments * @return An array of type <T> with the supplied arguments in the correct order */ @TruffleBoundary - private static <T> T[] permuteArguments(RFunction function, T[] suppliedArgs, String[] suppliedNames, FormalArguments formals, VarArgsFactory<T> listFactory, ArrayFactory<T> arrFactory, - SourceSection callSrc, SourceSection argsSrc, boolean forNextMethod) { - String[] formalNames = formals.getNames(); + private static MatchPermutation permuteArguments(RFunction function, String[] suppliedNames, FormalArguments formals, SourceSection callSrc, SourceSection argsSrc, boolean forNextMethod, + IntPredicate isVarSuppliedVarargs, IntFunction<String> errorString) { + // assert Arrays.stream(suppliedNames).allMatch(name -> name == null || !name.isEmpty()); // Preparations int varArgIndex = formals.getVarArgIndex(); boolean hasVarArgs = varArgIndex != FormalArguments.NO_VARARG; // MATCH by exact name - T[] resultArgs = arrFactory.newArray(formalNames.length); - BitSet matchedSuppliedArgs = new BitSet(suppliedNames.length); - BitSet matchedFormalArgs = new BitSet(formalNames.length); - int unmatchedNameCount = 0; // The nr of named supplied args that do not match - // si = suppliedIndex, fi = formalIndex - for (int si = 0; si < suppliedNames.length; si++) { - if (suppliedNames[si] == null || suppliedNames[si].isEmpty()) { + int[] resultPermutation = new int[formals.getNames().length]; + Arrays.fill(resultPermutation, UNMATCHED); + + boolean[] matchedSuppliedArgs = new boolean[suppliedNames.length]; + for (int suppliedIndex = 0; suppliedIndex < suppliedNames.length; suppliedIndex++) { + if (suppliedNames[suppliedIndex] == null || suppliedNames[suppliedIndex].isEmpty()) { continue; } // Search for argument name inside formal arguments - int fi = findParameterPosition(formalNames, suppliedNames[si], matchedFormalArgs, si, hasVarArgs, suppliedArgs[si], callSrc, argsSrc, varArgIndex, forNextMethod); - if (fi >= 0) { - resultArgs[fi] = suppliedArgs[si]; - matchedSuppliedArgs.set(si); - } else { - // Named supplied arg that has no match: Vararg candidate! - unmatchedNameCount++; + int formalIndex = findParameterPosition(formals.getNames(), suppliedNames[suppliedIndex], resultPermutation, suppliedIndex, hasVarArgs, callSrc, argsSrc, varArgIndex, forNextMethod, + errorString); + if (formalIndex != UNMATCHED) { + resultPermutation[formalIndex] = suppliedIndex; + matchedSuppliedArgs[suppliedIndex] = true; } } - // TODO MATCH by partial name + // TODO MATCH by partial name (up to the vararg, which consumes all non-exact matches) // MATCH by position - UnmatchedSuppliedIterator<T> siCursor = new UnmatchedSuppliedIterator<>(suppliedArgs, matchedSuppliedArgs); - for (int fi = 0; fi < resultArgs.length; fi++) { + int suppliedIndex = -1; + int regularArgumentCount = hasVarArgs ? varArgIndex : formals.getNames().length; + outer: for (int formalIndex = 0; formalIndex < regularArgumentCount; formalIndex++) { // Unmatched? - if (!matchedFormalArgs.get(fi)) { - while (siCursor.hasNext() && siCursor.nextIndex() < suppliedNames.length && suppliedNames[siCursor.nextIndex()] != null && !suppliedNames[siCursor.nextIndex()].isEmpty() && - !forNextMethod) { - // Slide over named parameters and find subsequent location of unnamed parameter - // (if processing args for NextMethod, try to match yet unmatched named - // parameters - do not slide over them) - siCursor.next(); + if (resultPermutation[formalIndex] == UNMATCHED) { + while (true) { + suppliedIndex++; + if (suppliedIndex == suppliedNames.length) { + // no more unmatched supplied arguments + break outer; + } + if (!matchedSuppliedArgs[suppliedIndex]) { + if (forNextMethod) { + // for NextMethod, unused parameters are matched even when named + break; + } + if (suppliedNames[suppliedIndex] == null || suppliedNames[suppliedIndex].isEmpty()) { + // unnamed parameter, match by position + break; + } + } } - boolean followsDots = hasVarArgs && fi >= varArgIndex; - if (siCursor.hasNext() && !followsDots) { - resultArgs[fi] = siCursor.next(); + resultPermutation[formalIndex] = suppliedIndex; - // set formal status AND "remove" supplied arg from list - matchedFormalArgs.set(fi); - siCursor.remove(); - } + // set formal status AND "remove" supplied arg from list + matchedSuppliedArgs[suppliedIndex] = true; } } // MATCH rest to vararg "..." if (hasVarArgs) { - assert listFactory != null; - int varArgCount = suppliedArgs.length - matchedSuppliedArgs.cardinality(); - - // Create vararg array (+ names if necessary) - T[] varArgsArray = arrFactory.newArray(varArgCount); - String[] namesArray = null; - if (unmatchedNameCount != 0) { - namesArray = new String[varArgCount]; - } + int varArgCount = suppliedNames.length - cardinality(matchedSuppliedArgs); + + // Create vararg array + int[] varArgsPermutation = new int[varArgCount]; + String[] namesArray = new String[varArgCount]; // Add every supplied argument that has not been matched int pos = 0; - UnmatchedSuppliedIterator<T> si = new UnmatchedSuppliedIterator<>(suppliedArgs, matchedSuppliedArgs); - while (si.hasNext()) { - T arg = si.next(); - si.remove(); - if (arrFactory.isMissing(arg)) { - // do not fold missing arguments into ... - varArgsArray = Utils.resizeArray(varArgsArray, varArgsArray.length - 1); - if (namesArray != null) { - namesArray = Utils.resizeArray(namesArray, namesArray.length - 1); - } - continue; - } - varArgsArray[pos] = arg; - if (namesArray != null) { - String suppliedName = suppliedNames[si.lastIndex()]; - namesArray[pos] = suppliedName; - } - pos++; - } - resultArgs[varArgIndex] = listFactory.makeList(varArgsArray, namesArray); - } - - // Error check: Unused argument? - int leftoverCount = suppliedArgs.length - matchedSuppliedArgs.cardinality(); - if (leftoverCount > 0) { - // Check if this is really an error. Might be an inlined "..."! - UnmatchedSuppliedIterator<T> si = new UnmatchedSuppliedIterator<>(suppliedArgs, matchedSuppliedArgs); - if (leftoverCount == 1) { - T arg = si.next(); - if (arrFactory.isVararg(arg)) { - return resultArgs; + for (suppliedIndex = 0; suppliedIndex < suppliedNames.length; suppliedIndex++) { + if (!matchedSuppliedArgs[suppliedIndex]) { + matchedSuppliedArgs[suppliedIndex] = true; + varArgsPermutation[pos] = suppliedIndex; + namesArray[pos] = suppliedNames[suppliedIndex]; + pos++; } } - // Definitely an error: Prepare error message - si.reset(); - throwUnusedArgumentError(leftoverCount, si, arrFactory, callSrc); - } - - return resultArgs; - } - - @TruffleBoundary - private static <T> void throwUnusedArgumentError(int leftoverCount, UnmatchedSuppliedIterator<T> si, ArrayFactory<T> arrFactory, SourceSection callSrc) { - // UNUSED_ARGUMENT(S)? - if (leftoverCount == 1) { - CompilerDirectives.transferToInterpreter(); - String argStr = arrFactory.debugString(si.next()); - throw RError.error(callSrc, RError.Message.UNUSED_ARGUMENT, argStr); - } - - // Create error message - T[] debugArgs = arrFactory.newArray(leftoverCount); - int pos = 0; - while (si.hasNext()) { - debugArgs[pos++] = si.next(); - } - - CompilerDirectives.transferToInterpreter(); - String argStr = arrFactory.debugString(debugArgs); - throw RError.error(callSrc, RError.Message.UNUSED_ARGUMENTS, argStr); - } - - /** - * Used in - * {@link ArgumentMatcher#permuteArguments(RFunction, Object[], String[], FormalArguments, VarArgsFactory, ArrayFactory, SourceSection, SourceSection, boolean)} - * for iteration over suppliedArgs. - * - * @param <T> - */ - private static class UnmatchedSuppliedIterator<T> implements Iterator<T> { - private static final int NO_MORE_ARGS = -1; - private int si; - private int lastSi; - @CompilationFinal private final T[] suppliedArgs; - private final BitSet matchedSuppliedArgs; - - public UnmatchedSuppliedIterator(T[] suppliedArgs, BitSet matchedSuppliedArgs) { - this.suppliedArgs = suppliedArgs; - this.matchedSuppliedArgs = matchedSuppliedArgs; - reset(); - } - - public void reset() { - si = 0; - lastSi = 0; - } + resultPermutation[varArgIndex] = VARARGS; + return new MatchPermutation(resultPermutation, varArgsPermutation, namesArray); + } else { + // Error check: Unused argument? (can only happen when there are no varargs) - /** - * @return Index of the argument returned by the last {@link #next()} call. - */ - public int lastIndex() { - return lastSi; - } - - /** - * @return The argument which is going to be returned from the next {@link #next()} call. - * @throws NoSuchElementException If {@link #hasNext()} == true! - */ - public int nextIndex() { - int next = getNextIndex(si); - if (next == NO_MORE_ARGS) { - throw new NoSuchElementException(); + suppliedIndex = 0; + while (suppliedIndex < suppliedNames.length && matchedSuppliedArgs[suppliedIndex]) { + suppliedIndex++; } - return next; - } - @Override - public boolean hasNext() { - return getNextIndex(si) != NO_MORE_ARGS; - } + if (suppliedIndex < suppliedNames.length) { + int leftoverCount = suppliedNames.length - cardinality(matchedSuppliedArgs); + if (leftoverCount == 1) { + if (isVarSuppliedVarargs.test(suppliedIndex)) { + return new MatchPermutation(resultPermutation, null, null); + } - private int getNextIndex(int from) { - if (from == NO_MORE_ARGS) { - return NO_MORE_ARGS; - } - int next = matchedSuppliedArgs.nextClearBit(from); - if (next == NO_MORE_ARGS || next >= suppliedArgs.length) { - return NO_MORE_ARGS; - } - return next; - } + // one unused argument + CompilerDirectives.transferToInterpreter(); + throw RError.error(callSrc, RError.Message.UNUSED_ARGUMENT, errorString.apply(suppliedIndex)); + } - @Override - public T next() { - int next = getNextIndex(si); - if (next == NO_MORE_ARGS) { - throw new NoSuchElementException(); + CompilerDirectives.transferToInterpreter(); + // multiple unused arguments + StringBuilder str = new StringBuilder(); + int cnt = 0; + for (; suppliedIndex < suppliedNames.length; suppliedIndex++) { + if (!matchedSuppliedArgs[suppliedIndex]) { + if (cnt++ > 0) { + str.append(", "); + } + str.append(errorString.apply(suppliedIndex)); + } + } + throw RError.error(callSrc, RError.Message.UNUSED_ARGUMENTS, str); } - lastSi = next; - si = getNextIndex(next + 1); - return suppliedArgs[lastSi]; + return new MatchPermutation(resultPermutation, null, null); } + } - @Override - public void remove() { - matchedSuppliedArgs.set(lastSi); + private static int cardinality(boolean[] array) { + int sum = 0; + for (boolean b : array) { + if (b) { + sum++; + } } + return sum; } /** * Searches for suppliedName inside formalNames and returns its (formal) index. * - * @param formalNames - * @param suppliedName - * @param matchedSuppliedArgs - * @param suppliedIndex - * @param hasVarArgs - * @param debugArgNode - * @param callSrc - * @param argsSrc - * @param varArgIndex - * @param forNextMethod - * * @return The position of the given suppliedName inside the formalNames. Throws errors if the * argument has been matched before */ - private static <T> int findParameterPosition(String[] formalNames, String suppliedName, BitSet matchedSuppliedArgs, int suppliedIndex, boolean hasVarArgs, T debugArgNode, SourceSection callSrc, - SourceSection argsSrc, int varArgIndex, boolean forNextMethod) { - int found = -1; + private static <T> int findParameterPosition(String[] formalNames, String suppliedName, int[] resultPermutation, int suppliedIndex, boolean hasVarArgs, SourceSection callSrc, + SourceSection argsSrc, int varArgIndex, boolean forNextMethod, IntFunction<String> errorString) { + int found = UNMATCHED; for (int i = 0; i < formalNames.length; i++) { if (formalNames[i] == null) { continue; } - final String formalName = formalNames[i]; + String formalName = formalNames[i]; if (formalName.equals(suppliedName)) { found = i; - if (matchedSuppliedArgs.get(found)) { + if (resultPermutation[found] != UNMATCHED) { // Has already been matched: Error! throw RError.error(argsSrc, RError.Message.FORMAL_MATCHED_MULTIPLE, formalName); } - matchedSuppliedArgs.set(found); break; } else if (!suppliedName.isEmpty() && formalName.startsWith(suppliedName) && ((varArgIndex != FormalArguments.NO_VARARG && i < varArgIndex) || varArgIndex == FormalArguments.NO_VARARG)) { // partial-match only if the formal argument is positioned before ... @@ -502,260 +514,57 @@ public class ArgumentMatcher { throw RError.error(argsSrc, RError.Message.ARGUMENT_MATCHES_MULTIPLE, 1 + suppliedIndex); } found = i; - if (matchedSuppliedArgs.get(found)) { + if (resultPermutation[found] != UNMATCHED) { throw RError.error(argsSrc, RError.Message.FORMAL_MATCHED_MULTIPLE, formalName); } - matchedSuppliedArgs.set(found); } } if (found >= 0 || hasVarArgs || forNextMethod) { return found; } - // Error! - String debugSrc = suppliedName; - if (debugArgNode instanceof RNode) { - SourceSection ss = ((RNode) debugArgNode).getSourceSection(); - if (ss != null && ss.getCode() != null) { - debugSrc = ((RNode) debugArgNode).getSourceSection().getCode(); - } - } - throw RError.error(callSrc, RError.Message.UNUSED_ARGUMENT, debugSrc); - } - - /** - * Walks a list of given arguments ({@link RNode}s) and wraps them in {@link PromiseNode}s - * individually by using promiseWrapper (unfolds varargs, too!) if necessary. - * - * @param function The function which is to be called - * @param arguments The arguments passed to the function call, already in correct order - * @param formals The {@link FormalArguments} for the given function - * @param promiseWrapper The {@link PromiseWrapper} implementation which handles the wrapping of - * individual arguments - * @param closureCache The {@link ClosureCache} for the supplied arguments - * @return A list of {@link RNode} wrapped in {@link PromiseNode}s - */ - @TruffleBoundary - private static RNode[] wrapInPromises(RFunction function, RNode[] arguments, FormalArguments formals, PromiseWrapper promiseWrapper, ClosureCache closureCache, SourceSection callSrc) { - RNode[] defaultArgs = formals.getDefaultArgs(); - RNode[] resArgs = arguments; - - // Check whether this is a builtin - RootNode rootNode = function.getTarget().getRootNode(); - final RBuiltinRootNode builtinRootNode = rootNode instanceof RBuiltinRootNode ? (RBuiltinRootNode) rootNode : null; - - // int logicalIndex = 0; As our builtin's 'evalsArgs' is meant for FastR arguments (which - // take "..." as one), we don't need a logicalIndex - for (int fi = 0; fi < arguments.length; fi++) { - RNode arg = arguments[fi]; // arg may be null, which denotes 'no arg supplied' - - // Has varargs? Unfold! - if (arg instanceof VarArgsAsObjectArrayNode) { - VarArgsAsObjectArrayNode varArgs = (VarArgsAsObjectArrayNode) arg; - int varArgsLen = varArgs.getArgumentNodes().length; - String[] newNames = varArgs.getNames() == null ? new String[varArgsLen] : Arrays.copyOf(varArgs.getNames(), varArgsLen); - RNode[] newVarArgs = Utils.resizeArray(varArgs.getArgumentNodes(), varArgsLen); - int index = 0; - for (int i = 0; i < varArgs.getArgumentNodes().length; i++) { - RNode varArg = varArgs.getArgumentNodes()[i]; - if (varArg == null) { - if (newNames[i] == null) { - // Skip all missing values (important for detection of emtpy "...", - // which consequently collapse - continue; - } else { - // But do not skip parameters ala "[...], builtins =, [...]" - varArg = ConstantNode.create(RMissing.instance); - } - } - newNames[index] = varArgs.getNames() == null ? null : varArgs.getNames()[i]; - newVarArgs[index] = varArg; - index++; - } - - // "Delete and shrink": Shrink only if necessary - int newLength = index; - if (newLength == 0) { - // Corner case: "f <- function(...) g(...); g <- function(...)" - // Insert correct "missing"! - resArgs[fi] = promiseWrapper.wrap(function, formals, builtinRootNode, closureCache, null, null, fi); - continue; - } - if (newNames.length > newLength) { - newNames = Arrays.copyOf(newNames, newLength); - newVarArgs = Arrays.copyOf(newVarArgs, newLength); - } - - EvalPolicy evalPolicy = promiseWrapper.getEvalPolicy(function, builtinRootNode, fi); - resArgs[fi] = PromiseNode.createVarArgs(varArgs.getSourceSection(), evalPolicy, newVarArgs, newNames, closureCache, callSrc); - } else { - // Normal argument: just wrap in promise - RNode defaultArg = fi < defaultArgs.length ? defaultArgs[fi] : null; - resArgs[fi] = promiseWrapper.wrap(function, formals, builtinRootNode, closureCache, arg, defaultArg, fi); - } - } - return resArgs; + throw RError.error(callSrc, RError.Message.UNUSED_ARGUMENT, errorString.apply(suppliedIndex)); } /** - * Interface for trading the cost of using reflection. - * - * <pre> - * Class<?> argClass = suppliedArgs.getClass().getComponentClass(); - * @SuppressWarning("unchecked") - * T[] resultArgs = (T[]) Array.newInstance(argClass, size) - * </pre> - * - * against a type safe virtual function call. - * - * @param <T> The component type of the arrays to be created + * @param builtinRootNode The {@link RBuiltinRootNode} of the function + * @param formalIndex The formalIndex of this argument + * @return A single suppliedArg and its corresponding defaultValue wrapped up into a + * {@link PromiseNode} */ - private interface ArrayFactory<T> { - /** - * @param length - * @return A fresh (type safe) array of type T - */ - T[] newArray(int length); - - /** - * @param arg - * @return Whether arg represents a <i>formal</i> "..." which carries no content - */ - default boolean isVararg(T arg) { - throw Utils.nyi("S3Dispatch should not have arg length mismatch!?"); - } - - /** - * @param arg - * @return Whether arg represents a missing argument - */ - default boolean isMissing(T arg) { - throw RInternalError.shouldNotReachHere(); - } - - /** - * @param args - * @return A {@link String} containing debug names of all given args - */ - String debugString(T[] args); - - @TruffleBoundary - default String debugString(T arg) { - T[] args = newArray(1); - args[0] = arg; - return debugString(args); - } - } - - /** - * {@link ArrayFactory} implementation for {@link RNode}. - */ - private static class RNodeArrayFactory implements ArrayFactory<RNode> { - public RNode[] newArray(int length) { - return new RNode[length]; - } - - @Override - public boolean isVararg(RNode arg) { - // Empty varargs get passed in as "...", and not unrolled. Thus we only have to check - // the RVNs name - String name = RMissingHelper.unwrapName(arg); - return name != null && ArgumentsTrait.isVarArg(name); - } - - @Override - public boolean isMissing(RNode arg) { - return false; - } - - @TruffleBoundary - public String debugString(RNode[] args) { - SourceSection src = Utils.sourceBoundingBox(args); - return String.valueOf(src); - } + public static EvalPolicy getEvalPolicy(RBuiltinRootNode builtinRootNode, int formalIndex) { + // This is for actual function calls. However, if the arguments are meant for a + // builtin, we have to consider whether they should be forced or not! + return builtinRootNode != null && builtinRootNode.evaluatesArg(formalIndex) ? EvalPolicy.INLINED : EvalPolicy.PROMISED; } /** - * {@link ArrayFactory} implementation for {@link Object}. + * @param formals {@link FormalArguments} as {@link ClosureCache} + * @param builtinRootNode The {@link RBuiltinRootNode} of the function + * @param closureCache {@link ClosureCache} + * @param suppliedArg The argument supplied for this parameter + * @param defaultValue The default value for this argument + * @param formalIndex The logicalIndex of this argument, also counting individual arguments in + * varargs + * @param isBuiltin + * @param noOpt + * @return Either suppliedArg or its defaultValue wrapped up into a {@link PromiseNode} (or + * {@link RMissing} in case neither is present! */ - private static class ObjectArrayFactory implements ArrayFactory<Object> { - public Object[] newArray(int length) { - return new Object[length]; - } - - @Override - public boolean isMissing(Object arg) { - return arg == RMissing.instance; - } - - @TruffleBoundary - public String debugString(Object[] args) { - StringBuilder b = new StringBuilder(); - for (int i = 0; i < args.length; i++) { - b.append(String.valueOf(args[i])); - if (i != args.length - 1) { - b.append(", "); - } - } - return b.toString(); - } - } - - /** - * This interface was introduced to reuse - * {@link ArgumentMatcher#wrapInPromises(RFunction, RNode[], FormalArguments, PromiseWrapper, ClosureCache, SourceSection)} - * and encapsulates the wrapping of a single argument into a {@link PromiseNode}. - */ - private interface PromiseWrapper { - /** - * @param function the {@link RFunction} being called - * @param builtinRootNode The {@link RBuiltinRootNode} of the function - * @param formalIndex The formalIndex of this argument - * @return A single suppliedArg and its corresponding defaultValue wrapped up into a - * {@link PromiseNode} - */ - EvalPolicy getEvalPolicy(RFunction function, RBuiltinRootNode builtinRootNode, int formalIndex); - - /** - * @param function The function this argument is wrapped for - * @param formals {@link FormalArguments} as {@link ClosureCache} - * @param builtinRootNode The {@link RBuiltinRootNode} of the function - * @param closureCache {@link ClosureCache} - * @param suppliedArg The argument supplied for this parameter - * @param defaultValue The default value for this argument - * @param formalIndex The logicalIndex of this argument, also counting individual arguments - * in varargs - * @return Either suppliedArg or its defaultValue wrapped up into a {@link PromiseNode} (or - * {@link RMissing} in case neither is present! - */ - RNode wrap(RFunction function, FormalArguments formals, RBuiltinRootNode builtinRootNode, ClosureCache closureCache, RNode suppliedArg, RNode defaultValue, int formalIndex); - } - - /** - * {@link PromiseWrapper} implementation for 'normal' function calls. - */ - private static class DefaultPromiseWrapper implements PromiseWrapper { - - private final boolean noOpt; - - public DefaultPromiseWrapper(boolean noOpt) { - this.noOpt = noOpt; - } - - public EvalPolicy getEvalPolicy(RFunction function, RBuiltinRootNode builtinRootNode, int formalIndex) { - // This is for actual function calls. However, if the arguments are meant for a builtin, - // we have to consider whether they should be forced or not! - return builtinRootNode != null && builtinRootNode.evaluatesArg(formalIndex) ? EvalPolicy.INLINED : EvalPolicy.PROMISED; - } - - @TruffleBoundary - public RNode wrap(RFunction function, FormalArguments formals, RBuiltinRootNode builtinRootNode, ClosureCache closureCache, RNode suppliedArg, RNode defaultValue, int formalIndex) { - // Determine whether to choose supplied argument or default value - RNode expr = null; - PromiseType promiseType = null; - if (suppliedArg != null) { - // Supplied arg - expr = suppliedArg; - promiseType = PromiseType.ARG_SUPPLIED; + @TruffleBoundary + public static RNode wrap(FormalArguments formals, RBuiltinRootNode builtinRootNode, ClosureCache closureCache, RNode suppliedArg, RNode defaultValue, int formalIndex, boolean isBuiltin, + boolean noOpt) { + // Determine whether to choose supplied argument or default value + RNode expr = null; + PromiseType promiseType = null; + if (suppliedArg != null) { + // Supplied arg + expr = suppliedArg; + promiseType = PromiseType.ARG_SUPPLIED; + } else { + // Default value + if (isBuiltin && defaultValue != null) { + expr = defaultValue; + promiseType = PromiseType.ARG_DEFAULT; } else { if (formals.getVarArgIndex() == formalIndex) { // "...", but empty @@ -765,170 +574,12 @@ public class ArgumentMatcher { return ConstantNode.create(RMissing.instance); } } - - // Create promise - EvalPolicy evalPolicy = getEvalPolicy(function, builtinRootNode, formalIndex); - Closure closure = closureCache.getOrCreateClosure(expr); - Closure defaultClosure = formals.getOrCreateClosure(defaultValue); - return PromiseNode.create(expr.getSourceSection(), RPromiseFactory.create(evalPolicy, promiseType, closure, defaultClosure), noOpt); - } - } - - /** - * {@link PromiseWrapper} implementation for arguments that are going to be used for 'inlined' - * builtins. - * - * @see RBuiltinRootNode#inline(InlinedArguments) - */ - private static class BuiltinInitPromiseWrapper implements PromiseWrapper { - - private final boolean noOpt; - - public BuiltinInitPromiseWrapper(boolean noOpt) { - this.noOpt = noOpt; - } - - public EvalPolicy getEvalPolicy(RFunction function, RBuiltinRootNode builtinRootNode, int formalIndex) { - // This is used for arguments that are going inlined for builtins - return !builtinRootNode.evaluatesArg(formalIndex) ? EvalPolicy.PROMISED : EvalPolicy.INLINED; - } - - /** - * @param function The function this argument is wrapped for - * @param formals {@link FormalArguments} as {@link ClosureCache} - * @param builtinRootNode The {@link RBuiltinRootNode} of the function - * @param closureCache {@link ClosureCache} - * @param suppliedArg The argument supplied for this parameter - * @param defaultValue The default value for this argument - * @param formalIndex The logicalIndex of this argument, also counting individual arguments - * in varargs - * @return Either suppliedArg or its defaultValue wrapped up into a {@link PromiseNode} (or - * {@link RMissing} in case neither is present! - */ - @TruffleBoundary - public RNode wrap(RFunction function, FormalArguments formals, RBuiltinRootNode builtinRootNode, ClosureCache closureCache, RNode suppliedArg, RNode defaultValue, int formalIndex) { - // Determine whether to choose supplied argument or default value - RNode expr = null; - PromiseType promiseType = null; - if (suppliedArg != null) { - // Supplied arg - expr = suppliedArg; - promiseType = PromiseType.ARG_SUPPLIED; - } else { - // Default value - if (defaultValue != null) { - expr = defaultValue; - promiseType = PromiseType.ARG_DEFAULT; - } else { - if (formals.getVarArgIndex() == formalIndex) { - // "...", but empty - return ConstantNode.create(RArgsValuesAndNames.EMPTY); - } else { - // In this case, we simply return RMissing (like R) - return ConstantNode.create(RMissing.instance); - } - } - } - - // Create promise - EvalPolicy evalPolicy = getEvalPolicy(function, builtinRootNode, formalIndex); - Closure closure = closureCache.getOrCreateClosure(expr); - Closure defaultClosure = formals.getOrCreateClosure(defaultValue); - return PromiseNode.create(expr.getSourceSection(), RPromiseFactory.create(evalPolicy, promiseType, closure, defaultClosure), noOpt); } - } - /** - * Abstraction for the generation of varargs. - * - * @param <T> The type of the resulting vararg - */ - public interface VarArgsFactory<T> { - T makeList(T[] elements, String[] names); - } - - /** - * {@link VarArgsFactory} implementation that returns varargs as <code>Object[]</code>. - * - */ - public static final class VarArgsAsObjectArrayFactory implements VarArgsFactory<Object> { - /** - * The call of {@link #nonNull} and the assertion in the "else" clause prevents the creation - * of an {@link RArgsValuesAndNames} containing any {@code null} values. Experimentally, - * only length 1 arrays ever contain {@code null} (from the conversion of {@link RMissing} - * into {@code null} in {@link S3DispatchNode#addArg}). Should this ever change perhaps - * these should be turned back into {@link RMissing}. Ideally, this invariant should be - * enforced by the caller(s). - */ - public Object makeList(Object[] elements, String[] names) { - if (elements.length > 0 && nonNull(elements)) { - return new RArgsValuesAndNames(elements, names); - } else { - assert elements.length == 0 || elements.length == 1; - return RArgsValuesAndNames.EMPTY; // RMissing.instance; - } - } - - private static boolean nonNull(Object[] elements) { - for (int i = 0; i < elements.length; i++) { - if (elements[i] == null) { - return false; - } - } - return true; - } - } - - /** - * A {@link RNode} that encapsulates a list of varargs (as {@link RNode}). - */ - public abstract static class VarArgsNode extends RNode { - @Children protected final RNode[] elementNodes; - - protected VarArgsNode(RNode[] elements) { - elementNodes = elements; - } - - public final RNode[] getArgumentNodes() { - return elementNodes; - } - } - - /** - * {@link VarArgsFactory} implementation that returns varargs as - * {@link VarArgsAsObjectArrayNode}. - */ - public static final class VarArgsAsObjectArrayNodeFactory implements VarArgsFactory<RNode> { - public RNode makeList(RNode[] elements, String[] names) { - if (elements.length > 0) { - return new VarArgsAsObjectArrayNode(elements, names); - } else { - // STRICT: This has to be revised! - return null; // ConstantNode.create(RMissing.instance); - } - } - } - - /** - * {@link VarArgsNode} that executes all its elements and returns the resulting value array. - */ - public static final class VarArgsAsObjectArrayNode extends VarArgsNode { - private String[] names; - - public VarArgsAsObjectArrayNode(RNode[] elements, String[] names) { - super(elements); - this.names = names; - } - - public String[] getNames() { - return names; - } - - @Override - @Deprecated - public Object execute(VirtualFrame frame) { - // Simple container - throw new UnsupportedOperationException(); - } + // Create promise + EvalPolicy evalPolicy = getEvalPolicy(builtinRootNode, formalIndex); + Closure closure = closureCache.getOrCreateClosure(expr); + Closure defaultClosure = formals.getOrCreateClosure(defaultValue); + return PromiseNode.create(expr.getSourceSection(), RPromiseFactory.create(evalPolicy, promiseType, closure, defaultClosure), noOpt); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentsTrait.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentsTrait.java index ce15734730b70bb3126b8fe4e3852bc29c1b90e7..43f101bb98306be41a9f9f1b0ef52e91b46d6833 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentsTrait.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentsTrait.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -95,7 +95,7 @@ public interface ArgumentsTrait { } static boolean isVarArg(String name) { - return name.equals(VARARG_NAME); + return name != null && name.equals(VARARG_NAME); } static boolean isVarArgGetter(String name) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchNode.java index a7fdfd52c5ae50b5584118911fbad77e45267725..72a5c3c29b3390fd41080f2f6ecbb629c6ad99d5 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchNode.java @@ -35,10 +35,10 @@ public abstract class DispatchNode extends RNode { } } - public abstract Object execute(VirtualFrame frame, RStringVector aType); + public abstract Object executeGeneric(VirtualFrame frame, RStringVector aType); @SuppressWarnings("unused") - public Object executeInternal(VirtualFrame frame, RStringVector aType, Object[] args) { + public Object executeInternalGeneric(VirtualFrame frame, RStringVector aType, Object[] args) { throw RInternalError.shouldNotReachHere(); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchedCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchedCallNode.java index 18a5d781b7d77f74fcedb8fe2ed15d9a8bfed23b..69b3825e07b5ce228aa7263026cb6a066a616a78 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchedCallNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/DispatchedCallNode.java @@ -103,15 +103,14 @@ public abstract class DispatchedCallNode extends RNode { private DispatchedCallNode specialize(RStringVector type) { CompilerAsserts.neverPartOfCompilation(); if (depth < INLINE_CACHE_SIZE) { - final DispatchNode current = createCurrentNode(type); - final DispatchedCallNode cachedNode = new CachedNode(current, new UninitializedDispatchedCallNode(this, this.depth + 1), type); - this.replace(cachedNode); - return cachedNode; + DispatchNode current = createCurrentNode(type); + return replace(new CachedNode(current, new UninitializedDispatchedCallNode(this, depth + 1), type)); } + RError.performanceWarning("S3 method dispatch fallback to generic"); return this.replace(new GenericDispatchNode(createCurrentNode(type))); } - protected DispatchNode createCurrentNode(RStringVector type) { + private DispatchNode createCurrentNode(RStringVector type) { switch (dispatchType) { case NextMethod: return new NextMethodDispatchNode(genericName, type, args, argNames, enclosingName); @@ -133,12 +132,12 @@ public abstract class DispatchedCallNode extends RNode { @Override public Object execute(VirtualFrame frame, RStringVector type) { - return dcn.execute(frame, type); + return dcn.executeGeneric(frame, type); } @Override public Object executeInternal(VirtualFrame frame, RStringVector type, Object[] args) { - return dcn.executeInternal(frame, type, args); + return dcn.executeInternalGeneric(frame, type, args); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java index 8ef7c3318313e02082e332746e47d598f1a3fbbb..2a81a8e002ee0ce3c70b347e4549040fa6c05e37 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java @@ -25,7 +25,7 @@ package com.oracle.truffle.r.nodes.function; import java.util.*; import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.CompilerDirectives.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.source.*; @@ -50,6 +50,15 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo @Child private InlineCacheNode<VirtualFrame, RNode> onExitExpressionCache; private final ConditionProfile onExitProfile = ConditionProfile.createBinaryProfile(); + private final ConditionProfile s3SlotsProfile = ConditionProfile.createBinaryProfile(); + @CompilationFinal private BranchProfile invalidateFrameSlotProfile; + @Child private FrameSlotNode dotGenericSlot; + @Child private FrameSlotNode dotMethodSlot; + @Child private FrameSlotNode dotClassSlot; + @Child private FrameSlotNode dotGenericCallEnvSlot; + @Child private FrameSlotNode dotGenericCallDefSlot; + @Child private FrameSlotNode dotGroupSlot; + /** * An instance of this node may be called from with the intention to have its execution leave a * footprint behind in a specific frame/environment, e.g., during library loading, commands from @@ -105,6 +114,9 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo VirtualFrame vf = substituteFrame ? (VirtualFrame) frame.getArguments()[0] : frame; try { verifyEnclosingAssumptions(vf); + if (s3SlotsProfile.profile(RArguments.hasS3Args(vf))) { + setupS3Slots(vf); + } return body.execute(vf); } catch (ReturnException ex) { returnProfile.enter(); @@ -130,6 +142,26 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo } } + private void setupS3Slots(VirtualFrame frame) { + if (dotGenericSlot == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + assert invalidateFrameSlotProfile == null && dotMethodSlot == null && dotClassSlot == null && dotGenericCallEnvSlot == null && dotGenericCallDefSlot == null && dotGroupSlot == null; + invalidateFrameSlotProfile = BranchProfile.create(); + dotGenericSlot = insert(FrameSlotNode.create(RRuntime.RDotGeneric, true)); + dotMethodSlot = insert(FrameSlotNode.create(RRuntime.RDotMethod, true)); + dotClassSlot = insert(FrameSlotNode.create(RRuntime.RDotClass, true)); + dotGenericCallEnvSlot = insert(FrameSlotNode.create(RRuntime.RDotGenericCallEnv, true)); + dotGenericCallDefSlot = insert(FrameSlotNode.create(RRuntime.RDotGenericDefEnv, true)); + dotGroupSlot = insert(FrameSlotNode.create(RRuntime.RDotGroup, true)); + } + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericSlot.executeFrameSlot(frame), RArguments.getS3Generic(frame), false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodSlot.executeFrameSlot(frame), RArguments.getS3Method(frame), false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotClassSlot.executeFrameSlot(frame), RArguments.getS3Class(frame), false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallEnvSlot.executeFrameSlot(frame), RArguments.getS3CallEnv(frame), false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallDefSlot.executeFrameSlot(frame), RArguments.getS3DefEnv(frame), false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGroupSlot.executeFrameSlot(frame), RArguments.getS3Group(frame), false, invalidateFrameSlotProfile); + } + @SuppressWarnings("unchecked") private static ArrayList<Object> getCurrentOnExitList(VirtualFrame frame, FrameSlot slot) { try { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java index 4186e79886227a42547281628f4a3ae73f5fd3e2..06b4de13d045b951f10f121badbd6d04cc7d3306 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java @@ -24,7 +24,10 @@ package com.oracle.truffle.r.nodes.function; import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter; import com.oracle.truffle.r.nodes.*; +import com.oracle.truffle.r.nodes.access.variables.*; import com.oracle.truffle.r.nodes.function.PromiseHelperNode.*; import com.oracle.truffle.r.nodes.function.opt.*; import com.oracle.truffle.r.nodes.instrument.*; @@ -32,85 +35,66 @@ import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.data.*; import com.oracle.truffle.r.runtime.env.*; -public abstract class FunctionExpressionNode extends RNode { - - @Override - public final RFunction execute(VirtualFrame frame) { - return executeFunction(frame); - } - - @Override - public abstract RFunction executeFunction(VirtualFrame frame); - - public static FunctionExpressionNode create(RFunction function) { - return new StaticFunctionExpressionNode(function); - } +public final class FunctionExpressionNode extends RNode { public static FunctionExpressionNode create(RootCallTarget callTarget) { - return new DynamicFunctionExpressionNode(callTarget); + return new FunctionExpressionNode(callTarget); } - public static final class StaticFunctionExpressionNode extends FunctionExpressionNode { + private final RootCallTarget callTarget; + private final PromiseDeoptimizeFrameNode deoptFrameNode; + private final boolean containsDispatch; - private final RFunction function; + public FunctionExpressionNode(RootCallTarget callTarget) { + this.callTarget = callTarget; + this.deoptFrameNode = EagerEvalHelper.optExprs() || EagerEvalHelper.optVars() ? new PromiseDeoptimizeFrameNode() : null; - public StaticFunctionExpressionNode(RFunction function) { - // TODO DEOPT needed here? - this.function = function; - } - - @Override - public RFunction executeFunction(VirtualFrame frame) { - return function; - } - - public RFunction getFunction() { - return function; - } + NodeCountFilter dispatchingMethodsFilter = node -> { + if (node instanceof ReadVariableNode) { + String identifier = ((ReadVariableNode) node).getIdentifier(); + return "UseMethod".equals(identifier) || "NextMethod".equals(identifier); + } + return false; + }; + this.containsDispatch = NodeUtil.countNodes(callTarget.getRootNode(), dispatchingMethodsFilter) > 0; } - public static final class DynamicFunctionExpressionNode extends FunctionExpressionNode { - - private final RootCallTarget callTarget; - private final PromiseDeoptimizeFrameNode deoptFrameNode; + @Override + public RFunction execute(VirtualFrame frame) { + return executeFunction(frame); + } - public DynamicFunctionExpressionNode(RootCallTarget callTarget) { - this.callTarget = callTarget; - this.deoptFrameNode = EagerEvalHelper.optExprs() || EagerEvalHelper.optVars() ? new PromiseDeoptimizeFrameNode() : null; + @Override + public RFunction executeFunction(VirtualFrame frame) { + MaterializedFrame matFrame = frame.materialize(); + if (deoptFrameNode != null) { + // Deoptimize every promise which is now in this frame, as it might leave it's stack + deoptFrameNode.deoptimizeFrame(matFrame); } - - @Override - public RFunction executeFunction(VirtualFrame frame) { - MaterializedFrame matFrame = frame.materialize(); - if (deoptFrameNode != null) { - // Deoptimize every promise which is now in this frame, as it might leave it's stack - deoptFrameNode.deoptimizeFrame(matFrame); - } - RFunction func = RDataFactory.createFunction("", callTarget, matFrame); - if (RInstrument.instrumentingEnabled()) { - RInstrument.checkDebugRequested(callTarget.toString(), func); - } - return func; + RFunction func = RDataFactory.createFunction("", callTarget, matFrame, containsDispatch); + if (RInstrument.instrumentingEnabled()) { + RInstrument.checkDebugRequested(callTarget.toString(), func); } + return func; + } - public RootCallTarget getCallTarget() { - return callTarget; - } + public RootCallTarget getCallTarget() { + return callTarget; + } - @Override - public boolean isSyntax() { - return true; - } + @Override + public boolean isSyntax() { + return true; + } - @Override - public void deparse(State state) { - ((FunctionDefinitionNode) callTarget.getRootNode()).deparse(state); - } + @Override + public void deparse(State state) { + ((FunctionDefinitionNode) callTarget.getRootNode()).deparse(state); + } - @Override - public RNode substitute(REnvironment env) { - FunctionDefinitionNode fdn = ((FunctionDefinitionNode) callTarget.getRootNode()).substituteFDN(env); - return new DynamicFunctionExpressionNode(Truffle.getRuntime().createCallTarget(fdn)); - } + @Override + public RNode substitute(REnvironment env) { + FunctionDefinitionNode fdn = ((FunctionDefinitionNode) callTarget.getRootNode()).substituteFDN(env); + return new FunctionExpressionNode(Truffle.getRuntime().createCallTarget(fdn)); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchCallNode.java index bbea2c08f5402f0ba98a5da3d4a83f6d2b1257b9..9844957a5770ce89f23085cb98eddb75bc910481 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchCallNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchCallNode.java @@ -26,7 +26,6 @@ import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.data.*; import com.oracle.truffle.r.runtime.data.model.*; import com.oracle.truffle.r.runtime.env.*; -import com.oracle.truffle.r.runtime.env.frame.*; import edu.umd.cs.findbugs.annotations.*; @@ -75,7 +74,7 @@ public abstract class GroupDispatchCallNode extends RNode { @Override public void deparse(State state) { - String name = this.getGenericName(); + String name = getGenericName(); RDeparse.Func func = RDeparse.getFunc(name); if (func != null) { // infix operator @@ -98,14 +97,14 @@ public abstract class GroupDispatchCallNode extends RNode { @CompilationFinal private final String genericName; private final int depth; - public UninitializedGroupDispatchCallNode(final String aGenericName, final String groupName, final CallArgumentsNode callArgNode) { + public UninitializedGroupDispatchCallNode(String aGenericName, String groupName, CallArgumentsNode callArgNode) { this.genericName = aGenericName; this.groupName = groupName; this.callArgsNode = callArgNode; this.depth = 0; } - private UninitializedGroupDispatchCallNode(final UninitializedGroupDispatchCallNode copy, final int depth) { + private UninitializedGroupDispatchCallNode(UninitializedGroupDispatchCallNode copy, int depth) { this.genericName = copy.genericName; this.groupName = copy.groupName; this.callArgsNode = copy.callArgsNode; @@ -137,7 +136,7 @@ public abstract class GroupDispatchCallNode extends RNode { return this.replace(new GenericDispatchNode(createGenericNode(argAndNames.getValues()))); } - private GroupDispatchNode createGenericNode(final Object[] evaluatedArgs) { + private GroupDispatchNode createGenericNode(Object[] evaluatedArgs) { if (this.groupName == RGroupGenerics.GROUP_OPS) { if (evaluatedArgs.length == 1) { return new GenericUnaryOpsGroupDispatchNode(this.genericName, this.callArgsNode.containsVarArgsSymbol(), this.getSourceSection(), this.callArgsNode.getEncapsulatingSourceSection()); @@ -157,7 +156,7 @@ public abstract class GroupDispatchCallNode extends RNode { } @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "GROUP_OPS is intended to be used as an identity") - protected GroupDispatchNode createCurrentNode(final Object[] evaluatedArgs) { + protected GroupDispatchNode createCurrentNode(Object[] evaluatedArgs) { if (this.groupName == RGroupGenerics.GROUP_OPS) { if (evaluatedArgs.length == 1) { return new UnaryOpsGroupDispatchNode(this.genericName, this.callArgsNode.containsVarArgsSymbol(), this.getSourceSection(), this.callArgsNode.getEncapsulatingSourceSection()); @@ -190,7 +189,7 @@ public abstract class GroupDispatchCallNode extends RNode { @Child private GroupDispatchCallNode nextNode; @Child private GroupDispatchNode currentNode; - CachedNode(final GroupDispatchNode currentNode, final GroupDispatchCallNode nextNode, final CallArgumentsNode callArgsNode) { + CachedNode(final GroupDispatchNode currentNode, GroupDispatchCallNode nextNode, CallArgumentsNode callArgsNode) { this.nextNode = nextNode; this.currentNode = currentNode; this.callArgsNode = callArgsNode; @@ -206,7 +205,7 @@ public abstract class GroupDispatchCallNode extends RNode { } @Override - public Object execute(VirtualFrame frame, final RArgsValuesAndNames argAndNames) { + public Object execute(VirtualFrame frame, RArgsValuesAndNames argAndNames) { if (currentNode.isSameType(argAndNames.getValues())) { return currentNode.execute(frame, argAndNames); } @@ -238,7 +237,7 @@ public abstract class GroupDispatchCallNode extends RNode { } @Override - public Object execute(VirtualFrame frame, final RArgsValuesAndNames argAndNames) { + public Object execute(VirtualFrame frame, RArgsValuesAndNames argAndNames) { return gdn.execute(frame, argAndNames); } @@ -273,7 +272,7 @@ class GroupDispatchNode extends S3DispatchNode { protected final SourceSection argSrc; @Override - public Object execute(VirtualFrame frame, RStringVector aType) { + public Object executeGeneric(VirtualFrame frame, RStringVector aType) { throw new AssertionError(); } @@ -303,7 +302,7 @@ class GroupDispatchNode extends S3DispatchNode { } protected void findTargetFunction(VirtualFrame frame) { - final String[] prefix = {genericName, groupName}; + String[] prefix = {genericName, groupName}; for (int i = 0; i < this.type.getLength(); ++i) { for (int j = 0; j < prefix.length; ++j) { findFunction(prefix[j], this.type.getDataAt(i), frame); @@ -328,7 +327,7 @@ class GroupDispatchNode extends S3DispatchNode { } } - public Object execute(VirtualFrame frame, final RArgsValuesAndNames argAndNames) { + public Object execute(VirtualFrame frame, RArgsValuesAndNames argAndNames) { Object[] evaluatedArgs = argAndNames.getValues(); String[] argNames = argAndNames.getNames(); if (!isExecuted) { @@ -348,33 +347,22 @@ class GroupDispatchNode extends S3DispatchNode { return executeHelper(frame, evaluatedArgs, argNames); } - protected Object callBuiltin(VirtualFrame frame, final Object[] evaluatedArgs, final String[] argNames) { + protected Object callBuiltin(VirtualFrame frame, Object[] evaluatedArgs, String[] argNames) { initBuiltin(frame); EvaluatedArguments reorderedArgs = reorderArgs(frame, builtinFunc, evaluatedArgs, argNames, this.hasVararg, this.callSrc); - Object[] argObject = RArguments.create(builtinFunc, this.callSrc, RArguments.getDepth(frame), reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); + Object[] argObject = RArguments.create(builtinFunc, this.callSrc, null, RArguments.getDepth(frame), reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); indirectCallNode.assignSourceSection(this.callSrc); return indirectCallNode.call(frame, builtinFunc.getTarget(), argObject); } - protected Object executeHelper(VirtualFrame frame, final Object[] evaluatedArgs, final String[] argNames) { + protected Object executeHelper(VirtualFrame frame, Object[] evaluatedArgs, String[] argNames) { EvaluatedArguments reorderedArgs = reorderArgs(frame, targetFunction, evaluatedArgs, argNames, this.hasVararg, this.callSrc); - Object[] argObject = RArguments.createS3Args(targetFunction, this.callSrc, RArguments.getDepth(frame) + 1, reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); - // todo: cannot create frame descriptors in compiled code - FrameDescriptor s3VarDefFrameDescriptor = new FrameDescriptor(); - FrameSlotChangeMonitor.initializeFrameDescriptor(s3VarDefFrameDescriptor, true); - VirtualFrame s3VarDefFrame = Truffle.getRuntime().createVirtualFrame(RArguments.create(null, null, RArguments.getDepth(frame) + 1), s3VarDefFrameDescriptor); - // todo: cannot create frame descriptors in compiled code - FrameDescriptor argFrameDescriptor = new FrameDescriptor(); - FrameSlotChangeMonitor.initializeFrameDescriptor(argFrameDescriptor, true); - VirtualFrame argFrame = Truffle.getRuntime().createVirtualFrame(argObject, argFrameDescriptor); - genCallEnv = frame; - defineVarsAsArguments(argFrame); - defineVarsInFrame(s3VarDefFrame); - wvnMethod = defineVarInFrame(s3VarDefFrame, wvnMethod, RRuntime.RDotMethod, dotMethod); - RArguments.setS3Method(argFrame, targetFunctionName); + Object[] argObject = RArguments.createS3Args(targetFunction, this.callSrc, null, RArguments.getDepth(frame) + 1, reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); + genCallEnv = frame.materialize(); + defineVarsAsArguments(argObject); + RArguments.setS3Method(argObject, dotMethod); if (writeGroup) { - wvnGroup = defineVarInFrame(s3VarDefFrame, wvnGroup, RRuntime.RDotGroup, groupName); - RArguments.setS3Group(argFrame, groupName); + RArguments.setS3Group(argObject, groupName); } indirectCallNode.assignSourceSection(this.callSrc); /* @@ -385,15 +373,7 @@ class GroupDispatchNode extends S3DispatchNode { * s3VarDefFrame. After the function returns reset the enclosing frame of the target * function. */ - MaterializedFrame enclosingFrame = targetFunction.getEnclosingFrame(); - MaterializedFrame mFrame = s3VarDefFrame.materialize(); - RArguments.setEnclosingFrame(mFrame, enclosingFrame); - targetFunction.setEnclosingFrame(mFrame); Object result = indirectCallNode.call(frame, targetFunction.getTarget(), argObject); - targetFunction.setEnclosingFrame(enclosingFrame); - RArguments.setEnclosingFrame(mFrame, null); - removeVars(mFrame); - removeVar(mFrame.getFrameDescriptor(), RRuntime.RDotGroup); return result; } @@ -412,12 +392,12 @@ class GroupDispatchNode extends S3DispatchNode { class GenericGroupDispatchNode extends GroupDispatchNode { - protected GenericGroupDispatchNode(String aGenericName, String groupName, final boolean hasVarArg, SourceSection callSrc, SourceSection argSrc) { + protected GenericGroupDispatchNode(String aGenericName, String groupName, boolean hasVarArg, SourceSection callSrc, SourceSection argSrc) { super(aGenericName, groupName, hasVarArg, callSrc, argSrc); } @Override - public Object execute(VirtualFrame frame, final RArgsValuesAndNames argAndNames) { + public Object execute(VirtualFrame frame, RArgsValuesAndNames argAndNames) { Object[] evaluatedArgs = argAndNames.getValues(); String[] argNames = argAndNames.getNames(); this.type = getArgClass(evaluatedArgs[0]); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/NextMethodDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/NextMethodDispatchNode.java index f4c68606fa1d3afce1c047c7199629c62d07230b..700cccf3bd9beb3b849605bd3533325047c06f6c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/NextMethodDispatchNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/NextMethodDispatchNode.java @@ -14,13 +14,11 @@ package com.oracle.truffle.r.nodes.function; import java.util.*; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.r.nodes.access.*; import com.oracle.truffle.r.nodes.access.variables.*; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.*; -import com.oracle.truffle.r.runtime.env.frame.*; public class NextMethodDispatchNode extends S3DispatchNode { @@ -59,7 +57,7 @@ public class NextMethodDispatchNode extends S3DispatchNode { } @Override - public Object execute(VirtualFrame frame, final RStringVector aType) { + public Object executeGeneric(VirtualFrame frame, RStringVector aType) { readGenericVars(frame); findTargetFunction(frame); storeValues(); @@ -132,19 +130,15 @@ public class NextMethodDispatchNode extends S3DispatchNode { private Object executeHelper(VirtualFrame frame) { EvaluatedArguments evaledArgs = processArgs(frame); - Object[] argObject = RArguments.createS3Args(targetFunction, getSourceSection(), RArguments.getDepth(frame) + 1, evaledArgs.getEvaluatedArgs(), evaledArgs.getNames()); - // todo: cannot create frame descriptors in compiled code - FrameDescriptor frameDescriptor = new FrameDescriptor(); - FrameSlotChangeMonitor.initializeFrameDescriptor(frameDescriptor, true); - final VirtualFrame newFrame = Truffle.getRuntime().createVirtualFrame(argObject, frameDescriptor); - defineVarsAsArguments(newFrame); + Object[] argObject = RArguments.createS3Args(targetFunction, getSourceSection(), null, RArguments.getDepth(frame) + 1, evaledArgs.getEvaluatedArgs(), evaledArgs.getNames()); + defineVarsAsArguments(argObject); if (storedFunctionName != null) { - RArguments.setS3Method(newFrame, storedFunctionName); + RArguments.setS3Method(argObject, storedFunctionName); } else { - RArguments.setS3Method(newFrame, targetFunctionName); + RArguments.setS3Method(argObject, targetFunctionName); } if (hasGroup) { - RArguments.setS3Group(newFrame, this.group); + RArguments.setS3Group(argObject, this.group); } return indirectCallNode.call(frame, targetFunction.getTarget(), argObject); } @@ -221,7 +215,16 @@ public class NextMethodDispatchNode extends S3DispatchNode { } else { handlePresentGroup(); } - String functionName = RArguments.getS3Method(frame); + + Object method = RArguments.getS3Method(frame); + String functionName; + if (method == null) { + functionName = null; + } else if (method instanceof String) { + functionName = (String) method; + } else { + functionName = ((RStringVector) method).getDataAt(0); + } if (functionName != null) { storedFunctionName = functionName; } 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 6f5d84e26facd2505cf0e6f8ef0b624797b5578c..1bc8944bdcd34344ac357dcac0615b4e4239dee9 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 @@ -23,6 +23,7 @@ package com.oracle.truffle.r.nodes.function; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; @@ -78,13 +79,13 @@ import com.oracle.truffle.r.runtime.env.*; * U = {@link UninitializedCallNode}: Forms the uninitialized end of the function PIC * D = {@link DispatchedCallNode}: Function fixed, no varargs * G = {@link GenericCallNode}: Function arbitrary, no varargs (generic case) - * + * * 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) * GV = {@link GenericVarArgsCallNode}: Function arbitrary, with arbitrary varargs (generic case) - * + * * (RB = {@link RBuiltinNode}: individual functions that are builtins are represented by this node * which is not aware of caching). Due to {@link CachedCallNode} (see below) this is transparent to * the cache and just behaves like a D/DGV) @@ -97,11 +98,11 @@ import com.oracle.truffle.r.runtime.env.*; * 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 @@ -109,7 +110,7 @@ import com.oracle.truffle.r.runtime.env.*; * DV * | * UVC <- varargs signature level cache - * + * * varargs, max varargs depth exceeded: * | * DV-DV-UV @@ -121,7 +122,7 @@ import com.oracle.truffle.r.runtime.env.*; * DV * | * DGV - * + * * varargs, max function depth exceeded: * | * DV-DV-DV-DV-GV @@ -581,14 +582,25 @@ public abstract class RCallNode extends RNode { @Child private DirectCallNode call; @Child private MatchedArgumentsNode matchedArgs; + private final boolean needsCallerFrame; + @CompilationFinal private boolean needsSplitting; + DispatchedCallNode(RFunction function, MatchedArguments matchedArgs) { this.matchedArgs = matchedArgs.createNode(); this.call = Truffle.getRuntime().createDirectCallNode(function.getTarget()); + this.needsCallerFrame = function.containsDispatch(); + this.needsSplitting = function.containsDispatch(); } @Override public Object execute(VirtualFrame frame, RFunction currentFunction) { - Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), RArguments.getDepth(frame) + 1, matchedArgs.executeArray(frame), matchedArgs.getNames()); + if (needsSplitting) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + needsSplitting = false; + call.cloneCallTarget(); + } + MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; + Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), callerFrame, RArguments.getDepth(frame) + 1, matchedArgs.executeArray(frame), matchedArgs.getNames()); return call.call(frame, argsObject); } @@ -620,7 +632,7 @@ public abstract class RCallNode extends RNode { if (lastCallTarget == currentFunction.getTarget() && lastMatchedArgs != null) { // poor man's caching succeeded - same function: no re-match needed - Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), RArguments.getDepth(frame) + 1, lastMatchedArgs.doExecuteArray(frame), lastMatchedArgs.getNames()); + Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), null, RArguments.getDepth(frame) + 1, lastMatchedArgs.doExecuteArray(frame), lastMatchedArgs.getNames()); return indirectCall.call(frame, currentFunction.getTarget(), argsObject); } @@ -628,7 +640,7 @@ public abstract class RCallNode extends RNode { this.lastMatchedArgs = matchedArgs; this.lastCallTarget = currentFunction.getTarget(); - Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), RArguments.getDepth(frame) + 1, matchedArgs.doExecuteArray(frame), matchedArgs.getNames()); + Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), null, RArguments.getDepth(frame) + 1, matchedArgs.doExecuteArray(frame), matchedArgs.getNames()); return indirectCall.call(frame, currentFunction.getTarget(), argsObject); } } @@ -700,6 +712,8 @@ public abstract class RCallNode extends RNode { @Child private MatchedArgumentsNode matchedArgs; private final VarArgsSignature cachedSignature; + private final boolean needsCallerFrame; + @CompilationFinal private boolean needsSplitting; /** * Whether this [DV] node is the root of the varargs sub-cache (cmp. {@link RCallNode}) @@ -719,6 +733,12 @@ public abstract class RCallNode extends RNode { this.cachedSignature = varArgsSignature; this.matchedArgs = matchedArgs.createNode(); this.isVarArgsRoot = isVarArgsRoot; + this.needsCallerFrame = function.containsDispatch(); + /* + * this is a simple heuristic - methods that need a caller frame should have call site - + * specific versions + */ + this.needsSplitting = function.containsDispatch(); } protected static DispatchedVarArgsCallNode create(VirtualFrame frame, CallArgumentsNode args, VarArgsCacheCallNode next, SourceSection callSrc, RFunction function, @@ -745,7 +765,14 @@ public abstract class RCallNode extends RNode { } // Our cached function and matched arguments do match, simply execute! - Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), RArguments.getDepth(frame) + 1, matchedArgs.executeArray(frame), matchedArgs.getNames()); + + if (needsSplitting) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + needsSplitting = false; + call.cloneCallTarget(); + } + MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; + Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), callerFrame, RArguments.getDepth(frame) + 1, matchedArgs.executeArray(frame), matchedArgs.getNames()); return call.call(frame, argsObject); } @@ -766,6 +793,8 @@ public abstract class RCallNode extends RNode { @Child private DirectCallNode call; @Child private CallArgumentsNode suppliedArgs; + @CompilationFinal private boolean needsCallerFrame; + DispatchedGenericVarArgsCallNode(RFunction function, CallArgumentsNode suppliedArgs) { this.call = Truffle.getRuntime().createDirectCallNode(function.getTarget()); this.suppliedArgs = suppliedArgs; @@ -779,7 +808,12 @@ public abstract class RCallNode extends RNode { UnrolledVariadicArguments argsValuesAndNames = suppliedArgs.executeFlatten(frame); MatchedArguments matchedArgs = ArgumentMatcher.matchArguments(currentFunction, argsValuesAndNames, getSourceSection(), getEncapsulatingSourceSection(), true); - Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), RArguments.getDepth(frame) + 1, matchedArgs.doExecuteArray(frame), matchedArgs.getNames()); + if (!needsCallerFrame && currentFunction.containsDispatch()) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + needsCallerFrame = true; + } + MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; + Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), callerFrame, RArguments.getDepth(frame) + 1, matchedArgs.doExecuteArray(frame), matchedArgs.getNames()); return call.call(frame, argsObject); } } @@ -805,7 +839,7 @@ public abstract class RCallNode extends RNode { UnrolledVariadicArguments argsValuesAndNames = args.executeFlatten(frame); MatchedArguments matchedArgs = ArgumentMatcher.matchArguments(currentFunction, argsValuesAndNames, getSourceSection(), getEncapsulatingSourceSection(), true); - Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), RArguments.getDepth(frame) + 1, matchedArgs.doExecuteArray(frame), matchedArgs.getNames()); + Object[] argsObject = RArguments.create(currentFunction, getSourceSection(), null, RArguments.getDepth(frame) + 1, matchedArgs.doExecuteArray(frame), matchedArgs.getNames()); return indirectCall.call(frame, currentFunction.getTarget(), argsObject); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3DispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3DispatchNode.java index 8ee6d6f623424035658c3a78cf9516c186040e75..6da31ee3a0428e487d7b6c1b0806d1f4b596f509 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3DispatchNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3DispatchNode.java @@ -11,36 +11,31 @@ package com.oracle.truffle.r.nodes.function; -import static com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.*; - import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; -import com.oracle.truffle.r.nodes.access.*; +import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.r.nodes.access.variables.*; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.*; public abstract class S3DispatchNode extends DispatchNode { + protected final BranchProfile errorProfile = BranchProfile.create(); + @Child private ReadVariableNode lookup; @CompilationFinal private String lastFun; - @Child private WriteVariableNode wvnCallEnv; - @Child private WriteVariableNode wvnGeneric; - @Child private WriteVariableNode wvnClass; - @Child protected WriteVariableNode wvnMethod; - @Child private WriteVariableNode wvnDefEnv; @Child protected PromiseHelperNode promiseHelper = new PromiseHelperNode(); @Child protected IndirectCallNode indirectCallNode = Truffle.getRuntime().createIndirectCallNode(); protected String targetFunctionName; protected RFunction targetFunction; protected RStringVector klass; protected FunctionCall funCall; - protected Frame genCallEnv; - protected Frame genDefEnv; + protected MaterializedFrame genCallEnv; + protected MaterializedFrame genDefEnv; protected boolean isFirst; // TODO: the executeHelper methods share quite a bit of code, but is it better or worse from @@ -152,83 +147,11 @@ public abstract class S3DispatchNode extends DispatchNode { return new StringBuilder(generic).append(RRuntime.RDOT).append(className).toString(); } - protected WriteVariableNode initWvn(WriteVariableNode wvn, String name) { - WriteVariableNode node = wvn; - if (node == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - node = WriteVariableNode.create(name, null, false, false); - insert(node); - } - return node; - } - - protected WriteVariableNode defineVarInFrame(VirtualFrame frame, WriteVariableNode wvn, String varName, Object value) { - addVar(frame, varName); - WriteVariableNode wvnCopy = initWvn(wvn, varName); - wvnCopy.execute(frame, value); - return wvnCopy; - } - - private static void addVar(VirtualFrame frame, final String varName) { - addVarHelper(frame.getFrameDescriptor(), varName); - } - - @TruffleBoundary - private static void addVarHelper(FrameDescriptor frameDescriptor, final String varName) { - findOrAddFrameSlot(frameDescriptor, varName); - } - - protected void defineVarsInFrame(VirtualFrame frame) { - addVars(frame); - wvnGeneric = defineVarInFrame(frame, wvnGeneric, RRuntime.RDotGeneric, genericName); - wvnClass = defineVarInFrame(frame, wvnClass, RRuntime.RDotClass, klass); - wvnCallEnv = defineVarInFrame(frame, wvnCallEnv, RRuntime.RDotGenericCallEnv, genCallEnv); - wvnDefEnv = defineVarInFrame(frame, wvnDefEnv, RRuntime.RDotGenericDefEnv, genDefEnv); - } - - protected void defineVarsAsArguments(VirtualFrame frame) { - RArguments.setS3Generic(frame, genericName); - RArguments.setS3Class(frame, klass); - RArguments.setS3CallEnv(frame, genCallEnv); - RArguments.setS3DefEnv(frame, genDefEnv); - } - - protected void addVars(VirtualFrame frame) { - addVars0(frame.getFrameDescriptor()); - } - - @TruffleBoundary - private static void addVars0(FrameDescriptor fDesc) { - findOrAddFrameSlot(fDesc, RRuntime.RDotGeneric); - findOrAddFrameSlot(fDesc, RRuntime.RDotMethod); - findOrAddFrameSlot(fDesc, RRuntime.RDotClass); - findOrAddFrameSlot(fDesc, RRuntime.RDotGenericCallEnv); - findOrAddFrameSlot(fDesc, RRuntime.RDotGenericDefEnv); - } - - protected void removeVars(Frame frame) { - removeVar(frame.getFrameDescriptor(), RRuntime.RDotGeneric); - removeVar(frame.getFrameDescriptor(), RRuntime.RDotMethod); - removeVar(frame.getFrameDescriptor(), RRuntime.RDotClass); - removeVar(frame.getFrameDescriptor(), RRuntime.RDotGenericCallEnv); - removeVar(frame.getFrameDescriptor(), RRuntime.RDotGenericDefEnv); - - } - - @TruffleBoundary - private static void removeVars0(FrameDescriptor fDesc) { - fDesc.removeFrameSlot(RRuntime.RDotGeneric); - fDesc.removeFrameSlot(RRuntime.RDotMethod); - fDesc.removeFrameSlot(RRuntime.RDotClass); - fDesc.removeFrameSlot(RRuntime.RDotGenericCallEnv); - fDesc.removeFrameSlot(RRuntime.RDotGenericDefEnv); - } - - @TruffleBoundary - protected static void removeVar(FrameDescriptor fDesc, final String varName) { - if (fDesc.findFrameSlot(varName) != null) { - fDesc.removeFrameSlot(varName); - } + protected void defineVarsAsArguments(Object[] args) { + RArguments.setS3Generic(args, genericName); + RArguments.setS3Class(args, klass); + RArguments.setS3CallEnv(args, genCallEnv); + RArguments.setS3DefEnv(args, genDefEnv); } private void checkLength(final String className, final String generic) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnaryOpsGroupDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnaryOpsGroupDispatchNode.java index 52e67541768268873be27717c1bbdeefd5cfb54f..ab54468f8ca7e517a8129e4dccf3898abcbd64a0 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnaryOpsGroupDispatchNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UnaryOpsGroupDispatchNode.java @@ -27,7 +27,7 @@ public class UnaryOpsGroupDispatchNode extends GroupDispatchNode { @Override protected Object callBuiltin(VirtualFrame frame, Object[] evaluatedArgs, String[] argNames) { initBuiltin(frame); - Object[] argObject = RArguments.create(builtinFunc, this.callSrc, RArguments.getDepth(frame) + 1, new Object[]{evaluatedArgs[0], RMissing.instance}); + Object[] argObject = RArguments.create(builtinFunc, callSrc, null, RArguments.getDepth(frame) + 1, new Object[]{evaluatedArgs[0], RMissing.instance}); return indirectCallNode.call(frame, builtinFunc.getTarget(), argObject); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodDispatchNode.java index bad5e48cdf749059528a71120ce654cd048a3131..3db86d0fc0c3390f8380a5069d6fa884c5e10df5 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodDispatchNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodDispatchNode.java @@ -13,14 +13,13 @@ package com.oracle.truffle.r.nodes.function; import java.util.*; -import com.oracle.truffle.api.CompilerDirectives.*; -import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.*; -import com.oracle.truffle.r.runtime.env.frame.*; /** * {@code UseMethod} is typically called like this: @@ -35,8 +34,8 @@ import com.oracle.truffle.r.runtime.env.frame.*; */ public class UseMethodDispatchNode extends S3DispatchNode { - private final BranchProfile errorProfile = BranchProfile.create(); private final ConditionProfile topLevelFrameProfile = ConditionProfile.createBinaryProfile(); + private final ConditionProfile callerFrameSlotPath = ConditionProfile.createBinaryProfile(); @CompilationFinal private final String[] suppliedArgNames; @@ -46,13 +45,19 @@ public class UseMethodDispatchNode extends S3DispatchNode { this.suppliedArgNames = evaledArgNames; } + private Frame getCallerFrame(VirtualFrame frame) { + Frame funFrame = RArguments.getCallerFrame(frame); + if (callerFrameSlotPath.profile(funFrame == null)) { + funFrame = Utils.getCallerFrame(frame, FrameAccess.MATERIALIZE); + RError.performanceWarning("slow caller frame access in UseMethod dispatch"); + } + // S3 method can be dispatched from top-level where there is no caller frame + return topLevelFrameProfile.profile(funFrame == null) ? frame : funFrame; + } + @Override public Object execute(VirtualFrame frame) { - Frame funFrame = Utils.getCallerFrame(frame, FrameAccess.MATERIALIZE); - // S3 method can be dispatched from top-level where there is no caller frame - if (topLevelFrameProfile.profile(funFrame == null)) { - funFrame = frame; - } + Frame funFrame = getCallerFrame(frame); if (targetFunction == null) { findTargetFunction(RArguments.getEnclosingFrame(frame)); } @@ -60,13 +65,9 @@ public class UseMethodDispatchNode extends S3DispatchNode { } @Override - public Object execute(VirtualFrame frame, RStringVector aType) { + public Object executeGeneric(VirtualFrame frame, RStringVector aType) { this.type = aType; - Frame funFrame = Utils.getCallerFrame(frame, FrameAccess.MATERIALIZE); - // S3 method can be dispatched from top-level where there is no caller frame - if (funFrame == null) { - funFrame = frame; - } + Frame funFrame = getCallerFrame(frame); findTargetFunction(RArguments.getEnclosingFrame(frame)); return executeHelper(frame, funFrame); } @@ -81,7 +82,7 @@ public class UseMethodDispatchNode extends S3DispatchNode { } @Override - public Object executeInternal(VirtualFrame frame, RStringVector aType, Object[] args) { + public Object executeInternalGeneric(VirtualFrame frame, RStringVector aType, Object[] args) { this.type = aType; // TBD getEnclosing? findTargetFunction(frame); @@ -103,7 +104,7 @@ public class UseMethodDispatchNode extends S3DispatchNode { } } EvaluatedArguments reorderedArgs = reorderArgs(frame, targetFunction, argValues, argNames, false, getSourceSection()); - return executeHelper2(callerFrame, reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); + return executeHelper2(frame, callerFrame.materialize(), reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); } private Object executeHelper(VirtualFrame callerFrame, Object[] args) { @@ -148,7 +149,7 @@ public class UseMethodDispatchNode extends S3DispatchNode { EvaluatedArguments evaledArgs = EvaluatedArguments.create(argValues, argNames); // ...to match them against the chosen function's formal arguments EvaluatedArguments reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(callerFrame, targetFunction, evaledArgs, getEncapsulatingSourceSection(), promiseHelper, false); - return executeHelper2(callerFrame, reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); + return executeHelper2(callerFrame, callerFrame.materialize(), reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames()); } private static void addArg(Object[] values, Object value, int index) { @@ -159,17 +160,13 @@ public class UseMethodDispatchNode extends S3DispatchNode { } } - @TruffleBoundary - private Object executeHelper2(Frame callerFrame, Object[] arguments, String[] argNames) { - Object[] argObject = RArguments.createS3Args(targetFunction, getSourceSection(), RArguments.getDepth(callerFrame) + 1, arguments, argNames); + private Object executeHelper2(VirtualFrame frame, MaterializedFrame callerFrame, Object[] arguments, String[] argNames) { + Object[] argObject = RArguments.createS3Args(targetFunction, getSourceSection(), null, RArguments.getDepth(callerFrame) + 1, arguments, argNames); // todo: cannot create frame descriptors in compiled code - FrameDescriptor frameDescriptor = new FrameDescriptor(); - FrameSlotChangeMonitor.initializeFrameDescriptor(frameDescriptor, true); - VirtualFrame newFrame = Truffle.getRuntime().createVirtualFrame(argObject, frameDescriptor); genCallEnv = callerFrame; - defineVarsAsArguments(newFrame); - RArguments.setS3Method(newFrame, targetFunctionName); - return indirectCallNode.call(newFrame, targetFunction.getTarget(), argObject); + defineVarsAsArguments(argObject); + RArguments.setS3Method(argObject, targetFunctionName); + return indirectCallNode.call(frame, targetFunction.getTarget(), argObject); } private void findTargetFunction(Frame callerFrame) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java index c20d6dda6a7872deac4799f413bf5259fd60210d..769660da7dd73c629c70e6b621fc4f6e4c5d998d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java @@ -86,14 +86,13 @@ public final class RArguments { private static final int INDEX_ENVIRONMENT = 0; private static final int INDEX_FUNCTION = 1; private static final int INDEX_CALL_SRC = 2; - private static final int INDEX_ENCLOSING_FRAME = 3; - private static final int INDEX_N_ARGS = 4; - private static final int INDEX_DEPTH = 5; - private static final int INDEX_IS_IRREGULAR = 6; - private static final int INDEX_N_NAMES = 7; - private static final int INDEX_ARGUMENTS = 8; - - private static final int S3_VAR_COUNT = 9; + private static final int INDEX_CALLER_FRAME = 3; + private static final int INDEX_ENCLOSING_FRAME = 4; + private static final int INDEX_N_ARGS = 5; + private static final int INDEX_DEPTH = 6; + private static final int INDEX_IS_IRREGULAR = 7; + private static final int INDEX_N_NAMES = 8; + private static final int INDEX_ARGUMENTS = 9; /* * These indices are relative to INDEX_ARGUMENTS + nArgs+ nNames */ @@ -103,6 +102,7 @@ public final class RArguments { private static final int S3_INDEX_CALL_ENV = 3; private static final int S3_INDEX_DEF_ENV = 4; private static final int S3_INDEX_GROUP = 5; + private static final int S3_VAR_COUNT = 6; /** * At the least, the array contains the function, enclosing frame, and numbers of arguments and @@ -127,7 +127,6 @@ public final class RArguments { } else { return arguments; } - } private static int getNArgs(Frame frame) { @@ -142,10 +141,12 @@ public final class RArguments { return INDEX_ARGUMENTS + (int) args[INDEX_N_ARGS] + (int) args[INDEX_N_NAMES]; } - private static void createHelper(Object[] a, REnvironment env, RFunction functionObj, SourceSection callSrc, int depth, MaterializedFrame enclosingFrame, Object[] evaluatedArgs, String[] names) { + private static void createHelper(Object[] a, REnvironment env, RFunction functionObj, SourceSection callSrc, MaterializedFrame callerFrame, int depth, MaterializedFrame enclosingFrame, + Object[] evaluatedArgs, String[] names) { a[INDEX_ENVIRONMENT] = env; a[INDEX_FUNCTION] = functionObj; a[INDEX_CALL_SRC] = callSrc; + a[INDEX_CALLER_FRAME] = callerFrame; a[INDEX_ENCLOSING_FRAME] = enclosingFrame; a[INDEX_DEPTH] = depth; a[INDEX_IS_IRREGULAR] = false; @@ -186,30 +187,31 @@ public final class RArguments { return a; } - public static Object[] create(RFunction functionObj, SourceSection callSrc, int depth) { - return create(functionObj, callSrc, depth, EMPTY_OBJECT_ARRAY); + public static Object[] create(RFunction functionObj, SourceSection callSrc, MaterializedFrame callerFrame, int depth) { + return create(functionObj, callSrc, callerFrame, depth, EMPTY_OBJECT_ARRAY); } - public static Object[] create(RFunction functionObj, SourceSection callSrc, int depth, Object[] evaluatedArgs) { + public static Object[] create(RFunction functionObj, SourceSection callSrc, MaterializedFrame callerFrame, int depth, Object[] evaluatedArgs) { if (functionObj != null) { - return create(null, functionObj, callSrc, depth, functionObj.getEnclosingFrame(), evaluatedArgs, EMPTY_STRING_ARRAY); + return create(null, functionObj, callSrc, callerFrame, depth, functionObj.getEnclosingFrame(), evaluatedArgs, EMPTY_STRING_ARRAY); } - return create(null, functionObj, callSrc, depth, null, evaluatedArgs, EMPTY_STRING_ARRAY); + return create(null, functionObj, callSrc, callerFrame, depth, null, evaluatedArgs, EMPTY_STRING_ARRAY); } - public static Object[] create(RFunction functionObj, SourceSection callSrc, int depth, Object[] evaluatedArgs, String[] names) { - return create(null, functionObj, callSrc, depth, functionObj.getEnclosingFrame(), evaluatedArgs, names); + public static Object[] create(RFunction functionObj, SourceSection callSrc, MaterializedFrame callerFrame, int depth, Object[] evaluatedArgs, String[] names) { + return create(null, functionObj, callSrc, callerFrame, depth, functionObj.getEnclosingFrame(), evaluatedArgs, names); } - public static Object[] create(REnvironment env, RFunction functionObj, SourceSection callSrc, int depth, MaterializedFrame enclosingFrame, Object[] evaluatedArgs, String[] names) { + public static Object[] create(REnvironment env, RFunction functionObj, SourceSection callSrc, MaterializedFrame callerFrame, int depth, MaterializedFrame enclosingFrame, Object[] evaluatedArgs, + String[] names) { Object[] a = new Object[MINIMAL_ARRAY_LENGTH + evaluatedArgs.length + names.length]; - createHelper(a, env, functionObj, callSrc, depth, enclosingFrame, evaluatedArgs, names); + createHelper(a, env, functionObj, callSrc, callerFrame, depth, enclosingFrame, evaluatedArgs, names); return a; } - public static Object[] createS3Args(RFunction functionObj, SourceSection callSrc, int depth, Object[] evaluatedArgs, String[] names) { + public static Object[] createS3Args(RFunction functionObj, SourceSection callSrc, MaterializedFrame callerFrame, int depth, Object[] evaluatedArgs, String[] names) { Object[] a = new Object[MINIMAL_ARRAY_LENGTH + evaluatedArgs.length + names.length + S3_VAR_COUNT]; - createHelper(a, null, functionObj, callSrc, depth, functionObj.getEnclosingFrame(), evaluatedArgs, names); + createHelper(a, null, functionObj, callSrc, callerFrame, depth, functionObj.getEnclosingFrame(), evaluatedArgs, names); return a; } @@ -230,13 +232,17 @@ public final class RArguments { return (String) args[s3StartIndex + S3_INDEX_GENERIC]; } - public static void setS3Generic(Frame frame, final String generic) { - Object[] args = getArgumentsWithEvalCheck(frame); + public static void setS3Generic(Object[] args, String generic) { int s3StartIndex = getS3StartIndex(args); assert (args.length > s3StartIndex); args[s3StartIndex + S3_INDEX_GENERIC] = generic; } + public static MaterializedFrame getCallerFrame(Frame frame) { + Object[] args = getArgumentsWithEvalCheck(frame); + return (MaterializedFrame) args[INDEX_CALLER_FRAME]; + } + public static RStringVector getS3Class(Frame frame) { Object[] args = getArgumentsWithEvalCheck(frame); int s3StartIndex = getS3StartIndex(args); @@ -247,59 +253,55 @@ public final class RArguments { } } - public static void setS3Class(Frame frame, final RStringVector klass) { - Object[] args = getArgumentsWithEvalCheck(frame); + public static void setS3Class(Object[] args, RStringVector klass) { int s3StartIndex = getS3StartIndex(args); assert (args.length > s3StartIndex); args[s3StartIndex + S3_INDEX_CLASS] = klass; } - public static String getS3Method(Frame frame) { + public static Object getS3Method(Frame frame) { Object[] args = getArgumentsWithEvalCheck(frame); int s3StartIndex = getS3StartIndex(args); if (args.length <= s3StartIndex) { return null; } else { - return (String) args[s3StartIndex + S3_INDEX_METHOD]; + return args[s3StartIndex + S3_INDEX_METHOD]; } } - public static void setS3Method(Frame frame, final String method) { - Object[] args = getArgumentsWithEvalCheck(frame); + public static void setS3Method(Object[] args, Object method) { int s3StartIndex = getS3StartIndex(args); assert (args.length > s3StartIndex); args[s3StartIndex + S3_INDEX_METHOD] = method; } - public static Frame getS3DefEnv(Frame frame) { + public static MaterializedFrame getS3DefEnv(Frame frame) { Object[] args = getArgumentsWithEvalCheck(frame); int s3StartIndex = getS3StartIndex(args); if (args.length <= s3StartIndex) { return null; } else { - return (Frame) args[s3StartIndex + S3_INDEX_DEF_ENV]; + return (MaterializedFrame) args[s3StartIndex + S3_INDEX_DEF_ENV]; } } - public static void setS3DefEnv(Frame frame, Frame defEnv) { - Object[] args = getArgumentsWithEvalCheck(frame); + public static void setS3DefEnv(Object[] args, MaterializedFrame defEnv) { int s3StartIndex = getS3StartIndex(args); assert (args.length > s3StartIndex); args[s3StartIndex + S3_INDEX_DEF_ENV] = defEnv; } - public static Frame getS3CallEnv(Frame frame) { + public static MaterializedFrame getS3CallEnv(Frame frame) { Object[] args = getArgumentsWithEvalCheck(frame); int s3StartIndex = getS3StartIndex(args); if (args.length <= s3StartIndex) { return null; } else { - return (Frame) args[s3StartIndex + S3_INDEX_CALL_ENV]; + return (MaterializedFrame) args[s3StartIndex + S3_INDEX_CALL_ENV]; } } - public static void setS3CallEnv(Frame frame, Frame callEnv) { - Object[] args = getArgumentsWithEvalCheck(frame); + public static void setS3CallEnv(Object[] args, MaterializedFrame callEnv) { int s3StartIndex = getS3StartIndex(args); assert (args.length > s3StartIndex); args[s3StartIndex + S3_INDEX_CALL_ENV] = callEnv; @@ -315,8 +317,7 @@ public final class RArguments { } } - public static void setS3Group(Frame frame, final String group) { - Object[] args = getArgumentsWithEvalCheck(frame); + public static void setS3Group(Object[] args, String group) { int s3StartIndex = getS3StartIndex(args); assert (args.length > s3StartIndex); args[s3StartIndex + S3_INDEX_GROUP] = group; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java index 41b27d75272f328e3ce5843170fff7baaea470b1..581f9e37b47aef1dd1df672f2ecfaaa8a32893a5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java @@ -398,12 +398,12 @@ public final class RDataFactory { return traceDataCreated(new RPairList(car, cdr, tag, type)); } - public static RFunction createFunction(String name, RootCallTarget target, MaterializedFrame enclosingFrame) { - return traceDataCreated(new RFunction(name, target, null, enclosingFrame)); + public static RFunction createFunction(String name, RootCallTarget target, MaterializedFrame enclosingFrame, boolean containsDispatch) { + return traceDataCreated(new RFunction(name, target, null, enclosingFrame, containsDispatch)); } public static RFunction createFunction(String name, RootCallTarget target, RBuiltin builtin, MaterializedFrame enclosingFrame) { - return traceDataCreated(new RFunction(name, target, builtin, enclosingFrame)); + return traceDataCreated(new RFunction(name, target, builtin, enclosingFrame, false)); } public static REnvironment createNewEnv(REnvironment parent, int size) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java index 13b1b1f5e74884d91488ce34954b915bd32b39e8..321f1fc4b79a99f250827dac9a07e32728b573a2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java @@ -45,13 +45,16 @@ public final class RFunction extends RScalar implements RAttributable { private final String name; private final RootCallTarget target; private final RBuiltin builtin; + private final boolean containsDispatch; + @CompilationFinal private StableValue<MaterializedFrame> enclosingFrame; protected RAttributes attributes; - RFunction(String name, RootCallTarget target, RBuiltin builtin, MaterializedFrame enclosingFrame) { + RFunction(String name, RootCallTarget target, RBuiltin builtin, MaterializedFrame enclosingFrame, boolean containsDispatch) { this.name = name; this.target = target; this.builtin = builtin; + this.containsDispatch = containsDispatch; this.enclosingFrame = new StableValue<>(enclosingFrame, "RFunction enclosing frame"); } @@ -63,6 +66,10 @@ public final class RFunction extends RScalar implements RAttributable { return builtin; } + public boolean containsDispatch() { + return containsDispatch; + } + public String getName() { return name; } @@ -96,7 +103,7 @@ public final class RFunction extends RScalar implements RAttributable { } public RFunction copy() { - return new RFunction(name, target, builtin, enclosingFrame.getValue()); + return new RFunction(name, target, builtin, enclosingFrame.getValue(), containsDispatch); } public RAttributes initAttributes() { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/REnvMaterializedFrame.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/REnvMaterializedFrame.java index e7f9e8c27d01e83bfd07d2dd48f53f97ddb0ad0c..0bef9b0f45dd95ee16b3bbe1fd04fc6c61826a5a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/REnvMaterializedFrame.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/REnvMaterializedFrame.java @@ -107,76 +107,91 @@ public class REnvMaterializedFrame implements MaterializedFrame { return arguments; } + @TruffleBoundary public Object getObject(FrameSlot slot) throws FrameSlotTypeException { verifyGet(slot, FrameSlotKind.Object); return map.get(slot.getIdentifier()); } + @TruffleBoundary public void setObject(FrameSlot slot, Object value) { verifySet(slot, FrameSlotKind.Object); map.put(slot.getIdentifier(), value); } + @TruffleBoundary public byte getByte(FrameSlot slot) throws FrameSlotTypeException { verifyGet(slot, FrameSlotKind.Byte); return (byte) map.get(slot.getIdentifier()); } + @TruffleBoundary public void setByte(FrameSlot slot, byte value) { verifySet(slot, FrameSlotKind.Byte); map.put(slot.getIdentifier(), value); } + @TruffleBoundary public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException { verifyGet(slot, FrameSlotKind.Boolean); return (boolean) map.get(slot.getIdentifier()); } + @TruffleBoundary public void setBoolean(FrameSlot slot, boolean value) { verifySet(slot, FrameSlotKind.Boolean); map.put(slot.getIdentifier(), value); } + @TruffleBoundary public int getInt(FrameSlot slot) throws FrameSlotTypeException { verifyGet(slot, FrameSlotKind.Int); return (int) map.get(slot.getIdentifier()); } + @TruffleBoundary public void setInt(FrameSlot slot, int value) { verifySet(slot, FrameSlotKind.Int); map.put(slot.getIdentifier(), value); } + @TruffleBoundary public long getLong(FrameSlot slot) throws FrameSlotTypeException { verifyGet(slot, FrameSlotKind.Long); return (long) map.get(slot.getIdentifier()); } + @TruffleBoundary public void setLong(FrameSlot slot, long value) { verifySet(slot, FrameSlotKind.Long); map.put(slot.getIdentifier(), value); } + @TruffleBoundary public float getFloat(FrameSlot slot) throws FrameSlotTypeException { verifyGet(slot, FrameSlotKind.Float); return (float) map.get(slot.getIdentifier()); } + @TruffleBoundary public void setFloat(FrameSlot slot, float value) { verifySet(slot, FrameSlotKind.Float); map.put(slot.getIdentifier(), value); } + @TruffleBoundary public double getDouble(FrameSlot slot) throws FrameSlotTypeException { verifyGet(slot, FrameSlotKind.Double); return (double) map.get(slot.getIdentifier()); } + @TruffleBoundary public void setDouble(FrameSlot slot, double value) { verifySet(slot, FrameSlotKind.Double); map.put(slot.getIdentifier(), value); } + @TruffleBoundary @Override public Object getValue(FrameSlot slot) { int slotIndex = slot.getIndex(); 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 a98e97d0bda8adb64d2edb0fd2e4250139ba0e6c..058623b032a3cb5d9a7eea35c837dc59ce9cfe01 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 @@ -65211,6 +65211,10 @@ character(0) [1] "Australia" "UK" "UK" "US" "US" "Australia" [7] NA +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinascharacter.testascharacter24 +#argv <- list(structure(list(4L), class = c('package_version', 'numeric_version')));as.character(argv[[1]]); +[1] "4" + ##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinascharacter.testascharacter25 #argv <- list(c(-Inf, NaN, Inf));as.character(argv[[1]]); [1] "-Inf" "NaN" "Inf" @@ -65271,6 +65275,10 @@ character(0) #argv <- list(c(34L, -45L));as.character(argv[[1]]); [1] "34" "-45" +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinascharacter.testascharacter40 +#argv <- list(structure(list(), class = 'numeric_version'));as.character(argv[[1]]); +character(0) + ##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinascharacter.testascharacter41 #argv <- list(structure(list(c0 = structure(character(0), class = 'AsIs')), .Names = 'c0', row.names = character(0), class = 'data.frame'));as.character(argv[[1]]); [1] "character(0)" @@ -75635,6 +75643,10 @@ logical(0) #argv <- list(1, 6); .Internal(rep.int(argv[[1]], argv[[2]])) [1] 1 1 1 1 1 1 +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint10 +#argv <- list(c(1L, 1L, 2L, 2L), 6); .Internal(rep.int(argv[[1]], argv[[2]])) + [1] 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 + ##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint11 #argv <- list(NA_character_, 3L); .Internal(rep.int(argv[[1]], argv[[2]])) [1] NA NA NA @@ -75651,6 +75663,10 @@ logical(0) #argv <- list(0.8625, 2); .Internal(rep.int(argv[[1]], argv[[2]])) [1] 0.8625 0.8625 +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint17 +#argv <- list(FALSE, FALSE); .Internal(rep.int(argv[[1]], argv[[2]])) +logical(0) + ##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint19 #argv <- list(structure(c(1974, 1974.08333333333, 1974.16666666667, 1974.25, 1974.33333333333, 1974.41666666667, 1974.5, 1974.58333333333, 1974.66666666667, 1974.75, 1974.83333333333, 1974.91666666667, 1975, 1975.08333333333, 1975.16666666667, 1975.25, 1975.33333333333, 1975.41666666667, 1975.5, 1975.58333333333, 1975.66666666667, 1975.75, 1975.83333333333, 1975.91666666667, 1976, 1976.08333333333, 1976.16666666667, 1976.25, 1976.33333333333, 1976.41666666667, 1976.5, 1976.58333333333, 1976.66666666667, 1976.75, 1976.83333333333, 1976.91666666667, 1977, 1977.08333333333, 1977.16666666667, 1977.25, 1977.33333333333, 1977.41666666667, 1977.5, 1977.58333333333, 1977.66666666667, 1977.75, 1977.83333333333, 1977.91666666667, 1978, 1978.08333333333, 1978.16666666667, 1978.25, 1978.33333333333, 1978.41666666667, 1978.5, 1978.58333333333, 1978.66666666667, 1978.75, 1978.83333333333, 1978.91666666667, 1979, 1979.08333333333, 1979.16666666667, 1979.25, 1979.33333333333, 1979.41666666667, 1979.5, 1979.58333333333, 1979.66666666667, 1979.75, 1979.83333333333, 1979.91666666667), .Tsp = c(1974, 1979.91666666667, 12), class = 'ts'), 3L); .Internal(rep.int(argv[[1]], argv[[2]])) [1] 1974.000 1974.083 1974.167 1974.250 1974.333 1974.417 1974.500 1974.583 @@ -75685,6 +75701,10 @@ logical(0) #argv <- list(NA_integer_, 1L); .Internal(rep.int(argv[[1]], argv[[2]])) [1] NA +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint20 +#argv <- list(NA, 10L); .Internal(rep.int(argv[[1]], argv[[2]])) + [1] NA NA NA NA NA NA NA NA NA NA + ##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint21 #argv <- list(c('C', 'A', 'B'), structure(list(C = 1L, A = 1L, B = 1L), .Names = c('C', 'A', 'B'))); .Internal(rep.int(argv[[1]], argv[[2]])) [1] "C" "A" "B" @@ -75702,6 +75722,14 @@ logical(0) [37] 0.26784 0.26784 0.26784 0.26784 0.26784 0.26784 0.26784 0.26784 0.26784 [46] 0.26784 0.26784 0.26784 0.26784 +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint25 +#argv <- list(NA, 5L); .Internal(rep.int(argv[[1]], argv[[2]])) +[1] NA NA NA NA NA + +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint26 +#argv <- list(TRUE, 6L); .Internal(rep.int(argv[[1]], argv[[2]])) +[1] TRUE TRUE TRUE TRUE TRUE TRUE + ##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint27 #argv <- list(structure(c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101), .Tsp = c(1, 101, 1), class = 'ts'), 3L); .Internal(rep.int(argv[[1]], argv[[2]])) [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @@ -75726,10 +75754,22 @@ logical(0) #argv <- list(1L, 4L); .Internal(rep.int(argv[[1]], argv[[2]])) [1] 1 1 1 1 +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint4 +#argv <- list(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), 1); .Internal(rep.int(argv[[1]], argv[[2]])) + [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint5 +#argv <- list(FALSE, 0L); .Internal(rep.int(argv[[1]], argv[[2]])) +logical(0) + ##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint6 #argv <- list('', 2L); .Internal(rep.int(argv[[1]], argv[[2]])) [1] "" "" +##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint7 +#argv <- list(TRUE, 1L); .Internal(rep.int(argv[[1]], argv[[2]])) +[1] TRUE + ##com.oracle.truffle.r.test.testrgen.TestrGenBuiltinrepint.testrepint8 #argv <- list(' ', 8L); .Internal(rep.int(argv[[1]], argv[[2]])) [1] " " " " " " " " " " " " " " " " diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java index 7e5deca932de4d9157242c19e319a94e704236e8..2f6789f30298cb6f03d80a4ced82a5dfe7941492 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/failing/FailingTests.java @@ -3249,12 +3249,6 @@ public class FailingTests extends TestBase { check("TestrGenBuiltinascharacter_testascharacter22_57067e2c0d6c38282b57535adb101e14"); } - @Test - public void TestrGenBuiltinascharacter_testascharacter24_fa6e2ffc98f3b422be091992652cc063() { - assertEval("argv <- list(structure(list(4L), class = c('package_version', 'numeric_version')));as.character(argv[[1]]);"); - check("TestrGenBuiltinascharacter_testascharacter24_fa6e2ffc98f3b422be091992652cc063"); - } - @Test public void TestrGenBuiltinascharacter_testascharacter28_be987cc5e86462dab4ec1574a5c96efd() { assertEval("argv <- list(structure(c(11323, 11330, 11337, 11344, 11351, 11358, 11365, 11372, 11379, 11386), class = 'Date'));as.character(argv[[1]]);"); @@ -3303,12 +3297,6 @@ public class FailingTests extends TestBase { check("TestrGenBuiltinascharacter_testascharacter4_b0efabdea893c5e3c24e0d077282fc6b"); } - @Test - public void TestrGenBuiltinascharacter_testascharacter40_2b19c43c5220d4933e35afa1bcc7236c() { - assertEval("argv <- list(structure(list(), class = 'numeric_version'));as.character(argv[[1]]);"); - check("TestrGenBuiltinascharacter_testascharacter40_2b19c43c5220d4933e35afa1bcc7236c"); - } - @Test public void TestrGenBuiltinascharacter_testascharacter42_4cd3aed711e78cfcab749a3f20dca4ba() { assertEval("argv <- list(structure(c(12784, 13879), class = 'Date'));as.character(argv[[1]]);"); @@ -10785,12 +10773,6 @@ public class FailingTests extends TestBase { check("TestrGenBuiltinrep_testrep9_3cc63793e525424d43ae3ba907a85d7a"); } - @Test - public void TestrGenBuiltinrepint_testrepint10_dde17f705e40806f5b55beae204599b7() { - assertEval("argv <- list(c(1L, 1L, 2L, 2L), 6); .Internal(rep.int(argv[[1]], argv[[2]]))"); - check("TestrGenBuiltinrepint_testrepint10_dde17f705e40806f5b55beae204599b7"); - } - @Test public void TestrGenBuiltinrepint_testrepint13_d31b70d4e01d550889ad6d9cb34b03cf() { assertEval("argv <- list(structure(1:4, .Label = c('A', 'B', 'C', 'D'), class = 'factor', .Names = c('a', 'b', 'c', 'd')), 2); .Internal(rep.int(argv[[1]], argv[[2]]))"); @@ -10803,60 +10785,18 @@ public class FailingTests extends TestBase { check("TestrGenBuiltinrepint_testrepint14_eb20631d35776b024d237f0e37558b93"); } - @Test - public void TestrGenBuiltinrepint_testrepint17_7a1213eafa82541b8a351bd5838a5af6() { - assertEval("argv <- list(FALSE, FALSE); .Internal(rep.int(argv[[1]], argv[[2]]))"); - check("TestrGenBuiltinrepint_testrepint17_7a1213eafa82541b8a351bd5838a5af6"); - } - @Test public void TestrGenBuiltinrepint_testrepint18_89d713aa24d3bbc416b09d5b3a7c0fcb() { assertEval("argv <- list(c(-1.74520963996789, -1.58308930128988, NA), 100L); .Internal(rep.int(argv[[1]], argv[[2]]))"); check("TestrGenBuiltinrepint_testrepint18_89d713aa24d3bbc416b09d5b3a7c0fcb"); } - @Test - public void TestrGenBuiltinrepint_testrepint20_491b0390b66db6a67cedcc2a42873e5a() { - assertEval("argv <- list(NA, 10L); .Internal(rep.int(argv[[1]], argv[[2]]))"); - check("TestrGenBuiltinrepint_testrepint20_491b0390b66db6a67cedcc2a42873e5a"); - } - @Test public void TestrGenBuiltinrepint_testrepint24_8280666f60f8465e6eefa702e913cf63() { assertEval("argv <- list(3.1e-06, 49); .Internal(rep.int(argv[[1]], argv[[2]]))"); check("TestrGenBuiltinrepint_testrepint24_8280666f60f8465e6eefa702e913cf63"); } - @Test - public void TestrGenBuiltinrepint_testrepint25_c8eaf452f45b00ae42d98c734a5cfffd() { - assertEval("argv <- list(NA, 5L); .Internal(rep.int(argv[[1]], argv[[2]]))"); - check("TestrGenBuiltinrepint_testrepint25_c8eaf452f45b00ae42d98c734a5cfffd"); - } - - @Test - public void TestrGenBuiltinrepint_testrepint26_ab3b24b0c9725d38798a7ad9e4076d5e() { - assertEval("argv <- list(TRUE, 6L); .Internal(rep.int(argv[[1]], argv[[2]]))"); - check("TestrGenBuiltinrepint_testrepint26_ab3b24b0c9725d38798a7ad9e4076d5e"); - } - - @Test - public void TestrGenBuiltinrepint_testrepint4_20bb6f9af6b07b4403c6affda51252a6() { - assertEval("argv <- list(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), 1); .Internal(rep.int(argv[[1]], argv[[2]]))"); - check("TestrGenBuiltinrepint_testrepint4_20bb6f9af6b07b4403c6affda51252a6"); - } - - @Test - public void TestrGenBuiltinrepint_testrepint5_cb990b8179a6fb9eaae1bb541f1d9486() { - assertEval("argv <- list(FALSE, 0L); .Internal(rep.int(argv[[1]], argv[[2]]))"); - check("TestrGenBuiltinrepint_testrepint5_cb990b8179a6fb9eaae1bb541f1d9486"); - } - - @Test - public void TestrGenBuiltinrepint_testrepint7_6887e9ead03307d35952a52816eb9b4c() { - assertEval("argv <- list(TRUE, 1L); .Internal(rep.int(argv[[1]], argv[[2]]))"); - check("TestrGenBuiltinrepint_testrepint7_6887e9ead03307d35952a52816eb9b4c"); - } - @Test public void TestrGenBuiltinretracemem_testretracemem1_2962f142b007b2052ba94b324866fab4() { assertEval("argv <- list(FALSE, FALSE);retracemem(argv[[1]],argv[[2]]);"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java index 235e9dcc301fb181fbc1d03f81c661db6464bcd6..23f5d45c72cad0a2e10a80aef6532c79f0acb7b1 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java @@ -37,7 +37,7 @@ public final class FastRSession implements RSession { * comparison. It does not separate error output as the test analysis doesn't need it. */ private static class ConsoleHandler implements RContext.ConsoleHandler { - private StringBuilder buffer = new StringBuilder(); + private final StringBuilder buffer = new StringBuilder(); @TruffleBoundary public void println(String s) { @@ -111,7 +111,11 @@ public final class FastRSession implements RSession { Load_RFFIFactory.initialize(); FastROptions.initialize(); REnvVars.initialize(); - REngine.initialize(new String[0], consoleHandler, false, false); + try { + REngine.initialize(new String[0], consoleHandler, false, false); + } finally { + System.out.print(consoleHandler.buffer.toString()); + } } @SuppressWarnings("deprecation") diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/testrgen/TestrGenBuiltinascharacter.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/testrgen/TestrGenBuiltinascharacter.java index 8636363a7656b2d739edeb996a13578e468ac556..4b7516036bf70e101e3f419db88052d0c7035c0e 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/testrgen/TestrGenBuiltinascharacter.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/testrgen/TestrGenBuiltinascharacter.java @@ -143,7 +143,6 @@ public class TestrGenBuiltinascharacter extends TestBase { } @Test - @Ignore public void testascharacter24() { assertEval("argv <- list(structure(list(4L), class = c(\'package_version\', \'numeric_version\')));as.character(argv[[1]]);"); } @@ -231,7 +230,6 @@ public class TestrGenBuiltinascharacter extends TestBase { } @Test - @Ignore public void testascharacter40() { assertEval("argv <- list(structure(list(), class = \'numeric_version\'));as.character(argv[[1]]);"); } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/testrgen/TestrGenBuiltinrepint.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/testrgen/TestrGenBuiltinrepint.java index fb2a20725d7bf89067fb56c5a6a8f18da8102b67..f0c6d123256818699dfb1fac5913ccb66e901b90 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/testrgen/TestrGenBuiltinrepint.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/testrgen/TestrGenBuiltinrepint.java @@ -33,13 +33,11 @@ public class TestrGenBuiltinrepint extends TestBase { } @Test - @Ignore public void testrepint4() { assertEval("argv <- list(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), 1); .Internal(rep.int(argv[[1]], argv[[2]]))"); } @Test - @Ignore public void testrepint5() { assertEval("argv <- list(FALSE, 0L); .Internal(rep.int(argv[[1]], argv[[2]]))"); } @@ -50,7 +48,6 @@ public class TestrGenBuiltinrepint extends TestBase { } @Test - @Ignore public void testrepint7() { assertEval("argv <- list(TRUE, 1L); .Internal(rep.int(argv[[1]], argv[[2]]))"); } @@ -66,7 +63,6 @@ public class TestrGenBuiltinrepint extends TestBase { } @Test - @Ignore public void testrepint10() { assertEval("argv <- list(c(1L, 1L, 2L, 2L), 6); .Internal(rep.int(argv[[1]], argv[[2]]))"); } @@ -88,7 +84,7 @@ public class TestrGenBuiltinrepint extends TestBase { } @Test - @Ignore + @Ignore("formatting") public void testrepint14() { assertEval("argv <- list(2e-08, 9); .Internal(rep.int(argv[[1]], argv[[2]]))"); } @@ -104,13 +100,12 @@ public class TestrGenBuiltinrepint extends TestBase { } @Test - @Ignore public void testrepint17() { assertEval("argv <- list(FALSE, FALSE); .Internal(rep.int(argv[[1]], argv[[2]]))"); } @Test - @Ignore + @Ignore("formatting") public void testrepint18() { assertEval("argv <- list(c(-1.74520963996789, -1.58308930128988, NA), 100L); .Internal(rep.int(argv[[1]], argv[[2]]))"); } @@ -121,7 +116,6 @@ public class TestrGenBuiltinrepint extends TestBase { } @Test - @Ignore public void testrepint20() { assertEval("argv <- list(NA, 10L); .Internal(rep.int(argv[[1]], argv[[2]]))"); } @@ -148,13 +142,11 @@ public class TestrGenBuiltinrepint extends TestBase { } @Test - @Ignore public void testrepint25() { assertEval("argv <- list(NA, 5L); .Internal(rep.int(argv[[1]], argv[[2]]))"); } @Test - @Ignore public void testrepint26() { assertEval("argv <- list(TRUE, 6L); .Internal(rep.int(argv[[1]], argv[[2]]))"); } diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py index 6f9812af15e02b1357be8b7e87bc42f974668748..38b17da9965298c5e06792fba8d24b40acb10913 100644 --- a/mx.fastr/suite.py +++ b/mx.fastr/suite.py @@ -220,6 +220,7 @@ suite = { "com.oracle.truffle.r.nodes.wrapper.processor" ], "workingSets" : "Truffle,FastR", + "jacoco" : "include", }, "com.oracle.truffle.r.nodes.builtin" : { @@ -237,6 +238,7 @@ suite = { "com.oracle.truffle.r.nodes.wrapper.processor", ], "workingSets" : "Truffle,FastR", + "jacoco" : "include", }, "com.oracle.truffle.r.test.ignore.processor" : { @@ -260,6 +262,7 @@ suite = { "javaCompliance" : "1.8", "annotationProcessors" : ["com.oracle.truffle.r.test.ignore.processor"], "workingSets" : "Truffle,FastR,Test", + "jacoco" : "include", }, "com.oracle.truffle.r.test.native" : { @@ -277,6 +280,7 @@ suite = { "checkstyle" : "com.oracle.truffle.r.runtime", "javaCompliance" : "1.8", "workingSets" : "Truffle,FastR", + "jacoco" : "include", }, "com.oracle.truffle.r.shell" : { @@ -288,6 +292,7 @@ suite = { "checkstyle" : "com.oracle.truffle.r.runtime", "javaCompliance" : "1.8", "workingSets" : "Truffle,FastR", + "jacoco" : "include", }, "com.oracle.truffle.r.runtime" : { @@ -300,6 +305,7 @@ suite = { "checkstyle" : "com.oracle.truffle.r.runtime", "javaCompliance" : "1.8", "workingSets" : "Truffle,FastR", + "jacoco" : "include", }, "com.oracle.truffle.r.runtime.ffi" : { @@ -327,6 +333,7 @@ suite = { "checkstyle" : "com.oracle.truffle.r.runtime", "javaCompliance" : "1.8", "workingSets" : "Truffle,FastR", + "jacoco" : "include", }, "com.oracle.truffle.r.native" : { @@ -343,7 +350,7 @@ suite = { "checkstyle" : "com.oracle.truffle.r.runtime", "javaCompliance" : "1.8", "workingSets" : "FastR", - + "jacoco" : "include", }, "com.oracle.truffle.r.library" : { @@ -354,6 +361,7 @@ suite = { "checkstyle" : "com.oracle.truffle.r.runtime", "javaCompliance" : "1.8", "workingSets" : "FastR", + "jacoco" : "include", },