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/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/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;