diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java index ea2ad49044969de8e673dd815a272e3177370ceb..186e8160881ca9c51f51aeb7e52ab7aa7d34d04a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java @@ -262,9 +262,14 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> { SimpleAccessVariable vAST = (SimpleAccessVariable) args.first().getValue(); String vSymbol = vAST.getSymbol().toString(); - // store a - final String a = "*tmp_a*"; - WriteVariableNode aAssign = WriteVariableNode.create(a, rhs, false, false); + //@formatter:off + // store a - need to use temporary, otherwise there is a failure in case multiple calls to + // the replacement form are chained: + // x<-c(1); y<-c(1); dim(x)<-1; dim(y)<-1; attr(x, "dimnames")<-(attr(y, "dimnames")<-list("b")) + //@formatter:on + + final Object a = new Object(); + WriteVariableNode aAssign = WriteVariableNode.create(a, rhs, false, false, true); // read v, assign tmp ReadVariableNode v = n.isSuper() ? ReadSuperVariableNode.create(vAST.getSource(), vSymbol, context, false, false) : ReadVariableNode.create(vAST.getSource(), vSymbol, context, false, false); @@ -279,7 +284,7 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> { rfArgs.add(args.getNode(i)); } } - rfArgs.add(AccessVariable.create(null, a, false)); + rfArgs.add(AccessVariable.create(null, a)); // replacement function call (use visitor for FunctionCall) FunctionCall rfCall = new FunctionCall(null, f.getName(), rfArgs); @@ -300,6 +305,11 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> { return ReadVariableNode.create(n.getSource(), n.getSymbol(), context, false, n.shouldCopyValue()); } + @Override + public RNode visit(SimpleAccessTempVariable n) { + return ReadVariableNode.create(n.getSource(), n.getSymbol(), context, false, false); + } + @Override public RNode visit(If n) { RNode condition = n.getCond().accept(this); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java index a102d2f90a429db4bffa9e61aff1df692a727e03..34708faa34db3d7e48264309cef3dd8cbf13391b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java @@ -47,7 +47,11 @@ public abstract class WriteVariableNode extends RNode { @com.oracle.truffle.api.CompilerDirectives.CompilationFinal boolean everSeenTemporary; @com.oracle.truffle.api.CompilerDirectives.CompilationFinal boolean everSeenSequence; - protected void writeObjectValue(@SuppressWarnings("unused") VirtualFrame virtualFrame, Frame frame, FrameSlot frameSlot, Object value) { + // the toBeCopied parameter is meant to prevent creation of the shared/non-temp vector; this + // needed for the implementation of the replacement forms of builtin functions as their last + // argument can be mutaded; for example, in "dimnames(x)<-list(1)", the assigned value list(1) + // must become list("1"), with the latter value returned as a result of the call + protected void writeObjectValue(@SuppressWarnings("unused") VirtualFrame virtualFrame, Frame frame, FrameSlot frameSlot, Object value, boolean toBeCopied) { Object newValue = value; if (!isArgWrite()) { Object frameValue; @@ -72,21 +76,33 @@ public abstract class WriteVariableNode extends RNode { CompilerDirectives.transferToInterpreterAndInvalidate(); everSeenTemporary = true; } - rVector.markNonTemporary(); + if (toBeCopied) { + RVector vectorCopy = rVector.copy(); + newValue = vectorCopy; + } else { + rVector.markNonTemporary(); + } } else if (rVector.isShared()) { if (!everSeenShared) { CompilerDirectives.transferToInterpreterAndInvalidate(); everSeenShared = true; } RVector vectorCopy = rVector.copy(); - vectorCopy.markNonTemporary(); + if (!toBeCopied) { + vectorCopy.markNonTemporary(); + } newValue = vectorCopy; } else { if (!everSeenNonShared) { CompilerDirectives.transferToInterpreterAndInvalidate(); everSeenNonShared = true; } - rVector.makeShared(); + if (toBeCopied) { + RVector vectorCopy = rVector.copy(); + newValue = vectorCopy; + } else { + rVector.makeShared(); + } } } } @@ -95,28 +111,34 @@ public abstract class WriteVariableNode extends RNode { frame.setObject(frameSlot, newValue); } - public static WriteVariableNode create(Object symbol, RNode rhs, boolean isArgWrite, boolean isSuper) { + public static WriteVariableNode create(Object symbol, RNode rhs, boolean isArgWrite, boolean isSuper, boolean toBeCopied) { if (!isSuper) { - return UnresolvedWriteLocalVariableNodeFactory.create(rhs, isArgWrite, symbol.toString()); + return UnresolvedWriteLocalVariableNodeFactory.create(rhs, isArgWrite, symbol.toString(), toBeCopied); } else { assert !isArgWrite; - return new UnresolvedWriteSuperVariableNode(rhs, symbol.toString()); + return new UnresolvedWriteSuperVariableNode(rhs, symbol.toString(), toBeCopied); } } + public static WriteVariableNode create(Object symbol, RNode rhs, boolean isArgWrite, boolean isSuper) { + return create(symbol, rhs, isArgWrite, isSuper, false); + } + public static WriteVariableNode create(SourceSection src, Object symbol, RNode rhs, boolean isArgWrite, boolean isSuper) { - WriteVariableNode wvn = create(symbol, rhs, isArgWrite, isSuper); + WriteVariableNode wvn = create(symbol, rhs, isArgWrite, isSuper, false); wvn.assignSourceSection(src); return wvn; } public abstract void execute(VirtualFrame frame, Object value); - @NodeField(name = "symbol", type = Object.class) + @NodeFields({@NodeField(name = "symbol", type = Object.class), @NodeField(name = "toBeCopied", type = boolean.class)}) public abstract static class UnresolvedWriteLocalVariableNode extends WriteVariableNode { public abstract Object getSymbol(); + public abstract boolean isToBeCopied(); + @Specialization public byte doLogical(VirtualFrame frame, byte value) { resolveAndSet(frame, value, FrameSlotKind.Byte); @@ -150,15 +172,17 @@ public abstract class WriteVariableNode extends RNode { private void resolveAndSet(VirtualFrame frame, Object value, FrameSlotKind initialKind) { CompilerAsserts.neverPartOfCompilation(); FrameSlot frameSlot = frame.getFrameDescriptor().findOrAddFrameSlot(getSymbol(), initialKind); - replace(ResolvedWriteLocalVariableNode.create(getRhs(), this.isArgWrite(), frameSlot)).execute(frame, value); + replace(ResolvedWriteLocalVariableNode.create(getRhs(), this.isArgWrite(), frameSlot, isToBeCopied())).execute(frame, value); } } - @NodeField(name = "frameSlot", type = FrameSlot.class) + @NodeFields({@NodeField(name = "frameSlot", type = FrameSlot.class), @NodeField(name = "toBeCopied", type = boolean.class)}) public abstract static class ResolvedWriteLocalVariableNode extends WriteVariableNode { - public static ResolvedWriteLocalVariableNode create(RNode rhs, boolean isArgWrite, FrameSlot frameSlot) { - return ResolvedWriteLocalVariableNodeFactory.create(rhs, isArgWrite, frameSlot); + public abstract boolean isToBeCopied(); + + public static ResolvedWriteLocalVariableNode create(RNode rhs, boolean isArgWrite, FrameSlot frameSlot, boolean toBeCopied) { + return ResolvedWriteLocalVariableNodeFactory.create(rhs, isArgWrite, frameSlot, toBeCopied); } @Specialization(guards = "isBooleanKind") @@ -181,13 +205,13 @@ public abstract class WriteVariableNode extends RNode { @Specialization(guards = "isObjectKind") public Object doObject(VirtualFrame frame, FrameSlot frameSlot, RInvisible value) { - super.writeObjectValue(frame, frame, frameSlot, value.get()); + super.writeObjectValue(frame, frame, frameSlot, value.get(), isToBeCopied()); return value; } @Specialization(guards = "isObjectKind") public Object doObject(VirtualFrame frame, FrameSlot frameSlot, Object value) { - super.writeObjectValue(frame, frame, frameSlot, value); + super.writeObjectValue(frame, frame, frameSlot, value, isToBeCopied()); return value; } } @@ -246,10 +270,12 @@ public abstract class WriteVariableNode extends RNode { @Child private RNode rhs; private final Object symbol; + private final boolean toBeCopied; - public UnresolvedWriteSuperVariableNode(RNode rhs, Object symbol) { + public UnresolvedWriteSuperVariableNode(RNode rhs, Object symbol, boolean toBeCopied) { this.rhs = adoptChild(rhs); this.symbol = symbol; + this.toBeCopied = toBeCopied; } @Override @@ -266,10 +292,10 @@ public abstract class WriteVariableNode extends RNode { // if this is the first node in the chain, needs the rhs and enclosingFrame nodes AccessEnclosingFrameNode enclosingFrameNode = RArguments.get(frame).getEnclosingFrame() == enclosingFrame ? AccessEnclosingFrameNodeFactory.create(1) : null; writeNode = WriteSuperVariableNodeFactory.create(getRhs(), enclosingFrameNode, new FrameSlotNode.PresentFrameSlotNode(enclosingFrame.getFrameDescriptor().findOrAddFrameSlot(symbol)), - this.isArgWrite()); + this.isArgWrite(), toBeCopied); } else { - WriteSuperVariableNode actualWriteNode = WriteSuperVariableNodeFactory.create(null, null, new FrameSlotNode.UnresolvedFrameSlotNode(symbol), this.isArgWrite()); - writeNode = new WriteSuperVariableConditionalNode(actualWriteNode, new UnresolvedWriteSuperVariableNode(null, symbol), getRhs()); + WriteSuperVariableNode actualWriteNode = WriteSuperVariableNodeFactory.create(null, null, new FrameSlotNode.UnresolvedFrameSlotNode(symbol), this.isArgWrite(), toBeCopied); + writeNode = new WriteSuperVariableConditionalNode(actualWriteNode, new UnresolvedWriteSuperVariableNode(null, symbol, toBeCopied), getRhs()); } replace(writeNode).execute(frame, value, enclosingFrame); } @@ -282,7 +308,7 @@ public abstract class WriteVariableNode extends RNode { execute(frame, value, enclosingFrame); } else { // we're in global scope, do a local write instead - replace(UnresolvedWriteLocalVariableNodeFactory.create(getRhs(), this.isArgWrite(), symbol.toString())).execute(frame, value); + replace(UnresolvedWriteLocalVariableNodeFactory.create(getRhs(), this.isArgWrite(), symbol.toString(), toBeCopied)).execute(frame, value); } } @@ -294,10 +320,13 @@ public abstract class WriteVariableNode extends RNode { @SuppressWarnings("unused") @NodeChildren({@NodeChild(value = "enclosingFrame", type = AccessEnclosingFrameNode.class), @NodeChild(value = "frameSlotNode", type = FrameSlotNode.class)}) + @NodeField(name = "toBeCopied", type = boolean.class) public abstract static class WriteSuperVariableNode extends AbstractWriteSuperVariableNode { protected abstract FrameSlotNode getFrameSlotNode(); + public abstract boolean isToBeCopied(); + @Specialization(guards = "isBooleanKind") public byte doBoolean(VirtualFrame frame, byte value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { enclosingFrame.setByte(frameSlot, value); @@ -318,13 +347,13 @@ public abstract class WriteVariableNode extends RNode { @Specialization(guards = "isObjectKind") public Object doObject(VirtualFrame frame, RInvisible value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { - super.writeObjectValue(frame, enclosingFrame, frameSlot, value.get()); + super.writeObjectValue(frame, enclosingFrame, frameSlot, value.get(), isToBeCopied()); return value; } @Specialization(guards = "isObjectKind") public Object doObject(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { - super.writeObjectValue(frame, enclosingFrame, frameSlot, value); + super.writeObjectValue(frame, enclosingFrame, frameSlot, value, isToBeCopied()); return value; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java index e58d4689d0194d5fb1d96cd4d0a1cef55ba36bd0..34a61f1d00b069756d99c7eff673eaed1224077b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java @@ -78,7 +78,7 @@ public abstract class UpdateDimNames extends RBuiltinNode { @Specialization(order = 3, guards = "!isZeroLength") public RAbstractVector updateDimnames(VirtualFrame frame, RAbstractVector vector, RList list) { RVector v = vector.materialize(); - v.setDimNames(list, this.getSourceSection()); + v.setDimNames(convertToListOfStrings(frame, list), this.getSourceSection()); return v; } diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/AccessVariable.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/AccessVariable.java index c3faf91f7ceefc716879b2589d327f6ff4f0c332..d73a6107ffcef192d69dee4d319d3b51b7557728 100644 --- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/AccessVariable.java +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/AccessVariable.java @@ -17,4 +17,8 @@ public abstract class AccessVariable extends ASTNode { public static ASTNode create(SourceSection src, String name, boolean shouldCopyValue) { return new SimpleAccessVariable(src, Symbol.getSymbol(name), shouldCopyValue); } + + public static ASTNode create(SourceSection src, Object tempSymbol) { + return new SimpleAccessTempVariable(src, tempSymbol); + } } diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/SimpleAccessTempVariable.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/SimpleAccessTempVariable.java new file mode 100644 index 0000000000000000000000000000000000000000..42cfa94bed056c13cdcb4de167b4277622f73c04 --- /dev/null +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/SimpleAccessTempVariable.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.parser.ast; + +import java.util.*; + +import com.oracle.truffle.api.*; + +@Precedence(Precedence.MAX) +public class SimpleAccessTempVariable extends AccessVariable { + + Object tempSymbol; + + public SimpleAccessTempVariable(SourceSection source, Object tempSymbol) { + this.source = source; + this.tempSymbol = tempSymbol; + } + + public Object getSymbol() { + return tempSymbol; + } + + @Override + public <R> R accept(Visitor<R> v) { + return v.visit(this); + } + + @Override + public <R> List<R> visitAll(Visitor<R> v) { + return Collections.emptyList(); + } +} diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/Visitor.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/Visitor.java index d370043d9652c7ba5760b256d60bc73b177754c5..d71960556103a5996768b1624e3d24a523595efb 100644 --- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/Visitor.java +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/Visitor.java @@ -76,6 +76,8 @@ public interface Visitor<R> { R visit(SimpleAccessVariable readVariable); + R visit(SimpleAccessTempVariable readVariable); + R visit(FieldAccess fieldAccess); R visit(SimpleAssignVariable assign); diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/tools/BasicVisitor.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/tools/BasicVisitor.java index 9638a45f56a11b8ddfcfe8dc8b5ce898fc942f6e..36299ca596ddfce2b659aae5e88182e66d766fbc 100644 --- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/tools/BasicVisitor.java +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/tools/BasicVisitor.java @@ -199,6 +199,11 @@ public class BasicVisitor<R> implements Visitor<R> { return visit((ASTNode) n); } + @Override + public R visit(SimpleAccessTempVariable n) { + return visit((ASTNode) n); + } + @Override public R visit(FieldAccess n) { return visit((ASTNode) n); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 20a60666f09f59c22f185612dc0602b91e70154e..0b4ebbdd37cd044028ddee89ff659d8447b2af23 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -1047,6 +1047,23 @@ $dimnames[[2]] +##com.oracle.truffle.r.test.simple.TestSimpleArithmetic.testUnaryNotPropagate +#{ x<-1:4; dim(x)<-c(2, 2); names(x)<-101:104; attr(x, "dimnames")<-list(201:202, 203:204); attr(x, "foo")<-"foo"; y<-!x; attributes(y) } +$names +[1] "101" "102" "103" "104" + +$dim +[1] 2 2 + +$dimnames +$dimnames[[1]] +[1] "201" "202" + +$dimnames[[2]] +[1] "203" "204" + + + ##com.oracle.truffle.r.test.simple.TestSimpleArithmetic.testUnaryNotRaw #{ a <- as.raw(12) ; !a } [1] f3 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleArithmetic.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleArithmetic.java index 032629c989d5acbb595e4c7ca38ad809917385ba..7861b1c6237f902763457f4789bb930ed13858c7 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleArithmetic.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleArithmetic.java @@ -388,10 +388,9 @@ public class TestSimpleArithmetic extends TestBase { } @Test - @Ignore - public void testUnaryNotPropagateIgnore() { + public void testUnaryNotPropagate() { // list of sequences should be converted to list of string vectors - assertEvalError("{ x<-1:4; dim(x)<-c(2, 2); names(x)<-101:104; attr(x, \"dimnames\")<-list(201:202, 203:204); attr(x, \"foo\")<-\"foo\"; y<-!x; attributes(y) }"); + assertEval("{ x<-1:4; dim(x)<-c(2, 2); names(x)<-101:104; attr(x, \"dimnames\")<-list(201:202, 203:204); attr(x, \"foo\")<-\"foo\"; y<-!x; attributes(y) }"); } @Test