From 7dfe6e8eb81f79b18251b2edbd80758bbd54d6ce Mon Sep 17 00:00:00 2001
From: Florian Angerer <florian.angerer@oracle.com>
Date: Tue, 29 Aug 2017 12:37:11 +0200
Subject: [PATCH] Implemented native functions 'Rf_VectorToPairList' and
 'Rf_asCharacterFactor'.

---
 .../ffi/impl/common/JavaUpCallsRFFIImpl.java  |  10 +
 .../impl/common/TracingUpCallsRFFIImpl.java   |  12 +
 .../ffi/impl/nodes/AttributesAccessNodes.java |  22 ++
 .../truffle/r/ffi/impl/nodes/CoerceNodes.java | 285 ++++++++++++++++++
 .../r/ffi/impl/nodes/CoerceVectorNode.java    | 167 ----------
 .../r/ffi/impl/nodes/FFIUpCallRootNode.java   |   4 +-
 .../r/ffi/impl/upcalls/StdUpCallsRFFI.java    |   4 +
 .../fficall/src/common/rffi_upcallsindex.h    | 138 ++++-----
 .../fficall/src/jni/Rinternals.c              |  16 +-
 .../Rinternals_truffle_common.h               |   5 +-
 10 files changed, 420 insertions(+), 243 deletions(-)
 create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java
 delete mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java

diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
index 59edf0bdf8..f004349cc8 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
@@ -1600,4 +1600,14 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         return 0;
     }
 
+    @Override
+    public Object Rf_VectorToPairList(Object x) {
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_VectorToPairList).call(x);
+    }
+
+    @Override
+    public Object Rf_asCharacterFactor(Object x) {
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_asCharacterFactor).call(x);
+    }
+
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java
index 3b49641693..d4287407b1 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java
@@ -884,4 +884,16 @@ final class TracingUpCallsRFFIImpl implements UpCallsRFFI {
         return delegate.Rf_copyMostAttrib(x, y);
     }
 
