From 76a5e7bfaf2fd94c551e7a53f63cd230e2bb9292 Mon Sep 17 00:00:00 2001
From: Lukas Stadler <lukas.stadler@oracle.com>
Date: Wed, 15 Nov 2017 17:03:44 +0100
Subject: [PATCH] convert ToString node to VectorAccess

---
 .../truffle/r/nodes/builtin/base/Cat.java     |   4 +-
 .../r/nodes/unary/CastStringBaseNode.java     |   2 +-
 .../truffle/r/nodes/unary/CastSymbolNode.java |   2 +-
 .../truffle/r/nodes/unary/ToStringNode.java   | 187 +++++++-----------
 4 files changed, 79 insertions(+), 116 deletions(-)

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
index a4b42e74a1..cee07fbd4b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
@@ -141,11 +141,11 @@ public abstract class Cat extends RBuiltinNode.Arg6 {
                 } else {
                     validateType(i + 1, obj);
                     for (int j = 0; j < objVec.getLength(); j++) {
-                        stringVecs.add(toString.executeString(objVec.getDataAtAsObject(j), false, ""));
+                        stringVecs.add(toString.executeString(objVec.getDataAtAsObject(j), ""));
                     }
                 }
             } else {
-                stringVecs.add(toString.executeString(obj, false, ""));
+                stringVecs.add(toString.executeString(obj, ""));
             }
         }
 
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 8d3a0456e3..aca07494f8 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
@@ -52,7 +52,7 @@ public abstract class CastStringBaseNode extends CastBaseNode {
     }
 
     protected String toString(Object value) {
-        return toString.executeString(value, false, ToStringNode.DEFAULT_SEPARATOR);
+        return toString.executeString(value, ToStringNode.DEFAULT_SEPARATOR);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
index 2b45b6639a..034b53109f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
@@ -58,7 +58,7 @@ public abstract class CastSymbolNode extends CastBaseNode {
     public abstract Object executeSymbol(Object o);
 
     private String toString(Object value) {
-        return toString.executeString(value, true, ToStringNode.DEFAULT_SEPARATOR);
+        return toString.executeString(value, ToStringNode.DEFAULT_SEPARATOR);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
index c28ada80ed..1aeae5ca87 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
@@ -22,7 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.CompilerAsserts;
+import java.util.EnumMap;
+
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
@@ -32,23 +33,19 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypes;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
@@ -60,72 +57,58 @@ public abstract class ToStringNode extends RBaseNode {
 
     @Child private ToStringNode recursiveToString;
 
-    private final ConditionProfile isCachedIntProfile = ConditionProfile.createBinaryProfile();
-    private final NACheck naCheck = NACheck.create();
-
-    private String toStringRecursive(Object o, boolean quotes, String separator) {
+    private String toStringRecursive(Object o, String separator) {
         if (recursiveToString == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             recursiveToString = insert(ToStringNodeGen.create());
         }
-        return recursiveToString.executeString(o, quotes, separator);
+        return recursiveToString.executeString(o, separator);
     }
 
-    public abstract String executeString(Object o, boolean quotes, String separator);
+    public abstract String executeString(Object o, String separator);
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(String value, boolean quotes, String separator) {
-        if (RRuntime.isNA(value)) {
-            return value;
-        }
-        if (quotes) {
-            return RRuntime.escapeString(value, false, true);
-        }
+    protected String toString(String value, @SuppressWarnings("unused") String separator) {
         return value;
 
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RNull vector, boolean quotes, String separator) {
+    protected String toString(@SuppressWarnings("unused") RNull vector, @SuppressWarnings("unused") String separator) {
         return "NULL";
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RFunction function, boolean quotes, String separator) {
+    protected String toString(RFunction function, @SuppressWarnings("unused") String separator) {
         return RRuntime.toString(function);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RSymbol symbol, boolean quotes, String separator) {
+    protected String toString(RSymbol symbol, @SuppressWarnings("unused") String separator) {
         return symbol.getName();
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RComplex complex, boolean quotes, String separator) {
+    protected String toString(RComplex complex, @SuppressWarnings("unused") String separator,
+                    @Cached("create()") NACheck naCheck) {
         naCheck.enable(complex);
         return naCheck.convertComplexToString(complex);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(RRaw raw, boolean quotes, String separator) {
+    protected String toString(RRaw raw, @SuppressWarnings("unused") String separator) {
         return RRuntime.rawToHexString(raw.getValue());
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(int operand, boolean quotes, String separator) {
+    protected String toString(int operand, @SuppressWarnings("unused") String separator) {
         return RRuntime.intToString(operand);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(double operand, boolean quotes, String separator) {
+    protected String toString(double operand, @SuppressWarnings("unused") String separator,
+                    @Cached("createBinaryProfile()") ConditionProfile isCachedIntProfile,
+                    @Cached("create()") NACheck naCheck) {
         int intValue = (int) operand;
         if (isCachedIntProfile.profile(intValue == operand && RRuntime.isCachedNumberString(intValue))) {
             return RRuntime.getCachedNumberString(intValue);
@@ -134,104 +117,84 @@ public abstract class ToStringNode extends RBaseNode {
         return naCheck.convertDoubleToString(operand);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected String toString(byte operand, boolean quotes, String separator) {
+    protected String toString(byte operand, @SuppressWarnings("unused") String separator) {
         return RRuntime.logicalToString(operand);
     }
 
     @Specialization
-    protected String toString(RS4Object obj, @SuppressWarnings("unused") boolean quotes, String separator,
-                    @Cached(value = "createWithImplicit()") ClassHierarchyNode hierarchy) {
+    @TruffleBoundary
+    protected String toString(RS4Object obj, @SuppressWarnings("unused") String separator,
+                    @Cached("createWithImplicit()") ClassHierarchyNode hierarchy) {
         RStringVector classHierarchy = hierarchy.execute(obj);
-        Object clazz;
-        if (classHierarchy.getLength() > 0) {
-            clazz = toString(classHierarchy.getDataAt(0), true, separator);
-        } else {
+        if (classHierarchy.getLength() == 0) {
             throw RInternalError.shouldNotReachHere("S4 object has no class");
         }
-        return Utils.stringFormat("<S4 object of class %s>", clazz);
+        return "<S4 object of class \"" + classHierarchy.getDataAt(0) + "\">";
     }
 
-    @FunctionalInterface
-    private interface ElementFunction {
-        String apply(int index, boolean quotes, String separator);
-    }
+    private static final EnumMap<RType, String> EMPTY = new EnumMap<>(RType.class);
 
-    private static String createResultForVector(RAbstractVector vector, boolean quotes, String separator, String empty, ElementFunction elementFunction) {
-        CompilerAsserts.neverPartOfCompilation();
-        int length = vector.getLength();
-        if (length == 0) {
-            return empty;
-        }
-        StringBuilder b = new StringBuilder();
-        for (int i = 0; i < length; i++) {
-            if (i > 0) {
-                b.append(separator);
-            }
-            b.append(elementFunction.apply(i, quotes, separator));
-        }
-        return b.toString();
+    static {
+        EMPTY.put(RType.Integer, "integer(0)");
+        EMPTY.put(RType.Double, "numeric(0)");
+        EMPTY.put(RType.Character, "character(0)");
+        EMPTY.put(RType.Logical, "logical(0)");
+        EMPTY.put(RType.Raw, "raw(0)");
+        EMPTY.put(RType.Complex, "complex(0)");
+        EMPTY.put(RType.List, "list()");
     }
 
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractIntVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "integer(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
-    }
-
-    @Specialization
     @TruffleBoundary
-    protected String toString(RAbstractDoubleVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "numeric(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
-    }
-
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractStringVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "character(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
-    }
-
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractLogicalVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "logical(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
-    }
-
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractRawVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "raw(0)", (index, q, s) -> RRuntime.rawToHexString(vector.getRawDataAt(index)));
+    private String vectorToString(RAbstractVector vector, String separator, VectorAccess vectorAccess) {
+        try (SequentialIterator iter = vectorAccess.access(vector)) {
+            int length = vectorAccess.getLength(iter);
+            if (length == 0) {
+                return EMPTY.get(vectorAccess.getType());
+            }
+            StringBuilder b = new StringBuilder();
+            if (vectorAccess.next(iter)) {
+                while (true) {
+                    if (vectorAccess.getType() == RType.List) {
+                        Object value = vectorAccess.getListElement(iter);
+                        if (value instanceof RAbstractListVector) {
+                            RAbstractListVector l = (RAbstractListVector) value;
+                            if (l.getLength() == 0) {
+                                b.append("list()");
+                            } else {
+                                b.append("list(").append(toStringRecursive(l, separator)).append(')');
+                            }
+                        } else {
+                            b.append(toStringRecursive(value, separator));
+                        }
+                    } else {
+                        b.append(vectorAccess.getString(iter));
+                    }
+                    if (!vectorAccess.next(iter)) {
+                        break;
+                    }
+                    b.append(separator);
+                }
+            }
+            return b.toString();
+        }
     }
 
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RAbstractComplexVector vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "complex(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s));
+    @Specialization(guards = "vectorAccess.supports(vector)")
+    protected String toStringVectorCached(RAbstractVector vector, String separator,
+                    @Cached("vector.access()") VectorAccess vectorAccess) {
+        return vectorToString(vector, separator, vectorAccess);
     }
 
-    @Specialization
-    @TruffleBoundary
-    protected String toString(RList vector, boolean quotes, String separator) {
-        return createResultForVector(vector, quotes, separator, "list()", (index, q, s) -> {
-            Object value = vector.getDataAt(index);
-            if (value instanceof RList) {
-                RList l = (RList) value;
-                if (l.getLength() == 0) {
-                    return "list()";
-                } else {
-                    return "list(" + toStringRecursive(l, q, s) + ')';
-                }
-            } else {
-                return toStringRecursive(value, q, s);
-            }
-        });
+    @Specialization(replaces = "toStringVectorCached")
+    protected String toStringVectorGeneric(RAbstractVector vector, String separator) {
+        return vectorToString(vector, separator, vector.slowPathAccess());
     }
 
     @SuppressWarnings("unused")
     @Specialization
     @TruffleBoundary
-    protected String toString(REnvironment env, boolean quotes, String separator) {
+    protected String toString(REnvironment env, String separator) {
         return env.toString();
     }
 }
-- 
GitLab