diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java index 588b62059700f448f74fa5895cd41fbd96e957ad..f34298e87262cbdbebedb105b912514ccbe1cfbc 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java @@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.builtin.base; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.r.nodes.builtin.*; +import com.oracle.truffle.r.nodes.control.RLengthNode; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.*; import com.oracle.truffle.r.runtime.data.model.*; @@ -138,12 +139,12 @@ public abstract class AnyNA extends RBuiltinNode { @Specialization protected byte isNA(RList list, // @Cached("createRecursive()") AnyNA recursive, // - @Cached("createClassProfile()") ValueProfile elementProfile) { + @Cached("createClassProfile()") ValueProfile elementProfile, // + @Cached("create()") RLengthNode length) { controlVisibility(); for (int i = 0; i < list.getLength(); i++) { Object value = elementProfile.profile(list.getDataAt(i)); - if (value instanceof Byte || value instanceof Integer || value instanceof Double || value instanceof RComplex || value instanceof RScalar || - (value instanceof RAbstractContainer && ((RAbstractContainer) value).getLength() == 1)) { + if (length.executeInteger(value) == 1) { byte result = recursive.execute(value); if (result == RRuntime.LOGICAL_TRUE) { return RRuntime.LOGICAL_TRUE; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index c41434b4ae6f59f1b88de9460efaa198e1f89654..e6e5f6d68cca2ca8979585a43ac501cacc01b81d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -534,7 +534,5 @@ public class BasePackage extends RBuiltinPackage { addFastPath(baseFrame, "pmin", FastPathFactory.EVALUATE_ARGS); addFastPath(baseFrame, "cbind", FastPathFactory.FORCED_EAGER_ARGS); addFastPath(baseFrame, "rbind", FastPathFactory.FORCED_EAGER_ARGS); -// addFastPath(baseFrame, "cbind.data.frame", FastPathFactory.FORCED_EAGER_ARGS); -// addFastPath(baseFrame, "rbind.data.frame", FastPathFactory.FORCED_EAGER_ARGS); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InfixEmulationFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InfixEmulationFunctions.java index ab394b0a0bc19ee76120ac99b01126cba387112c..e6c2175704a67dffaa2028632a344a03f20cf090 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InfixEmulationFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InfixEmulationFunctions.java @@ -131,50 +131,37 @@ public class InfixEmulationFunctions { @NodeChild(value = "op") protected abstract static class PromiseEvaluator extends RNode { - protected abstract Object execute(VirtualFrame frame, Object op); - - @Child private PromiseHelperNode promiseHelper; - @Child private PromiseEvaluator evalRecursive; - - protected Object evalRecursive(VirtualFrame frame, Object op) { - if (evalRecursive == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - evalRecursive = insert(PromiseEvaluatorNodeGen.create(null)); - } - return evalRecursive.execute(frame, op); + protected PromiseEvaluator create() { + return PromiseEvaluatorNodeGen.create(null); } + protected abstract Object execute(VirtualFrame frame, Object op); + @Specialization(guards = {"!isRPromise(op)", "!isRArgsValuesAndNames(op)"}) protected Object eval(Object op) { return op; } @Specialization - protected Object eval(VirtualFrame frame, RPromise p) { - if (promiseHelper == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - promiseHelper = insert(new PromiseHelperNode()); - } + protected Object eval(VirtualFrame frame, RPromise p, // + @Cached("new()") PromiseHelperNode promiseHelper) { return promiseHelper.evaluate(frame, p); } - @Specialization(guards = "!argsEmpty(args)") - protected RArgsValuesAndNames eval(VirtualFrame frame, RArgsValuesAndNames args) { + @Specialization(guards = "!args.isEmpty()") + protected RArgsValuesAndNames eval(VirtualFrame frame, RArgsValuesAndNames args, // + @Cached("create()") PromiseEvaluator evalRecursive) { Object[] values = args.getArguments(); for (int i = 0; i < values.length; i++) { - values[i] = evalRecursive(frame, values[i]); + values[i] = evalRecursive.execute(frame, values[i]); } return args; } - @Specialization(guards = "argsEmpty(args)") + @Specialization(guards = "args.isEmpty()") protected RArgsValuesAndNames evalEmpty(RArgsValuesAndNames args) { return args; } - - protected boolean argsEmpty(RArgsValuesAndNames args) { - return args.isEmpty(); - } } public abstract static class AccessArrayBuiltin extends RBuiltinNode { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java index 33ab0665fcfb19b8623ee899ee6787fc76b9bf24..9f89a8bae7bf4b0dca628e4aa75795693a866c2f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java @@ -266,7 +266,7 @@ public abstract class Match extends RBuiltinNode { return RDataFactory.createIntVector(result, setCompleteState(matchAll, nomatch)); } - @Specialization() + @Specialization protected RIntVector match(RAbstractIntVector x, RAbstractLogicalVector table, Object nomatchObj, @SuppressWarnings("unused") Object incomparables) { controlVisibility(); int nomatch = castInt(nomatchObj); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java index 6af4211c0cd71a3be0586483b456c8c595f57769..d9d8315dc19c347dc4f6129139fed19a536b43dd 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java @@ -51,6 +51,7 @@ public class TrigExpFunctions { } protected double op(@SuppressWarnings("unused") double x) { + // not abstract because this would confuse the DSL annotation processor throw RInternalError.shouldNotReachHere("this method needs to be implemented in subclasses"); } 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 a65dbc2ae0a26e890167c5e3c7aa75a66b9c4747..8340526e313bd3bbd74333064ff14946f6eb7994 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 @@ -142,15 +142,6 @@ public final class RTruffleVisitor extends BasicVisitor<RSyntaxNode> { @Override public RSyntaxNode visit(Function func) { -// FastPathFactory f = EvaluatedArgumentsVisitor.process(func); -// if (f != null) { -// System.out.println("////////////////////////////////"); -// if (func.getDebugName() != null) { -// System.out.println("// " + func.getDebugName()); -// } -// System.out.println(func.getSource().getCode()); -// System.out.println("names: " + f + "\n"); -// } RootCallTarget callTarget = null; try { callTarget = createFunctionCallTarget(func); 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 5a54b08ad797cf5268242394a573dedd98d565c5..65ffe8de46ee7b9c3fc4055dad9cd39d37b1d048 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 @@ -86,12 +86,12 @@ import com.oracle.truffle.r.runtime.nodes.*; * U = {@link UninitializedCallNode}: Forms the uninitialized end of the function PIC * D = {@link DispatchedCallNode}: Function fixed, no varargs * G = {@link GenericCallNode}: Function arbitrary - * + * * UV = {@link UninitializedCallNode} with varargs, * UVC = {@link UninitializedVarArgsCacheCallNode} with varargs, for varargs cache * DV = {@link DispatchedVarArgsCallNode}: Function fixed, with cached varargs * DGV = {@link DispatchedGenericVarArgsCallNode}: Function fixed, with arbitrary varargs (generic case) - * + * * (RB = {@link RBuiltinNode}: individual functions that are builtins are represented by this node * which is not aware of caching). Due to {@link CachedCallNode} (see below) this is transparent to * the cache and just behaves like a D/DGV) @@ -104,11 +104,11 @@ import com.oracle.truffle.r.runtime.nodes.*; * 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 @@ -116,7 +116,7 @@ import com.oracle.truffle.r.runtime.nodes.*; * DV * | * UVC <- varargs signature level cache - * + * * varargs, max varargs depth exceeded: * | * DV-DV-UV @@ -128,7 +128,7 @@ import com.oracle.truffle.r.runtime.nodes.*; * DV * | * DGV - * + * * varargs, max function depth exceeded: * | * DV-DV-DV-DV-GV @@ -166,6 +166,8 @@ public final class RCallNode extends RNode implements RSyntaxNode { private static final int FUNCTION_INLINE_CACHE_SIZE = 4; private static final int VARARGS_INLINE_CACHE_SIZE = 4; + private static final Object[] defaultTempIdentifiers = new Object[]{new Object(), new Object(), new Object(), new Object()}; + @Child private RNode functionNode; @Child private PromiseHelperNode promiseHelper; @Child private RootCallNode call; @@ -203,8 +205,6 @@ public final class RCallNode extends RNode implements RSyntaxNode { private final SyntaxArguments arguments; private final ArgumentsSignature signature; - private final Object tempIdentifier = new Object(); - private final ValueProfile builtinProfile = ValueProfile.createIdentityProfile(); private final ConditionProfile implicitTypeProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile resultIsBuiltinProfile = ConditionProfile.createBinaryProfile(); @@ -213,6 +213,8 @@ public final class RCallNode extends RNode implements RSyntaxNode { private final BranchProfile errorProfile = BranchProfile.create(); private final ConditionProfile isRFunctionProfile = ConditionProfile.createBinaryProfile(); + private int tempIdentifier; + @Child private Node foreignCall; @CompilationFinal private int foreignCallArgCount; @Child private CallArgumentsNode foreignCallArguments; @@ -267,13 +269,28 @@ public final class RCallNode extends RNode implements RSyntaxNode { if (builtin.getDispatch() == RDispatch.INTERNAL_GENERIC) { if (internalDispatchCall == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - dispatchTempSlot = insert(FrameSlotNode.createInitialized(frame.getFrameDescriptor(), tempIdentifier, true)); - internalDispatchCall = insert(new UninitializedCallNode(this, tempIdentifier)); + dispatchTempSlot = insert(FrameSlotNode.createInitialized(frame.getFrameDescriptor(), defaultTempIdentifiers[0], true)); + internalDispatchCall = insert(new UninitializedCallNode(this, defaultTempIdentifiers[0])); dispatchArgument = insert(NodeUtil.cloneNode(arguments.v[0].asRNode())); dispatchLookup = insert(S3FunctionLookupNode.create(true, false)); classHierarchyNode = insert(ClassHierarchyNodeGen.create(false)); } FrameSlot slot = dispatchTempSlot.executeFrameSlot(frame); + try { + if (frame.isObject(slot) && frame.getObject(slot) != null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + // keep the complete loop in the slow path + do { + tempIdentifier++; + Object identifier = tempIdentifier < defaultTempIdentifiers.length ? defaultTempIdentifiers[tempIdentifier] : new Object(); + dispatchTempSlot.replace(FrameSlotNode.createInitialized(frame.getFrameDescriptor(), identifier, true)); + internalDispatchCall.replace(new UninitializedCallNode(this, identifier)); + slot = dispatchTempSlot.executeFrameSlot(frame); + } while (frame.isObject(slot) && frame.getObject(slot) != null); + } + } catch (FrameSlotTypeException e) { + throw RInternalError.shouldNotReachHere(); + } try { Object dispatch = dispatchArgument.execute(frame); frame.setObject(slot, dispatch); @@ -816,8 +833,6 @@ public final class RCallNode extends RNode implements RSyntaxNode { this.fastPath = function.getFastPath() == null ? null : function.getFastPath().create(); if (fastPath == null) { this.call = Truffle.getRuntime().createDirectCallNode(function.getTarget()); - } else { -// System.out.println("created fast path " + fastPath); } } @@ -830,7 +845,6 @@ public final class RCallNode extends RNode implements RSyntaxNode { } CompilerDirectives.transferToInterpreterAndInvalidate(); fastPath = null; -// System.out.println("falling back to method execution"); call = insert(Truffle.getRuntime().createDirectCallNode(callTarget)); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java index 509fdaf3ecde3458552ff8e8d43c37aaa95ae8b9..fb258a3dd7f7ee6c17c2106873339e6dc165e28c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java @@ -125,7 +125,7 @@ public final class BinaryMapNode extends RBaseNode { int[] leftDimensions = left.getDimensions(); int[] rightDimensions = right.getDimensions(); int leftLength = leftDimensions.length; - int rightLength = leftDimensions.length; + int rightLength = rightDimensions.length; if (leftLength != rightLength) { return true; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/FastPathFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/FastPathFactory.java index e5b4d03fb40500fd8ef2935e306eaca5bff869f0..ae926e03902f4783eead60a70b156a00161d36ff 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/FastPathFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/FastPathFactory.java @@ -25,7 +25,10 @@ package com.oracle.truffle.r.runtime.data; import com.oracle.truffle.r.runtime.nodes.*; /** - * This implies that all arguments can be evaluated eagerly. + * This interface can be used to provide a fast path, implemented in Java, for an R function. This + * may be useful for cases in which there is a significantly simpler implementation for a known + * configuration of arguments. Returning {@code null} from the fast path node will revert the call + * site so that it calls the normal R code again. */ @FunctionalInterface public interface FastPathFactory { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java index 201d764c35a9741970e67ded5bed49ef28c217e8..0acbdafe954d70ef93bd6d71248274c59cef9ba0 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java @@ -906,6 +906,10 @@ public abstract class BinaryArithmetic extends Operation { private static class Max extends BinaryArithmetic { + private final BranchProfile incomparableProfile = BranchProfile.create(); + private final BranchProfile zeroProfile = BranchProfile.create(); + private final ConditionProfile compareProfile = ConditionProfile.createBinaryProfile(); + public Max() { super(true, true, true); } @@ -924,11 +928,13 @@ public abstract class BinaryArithmetic extends Operation { public double op(double left, double right) { // explicit checks, since Math.max uses a non-final static field if (left != left) { + incomparableProfile.enter(); return left; } else if (left == 0.0d && right == 0.0d && Double.doubleToRawLongBits(left) == Double.doubleToRawLongBits(-0.0d)) { + zeroProfile.enter(); return right; } else { - return left >= right ? left : right; + return compareProfile.profile(left >= right) ? left : right; } } @@ -947,6 +953,10 @@ public abstract class BinaryArithmetic extends Operation { private static class Min extends BinaryArithmetic { + private final BranchProfile incomparableProfile = BranchProfile.create(); + private final BranchProfile zeroProfile = BranchProfile.create(); + private final ConditionProfile compareProfile = ConditionProfile.createBinaryProfile(); + public Min() { super(true, true, true); } @@ -963,13 +973,15 @@ public abstract class BinaryArithmetic extends Operation { @Override public double op(double left, double right) { - // explicit checks, since Math.max uses a non-final static field + // explicit checks, since Math.min uses a non-final static field if (left != left) { + incomparableProfile.enter(); return left; } else if (left == 0.0d && right == 0.0d && Double.doubleToRawLongBits(right) == Double.doubleToRawLongBits(-0.0d)) { + zeroProfile.enter(); return right; } else { - return left <= right ? left : right; + return compareProfile.profile(left <= right) ? left : right; } }