diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java index b945b240a632d3354d46a864d80ba6c83f3d4cfd..3dc6a3207c656f8f9fd63f32780bd86192b3f97a 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java @@ -36,6 +36,7 @@ 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.runtime.RDeparse; +import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; @@ -50,7 +51,7 @@ public abstract class AsCharacter extends RBuiltinNode.Arg2 { static { Casts casts = new Casts(AsCharacter.class); - casts.arg("x").returnIf(missingValue().or(nullValue()), emptyStringVector()).mapIf(instanceOf(RAbstractListVector.class).not(), asStringVector()); + casts.arg("x").defaultWarningContext(RError.NO_CALLER).returnIf(missingValue().or(nullValue()), emptyStringVector()).mapIf(instanceOf(RAbstractListVector.class).not(), asStringVector()); } @Specialization(guards = "reuseTemporaryNode.supports(v)", limit = "getVectorAccessCacheSize()") diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/MatchInternalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/MatchInternalNode.java index be17acf17cd76042091b6b6457a4d11871a6d95d..998ea0057699a111d243471fc0ae03c025e95a30 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/MatchInternalNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/MatchInternalNode.java @@ -64,7 +64,7 @@ public abstract class MatchInternalNode extends RBaseNode { CompilerDirectives.transferToInterpreterAndInvalidate(); castString = insert(CastStringNodeGen.create(false, false, false)); } - return (RAbstractStringVector) castString.doCast(operand); + return (RAbstractStringVector) RRuntime.asAbstractVector(castString.doCast(operand)); } protected boolean isSequence(RAbstractVector vec) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java index 198ee3b003554aba713b10fb3da6db947fe56e3f..7c8a2db5b90a8d2364f7d1a49de2aeabe79cedbc 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java @@ -240,8 +240,8 @@ public final class PipelineToCastNode { return step.vectorCoercion ? CastDoubleNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, false, step.useClosure) : CastDoubleBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, false, step.useClosure); case Character: - return step.vectorCoercion ? CastStringNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes) - : CastStringBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes); + return step.vectorCoercion ? CastStringNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, false, false, warningContext) + : CastStringBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, false, false, warningContext); case Logical: return step.vectorCoercion ? CastLogicalNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes) : CastLogicalBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java index 74fe4684bf3321d87b4433281ba4ef18dfe1b287..59fd9a9746746841190b0139b3b926f2db832808 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.nodes.unary; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.runtime.RError.ErrorContext; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RMissing; @@ -41,6 +42,10 @@ public abstract class CastStringBaseNode extends CastBaseNode { super(preserveNames, preserveDimensions, preserveAttributes, forRFFI); } + protected CastStringBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI, boolean useClosure, ErrorContext warningContext) { + super(preserveNames, preserveDimensions, preserveAttributes, forRFFI, useClosure, warningContext); + } + @Override protected final RType getTargetType() { return RType.Character; @@ -71,7 +76,7 @@ public abstract class CastStringBaseNode extends CastBaseNode { } @Specialization - protected String doRaw(RComplex value) { + protected String doComplex(RComplex value) { return toString(value); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java index 27237af6ec3077967c10ccfefec6b3f84f23b722..7dc6274f0be7b3becf98a7185608cb2a66bb8e22 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java @@ -29,8 +29,10 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.runtime.DSLConfig; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.ErrorContext; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RForeignBooleanWrapper; import com.oracle.truffle.r.runtime.data.RForeignDoubleWrapper; @@ -42,11 +44,14 @@ import com.oracle.truffle.r.runtime.data.RStringSequence; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.interop.ForeignArray2R; -@ImportStatic(RRuntime.class) +@ImportStatic({RRuntime.class, DSLConfig.class}) public abstract class CastStringNode extends CastStringBaseNode { @Child private CastStringNode recursiveCastString; @@ -59,6 +64,10 @@ public abstract class CastStringNode extends CastStringBaseNode { super(preserveNames, preserveDimensions, preserveAttributes, forRFFI); } + protected CastStringNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI, boolean useClosure, ErrorContext warningContext) { + super(preserveNames, preserveDimensions, preserveAttributes, forRFFI, useClosure, warningContext); + } + public abstract Object executeString(int o); public abstract Object executeString(double o); @@ -75,10 +84,6 @@ public abstract class CastStringNode extends CastStringBaseNode { return ret; } - protected boolean isIntSequence(RAbstractContainer c) { - return c instanceof RIntSequence; - } - @Specialization protected RAbstractStringVector doStringVector(RAbstractStringVector vector) { return vector; @@ -89,24 +94,57 @@ public abstract class CastStringNode extends CastStringBaseNode { return factory().createStringSequence("", "", vector.getStart(), vector.getStride(), vector.getLength()); } - @Specialization(guards = {"!isIntSequence(operandIn)", "!isRAbstractStringVector(operandIn)", "!isForeignWrapper(operandIn)"}) - protected RStringVector doAbstractContainer(RAbstractContainer operandIn, + @Specialization(guards = {"uAccess.supports(operandIn)", "handleAsAtomic(operandIn)"}, limit = "getGenericVectorAccessCacheSize()") + protected RStringVector doAbstractAtomicVector(RAbstractAtomicVector operandIn, @Cached("createClassProfile()") ValueProfile operandProfile, - @Cached("createBinaryProfile()") ConditionProfile isLanguageProfile) { + @Cached("operandIn.access()") VectorAccess uAccess) { RAbstractContainer operand = operandProfile.profile(operandIn); String[] sdata = new String[operand.getLength()]; - // conversions to character will not introduce new NAs - for (int i = 0; i < operand.getLength(); i++) { - Object o = operand.getDataAtAsObject(i); - if (isLanguageProfile.profile((o instanceof RPairList && ((RPairList) o).isLanguage()))) { - sdata[i] = RDeparse.deparse(o); - } else { - sdata[i] = toString(o); + // conversions to character will not introduce new NAs, + // but lets pass the warning context anyway + try (VectorAccess.SequentialIterator sIter = uAccess.access(operand, warningContext())) { + while (uAccess.next(sIter)) { + int i = sIter.getIndex(); + sdata[i] = uAccess.getString(sIter); + } + } + return vectorCopy(operand, sdata); + } + + @Specialization(replaces = "doAbstractAtomicVector", guards = "handleAsAtomic(operandIn)") + protected RStringVector doAbstractAtomicVectorGeneric(RAbstractAtomicVector operandIn, + @Cached("createClassProfile()") ValueProfile operandProfile) { + return doAbstractAtomicVector(operandIn, operandProfile, operandIn.slowPathAccess()); + } + + @Specialization(guards = {"uAccess.supports(x)", "handleAsNonAtomic(x)"}, limit = "getGenericVectorAccessCacheSize()") + protected RStringVector doNonAtomic(RAbstractContainer x, + @Cached("createClassProfile()") ValueProfile operandProfile, + @Cached("createBinaryProfile()") ConditionProfile isLanguageProfile, + @Cached("x.access()") VectorAccess uAccess) { + RAbstractContainer operand = operandProfile.profile(x); + String[] sdata = new String[operand.getLength()]; + try (VectorAccess.SequentialIterator sIter = uAccess.access(operand, warningContext())) { + while (uAccess.next(sIter)) { + int i = sIter.getIndex(); + Object o = uAccess.getListElement(sIter); + if (isLanguageProfile.profile((o instanceof RPairList && ((RPairList) o).isLanguage()))) { + sdata[i] = RDeparse.deparse(o); + } else { + sdata[i] = toString(o); + } } } return vectorCopy(operand, sdata); } + @Specialization(replaces = "doNonAtomic", guards = "handleAsNonAtomic(list)") + protected RStringVector doNonAtomicGeneric(RAbstractListVector list, + @Cached("createClassProfile()") ValueProfile operandProfile, + @Cached("createBinaryProfile()") ConditionProfile isLanguageProfile) { + return doNonAtomic(list, operandProfile, isLanguageProfile, list.slowPathAccess()); + } + @Specialization(guards = "isForeignObject(obj)") protected RAbstractStringVector doForeignObject(TruffleObject obj, @Cached("create()") ForeignArray2R foreignArray2R) { @@ -128,10 +166,6 @@ public abstract class CastStringNode extends CastStringBaseNode { return s.getName(); } - protected boolean isForeignWrapper(Object value) { - return value instanceof RForeignWrapper; - } - @Specialization protected RAbstractStringVector doForeignWrapper(RForeignBooleanWrapper operand) { return RClosures.createToStringVector(operand, true); @@ -147,6 +181,22 @@ public abstract class CastStringNode extends CastStringBaseNode { return RClosures.createToStringVector(operand, true); } + protected boolean isForeignWrapper(Object value) { + return value instanceof RForeignWrapper; + } + + protected boolean isIntSequence(RAbstractContainer c) { + return c instanceof RIntSequence; + } + + protected boolean handleAsAtomic(RAbstractAtomicVector x) { + return !isForeignWrapper(x) && !(x instanceof RIntSequence || x instanceof RAbstractStringVector); + } + + protected boolean handleAsNonAtomic(RAbstractContainer x) { + return !isForeignWrapper(x) && !(x instanceof RAbstractAtomicVector); + } + public static CastStringNode create() { return CastStringNodeGen.create(true, true, true); } 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 84853d8c5effef726e1d85bc70526307c8bd5af1..90ba93d5263ffe1a41a2d0d5d3be49392e4d2313 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 @@ -6087,6 +6087,10 @@ character(0) #{ as.character(1) } [1] "1" +##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testAsCharacter# +#{ as.character(1.1:3.1) } +[1] "1.1" "2.1" "3.1" + ##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testAsCharacter# #{ as.character(1:3) } [1] "1" "2" "3" diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascharacter.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascharacter.java index ddab265dc9a62945bf2436cd73fe2cac41dacae8..6e399a441abd6d4f46051720d2ed0de86bbe484e 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascharacter.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascharacter.java @@ -264,6 +264,7 @@ public class TestBuiltin_ascharacter extends TestBase { assertEval("{ as.character(1L) }"); assertEval("{ as.character(TRUE) }"); assertEval("{ as.character(1:3) }"); + assertEval("{ as.character(1.1:3.1) }"); assertEval("{ as.character(NULL) }"); assertEval("{ as.character(list(1,2,3)) }");