diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java index 92d043c445615d2a431604f7e0f7f12b965093ca..6f3c3bc9c082d8bd0b8362e9ead3982deed14382 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java @@ -41,10 +41,11 @@ import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.base.AsVectorNodeGen.AsVectorInternalNodeGen; import com.oracle.truffle.r.nodes.builtin.base.AsVectorNodeGen.AsVectorInternalNodeGen.CastPairListNodeGen; +import com.oracle.truffle.r.nodes.function.CallMatcherNode; import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode; -import com.oracle.truffle.r.nodes.function.UseMethodInternalNode; +import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result; import com.oracle.truffle.r.nodes.unary.CastComplexNode; import com.oracle.truffle.r.nodes.unary.CastDoubleNode; import com.oracle.truffle.r.nodes.unary.CastExpressionNode; @@ -77,7 +78,9 @@ public abstract class AsVector extends RBuiltinNode { @Child private AsVectorInternal internal = AsVectorInternalNodeGen.create(); @Child private ClassHierarchyNode classHierarchy = ClassHierarchyNodeGen.create(false, false); - @Child private UseMethodInternalNode useMethod; + + @Child private S3FunctionLookupNode lookup; + @Child private CallMatcherNode callMatcher; private final ConditionProfile hasClassProfile = ConditionProfile.createBinaryProfile(); @@ -98,16 +101,19 @@ public abstract class AsVector extends RBuiltinNode { // However, removing it causes unit test failures RStringVector clazz = classHierarchy.execute(x); if (hasClassProfile.profile(clazz != null)) { - if (useMethod == null) { - // Note: this dispatch takes care of factor, because there is as.vector.factor - // specialization in R + // Note: this dispatch takes care of factor, because there is as.vector.factor + // specialization in R + if (lookup == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - useMethod = insert(new UseMethodInternalNode("as.vector", SIGNATURE, false)); + lookup = insert(S3FunctionLookupNode.create(false, false)); } - try { - return useMethod.execute(frame, clazz, new Object[]{x, mode}); - } catch (S3FunctionLookupNode.NoGenericMethodException e) { - // fallthrough + Result lookupResult = lookup.execute(frame, "as.vector", clazz, null, frame.materialize(), null); + if (lookupResult != null) { + if (callMatcher == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + callMatcher = insert(CallMatcherNode.create(false)); + } + return callMatcher.execute(frame, SIGNATURE, new Object[]{x, mode}, lookupResult.function, lookupResult.targetFunctionName, lookupResult.createS3Args(frame)); } } return internal.execute(x, mode); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java index 0a95c508e5ae397f7717df4e96528108cb1d0c27..13294d4f362ab562c0db9a44cb1426995eaca939 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java @@ -43,8 +43,9 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAt import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.function.CallMatcherNode; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode; -import com.oracle.truffle.r.nodes.function.UseMethodInternalNode; +import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result; import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode; import com.oracle.truffle.r.nodes.unary.CastComplexNode; import com.oracle.truffle.r.nodes.unary.CastDoubleNode; @@ -97,10 +98,12 @@ public abstract class Bind extends RBaseNode { public abstract Object execute(VirtualFrame frame, int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, int precedence); @Child private CastToVectorNode castVector; - @Child private UseMethodInternalNode dcn; @Child private CastLogicalNode castLogical; @Child private GetDimAttributeNode getDimsNode; + @Child private S3FunctionLookupNode lookup; + @Child private CallMatcherNode callMatcher; + private final BindType type; private final ConditionProfile nullNamesProfile = ConditionProfile.createBinaryProfile(); @@ -162,15 +165,19 @@ public abstract class Bind extends RBaseNode { @Specialization(guards = {"args.length > 0", "isDataFrame(args)"}) protected Object allDataFrame(VirtualFrame frame, int deparseLevel, @SuppressWarnings("unused") Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) { - if (dcn == null) { + if (lookup == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - dcn = insert(new UseMethodInternalNode(type.toString(), SIGNATURE, false)); + lookup = insert(S3FunctionLookupNode.create(false, false)); } - try { - return dcn.execute(frame, DATA_FRAME_CLASS, new Object[]{deparseLevel, promiseArgs}); - } catch (S3FunctionLookupNode.NoGenericMethodException e) { + Result lookupResult = lookup.execute(frame, type.toString(), DATA_FRAME_CLASS, null, frame.materialize(), null); + if (lookupResult == null) { throw RInternalError.shouldNotReachHere(); } + if (callMatcher == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + callMatcher = insert(CallMatcherNode.create(false)); + } + return callMatcher.execute(frame, SIGNATURE, new Object[]{deparseLevel, promiseArgs}, lookupResult.function, lookupResult.targetFunctionName, lookupResult.createS3Args(frame)); } private Object bindInternal(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, CastNode castNode, boolean needsVectorCast, SetDimAttributeNode setDimNode, diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java index c4a29770e6ed51657735ce8b9077e9e4990673ba..c492da931b26adedf73a7520833fdd76fd63ed4d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java @@ -52,13 +52,13 @@ public abstract class CRC64 extends RBuiltinNode { bytes = crc64(bytes); long l = 0; for (int i = 0; i < bytes.length; i++) { - l += ((long) bytes[i] & 0xffL) << (8 * i); + l += (bytes[i] & 0xffL) << (8 * i); } return RDataFactory.createStringVector(Long.toHexString(l)); } @TruffleBoundary - private byte[] crc64(byte[] bytes) { + private static byte[] crc64(byte[] bytes) { org.tukaani.xz.check.CRC64 crc = new org.tukaani.xz.check.CRC64(); crc.update(bytes); return crc.finish(); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java index 54ecf0b6dc9db4eaf3fcfd74062c55e6372bb18c..4cd34ed9f441d06c369bdfc1c72c98880a2d1d24 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java @@ -17,7 +17,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; @@ -89,21 +88,18 @@ public abstract class Lapply extends RBuiltinNode { private static final class ExtractElementInternal extends RSourceSectionNode implements RSyntaxCall { - protected ExtractElementInternal() { + @Child private ExtractVectorNode extractElementNode = ExtractVectorNodeGen.create(ElementAccessMode.SUBSCRIPT, false); + private final FrameSlot vectorSlot; + private final FrameSlot indexSlot; + + protected ExtractElementInternal(FrameSlot vectorSlot, FrameSlot indexSlot) { super(RSyntaxNode.LAZY_DEPARSE); + this.vectorSlot = vectorSlot; + this.indexSlot = indexSlot; } - @Child private ExtractVectorNode extractElementNode = ExtractVectorNodeGen.create(ElementAccessMode.SUBSCRIPT, false); - @CompilationFinal private FrameSlot vectorSlot; - @CompilationFinal private FrameSlot indexSlot; - @Override public Object execute(VirtualFrame frame) { - if (vectorSlot == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - vectorSlot = frame.getFrameDescriptor().findFrameSlot("X"); - indexSlot = frame.getFrameDescriptor().findFrameSlot("i"); - } try { return extractElementNode.apply(frame, frame.getObject(vectorSlot), new Object[]{frame.getInt(indexSlot)}, RRuntime.LOGICAL_TRUE, RRuntime.LOGICAL_TRUE); } catch (FrameSlotTypeException e) { @@ -149,8 +145,8 @@ public abstract class Lapply extends RBuiltinNode { @Cached("createVectorSlot(frame)") FrameSlot vectorSlot, // @Cached("create()") RLengthNode lengthNode, // @Cached("createCountingProfile()") LoopConditionProfile loop, // - @Cached("createCallNode()") RCallNode firstCallNode, // - @Cached("createCallNode()") RCallNode callNode) { + @Cached("createCallNode(vectorSlot, indexSlot)") RCallNode firstCallNode, // + @Cached("createCallNode(vectorSlot, indexSlot)") RCallNode callNode) { // TODO: R switches to double if x.getLength() is greater than 2^31-1 frame.setObject(vectorSlot, vector); int length = lengthNode.executeInteger(frame, vector); @@ -171,10 +167,10 @@ public abstract class Lapply extends RBuiltinNode { /** * Creates the {@link RCallNode} for this target and {@code varArgs}. */ - protected RCallNode createCallNode() { + protected RCallNode createCallNode(FrameSlot vectorSlot, FrameSlot indexSlot) { CompilerAsserts.neverPartOfCompilation(); - ExtractElementInternal element = new ExtractElementInternal(); + ExtractElementInternal element = new ExtractElementInternal(vectorSlot, indexSlot); ReadVariableNode readArgs = ReadVariableNode.createSilent(ArgumentsSignature.VARARG_NAME, RType.Any); return RCallNode.createCall(createCallSourceSection(), ReadVariableNode.create("FUN"), ArgumentsSignature.get(null, "..."), element, readArgs); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java index da099379b27d2dde035be4f0c2cd48c14c135918..cf0585f4b13e7078466524a68b3ae09b79fbbb28 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java @@ -63,7 +63,7 @@ import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RTypedValue; -import com.oracle.truffle.r.runtime.data.RTypes; +import com.oracle.truffle.r.runtime.data.RTypesFlatLayout; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; @@ -85,7 +85,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; */ public final class ReadVariableNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxLookup { - private static final int MAX_INVALIDATION_COUNT = 3; + private static final int MAX_INVALIDATION_COUNT = 8; private enum ReadKind { Normal, @@ -184,20 +184,22 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta Object result; if (read == null) { - initializeRead(frame, variableFrame); + CompilerDirectives.transferToInterpreterAndInvalidate(); + initializeRead(frame, variableFrame, false); } try { result = read.execute(frame, variableFrame); } catch (InvalidAssumptionException | LayoutChangedException | FrameSlotTypeException e) { + CompilerDirectives.transferToInterpreterAndInvalidate(); int iterations = 0; while (true) { iterations++; - initializeRead(frame, variableFrame); + initializeRead(frame, variableFrame, true); try { result = read.execute(frame, variableFrame); } catch (InvalidAssumptionException | LayoutChangedException | FrameSlotTypeException e2) { if (iterations > 10) { - throw new RInternalError("too many iterations during RVN initialization: " + identifier); + throw new RInternalError("too many iterations during RVN initialization: " + identifier + " " + e2 + " " + read + " " + getRootNode()); } continue; } @@ -217,10 +219,13 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta return result; } - private void initializeRead(VirtualFrame frame, Frame variableFrame) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - read = initialize(frame, variableFrame); - needsCopying = kind == ReadKind.Copying && !(read instanceof Match || read instanceof DescriptorStableMatch); + private synchronized void initializeRead(VirtualFrame frame, Frame variableFrame, boolean invalidate) { + CompilerAsserts.neverPartOfCompilation(); + // do nothing if another thread initialized in the meantime + if (invalidate || read == null) { + read = initialize(frame, variableFrame); + needsCopying = kind == ReadKind.Copying && !(read instanceof Match || read instanceof DescriptorStableMatch); + } } private static final class LayoutChangedException extends SlowPathException { @@ -478,27 +483,52 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta private final class LookupLevel extends DescriptorLevel { private final LookupResult lookup; - private final ValueProfile frameProfile = ValueProfile.createClassProfile(); private final ConditionProfile nullValueProfile = kind == ReadKind.Silent ? null : ConditionProfile.createBinaryProfile(); private LookupLevel(LookupResult lookup) { this.lookup = lookup; + assert !(lookup instanceof FrameAndSlotLookupResult); } @Override public Object execute(VirtualFrame frame) throws InvalidAssumptionException, LayoutChangedException, FrameSlotTypeException { - Object value; - if (lookup instanceof FrameAndSlotLookupResult) { - FrameAndSlotLookupResult frameAndSlotLookupResult = (FrameAndSlotLookupResult) lookup; - value = profiledGetValue(seenValueKinds, frameProfile.profile(frameAndSlotLookupResult.getFrame()), frameAndSlotLookupResult.getSlot()); - } else { - value = lookup.getValue(); - } + Object value = lookup.getValue(); if (kind != ReadKind.Silent && nullValueProfile.profile(value == null)) { throw RError.error(RError.SHOW_CALLER, mode == RType.Function ? RError.Message.UNKNOWN_FUNCTION : RError.Message.UNKNOWN_OBJECT, identifier); } return value; } + + @Override + public String toString() { + return "<LU>"; + } + } + + private final class FrameAndSlotLookupLevel extends DescriptorLevel { + + private final FrameAndSlotLookupResult lookup; + private final ValueProfile frameProfile = ValueProfile.createClassProfile(); + private final ConditionProfile isNullProfile = ConditionProfile.createBinaryProfile(); + + private FrameAndSlotLookupLevel(FrameAndSlotLookupResult lookup) { + this.lookup = lookup; + } + + @Override + public Object execute(VirtualFrame frame) throws InvalidAssumptionException, LayoutChangedException, FrameSlotTypeException { + Object value = profiledGetValue(seenValueKinds, frameProfile.profile(lookup.getFrame()), lookup.getSlot()); + if (!checkType(frame, value, isNullProfile)) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw new LayoutChangedException(); + } + return value; + } + + @Override + public String toString() { + return "<FSLU>"; + } } private FrameLevel initialize(VirtualFrame frame, Frame variableFrame) { @@ -538,8 +568,14 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta evalPromiseSlowPathWithName(identifierAsString, frame, (RPromise) lookup.getValue()); } if (lookup != null) { - if (lookup.getValue() == null || checkTypeSlowPath(frame, lookup.getValue())) { - return new LookupLevel(lookup); + if (lookup instanceof FrameAndSlotLookupResult) { + if (checkTypeSlowPath(frame, lookup.getValue())) { + return new FrameAndSlotLookupLevel((FrameAndSlotLookupResult) lookup); + } + } else { + if (lookup.getValue() == null || checkTypeSlowPath(frame, lookup.getValue())) { + return new LookupLevel(lookup); + } } } } catch (InvalidAssumptionException e) { @@ -880,7 +916,7 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta /* * This is RRuntime.checkType in the node form. */ -@TypeSystemReference(RTypes.class) +@TypeSystemReference(RTypesFlatLayout.class) abstract class CheckTypeNode extends RBaseNode { public abstract boolean executeBoolean(Object o); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java index 00fd37061cd9548111df37b17ddf621dea0401ca..3a3f0fe6d7477ce2aa7426dd4c7ae506f7867b8e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java @@ -23,7 +23,6 @@ package com.oracle.truffle.r.nodes.binary; import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; @@ -65,26 +64,19 @@ public abstract class BinaryBooleanScalarNode extends RBuiltinNode { BinaryBooleanScalarNode(BooleanOperationFactory factory) { this.booleanLogic = factory.createOperation(); + logic = new BinaryMapBooleanFunctionNode(booleanLogic); + leftCast = LogicalScalarCastNodeGen.create(booleanLogic.opName(), "x", logic.getLeftNACheck()); + leftBox = BoxPrimitiveNodeGen.create(); + rightCast = LogicalScalarCastNodeGen.create(booleanLogic.opName(), "y", logic.getRightNACheck()); + rightBox = BoxPrimitiveNodeGen.create(); + promiseHelper = new PromiseCheckHelperNode(); } @Specialization protected byte binary(VirtualFrame frame, Object leftValue, Object rightValue) { - if (leftCast == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - logic = insert(new BinaryMapBooleanFunctionNode(booleanLogic)); - leftCast = insert(LogicalScalarCastNodeGen.create(booleanLogic.opName(), "x", logic.getLeftNACheck())); - leftBox = insert(BoxPrimitiveNodeGen.create()); - } byte left = leftCast.executeCast(leftBox.execute(leftValue)); if (profile.profile(logic.requiresRightOperand(left))) { - if (rightCast == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - rightCast = insert(LogicalScalarCastNodeGen.create(booleanLogic.opName(), "y", logic.getRightNACheck())); - rightBox = insert(BoxPrimitiveNodeGen.create()); - promiseHelper = insert(new PromiseCheckHelperNode()); - } - byte right = rightCast.executeCast(rightBox.execute(promiseHelper.checkEvaluate(frame, rightValue))); - return logic.applyLogical(left, right); + return logic.applyLogical(left, rightCast.executeCast(rightBox.execute(promiseHelper.checkEvaluate(frame, rightValue)))); } return left; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentStatePush.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentStatePush.java index 3e3347bf7972c9421593be2388be054e9a88a0bc..6100faa0f41002be34f10714130b93693fffade9 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentStatePush.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentStatePush.java @@ -24,25 +24,33 @@ package com.oracle.truffle.r.nodes.function; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout; import com.oracle.truffle.r.nodes.access.WriteLocalFrameVariableNode; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RArguments; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RShareable; +import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; /** * A {@link ArgumentStatePush} is used to bump up state transition for function arguments. */ +@TypeSystemReference(EmptyTypeSystemFlatLayout.class) public abstract class ArgumentStatePush extends Node { public abstract void executeObject(VirtualFrame frame, Object shareable); + @Child private WriteLocalFrameVariableNode write; + private final ConditionProfile isRefCountUpdateable = ConditionProfile.createBinaryProfile(); private final int index; @@ -57,76 +65,59 @@ public abstract class ArgumentStatePush extends Node { this.index = index; } - public boolean refCounted() { - return mask > 0; + protected int createWriteArgMask(VirtualFrame frame, RShareable shareable) { + if (shareable instanceof RAbstractContainer) { + if (shareable instanceof RLanguage || ((RAbstractContainer) shareable).getLength() < REF_COUNT_SIZE_THRESHOLD) { + // don't decrement ref count for small objects or language objects- this + // is pretty conservative and can be further finessed + return -1; + } + } + RFunction fun = RArguments.getFunction(frame); + if (fun == null) { + return -1; + } + Object root = fun.getRootNode(); + if (!(root instanceof FunctionDefinitionNode)) { + // root is RBuiltinRootNode + return -1; + } + FunctionDefinitionNode fdn = (FunctionDefinitionNode) root; + PostProcessArgumentsNode postProcessNode = fdn.getArgPostProcess(); + if (postProcessNode == null) { + // arguments to this function are not to be reference counted + return -1; + } + if (!postProcessNode.updateBits(index)) { + // this will fail if the index is too big + return -1; + } + return 1 << index; } @Specialization - public void transitionState(VirtualFrame frame, RShareable shareable) { + public void transitionState(VirtualFrame frame, RSharingAttributeStorage shareable, + @Cached("createWriteArgMask(frame, shareable)") int writeArgMask) { if (isRefCountUpdateable.profile(!shareable.isSharedPermanent())) { shareable.incRefCount(); - if (!FastROptions.RefCountIncrementOnly.getBooleanValue()) { - if (mask == 0) { + if (writeArgMask != -1 && !FastROptions.RefCountIncrementOnly.getBooleanValue()) { + if (write == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - if (shareable instanceof RAbstractContainer) { - if (shareable instanceof RLanguage || ((RAbstractContainer) shareable).getLength() < REF_COUNT_SIZE_THRESHOLD) { - // don't decrement ref count for small objects or language objects- this - // is - // pretty conservative and can be further finessed - mask = -1; - return; - } - } - RFunction fun = RArguments.getFunction(frame); - if (fun == null) { - mask = -1; - return; - } - Object root = fun.getRootNode(); - if (!(root instanceof FunctionDefinitionNode)) { - // root is RBuiltinRootNode - mask = -1; - return; - } - FunctionDefinitionNode fdn = (FunctionDefinitionNode) root; - PostProcessArgumentsNode postProcessNode = fdn.getArgPostProcess(); - if (postProcessNode == null) { - // arguments to this function are not to be reference counted - mask = -1; - return; - } - // this is needed for when FunctionDefinitionNode is split by the Truffle - // runtime - postProcessNode = postProcessNode.getActualNode(); - if (index >= Math.min(postProcessNode.getLength(), MAX_COUNTED_ARGS)) { - mask = -1; - return; - } - mask = 1 << index; - int transArgsBitSet = postProcessNode.transArgsBitSet; - postProcessNode.transArgsBitSet = transArgsBitSet | mask; - writeArgNode = insert(WriteLocalFrameVariableNode.createForRefCount(Integer.valueOf(mask))); - } - if (mask != -1) { - writeArgNode.execute(frame, shareable); + write = insert(WriteLocalFrameVariableNode.createForRefCount(Integer.valueOf(writeArgMask))); } + write.execute(frame, shareable); } } } + @Specialization + public void transitionState(RShareable shareable) { + throw RInternalError.shouldNotReachHere("unexpected RShareable that is not RSharingAttributeStorage: " + shareable.getClass()); + } + @Specialization(guards = "!isShareable(o)") - public void transitionStateNonShareable(VirtualFrame frame, @SuppressWarnings("unused") Object o) { - if (mask > 0) { - // this argument used to be reference counted but is no longer - CompilerDirectives.transferToInterpreterAndInvalidate(); - RFunction fun = RArguments.getFunction(frame); - assert fun != null; - FunctionDefinitionNode fdn = (FunctionDefinitionNode) fun.getRootNode(); - assert fdn != null; - int transArgsBitSet = fdn.getArgPostProcess().transArgsBitSet; - fdn.getArgPostProcess().transArgsBitSet = transArgsBitSet & (~mask); - mask = -1; - } + public void transitionStateNonShareable(@SuppressWarnings("unused") Object o) { + // do nothing } protected boolean isShareable(Object o) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java index 6359e94caa2fbf0e94bdf95af98c5b7dc4633ace..818244e964bd14a74c07476e39b4bb09d00706fa 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java @@ -161,8 +161,18 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum return Arguments.create(values, ArgumentsSignature.get(newNames)); } - private ArgumentsSignature cachedVarArgsSignature; - private ArgumentsSignature cachedResultSignature; + private static final class CachedSignature { + private final ArgumentsSignature signature; + private final ArgumentsSignature resultSignature; + + protected CachedSignature(ArgumentsSignature signature, ArgumentsSignature resultSignature) { + this.signature = signature; + this.resultSignature = resultSignature; + } + } + + private CachedSignature cachedVarArgsSignature; + private final BranchProfile regenerateSignatureProfile = BranchProfile.create(); public ArgumentsSignature flattenNames(RArgsValuesAndNames varArgs) { @@ -170,15 +180,15 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum return signature; } ArgumentsSignature varArgsSignature = varArgs.getSignature(); - if (cachedVarArgsSignature == null) { + CachedSignature cached = cachedVarArgsSignature; + if (cached == null) { CompilerDirectives.transferToInterpreter(); } - if (varArgsSignature == cachedVarArgsSignature) { - return cachedResultSignature; + if (cached == null || varArgsSignature != cached.signature) { + regenerateSignatureProfile.enter(); + cachedVarArgsSignature = cached = new CachedSignature(varArgsSignature, flattenNamesInternal(varArgsSignature)); } - regenerateSignatureProfile.enter(); - cachedVarArgsSignature = varArgsSignature; - return cachedResultSignature = flattenNamesInternal(varArgsSignature); + return cached.resultSignature; } @TruffleBoundary diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java index 9454d1b46b985707c8c836d1c714a9b1b86936e3..e034cfa67da52aab6d8a18ab88da0b95344e6a95 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java @@ -60,7 +60,7 @@ public abstract class CallMatcherNode extends RBaseNode { private static final int MAX_CACHE_DEPTH = 3; public static CallMatcherNode create(boolean argsAreEvaluated) { - return new CallMatcherUninitializedNode(argsAreEvaluated); + return new CallMatcherUninitializedNode(argsAreEvaluated, 0); } public abstract Object execute(VirtualFrame frame, ArgumentsSignature suppliedSignature, Object[] suppliedArguments, RFunction function, String functionName, DispatchArgs dispatchArgs); @@ -151,19 +151,20 @@ public abstract class CallMatcherNode extends RBaseNode { @NodeInfo(cost = NodeCost.UNINITIALIZED) private static final class CallMatcherUninitializedNode extends CallMatcherNode { - CallMatcherUninitializedNode(boolean argsAreEvaluated) { + CallMatcherUninitializedNode(boolean argsAreEvaluated, int depth) { super(argsAreEvaluated); + this.depth = depth; } - private int depth; + private final int depth; @Override public Object execute(VirtualFrame frame, ArgumentsSignature suppliedSignature, Object[] suppliedArguments, RFunction function, String functionName, DispatchArgs dispatchArgs) { CompilerDirectives.transferToInterpreterAndInvalidate(); - if (++depth > MAX_CACHE_DEPTH) { + if (depth > MAX_CACHE_DEPTH) { return replace(new CallMatcherGenericNode(argsAreEvaluated)).execute(frame, suppliedSignature, suppliedArguments, function, functionName, dispatchArgs); } else { - CallMatcherCachedNode cachedNode = replace(specialize(suppliedSignature, suppliedArguments, function, this)); + CallMatcherCachedNode cachedNode = replace(specialize(suppliedSignature, suppliedArguments, function, new CallMatcherUninitializedNode(argsAreEvaluated, depth + 1))); // for splitting if necessary if (cachedNode.call != null && RCallNode.needsSplitting(function.getTarget())) { cachedNode.call.getCallNode().cloneCallTarget(); 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 4a2c89ad48a62fc5debd7c6be8f4bb3ca2864f8e..2e3030709b306ecc445d7a5bdf376c11bf1ea4f5 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 @@ -30,6 +30,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; @@ -101,24 +102,13 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo private final BranchProfile breakProfile = BranchProfile.create(); private final BranchProfile nextProfile = BranchProfile.create(); - @CompilationFinal private BranchProfile invalidateFrameSlotProfile; - // S3/S4 slots - @Child private FrameSlotNode dotGenericSlot; - @Child private FrameSlotNode dotMethodSlot; - // S3 slots - @Child private FrameSlotNode dotClassSlot; - @Child private FrameSlotNode dotGenericCallEnvSlot; - @Child private FrameSlotNode dotGenericCallDefSlot; - @Child private FrameSlotNode dotGroupSlot; - // S4 slots - @Child private FrameSlotNode dotDefinedSlot; - @Child private FrameSlotNode dotTargetSlot; - @Child private FrameSlotNode dotMethodsSlot; - @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); @Child private PostProcessArgumentsNode argPostProcess; + @Child private SetupS3ArgsNode setupS3Args; + @Child private SetupS4ArgsNode setupS4Args; + private final boolean needsSplitting; @CompilationFinal private boolean containsDispatch; @@ -317,55 +307,88 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo } } + private abstract static class SetupDispatchNode extends Node { + // S3/S4 slots + private final FrameSlot dotGenericSlot; + private final FrameSlot dotMethodSlot; + + final BranchProfile invalidateFrameSlotProfile = BranchProfile.create(); + + SetupDispatchNode(FrameDescriptor frameDescriptor) { + dotGenericSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC, FrameSlotKind.Object); + dotMethodSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_METHOD, FrameSlotKind.Object); + } + + void execute(VirtualFrame frame, DispatchArgs args) { + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericSlot, args.generic, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodSlot, args.method, false, invalidateFrameSlotProfile); + } + } + + private static final class SetupS3ArgsNode extends SetupDispatchNode { + // S3 slots + private final FrameSlot dotClassSlot; + private final FrameSlot dotGenericCallEnvSlot; + private final FrameSlot dotGenericCallDefSlot; + private final FrameSlot dotGroupSlot; + + SetupS3ArgsNode(FrameDescriptor frameDescriptor) { + super(frameDescriptor); + dotClassSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_CLASS, FrameSlotKind.Object); + dotGenericCallEnvSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC_CALL_ENV, FrameSlotKind.Object); + dotGenericCallDefSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC_DEF_ENV, FrameSlotKind.Object); + dotGroupSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GROUP, FrameSlotKind.Object); + } + + void execute(VirtualFrame frame, S3Args args) { + super.execute(frame, args); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotClassSlot, args.clazz, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallEnvSlot, args.callEnv, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallDefSlot, args.defEnv, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGroupSlot, args.group, false, invalidateFrameSlotProfile); + } + } + + private static final class SetupS4ArgsNode extends SetupDispatchNode { + // S4 slots + private final FrameSlot dotDefinedSlot; + private final FrameSlot dotTargetSlot; + private final FrameSlot dotMethodsSlot; + + SetupS4ArgsNode(FrameDescriptor frameDescriptor) { + super(frameDescriptor); + dotDefinedSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_DEFINED, FrameSlotKind.Object); + dotTargetSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_TARGET, FrameSlotKind.Object); + dotMethodsSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_METHODS, FrameSlotKind.Object); + } + + void execute(VirtualFrame frame, S4Args args) { + super.execute(frame, args); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotDefinedSlot, args.defined, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotTargetSlot, args.target, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodsSlot, args.methods, false, invalidateFrameSlotProfile); + } + } + private void setupDispatchSlots(VirtualFrame frame) { DispatchArgs dispatchArgs = RArguments.getDispatchArgs(frame); if (dispatchArgs == null) { return; } - if (dotGenericSlot == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - assert invalidateFrameSlotProfile == null && dotMethodSlot == null; - invalidateFrameSlotProfile = BranchProfile.create(); - FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); - - dotGenericSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_GENERIC, true)); - dotMethodSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_METHOD, true)); - } - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericSlot.executeFrameSlot(frame), dispatchArgs.generic, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodSlot.executeFrameSlot(frame), dispatchArgs.method, false, invalidateFrameSlotProfile); - if (dispatchArgs instanceof S3Args) { S3Args s3Args = (S3Args) dispatchArgs; - if (dotClassSlot == null) { + if (setupS3Args == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - assert dotGenericCallEnvSlot == null && dotGenericCallDefSlot == null && dotGroupSlot == null; - invalidateFrameSlotProfile = BranchProfile.create(); - FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); - - dotClassSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_CLASS, true)); - dotGenericCallEnvSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_GENERIC_CALL_ENV, true)); - dotGenericCallDefSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_GENERIC_DEF_ENV, true)); - dotGroupSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_GROUP, true)); + setupS3Args = insert(new SetupS3ArgsNode(frame.getFrameDescriptor())); } - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotClassSlot.executeFrameSlot(frame), s3Args.clazz, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallEnvSlot.executeFrameSlot(frame), s3Args.callEnv, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallDefSlot.executeFrameSlot(frame), s3Args.defEnv, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGroupSlot.executeFrameSlot(frame), s3Args.group, false, invalidateFrameSlotProfile); + setupS3Args.execute(frame, s3Args); } else { S4Args s4Args = (S4Args) dispatchArgs; - if (dotDefinedSlot == null) { + if (setupS4Args == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - assert dotTargetSlot == null && dotMethodsSlot == null; - invalidateFrameSlotProfile = BranchProfile.create(); - FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); - - dotDefinedSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_DEFINED, true)); - dotTargetSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_TARGET, true)); - dotMethodsSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_METHODS, true)); + setupS4Args = insert(new SetupS4ArgsNode(frame.getFrameDescriptor())); } - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotDefinedSlot.executeFrameSlot(frame), s4Args.defined, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotTargetSlot.executeFrameSlot(frame), s4Args.target, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodsSlot.executeFrameSlot(frame), s4Args.methods, false, invalidateFrameSlotProfile); + setupS4Args.execute(frame, s4Args); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PostProcessArgumentsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PostProcessArgumentsNode.java index 70c054c22da7929dfaac6ae718dd7b1af33e3650..e808377fefc5bedf97ad147c5d5950c6cfbd272a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PostProcessArgumentsNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PostProcessArgumentsNode.java @@ -22,13 +22,11 @@ */ package com.oracle.truffle.r.nodes.function; -import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.api.utilities.AssumedValue; import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RShareable; @@ -41,28 +39,20 @@ import com.oracle.truffle.r.runtime.nodes.RNode; public final class PostProcessArgumentsNode extends RNode { @Children private final LocalReadVariableNode[] sequence; - @Child private PostProcessArgumentsNode nextOptPostProccessArgNode; - @CompilationFinal int transArgsBitSet; - // the first time this node is cloned (via FunctionDefinitionNode) it's from the trufflerizer - - // in this case we should not create the node chain chain in the clone operation (below) at the - // reference count meta data needs to be associated with this node and not its clone - @CompilationFinal private boolean createClone; + // stays the same during cloning + private final AssumedValue<Integer> transArgsBitSet; + + private final ConditionProfile isNonNull = ConditionProfile.createBinaryProfile(); private final ConditionProfile isRefCountUpdateable = ConditionProfile.createBinaryProfile(); - private PostProcessArgumentsNode(LocalReadVariableNode[] sequence) { - this.sequence = sequence; - this.createClone = false; - this.transArgsBitSet = 0; + private PostProcessArgumentsNode(int length) { + this.sequence = new LocalReadVariableNode[Math.min(length, ArgumentStatePush.MAX_COUNTED_ARGS)]; + this.transArgsBitSet = new AssumedValue<>("PostProcessArgumentsNode.transArgsBitSet", 0); } public static PostProcessArgumentsNode create(int length) { - int maxLength = Math.min(length, ArgumentStatePush.MAX_COUNTED_ARGS); - LocalReadVariableNode[] argReadNodes = new LocalReadVariableNode[maxLength]; - for (int i = 0; i < maxLength; i++) { - argReadNodes[i] = LocalReadVariableNode.create(Integer.valueOf(1 << i), false); - } - return new PostProcessArgumentsNode(argReadNodes); + return new PostProcessArgumentsNode(length); } public int getLength() { @@ -72,20 +62,20 @@ public final class PostProcessArgumentsNode extends RNode { @Override @ExplodeLoop public Object execute(VirtualFrame frame) { - if (transArgsBitSet > 0) { + int bits = transArgsBitSet.get(); + if (bits != 0) { for (int i = 0; i < sequence.length; i++) { int mask = 1 << i; - if ((transArgsBitSet & mask) == mask) { - RShareable s = (RShareable) sequence[i].execute(frame); - if (s == null) { - // it happens rarely in compiled code, but if it does happen, stop - // decrementing reference counts + if ((bits & mask) != 0) { + if (sequence[i] == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - transArgsBitSet = ArgumentStatePush.INVALID_INDEX; - break; + sequence[i] = insert(LocalReadVariableNode.create(Integer.valueOf(mask), false)); } - if (isRefCountUpdateable.profile(!s.isSharedPermanent())) { - s.decRefCount(); + RShareable s = (RShareable) sequence[i].execute(frame); + if (isNonNull.profile(s != null)) { + if (isRefCountUpdateable.profile(!s.isSharedPermanent())) { + s.decRefCount(); + } } } } @@ -93,38 +83,15 @@ public final class PostProcessArgumentsNode extends RNode { return RNull.instance; } - @Override - public Node deepCopy() { - CompilerAsserts.neverPartOfCompilation(); - if (createClone) { - return deepCopyUnconditional(); - } else { - this.createClone = true; - return this; - } - } - - /* - * Deep copies are also made from other places than the trufflerizer, in which case we need to - * always create the node chain. - */ - private PostProcessArgumentsNode deepCopyUnconditional() { - CompilerAsserts.neverPartOfCompilation(); - PostProcessArgumentsNode copy = (PostProcessArgumentsNode) super.deepCopy(); - nextOptPostProccessArgNode = insert(copy); - return copy; - - } - - PostProcessArgumentsNode getActualNode() { - CompilerAsserts.neverPartOfCompilation(); - if (nextOptPostProccessArgNode == null) { - return this; - } else { - PostProcessArgumentsNode nextNode = nextOptPostProccessArgNode.getActualNode(); - // shorten up the lookup chain - nextOptPostProccessArgNode = insert(nextNode); - return nextNode; + public boolean updateBits(int index) { + if (index < sequence.length) { + int bits = transArgsBitSet.get(); + int newBits = bits | (1 << index); + if (newBits != bits) { + transArgsBitSet.set(newBits); + } + return true; } + return false; } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java index c46789e565ff14114ae83507b1e84a267fab3d1d..e9a22756634aa1683cf6ee0403f0649c818f0869 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java @@ -409,8 +409,17 @@ public abstract class PromiseNode extends RNode { private final ConditionProfile argsValueAndNamesProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile containsVarargProfile = ConditionProfile.createBinaryProfile(); - @CompilationFinal ArgumentsSignature cachedVarArgSignature; - @CompilationFinal ArgumentsSignature cachedResultSignature; + private static final class Cache { + private final ArgumentsSignature signature; + private final ArgumentsSignature result; + + protected Cache(ArgumentsSignature signature, ArgumentsSignature result) { + this.signature = signature; + this.result = result; + } + } + + @CompilationFinal private Cache varArgsCache; InlineVarArgsNode(RNode[] nodes, ArgumentsSignature signature) { this.varargs = nodes; @@ -455,13 +464,20 @@ public abstract class PromiseNode extends RNode { if (evaluatedArgs.length == 1) { finalSignature = ((RArgsValuesAndNames) evaluatedArgs[0]).getSignature(); } else { - if (cachedVarArgSignature == ArgumentsSignature.INVALID_SIGNATURE) { + Cache cache = varArgsCache; + if (cache == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + finalSignature = createSignature(evaluatedArgs, flattenedArgs.length); + varArgsCache = new Cache(varArgSignature, finalSignature); + } else if (cache.signature == ArgumentsSignature.INVALID_SIGNATURE) { finalSignature = createSignature(evaluatedArgs, flattenedArgs.length); - } else if (varArgSignature == cachedVarArgSignature) { - finalSignature = cachedResultSignature; + } else if (varArgSignature == cache.signature) { + finalSignature = cache.result; } else { + CompilerDirectives.transferToInterpreterAndInvalidate(); + // fallback to the generic case finalSignature = createSignature(evaluatedArgs, flattenedArgs.length); - cachedVarArgSignature = cachedVarArgSignature == null ? finalSignature : ArgumentsSignature.INVALID_SIGNATURE; + varArgsCache = new Cache(ArgumentsSignature.INVALID_SIGNATURE, null); } } return new RArgsValuesAndNames(flattenedArgs, finalSignature); 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 d202fe1015cfe2a332ff77da078972284f3fecf1..4e172dbb8c5580e2dffd05863735790ea208d5b7 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 @@ -35,6 +35,7 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; +import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; @@ -55,14 +56,12 @@ import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.RRootNode; import com.oracle.truffle.r.nodes.access.ConstantNode; -import com.oracle.truffle.r.nodes.access.FrameSlotNode; import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinRootNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode; import com.oracle.truffle.r.nodes.function.RCallNodeGen.FunctionDispatchNodeGen; -import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.NoGenericMethodException; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result; import com.oracle.truffle.r.nodes.function.call.CallRFunctionNode; import com.oracle.truffle.r.nodes.function.call.PrepareArguments; @@ -234,11 +233,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS } protected FunctionDispatch createUninitializedCall() { - return FunctionDispatchNodeGen.create(this, null, explicitArgs == null ? false : true); + return FunctionDispatchNodeGen.create(this, explicitArgs != null, null); } protected FunctionDispatch createUninitializedExplicitCall() { - return FunctionDispatchNodeGen.create(this, null, true); + return FunctionDispatchNodeGen.create(this, true, null); } /** @@ -284,7 +283,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS @Cached("createBinaryProfile()") ConditionProfile resultIsBuiltinProfile) { RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin()); Object dispatchObject = dispatchArgument.execute(frame); - dispatchTempSlot.initialize(frame, dispatchObject, () -> internalDispatchCall = null); + FrameSlot slot = dispatchTempSlot.initialize(frame, dispatchObject); try { RStringVector type = classHierarchyNode.execute(dispatchObject); S3Args s3Args; @@ -301,13 +300,13 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS s3Args = null; resultFunction = function; } - if (internalDispatchCall == null) { + if (internalDispatchCall == null || internalDispatchCall.tempFrameSlot != slot) { CompilerDirectives.transferToInterpreterAndInvalidate(); - internalDispatchCall = insert(FunctionDispatchNodeGen.create(this, new Object[]{dispatchTempSlot.getIdentifier()}, false)); + internalDispatchCall = insert(FunctionDispatchNodeGen.create(this, false, slot)); } return internalDispatchCall.execute(frame, resultFunction, lookupVarArgs(frame), s3Args, null); } finally { - dispatchTempSlot.cleanup(frame, dispatchObject); + TemporarySlotNode.cleanup(frame, dispatchObject, slot); } } @@ -399,21 +398,13 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS RStringVector typeX = classHierarchyNodeX.execute(promiseHelperNode.checkEvaluate(frame, args[typeXIdx])); Result resultX = null; if (implicitTypeProfileX.profile(typeX != null)) { - try { - resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), null); - } catch (NoGenericMethodException e) { - // fall-through - } + resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), null); } Result resultY = null; if (args.length > 1 && dispatch == RDispatch.OPS_GROUP_GENERIC) { RStringVector typeY = classHierarchyNodeY.execute(promiseHelperNode.checkEvaluate(frame, args[1])); if (implicitTypeProfileY.profile(typeY != null)) { - try { - resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), null); - } catch (NoGenericMethodException e) { - // fall-through - } + resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), null); } } @@ -548,11 +539,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS return getParentCallNode().getFunctionNode(); } - public CallArgumentsNode createArguments(Object[] dispatchTempIdentifiers, boolean modeChange, boolean modeChangeAppliesToAll) { + public CallArgumentsNode createArguments(FrameSlot tempFrameSlot, boolean modeChange, boolean modeChangeAppliesToAll) { RNode[] args = new RNode[arguments.length]; for (int i = 0; i < arguments.length; i++) { - if (dispatchTempIdentifiers != null && i < dispatchTempIdentifiers.length) { - args[i] = new GetTempNode(dispatchTempIdentifiers[i], arguments[i]); + if (tempFrameSlot != null && i == 0) { + args[i] = new GetTempNode(tempFrameSlot, arguments[i]); } else { args[i] = arguments[i] == null ? null : RASTUtils.cloneNode(arguments[i].asRNode()); } @@ -570,7 +561,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS */ public static RNode createInternalCall(RCallNode internalCallArg, RFunction function) { CompilerAsserts.neverPartOfCompilation(); - return new InternalNode(FunctionDispatchNodeGen.create(internalCallArg, null, false), function, internalCallArg.lookupVarArgs != null); + return new InternalNode(FunctionDispatchNodeGen.create(internalCallArg, false, null), function, internalCallArg.lookupVarArgs != null); } @NodeInfo(cost = NodeCost.NONE) @@ -654,11 +645,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS private static final class GetTempNode extends RNode { - @Child private FrameSlotNode slot; + private final FrameSlot slot; private final RSyntaxNode arg; - GetTempNode(Object identifier, RSyntaxNode arg) { - slot = FrameSlotNode.createTemp(identifier, false); + GetTempNode(FrameSlot slot, RSyntaxNode arg) { + this.slot = slot; this.arg = arg; } @@ -670,7 +661,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS @Override public Object execute(VirtualFrame frame) { try { - return frame.getObject(slot.executeFrameSlot(frame)); + return frame.getObject(slot); } catch (FrameSlotTypeException e) { throw RInternalError.shouldNotReachHere(); } @@ -691,13 +682,14 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS protected static final int CACHE_SIZE = 4; private final RCallNode originalCall; - private final Object[] dispatchTempIdentifiers; private final boolean explicitArgs; - public FunctionDispatch(RCallNode originalCall, Object[] dispatchTempIdentifiers, boolean explicitArgs) { + private final FrameSlot tempFrameSlot; + + public FunctionDispatch(RCallNode originalCall, boolean explicitArgs, FrameSlot tempFrameSlot) { this.originalCall = originalCall; - this.dispatchTempIdentifiers = dispatchTempIdentifiers; this.explicitArgs = explicitArgs; + this.tempFrameSlot = tempFrameSlot; } protected LeafCallNode createCacheNode(RootCallTarget cachedTarget) { @@ -717,7 +709,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS if (explicitArgs) { return PrepareArguments.createExplicit(root); } else { - CallArgumentsNode args = originalCall.createArguments(dispatchTempIdentifiers, root.getBuiltin() == null, true); + CallArgumentsNode args = originalCall.createArguments(tempFrameSlot, root.getBuiltin() == null, true); return PrepareArguments.create(root, args, noOpt); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java index 41082f5156c4439809ac6c083d56da246f3f28c3..2ddb5474316dbf7260cda12b317c9002b32fb671 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java @@ -23,7 +23,6 @@ import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.ControlFlowException; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; @@ -33,6 +32,7 @@ import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RArguments.S3Args; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; @@ -74,18 +74,22 @@ public abstract class S3FunctionLookupNode extends RBaseNode { this.targetFunctionName = targetFunctionName; this.groupMatch = groupMatch; } + + public S3Args createS3Args(Frame frame) { + return new S3Args(generic, clazz, targetFunctionName, frame.materialize(), null, null); + } } public static S3FunctionLookupNode create(boolean throwsError, boolean nextMethod) { - return new UseMethodFunctionLookupUninitializedNode(throwsError, nextMethod); + return new UseMethodFunctionLookupUninitializedNode(throwsError, nextMethod, 0); } public static S3FunctionLookupNode createWithError() { - return new UseMethodFunctionLookupUninitializedNode(true, false); + return new UseMethodFunctionLookupUninitializedNode(true, false, 0); } public static S3FunctionLookupNode createWithException() { - return new UseMethodFunctionLookupUninitializedNode(false, false); + return new UseMethodFunctionLookupUninitializedNode(false, false, 0); } @FunctionalInterface @@ -235,19 +239,21 @@ public abstract class S3FunctionLookupNode extends RBaseNode { @NodeInfo(cost = NodeCost.UNINITIALIZED) private static final class UseMethodFunctionLookupUninitializedNode extends S3FunctionLookupNode { - private int depth; + private final int depth; - UseMethodFunctionLookupUninitializedNode(boolean throwsError, boolean nextMethod) { + UseMethodFunctionLookupUninitializedNode(boolean throwsError, boolean nextMethod, int depth) { super(throwsError, nextMethod); + this.depth = depth; } @Override public Result execute(VirtualFrame frame, String genericName, RStringVector type, String group, MaterializedFrame callerFrame, MaterializedFrame genericDefFrame) { CompilerDirectives.transferToInterpreterAndInvalidate(); - if (++depth > MAX_CACHE_DEPTH) { + if (depth > MAX_CACHE_DEPTH) { return replace(new UseMethodFunctionLookupGenericNode(throwsError, nextMethod)).execute(frame, genericName, type, group, callerFrame, genericDefFrame); } else { - UseMethodFunctionLookupCachedNode cachedNode = replace(specialize(frame, genericName, type, group, callerFrame, genericDefFrame, this)); + UseMethodFunctionLookupCachedNode cachedNode = replace( + specialize(frame, genericName, type, group, callerFrame, genericDefFrame, new UseMethodFunctionLookupUninitializedNode(throwsError, nextMethod, depth + 1))); return cachedNode.execute(frame, genericName, type, group, callerFrame, genericDefFrame); } } @@ -329,7 +335,7 @@ public abstract class S3FunctionLookupNode extends RBaseNode { } throw RError.error(this, RError.Message.UNKNOWN_FUNCTION_USE_METHOD, genericName, type); } else { - throw S3FunctionLookupNode.NoGenericMethodException.instance; + return null; } } while (true); CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -431,19 +437,10 @@ public abstract class S3FunctionLookupNode extends RBaseNode { } throw RError.error(this, RError.Message.UNKNOWN_FUNCTION_USE_METHOD, genericName, RRuntime.toString(type)); } else { - throw S3FunctionLookupNode.NoGenericMethodException.instance; + return null; } } return result; } } - - @SuppressWarnings("serial") - public static final class NoGenericMethodException extends ControlFlowException { - private static final NoGenericMethodException instance = new NoGenericMethodException(); - - private NoGenericMethodException() { - // singleton - } - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java index cab3f3c4da90b28fb840338a03006ebcd7bb9b31..03e13b0d068b6a277a8511029d130b4bab6ba20b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java @@ -37,33 +37,35 @@ public final class TemporarySlotNode extends Node { @CompilationFinal private FrameSlot tempSlot; private int tempIdentifier; - private Object identifier; - public void initialize(VirtualFrame frame, Object value, Runnable invalidate) { + public FrameSlot initialize(VirtualFrame frame, Object value) { if (tempSlot == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - tempSlot = frame.getFrameDescriptor().findOrAddFrameSlot(identifier = defaultTempIdentifiers[0], FrameSlotKind.Object); - invalidate.run(); + tempSlot = frame.getFrameDescriptor().findOrAddFrameSlot(defaultTempIdentifiers[0], FrameSlotKind.Object); } + FrameSlot slot = tempSlot; try { - if (frame.getObject(tempSlot) != null) { + if (frame.getObject(slot) != null) { CompilerDirectives.transferToInterpreterAndInvalidate(); // keep the complete loop in the slow path do { tempIdentifier++; - identifier = tempIdentifier < defaultTempIdentifiers.length ? defaultTempIdentifiers[tempIdentifier] : new Object(); - tempSlot = frame.getFrameDescriptor().findOrAddFrameSlot(identifier, FrameSlotKind.Object); - invalidate.run(); - } while (frame.getObject(tempSlot) != null); + Object identifier = tempIdentifier < defaultTempIdentifiers.length ? defaultTempIdentifiers[tempIdentifier] : new Object(); + tempSlot = slot = frame.getFrameDescriptor().findOrAddFrameSlot(identifier, FrameSlotKind.Object); + if (frame.getObject(slot) == null) { + break; + } + } while (true); } } catch (FrameSlotTypeException e) { CompilerDirectives.transferToInterpreter(); throw RInternalError.shouldNotReachHere(); } - frame.setObject(tempSlot, value); + frame.setObject(slot, value); + return slot; } - public void cleanup(VirtualFrame frame, Object object) { + public static void cleanup(VirtualFrame frame, Object object, FrameSlot tempSlot) { try { assert frame.getObject(tempSlot) == object; } catch (FrameSlotTypeException e) { @@ -71,8 +73,4 @@ public final class TemporarySlotNode extends Node { } frame.setObject(tempSlot, null); } - - public Object getIdentifier() { - return identifier; - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodInternalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodInternalNode.java deleted file mode 100644 index 739931976e6def1f5933a27c1c92806339e413c4..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodInternalNode.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (c) 2014, Purdue University - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.nodes.function; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result; -import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.FastROptions; -import com.oracle.truffle.r.runtime.RArguments.S3Args; -import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.nodes.RNode; - -public final class UseMethodInternalNode extends RNode { - - @Child private ClassHierarchyNode classHierarchyNode = ClassHierarchyNodeGen.create(true, true); - @Child private S3FunctionLookupNode lookup = S3FunctionLookupNode.create(false, false); - @Child private CallMatcherNode callMatcher = CallMatcherNode.create(false); - @Child private PreProcessArgumentsNode argPreProcess; - - private final String generic; - private final ArgumentsSignature signature; - private final boolean wrap; - - public UseMethodInternalNode(String generic, ArgumentsSignature signature, boolean wrap) { - this.generic = generic; - this.signature = signature; - this.wrap = wrap && FastROptions.InvisibleArgs.getBooleanValue(); - } - - public Object execute(VirtualFrame frame, RStringVector type, Object[] arguments) { - Result lookupResult = lookup.execute(frame, generic, type, null, frame.materialize(), null); - if (wrap) { - assert arguments != null; - if (argPreProcess == null || argPreProcess.getLength() != arguments.length) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - argPreProcess = insert(PreProcessArgumentsNode.create(arguments.length)); - } - argPreProcess.execute(frame, arguments); - } - S3Args s3Args = new S3Args(generic, lookupResult.clazz, lookupResult.targetFunctionName, frame.materialize(), null, null); - return callMatcher.execute(frame, signature, arguments, lookupResult.function, lookupResult.targetFunctionName, s3Args); - } - - @Override - public Object execute(VirtualFrame frame) { - throw RInternalError.shouldNotReachHere(); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentNode.java index 7ed844a144758904c56d2f9e9463f19e2c1d3673..8a6471d4845ffb956178fdb29cb6fac32f94240a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentNode.java @@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.function; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.UnexpectedResultException; -import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.r.nodes.access.ConstantNode; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; @@ -44,8 +43,6 @@ public final class WrapArgumentNode extends WrapArgumentBaseNode { @Child private ArgumentStatePush argPushStateNode; - private final BranchProfile refCounted = BranchProfile.create(); - private WrapArgumentNode(RNode operand, boolean modeChange, int index) { super(operand, modeChange); this.modeChange = modeChange; @@ -79,9 +76,6 @@ public final class WrapArgumentNode extends WrapArgumentBaseNode { if (rShareable != null) { shareable.enter(); argPushStateNode.executeObject(frame, rShareable); - } else if (argPushStateNode.refCounted()) { - refCounted.enter(); - argPushStateNode.executeObject(frame, RNull.instance); } } return result; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java index 60218f9968d1610f1a04a6f303e88eb16bbd1e53..5b48ec10193c4ede8faf5340e4ed14b5eee1032d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java @@ -23,15 +23,23 @@ package com.oracle.truffle.r.nodes.function.call; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout; import com.oracle.truffle.r.nodes.RRootNode; import com.oracle.truffle.r.nodes.function.ArgumentMatcher; import com.oracle.truffle.r.nodes.function.ArgumentMatcher.MatchPermutation; import com.oracle.truffle.r.nodes.function.CallArgumentsNode; import com.oracle.truffle.r.nodes.function.FormalArguments; import com.oracle.truffle.r.nodes.function.RCallNode; +import com.oracle.truffle.r.nodes.function.call.PrepareArgumentsFactory.PrepareArgumentsDefaultNodeGen; +import com.oracle.truffle.r.nodes.function.call.PrepareArgumentsFactory.PrepareArgumentsExplicitNodeGen; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments.S3DefaultArguments; @@ -44,171 +52,111 @@ import com.oracle.truffle.r.runtime.nodes.RNode; * rules. It implements two different paths: one for arguments provided as an * {@link CallArgumentsNode}, i.e., unevaluated arguments, and another path for evaluated arguments. */ +@TypeSystemReference(EmptyTypeSystemFlatLayout.class) public abstract class PrepareArguments extends Node { - private static final int CACHE_SIZE = 4; + protected static final int CACHE_SIZE = 8; - /** - * Returns the argument values and corresponding signature. The signature represents the - * original call signature reordered in the same way as the arguments. For s3DefaultArguments - * motivation see {@link RCallNode#callGroupGeneric}. - */ - public abstract RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call); + abstract static class PrepareArgumentsDefault extends PrepareArguments { - public static PrepareArguments create(RRootNode target, CallArgumentsNode args, boolean noOpt) { - return new UninitializedPrepareArguments(target, args, noOpt); - } + protected final RRootNode target; + protected final CallArgumentsNode sourceArguments; // not used as a node + protected final boolean noOpt; - public static PrepareArguments createExplicit(RRootNode target) { - return new UninitializedExplicitPrepareArguments(target); - } + static final class ArgumentsAndSignature extends Node { + @Children private final RNode[] matchedArguments; + private final ArgumentsSignature matchedSuppliedSignature; - @ExplodeLoop - private static RArgsValuesAndNames executeArgs(RNode[] arguments, ArgumentsSignature suppliedSignature, VirtualFrame frame) { - Object[] result = new Object[arguments.length]; - for (int i = 0; i < arguments.length; i++) { - result[i] = arguments[i].execute(frame); + protected ArgumentsAndSignature(RNode[] matchedArguments, ArgumentsSignature matchedSuppliedSignature) { + this.matchedArguments = matchedArguments; + this.matchedSuppliedSignature = matchedSuppliedSignature; + } } - return new RArgsValuesAndNames(result, suppliedSignature); - } - - private static RArgsValuesAndNames executeArgs(Arguments<RNode> matched, VirtualFrame frame) { - return executeArgs(matched.getArguments(), matched.getSignature(), frame); - } - - private static final class UninitializedPrepareArguments extends PrepareArguments { - private final RRootNode target; - private final CallArgumentsNode sourceArguments; // not used as a node - private final boolean noOpt; - private int depth = CACHE_SIZE; + protected static ArgumentsSignature getSignatureOrNull(RArgsValuesAndNames args) { + return args == null ? null : args.getSignature(); + } - UninitializedPrepareArguments(RRootNode target, CallArgumentsNode sourceArguments, boolean noOpt) { + protected PrepareArgumentsDefault(RRootNode target, CallArgumentsNode sourceArguments, boolean noOpt) { this.target = target; this.sourceArguments = sourceArguments; this.noOpt = noOpt; } - @Override - public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - PrepareArguments next; - if (depth-- > 0) { - next = new CachedPrepareArguments(this, target, call, sourceArguments, varArgs == null ? null : varArgs.getSignature(), s3DefaultArguments, noOpt); - } else { - next = new GenericPrepareArguments(target, sourceArguments); - } - return replace(next).execute(frame, varArgs, s3DefaultArguments, call); - } - } - - private static final class CachedPrepareArguments extends PrepareArguments { - - @Child private PrepareArguments next; - @Children private final RNode[] matchedArguments; - private final ArgumentsSignature matchedSuppliedSignature; - private final ArgumentsSignature cachedVarArgSignature; - private final Object cachedS3DefaultArguments; - - CachedPrepareArguments(PrepareArguments next, RRootNode target, RCallNode call, CallArgumentsNode args, ArgumentsSignature varArgSignature, S3DefaultArguments s3DefaultArguments, - boolean noOpt) { - this.next = next; - cachedVarArgSignature = varArgSignature; - Arguments<RNode> matched = ArgumentMatcher.matchArguments(target, args, varArgSignature, s3DefaultArguments, call, noOpt); - this.matchedArguments = matched.getArguments(); - this.matchedSuppliedSignature = matched.getSignature(); - this.cachedS3DefaultArguments = s3DefaultArguments; + protected ArgumentsAndSignature createArguments(RCallNode call, ArgumentsSignature varArgSignature, S3DefaultArguments s3DefaultArguments) { + Arguments<RNode> matched = ArgumentMatcher.matchArguments(target, sourceArguments, varArgSignature, s3DefaultArguments, call, noOpt); + return new ArgumentsAndSignature(matched.getArguments(), matched.getSignature()); } - @Override @ExplodeLoop - public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) { - assert (cachedVarArgSignature != null) == (varArgs != null); - if ((cachedVarArgSignature == null || cachedVarArgSignature == varArgs.getSignature()) && cachedS3DefaultArguments == s3DefaultArguments) { - return executeArgs(matchedArguments, matchedSuppliedSignature, frame); + private static RArgsValuesAndNames executeArgs(RNode[] arguments, ArgumentsSignature suppliedSignature, VirtualFrame frame) { + Object[] result = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + result[i] = arguments[i].execute(frame); } - return next.execute(frame, varArgs, s3DefaultArguments, call); + return new RArgsValuesAndNames(result, suppliedSignature); } - } - - private static final class GenericPrepareArguments extends PrepareArguments { - private final RRootNode target; - private final CallArgumentsNode args; // not used as a node - - GenericPrepareArguments(RRootNode target, CallArgumentsNode args) { - this.target = target; - this.args = args; + @Specialization(limit = "CACHE_SIZE", guards = {"cachedVarArgSignature == null || cachedVarArgSignature == varArgs.getSignature()", "cachedS3DefaultArguments == s3DefaultArguments"}) + public RArgsValuesAndNames prepare(VirtualFrame frame, RArgsValuesAndNames varArgs, @SuppressWarnings("unused") S3DefaultArguments s3DefaultArguments, + @SuppressWarnings("unused") RCallNode call, + @Cached("getSignatureOrNull(varArgs)") ArgumentsSignature cachedVarArgSignature, + @Cached("createArguments(call, cachedVarArgSignature, s3DefaultArguments)") ArgumentsAndSignature arguments, + @SuppressWarnings("unused") @Cached("s3DefaultArguments") S3DefaultArguments cachedS3DefaultArguments) { + assert (cachedVarArgSignature != null) == (varArgs != null); + return executeArgs(arguments.matchedArguments, arguments.matchedSuppliedSignature, frame); } - @Override - public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) { + @Fallback + public RArgsValuesAndNames prepareGeneric(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call) { CompilerDirectives.transferToInterpreter(); ArgumentsSignature varArgSignature = varArgs == null ? null : varArgs.getSignature(); - Arguments<RNode> matchedArgs = ArgumentMatcher.matchArguments(target, args, varArgSignature, s3DefaultArguments, RError.ROOTNODE, true); - return executeArgs(matchedArgs, frame); + Arguments<RNode> matchedArgs = ArgumentMatcher.matchArguments(target, sourceArguments, varArgSignature, s3DefaultArguments, RError.ROOTNODE, true); + return executeArgs(matchedArgs.getArguments(), matchedArgs.getSignature(), frame); } } - private static final class UninitializedExplicitPrepareArguments extends PrepareArguments { + abstract static class PrepareArgumentsExplicit extends PrepareArguments { - private final RRootNode target; - private int depth = CACHE_SIZE; + protected final RRootNode target; + private final FormalArguments formals; - UninitializedExplicitPrepareArguments(RRootNode target) { + protected PrepareArgumentsExplicit(RRootNode target) { this.target = target; + this.formals = target.getFormalArguments(); } - @Override - public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - PrepareArguments next; - if (depth-- > 0) { - next = new CachedExplicitPrepareArguments(this, target, call, explicitArgs == null ? null : explicitArgs.getSignature()); - } else { - next = new GenericExplicitPrepareArguments(target); - } - return replace(next).execute(frame, explicitArgs, s3DefaultArguments, call); + protected MatchPermutation createArguments(RCallNode call, ArgumentsSignature explicitArgSignature) { + return ArgumentMatcher.matchArguments(explicitArgSignature, formals.getSignature(), call, target.getBuiltin()); } - } - - private static final class CachedExplicitPrepareArguments extends PrepareArguments { - - @Child private PrepareArguments next; - - private final MatchPermutation permutation; - private final ArgumentsSignature cachedExplicitArgSignature; - private final FormalArguments formals; - CachedExplicitPrepareArguments(PrepareArguments next, RRootNode target, RCallNode call, ArgumentsSignature explicitArgSignature) { - this.next = next; - formals = target.getFormalArguments(); - permutation = ArgumentMatcher.matchArguments(explicitArgSignature, formals.getSignature(), call, target.getBuiltin()); - cachedExplicitArgSignature = explicitArgSignature; + @Specialization(limit = "CACHE_SIZE", guards = {"cachedExplicitArgSignature == explicitArgs.getSignature()"}) + public RArgsValuesAndNames prepare(RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call, + @SuppressWarnings("unused") @Cached("explicitArgs.getSignature()") ArgumentsSignature cachedExplicitArgSignature, + @Cached("createArguments(call, cachedExplicitArgSignature)") MatchPermutation permutation) { + return ArgumentMatcher.matchArgumentsEvaluated(permutation, explicitArgs.getArguments(), s3DefaultArguments, formals); } - @Override - public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) { - if (cachedExplicitArgSignature == explicitArgs.getSignature()) { - return ArgumentMatcher.matchArgumentsEvaluated(permutation, explicitArgs.getArguments(), s3DefaultArguments, formals); - } - return next.execute(frame, explicitArgs, s3DefaultArguments, call); + @Fallback + @TruffleBoundary + public RArgsValuesAndNames prepareGeneric(RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call) { + // Function and arguments may change every call: Flatt'n'Match on SlowPath! :-/ + return ArgumentMatcher.matchArgumentsEvaluated(target, explicitArgs, s3DefaultArguments, RError.ROOTNODE); } } - private static final class GenericExplicitPrepareArguments extends PrepareArguments { - - private final RRootNode target; + /** + * Returns the argument values and corresponding signature. The signature represents the + * original call signature reordered in the same way as the arguments. For s3DefaultArguments + * motivation see {@link RCallNode#callGroupGeneric}. + */ + public abstract RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call); - GenericExplicitPrepareArguments(RRootNode target) { - this.target = target; - } + public static PrepareArguments create(RRootNode target, CallArgumentsNode args, boolean noOpt) { + return PrepareArgumentsDefaultNodeGen.create(target, args, noOpt); + } - @Override - public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) { - CompilerDirectives.transferToInterpreter(); - // Function and arguments may change every call: Flatt'n'Match on SlowPath! :-/ - return ArgumentMatcher.matchArgumentsEvaluated(target, explicitArgs, s3DefaultArguments, RError.ROOTNODE); - } + public static PrepareArguments createExplicit(RRootNode target) { + return PrepareArgumentsExplicitNodeGen.create(target); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestTestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestTestBase.java index 235264d8223d504e607cfffac0f69e535ecf3017..be53842774b8ccb73b1a0cdf99dc7a8322c0a420 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestTestBase.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestTestBase.java @@ -55,7 +55,7 @@ public class TestTestBase extends TestBase { getCode("cat('Warning message: In .Internal(foo(42)): IgnoreWarningContext diff message')", "cat('Warning message in foo(42): IgnoreWarningContext should fail')")); } - private String getCode(String fastr, String gnur) { + private static String getCode(String fastr, String gnur) { return "if (exists('.fastr.identity')) { " + fastr + " } else { " + gnur + " }"; } }