diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RForceAndCallNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RForceAndCallNode.java index 83a081c08d2a11c64e62178908e6e5839a694399..9d4e21f1b34247478eafbc45e3853c07b1bd77d3 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RForceAndCallNode.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RForceAndCallNode.java @@ -31,8 +31,6 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.profiles.ValueProfile; -import com.oracle.truffle.r.nodes.InlineCacheNode; -import com.oracle.truffle.r.nodes.InlineCacheNodeGen; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.RCallerHelper; @@ -58,7 +56,6 @@ public abstract class RForceAndCallNode extends RBaseNode { return RForceAndCallNodeGen.create(); } - @Child private InlineCacheNode closureEvalNode = InlineCacheNodeGen.create(10); @Child private PromiseHelperNode promiseHelper = new PromiseHelperNode(); public abstract Object executeObject(Object e, Object f, int n, Object env); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java index c421919dd786ec696a0d35f79a49d4edffdb0018..0a00020df6eb13c27a0c646067ebcac807ef2f16 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java @@ -31,23 +31,29 @@ 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.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.helpers.RFactorNodes.GetLevels; import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.CastStringNodeGen; import com.oracle.truffle.r.nodes.unary.GetNonSharedNode; +import com.oracle.truffle.r.nodes.unary.IsFactorNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.closures.RClosures; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; @RBuiltin(name = "names<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, dispatch = INTERNAL_GENERIC, behavior = PURE) public abstract class UpdateNames extends RBuiltinNode.Arg2 { @Child private CastStringNode castStringNode; + @Child private GetLevels getFactorLevels; static { Casts casts = new Casts(UpdateNames.class); @@ -66,8 +72,17 @@ public abstract class UpdateNames extends RBuiltinNode.Arg2 { @Specialization @TruffleBoundary - protected RAbstractContainer updateNames(RAbstractContainer container, Object names, + protected RAbstractContainer updateNames(RAbstractContainer container, Object namesArg, + @Cached("new()") IsFactorNode isFactorNode, + @Cached("createBinaryProfile()") ConditionProfile isFactorProfile, @Cached("create()") GetNonSharedNode nonShared) { + Object names = namesArg; + if (isFactorProfile.profile(isFactorNode.executeIsFactor(names))) { + final RStringVector levels = getFactorLevels(names); + if (levels != null) { + names = RClosures.createFactorToVector((RAbstractIntVector) names, true, levels); + } + } Object newNames = castString(names); RAbstractContainer result = ((RAbstractContainer) nonShared.execute(container)).materialize(); if (newNames == RNull.instance) { @@ -95,6 +110,16 @@ public abstract class UpdateNames extends RBuiltinNode.Arg2 { return result; } + private RStringVector getFactorLevels(Object names) { + if (getFactorLevels == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getFactorLevels = insert(GetLevels.create()); + } + assert names instanceof RAbstractIntVector; + final RStringVector levels = getFactorLevels.execute((RAbstractIntVector) names); + return levels; + } + @Specialization protected Object updateNames(RNull n, @SuppressWarnings("unused") RNull names) { return n; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java index c739628c0e6806973e59f730dbe23ba968f37b4a..3a8f8339ef384e17bc2d13e4c08718d55d2c17d0 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java @@ -26,6 +26,7 @@ import com.oracle.truffle.api.Assumption; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.frame.Frame; +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.VirtualFrame; @@ -59,6 +60,7 @@ public final class LocalReadVariableNode extends Node { @CompilationFinal private ConditionProfile isPromiseProfile; @CompilationFinal private FrameSlot frameSlot; + @CompilationFinal private FrameDescriptor frameDescriptor; @CompilationFinal private Assumption notInFrame; @CompilationFinal private Assumption containsNoActiveBindingAssumption; @@ -84,12 +86,13 @@ public final class LocalReadVariableNode extends Node { public Object execute(VirtualFrame frame, Frame variableFrame) { Frame profiledVariableFrame = frameProfile.profile(variableFrame); - if (frameSlot == null && notInFrame == null || (frameSlot != null && frameSlot.getFrameDescriptor() != variableFrame.getFrameDescriptor())) { + if (frameSlot == null && notInFrame == null || (frameSlot != null && frameDescriptor != variableFrame.getFrameDescriptor())) { CompilerDirectives.transferToInterpreterAndInvalidate(); if (identifier.toString().isEmpty()) { throw RError.error(RError.NO_CALLER, RError.Message.ZERO_LENGTH_VARIABLE); } - frameSlot = profiledVariableFrame.getFrameDescriptor().findFrameSlot(identifier); + frameDescriptor = profiledVariableFrame.getFrameDescriptor(); + frameSlot = frameDescriptor.findFrameSlot(identifier); notInFrame = frameSlot == null ? profiledVariableFrame.getFrameDescriptor().getNotInFrameAssumption(identifier) : null; } // check if the slot is missing / wrong type in current frame diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_namesassign.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_namesassign.java index e94fb1a49b5fa449cdd3c4834f4f3deb38b1e6bb..aa4fd44b0f12ec8170a74d1ba4ac40f1ce5d4aba 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_namesassign.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_namesassign.java @@ -167,4 +167,10 @@ public class TestBuiltin_namesassign extends TestBase { public void testUpdateDimnamesPairlist() { assertEval("{ l <- vector('pairlist',2); names(l)<-c('a','b'); l; }"); } + + @Test + public void testUpdateNamesByFactors() { + assertEval("{ x <- c(1,2,1,3); f <- factor(x, labels = c(\"a\",\"b\",\"c\")); names(x)<-f; x; }"); + } + }