+    @Override
+    public Object Rf_VectorToPairList(Object x) {
+        RFFIUtils.traceUpCall("Rf_VectorToPairlist", x);
+        return delegate.Rf_VectorToPairList(x);
+    }
+
+    @Override
+    public Object Rf_asCharacterFactor(Object x) {
+        RFFIUtils.traceUpCall("Rf_asCharacterFactor", x);
+        return delegate.Rf_asCharacterFactor(x);
+    }
+
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.java
index 12afbe0f64..ca69260198 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.java
@@ -1,3 +1,25 @@
+/*
+ * Copyright (c) 2017, 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.ffi.impl.nodes;
 
 import com.oracle.truffle.api.CompilerDirectives;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java
new file mode 100644
index 0000000000..ad332c7065
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2017, 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.ffi.impl.nodes;
+
+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.r.nodes.attributes.CopyOfRegAttributesNode;
+import com.oracle.truffle.r.nodes.attributes.GetAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
+import com.oracle.truffle.r.nodes.helpers.RFactorNodes;
+import com.oracle.truffle.r.nodes.unary.CastComplexNode;
+import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
+import com.oracle.truffle.r.nodes.unary.CastExpressionNode;
+import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
+import com.oracle.truffle.r.nodes.unary.CastListNode;
+import com.oracle.truffle.r.nodes.unary.CastLogicalNode;
+import com.oracle.truffle.r.nodes.unary.CastNode;
+import com.oracle.truffle.r.nodes.unary.CastRawNode;
+import com.oracle.truffle.r.nodes.unary.CastStringNode;
+import com.oracle.truffle.r.nodes.unary.CastSymbolNode;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.RShareable;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.RTypedValue;
+import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
+
+public final class CoerceNodes {
+
+    abstract static class VectorToPairListNode extends FFIUpCallNode.Arg1 {
+
+        @Child private CopyOfRegAttributesNode copyRegAttributesNode;
+        @Child private GetNamesAttributeNode getNamesAttributeNode;
+
+        @Specialization
+        protected Object convert(RAbstractVector v) {
+
+            RStringVector names = getNamesAttributeNode.getNames(v);
+            SEXPTYPE gnurType = SEXPTYPE.gnuRTypeForObject(v);
+
+            RPairList head = null;
+            RPairList prev = null;
+            assert names == null || names.getLength() == v.getLength();
+            for (int i = 0; i < v.getLength(); i++) {
+                Object element = v.getDataAtAsObject(i);
+                adjustSharing(v, element);
+                RPairList cur = RDataFactory.createPairList(element, RNull.instance, names != null ? names.getDataAt(i) : RNull.instance, gnurType);
+
+                if (prev == null) {
+                    assert head == null;
+                    head = cur;
+                } else {
+                    prev.setCdr(cur);
+                }
+                prev = cur;
+            }
+            if (head != null) {
+                // also copy regular attributes
+                copyRegAttributesNode.execute(v, head);
+                return head;
+            }
+            return RNull.instance;
+        }
+
+        private static void adjustSharing(RAbstractVector origin, Object element) {
+            if (origin instanceof RShareable) {
+                int v = getSharingLevel((RShareable) origin);
+                if (element instanceof RShareable) {
+                    RShareable r = (RShareable) element;
+                    if (v == 2) {
+                        // we play it safe: if the caller wants this instance to be shared, they may
+                        // expect it to never become non-shared again, which could happen in FastR
+                        r.makeSharedPermanent();
+                    }
+                    if (v == 1 && r.isTemporary()) {
+                        r.incRefCount();
+                    }
+                }
+            }
+        }
+
+        public static VectorToPairListNode create() {
+            return CoerceNodesFactory.VectorToPairListNodeGen.create();
+        }
+
+        private static int getSharingLevel(RShareable r) {
+            return r.isTemporary() ? 0 : r.isShared() ? 2 : 1;
+        }
+    }
+
+    abstract static class AsCharacterFactor extends FFIUpCallNode.Arg1 {
+
+        @Child private InheritsCheckNode inheritsFactorNode = InheritsCheckNode.createFactor();
+        @Child private GetAttributeNode getAttributeNode = GetAttributeNode.create();
+        @Child private RFactorNodes.GetLevels getLevels = RFactorNodes.GetLevels.create();
+
+        @Specialization
+        protected Object doFactor(RAbstractIntVector o) {
+            if (!inheritsFactorNode.execute(o)) {
+                throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, "attempting to coerce non-factor");
+            }
+
+            RStringVector levels = getLevels.execute(o);
+            if (levels == null) {
+                throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, "malformed factor");
+            }
+
+            String[] data = new String[o.getLength()];
+            boolean isComplete = true;
+            int nl = levels.getLength();
+            for (int i = 0; i < o.getLength(); i++) {
+                assert !o.isComplete() || o.getDataAt(i) != RRuntime.INT_NA;
+                int idx = o.getDataAt(i);
+                if (idx == RRuntime.INT_NA) {
+                    data[i] = RRuntime.STRING_NA;
+                    isComplete = false;
+                } else if (idx >= 1 && idx <= nl) {
+                    data[i] = levels.getDataAt(idx - 1);
+                } else {
+                    throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, "malformed factor");
+                }
+            }
+
+            return RDataFactory.createStringVector(data, isComplete);
+        }
+
+        public static AsCharacterFactor create() {
+            return CoerceNodesFactory.AsCharacterFactorNodeGen.create();
+        }
+
+    }
+
+    /**
+     * Implements Rf_coerceVector.
+     */
+    abstract static class CoerceVectorNode extends FFIUpCallNode.Arg2 {
+
+        public static CoerceVectorNode create() {
+            return CoerceNodesFactory.CoerceVectorNodeGen.create();
+        }
+
+        @Specialization(guards = "value.isS4()")
+        Object doS4Object(@SuppressWarnings("unused") RTypedValue value, @SuppressWarnings("unused") int mode) {
+            throw RError.nyi(RError.NO_CALLER, "Rf_coerceVector for S4 objects.");
+        }
+
+        // Note: caches should cover all valid possibilities
+        @Specialization(guards = {"!isS4Object(value)", "isNotList(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99")
+        Object doCached(Object value, @SuppressWarnings("unused") int mode,
+                        @Cached("mode") @SuppressWarnings("unused") int cachedMode,
+                        @Cached("createCastNode(cachedMode)") CastNode castNode) {
+            return castNode.doCast(value);
+        }
+
+        // Lists are coerced with only preserved names unlike other types
+        @Specialization(guards = {"!isS4Object(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99")
+        Object doCached(RList value, @SuppressWarnings("unused") int mode,
+                        @Cached("mode") @SuppressWarnings("unused") int cachedMode,
+                        @Cached("createCastNodeForList(cachedMode)") CastNode castNode) {
+            return castNode.doCast(value);
+        }
+
+        @Fallback
+        @TruffleBoundary
+        Object doFallback(Object value, Object mode) {
+            String type = value != null ? value.getClass().getSimpleName() : "null";
+            throw RInternalError.unimplemented(String.format("Rf_coerceVector unimplemented for type %s or mode %s.", type, mode));
+        }
+
+        static boolean isS4Object(Object obj) {
+            return obj instanceof RTypedValue && ((RTypedValue) obj).isS4();
+        }
+
+        static boolean isNotList(Object obj) {
+            return !(obj instanceof RList);
+        }
+
+        static boolean isValidMode(int mode) {
+            return mode >= SEXPTYPE.NILSXP.code && mode <= SEXPTYPE.RAWSXP.code;
+        }
+
+        static CastNode createCastNode(int mode) {
+            return createCastNode(mode, false);
+        }
+
+        static CastNode createCastNodeForList(int mode) {
+            return createCastNode(mode, true);
+        }
+
+        private static CastNode createCastNode(int mode, boolean forList) {
+            SEXPTYPE type = SEXPTYPE.mapInt(mode);
+            boolean preserveDims = !forList;
+            boolean preserveAttrs = !forList;
+            switch (type) {
+                case SYMSXP:
+                    return CastSymbolNode.createForRFFI(false, false, false);
+                case NILSXP:
+                    return new CastNullNode();
+                case LISTSXP:
+                    throw RInternalError.unimplemented("Rf_coerceVector unimplemented for PairLists.");
+                case LANGSXP:
+                    throw RInternalError.unimplemented("Rf_coerceVector unimplemented for RLanguage.");
+                case ENVSXP:
+                    return new EnvironmentCast();
+                case VECSXP:
+                    return CastListNode.createForRFFI(true, forList, forList);
+                case EXPRSXP:
+                    return CastExpressionNode.createForRFFI();
+                case INTSXP:
+                    return CastIntegerNode.createForRFFI(true, preserveDims, preserveAttrs);
+                case REALSXP:
+                    return CastDoubleNode.createForRFFI(true, preserveDims, preserveAttrs);
+                case LGLSXP:
+                    return CastLogicalNode.createForRFFI(true, preserveDims, preserveAttrs);
+                case STRSXP:
+                    return CastStringNode.createForRFFI(true, preserveDims, preserveAttrs);
+                case CPLXSXP:
+                    return CastComplexNode.createForRFFI(true, preserveDims, preserveAttrs);
+                case RAWSXP:
+                    return CastRawNode.createForRFFI(true, preserveDims, preserveAttrs);
+                default:
+                    throw RInternalError.unimplemented(String.format("Rf_coerceVector called with unimplemented mode %d (type %s).", mode, type));
+            }
+        }
+
+        private static final class CastNullNode extends CastNode {
+            @Override
+            @TruffleBoundary
+            public Object execute(Object value) {
+                if (value instanceof RList) {
+                    throw RError.error(RError.NO_CALLER, Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, "list", "coerceVectorList");
+                } else {
+                    throw RError.error(RError.NO_CALLER, Message.CANNOT_COERCE, getTypeName(value), "NULL");
+                }
+            }
+
+            private static String getTypeName(Object val) {
+                Object value = RRuntime.convertScalarVectors(val);
+                if (value == null) {
+                    return "null";
+                }
+                return value instanceof RTypedValue ? ((RTypedValue) value).getRType().getName() : value.getClass().getSimpleName();
+            }
+        }
+
+        private static final class EnvironmentCast extends CastNode {
+            @Override
+            @TruffleBoundary
+            public Object execute(Object value) {
+                throw RError.error(RError.NO_CALLER, Message.ENVIRONMENTS_COERCE);
+            }
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java
deleted file mode 100644
index 32da1b5c50..0000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (c) 2017, 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.ffi.impl.nodes;
-
-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.r.nodes.unary.CastComplexNode;
-import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
-import com.oracle.truffle.r.nodes.unary.CastExpressionNode;
-import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
-import com.oracle.truffle.r.nodes.unary.CastListNode;
-import com.oracle.truffle.r.nodes.unary.CastLogicalNode;
-import com.oracle.truffle.r.nodes.unary.CastNode;
-import com.oracle.truffle.r.nodes.unary.CastRawNode;
-import com.oracle.truffle.r.nodes.unary.CastStringNode;
-import com.oracle.truffle.r.nodes.unary.CastSymbolNode;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RError.Message;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
-import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
-
-/**
- * Implements Rf_coerceVector.
- */
-public abstract class CoerceVectorNode extends FFIUpCallNode.Arg2 {
-
-    public static CoerceVectorNode create() {
-        return CoerceVectorNodeGen.create();
-    }
-
-    @Specialization(guards = "value.isS4()")
-    Object doS4Object(@SuppressWarnings("unused") RTypedValue value, @SuppressWarnings("unused") int mode) {
-        throw RError.nyi(RError.NO_CALLER, "Rf_coerceVector for S4 objects.");
-    }
-
-    // Note: caches should cover all valid possibilities
-    @Specialization(guards = {"!isS4Object(value)", "isNotList(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99")
-    Object doCached(Object value, @SuppressWarnings("unused") int mode,
-                    @Cached("mode") @SuppressWarnings("unused") int cachedMode,
-                    @Cached("createCastNode(cachedMode)") CastNode castNode) {
-        return castNode.doCast(value);
-    }
-
-    // Lists are coerced with only preserved names unlike other types
-    @Specialization(guards = {"!isS4Object(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99")
-    Object doCached(RList value, @SuppressWarnings("unused") int mode,
-                    @Cached("mode") @SuppressWarnings("unused") int cachedMode,
-                    @Cached("createCastNodeForList(cachedMode)") CastNode castNode) {
-        return castNode.doCast(value);
-    }
-
-    @Fallback
-    @TruffleBoundary
-    Object doFallback(Object value, Object mode) {
-        String type = value != null ? value.getClass().getSimpleName() : "null";
-        throw RInternalError.unimplemented(String.format("Rf_coerceVector unimplemented for type %s or mode %s.", type, mode));
-    }
-
-    static boolean isS4Object(Object obj) {
-        return obj instanceof RTypedValue && ((RTypedValue) obj).isS4();
-    }
-
-    static boolean isNotList(Object obj) {
-        return !(obj instanceof RList);
-    }
-
-    static boolean isValidMode(int mode) {
-        return mode >= SEXPTYPE.NILSXP.code && mode <= SEXPTYPE.RAWSXP.code;
-    }
-
-    static CastNode createCastNode(int mode) {
-        return createCastNode(mode, false);
-    }
-
-    static CastNode createCastNodeForList(int mode) {
-        return createCastNode(mode, true);
-    }
-
-    private static CastNode createCastNode(int mode, boolean forList) {
-        SEXPTYPE type = SEXPTYPE.mapInt(mode);
-        boolean preserveDims = !forList;
-        boolean preserveAttrs = !forList;
-        switch (type) {
-            case SYMSXP:
-                return CastSymbolNode.createForRFFI(false, false, false);
-            case NILSXP:
-                return new CastNullNode();
-            case LISTSXP:
-                throw RInternalError.unimplemented("Rf_coerceVector unimplemented for PairLists.");
-            case LANGSXP:
-                throw RInternalError.unimplemented("Rf_coerceVector unimplemented for RLanguage.");
-            case ENVSXP:
-                return new EnvironmentCast();
-            case VECSXP:
-                return CastListNode.createForRFFI(true, forList, forList);
-            case EXPRSXP:
-                return CastExpressionNode.createForRFFI();
-            case INTSXP:
-                return CastIntegerNode.createForRFFI(true, preserveDims, preserveAttrs);
-            case REALSXP:
-                return CastDoubleNode.createForRFFI(true, preserveDims, preserveAttrs);
-            case LGLSXP:
-                return CastLogicalNode.createForRFFI(true, preserveDims, preserveAttrs);
-            case STRSXP:
-                return CastStringNode.createForRFFI(true, preserveDims, preserveAttrs);
-            case CPLXSXP:
-                return CastComplexNode.createForRFFI(true, preserveDims, preserveAttrs);
-            case RAWSXP:
-                return CastRawNode.createForRFFI(true, preserveDims, preserveAttrs);
-            default:
-                throw RInternalError.unimplemented(String.format("Rf_coerceVector called with unimplemented mode %d (type %s).", mode, type));
-        }
-    }
-
-    private static final class CastNullNode extends CastNode {
-        @Override
-        @TruffleBoundary
-        public Object execute(Object value) {
-            if (value instanceof RList) {
-                throw RError.error(RError.NO_CALLER, Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, "list", "coerceVectorList");
-            } else {
-                throw RError.error(RError.NO_CALLER, Message.CANNOT_COERCE, getTypeName(value), "NULL");
-            }
-        }
-
-        private static String getTypeName(Object val) {
-            Object value = RRuntime.convertScalarVectors(val);
-            if (value == null) {
-                return "null";
-            }
-            return value instanceof RTypedValue ? ((RTypedValue) value).getRType().getName() : value.getClass().getSimpleName();
-        }
-    }
-
-    private static final class EnvironmentCast extends CastNode {
-        @Override
-        @TruffleBoundary
-        public Object execute(Object value) {
-            throw RError.error(RError.NO_CALLER, Message.ENVIRONMENTS_COERCE);
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java
index e8a06297ba..de10716282 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java
@@ -99,7 +99,7 @@ public final class FFIUpCallRootNode extends RootNode {
         FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asLogical, AsLogicalNodeGen::create);
         FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asInteger, AsIntegerNodeGen::create);
         FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asChar, AsCharNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_coerceVector, CoerceVectorNode::create);
+        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_coerceVector, CoerceNodes.CoerceVectorNode::create);
         FFIUpCallRootNode.add(RFFIUpCallTable.CAR, CARNodeGen::create);
         FFIUpCallRootNode.add(RFFIUpCallTable.CDR, CDRNodeGen::create);
         FFIUpCallRootNode.add(RFFIUpCallTable.CADR, CADRNodeGen::create);
@@ -116,5 +116,7 @@ public final class FFIUpCallRootNode extends RootNode {
         FFIUpCallRootNode.add(RFFIUpCallTable.Rf_namesgets, MiscNodesFactory.NamesGetsNodeGen::create);
         FFIUpCallRootNode.add(RFFIUpCallTable.TAG, AttributesAccessNodesFactory.TAGNodeGen::create);
         FFIUpCallRootNode.add(RFFIUpCallTable.Rf_copyMostAttrib, AttributesAccessNodesFactory.CopyMostAttribNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_VectorToPairList, CoerceNodes.VectorToPairListNode::create);
+        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asCharacterFactor, CoerceNodes.AsCharacterFactor::create);
     }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
index 1dd634f978..6226535d30 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
@@ -306,4 +306,8 @@ public interface StdUpCallsRFFI {
     Object Rf_namesgets(Object vec, Object val);
 
     int Rf_copyMostAttrib(Object x, Object y);
+
+    Object Rf_VectorToPairList(Object x);
+
+    Object Rf_asCharacterFactor(Object x);
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h
index 23862841f7..e414fb91e6 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h
+++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h
@@ -78,74 +78,76 @@
 #define Rf_ScalarInteger_x 73
 #define Rf_ScalarLogical_x 74
 #define Rf_ScalarString_x 75
-#define Rf_allocArray_x 76
-#define Rf_allocMatrix_x 77
-#define Rf_allocVector_x 78
-#define Rf_any_duplicated_x 79
-#define Rf_asChar_x 80
-#define Rf_asInteger_x 81
-#define Rf_asLogical_x 82
-#define Rf_asReal_x 83
-#define Rf_classgets_x 84
-#define Rf_coerceVector_x 85
-#define Rf_cons_x 86
-#define Rf_copyListMatrix_x 87
-#define Rf_copyMatrix_x 88
-#define Rf_copyMostAttrib_x 89
-#define Rf_defineVar_x 90
-#define Rf_dunif_x 91
-#define Rf_duplicate_x 92
-#define Rf_error_x 93
-#define Rf_errorcall_x 94
-#define Rf_eval_x 95
-#define Rf_findFun_x 96
-#define Rf_findVar_x 97
-#define Rf_findVarInFrame_x 98
-#define Rf_findVarInFrame3_x 99
-#define Rf_getAttrib_x 100
-#define Rf_gsetVar_x 101
-#define Rf_inherits_x 102
-#define Rf_install_x 103
-#define Rf_installChar_x 104
-#define Rf_isNull_x 105
-#define Rf_isString_x 106
-#define Rf_lengthgets_x 107
-#define Rf_mkCharLenCE_x 108
-#define Rf_namesgets_x 109
-#define Rf_ncols_x 110
-#define Rf_nrows_x 111
-#define Rf_punif_x 112
-#define Rf_qunif_x 113
-#define Rf_runif_x 114
-#define Rf_setAttrib_x 115
-#define Rf_str2type_x 116
-#define Rf_warning_x 117
-#define Rf_warningcall_x 118
-#define Rprintf_x 119
-#define SETCADR_x 120
-#define SETCAR_x 121
-#define SETCDR_x 122
-#define SET_NAMED_FASTR_x 123
-#define SET_RDEBUG_x 124
-#define SET_RSTEP_x 125
-#define SET_S4_OBJECT_x 126
-#define SET_STRING_ELT_x 127
-#define SET_SYMVALUE_x 128
-#define SET_TAG_x 129
-#define SET_TYPEOF_FASTR_x 130
-#define SET_VECTOR_ELT_x 131
-#define STRING_ELT_x 132
-#define SYMVALUE_x 133
-#define TAG_x 134
-#define TYPEOF_x 135
-#define UNSET_S4_OBJECT_x 136
-#define VECTOR_ELT_x 137
-#define getConnectionClassString_x 138
-#define getOpenModeString_x 139
-#define getSummaryDescription_x 140
-#define isSeekable_x 141
-#define unif_rand_x 142
+#define Rf_VectorToPairList_x 76
+#define Rf_allocArray_x 77
+#define Rf_allocMatrix_x 78
+#define Rf_allocVector_x 79
+#define Rf_any_duplicated_x 80
+#define Rf_asChar_x 81
+#define Rf_asCharacterFactor_x 82
+#define Rf_asInteger_x 83
+#define Rf_asLogical_x 84
+#define Rf_asReal_x 85
+#define Rf_classgets_x 86
+#define Rf_coerceVector_x 87
+#define Rf_cons_x 88
+#define Rf_copyListMatrix_x 89
+#define Rf_copyMatrix_x 90
+#define Rf_copyMostAttrib_x 91
+#define Rf_defineVar_x 92
+#define Rf_dunif_x 93
+#define Rf_duplicate_x 94
+#define Rf_error_x 95
+#define Rf_errorcall_x 96
+#define Rf_eval_x 97
+#define Rf_findFun_x 98
+#define Rf_findVar_x 99
+#define Rf_findVarInFrame_x 100
+#define Rf_findVarInFrame3_x 101
+#define Rf_getAttrib_x 102
+#define Rf_gsetVar_x 103
+#define Rf_inherits_x 104
+#define Rf_install_x 105
+#define Rf_installChar_x 106
+#define Rf_isNull_x 107
+#define Rf_isString_x 108
+#define Rf_lengthgets_x 109
+#define Rf_mkCharLenCE_x 110
+#define Rf_namesgets_x 111
+#define Rf_ncols_x 112
+#define Rf_nrows_x 113
+#define Rf_punif_x 114
+#define Rf_qunif_x 115
+#define Rf_runif_x 116
+#define Rf_setAttrib_x 117
+#define Rf_str2type_x 118
+#define Rf_warning_x 119
+#define Rf_warningcall_x 120
+#define Rprintf_x 121
+#define SETCADR_x 122
+#define SETCAR_x 123
+#define SETCDR_x 124
+#define SET_NAMED_FASTR_x 125
+#define SET_RDEBUG_x 126
+#define SET_RSTEP_x 127
+#define SET_S4_OBJECT_x 128
+#define SET_STRING_ELT_x 129
+#define SET_SYMVALUE_x 130
+#define SET_TAG_x 131
+#define SET_TYPEOF_FASTR_x 132
+#define SET_VECTOR_ELT_x 133
+#define STRING_ELT_x 134
+#define SYMVALUE_x 135
+#define TAG_x 136
+#define TYPEOF_x 137
+#define UNSET_S4_OBJECT_x 138
+#define VECTOR_ELT_x 139
+#define getConnectionClassString_x 140
+#define getOpenModeString_x 141
+#define getSummaryDescription_x 142
+#define isSeekable_x 143
+#define unif_rand_x 144
 
-#define UPCALLS_TABLE_SIZE 143
+#define UPCALLS_TABLE_SIZE 145
 
 #endif // RFFI_UPCALLSINDEX_H
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
index 2ee61ef405..5dcff7874a 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
@@ -105,6 +105,8 @@ static jmethodID Rf_coerceVectorMethodID;
 static jmethodID Rf_mkCharLenCEMethodID;
 static jmethodID Rf_asLogicalMethodID;
 static jmethodID Rf_PairToVectorListMethodID;
+static jmethodID Rf_VectorToPairListMethodID;
+static jmethodID Rf_asCharacterFactorMethodID;
 static jmethodID gnuRCodeForObjectMethodID;
 static jmethodID NAMED_MethodID;
 static jmethodID SET_TYPEOF_FASTR_MethodID;
@@ -228,6 +230,8 @@ void init_internals(JNIEnv *env) {
         Rf_coerceVectorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_coerceVector", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
 	Rf_asLogicalMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asLogical", "(Ljava/lang/Object;)I", 0);
 	Rf_PairToVectorListMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_PairToVectorList", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_VectorToPairListMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_VectorToPairList", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_asCharacterFactorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asCharacterFactor", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
 	NAMED_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "NAMED", "(Ljava/lang/Object;)I", 0);
 	SET_TYPEOF_FASTR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_TYPEOF_FASTR", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
 	SET_NAMED_FASTR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_NAMED_FASTR", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
@@ -1190,13 +1194,17 @@ SEXP Rf_PairToVectorList(SEXP x){
 }
 
 SEXP Rf_VectorToPairList(SEXP x){
-	unimplemented("Rf_VectorToPairList");
-	return NULL;
+	TRACE(TARGp, x);
+	JNIEnv *thisenv = getEnv();
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_VectorToPairListMethodID, x);
+	return checkRef(thisenv, result);
 }
 
 SEXP Rf_asCharacterFactor(SEXP x){
-	unimplemented("Rf_VectorToPairList");
-	return NULL;
+	TRACE(TARGp, x);
+	JNIEnv *thisenv = getEnv();
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_asCharacterFactorMethodID, x);
+	return checkRef(thisenv, result);
 }
 
 int Rf_asLogical(SEXP x){
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
index 1acc334cb5..767572ed9d 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
@@ -763,12 +763,11 @@ SEXP Rf_PairToVectorList(SEXP x){
 }
 
 SEXP Rf_VectorToPairList(SEXP x){
-	return unimplemented("Rf_VectorToPairList");
+	return checkRef(((call_Rf_VectorToPairList) callbacks[Rf_VectorToPairList_x])(x));
 }
 
 SEXP Rf_asCharacterFactor(SEXP x){
-	unimplemented("Rf_VectorToPairList");
-	return NULL;
+	return checkRef(((call_Rf_asCharacterFactor) callbacks[Rf_asCharacterFactor_x])(x));
 }
 
 int Rf_asLogical(SEXP x){
-- 
GitLab