From 8122108b346fab45f6ed5fd8fe33d7647ebc1fc6 Mon Sep 17 00:00:00 2001
From: Tomas Stupka <tomas.stupka@oracle.com>
Date: Tue, 7 Aug 2018 17:31:55 +0200
Subject: [PATCH] use VectorAccess in CastStringNode

---
 .../r/nodes/builtin/base/AsCharacter.java     |  3 +-
 .../r/nodes/builtin/MatchInternalNode.java    |  2 +-
 .../builtin/casts/PipelineToCastNode.java     |  4 +-
 .../r/nodes/unary/CastStringBaseNode.java     |  7 +-
 .../truffle/r/nodes/unary/CastStringNode.java | 88 +++++++++++++++----
 .../truffle/r/test/ExpectedTestOutput.test    |  4 +
 .../builtins/TestBuiltin_ascharacter.java     |  1 +
 7 files changed, 85 insertions(+), 24 deletions(-)

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 b945b240a6..3dc6a3207c 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 be17acf17c..998ea00576 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 198ee3b003..7c8a2db5b9 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 74fe4684bf..59fd9a9746 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 27237af6ec..7dc6274f0b 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 84853d8c5e..90ba93d526 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 ddab265dc9..6e399a441a 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)) }");
-- 
GitLab