From a07d8cc7e998d0bd07e8c64f2ba78046caedb5f6 Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Fri, 10 Feb 2017 12:29:34 +0100
Subject: [PATCH] RFFI compatible mode for coercions (CastNodes)

Adds a flag to CastBaseNode that indicates that it should behave in a way
compatible with coercions exposed by the R native interface.
---
 .../truffle/r/nodes/unary/CastBaseNode.java   | 43 ++++++++++++++++---
 .../r/nodes/unary/CastComplexNode.java        | 12 +++++-
 .../r/nodes/unary/CastDoubleBaseNode.java     |  6 ++-
 .../truffle/r/nodes/unary/CastDoubleNode.java | 10 ++++-
 .../r/nodes/unary/CastExpressionNode.java     | 13 +++++-
 .../r/nodes/unary/CastIntegerBaseNode.java    |  6 ++-
 .../r/nodes/unary/CastIntegerNode.java        | 10 ++++-
 .../truffle/r/nodes/unary/CastListNode.java   | 12 +++++-
 .../r/nodes/unary/CastLogicalBaseNode.java    |  6 ++-
 .../r/nodes/unary/CastLogicalNode.java        | 12 +++++-
 .../truffle/r/nodes/unary/CastRawNode.java    | 18 ++++++--
 .../r/nodes/unary/CastStringBaseNode.java     |  8 +++-
 .../truffle/r/nodes/unary/CastStringNode.java | 12 +++++-
 .../truffle/r/nodes/unary/CastSymbolNode.java | 24 ++++++++++-
 .../r/nodes/unary/CastToAttributableNode.java |  8 +++-
 .../r/nodes/unary/CastToContainerNode.java    |  8 +++-
 .../com/oracle/truffle/r/runtime/RError.java  |  2 +-
 17 files changed, 177 insertions(+), 33 deletions(-)

diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
index 1f77dc7c61..f136727e66 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
@@ -34,10 +34,12 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNames
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.runtime.NullProfile;
 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.RType;
 import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.RVector;
@@ -62,21 +64,37 @@ public abstract class CastBaseNode extends CastNode {
 
     protected final RBaseNode messageCallObj;
 
+    /**
+     * GnuR provides several, sometimes incompatible, ways to coerce given value to given type. This
+     * flag tells the cast node that it should behave in a way compatible with functions exposed by
+     * the native interface.
+     */
+    private final boolean forRFFI;
+
     protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
+        this(preserveNames, preserveDimensions, preserveAttributes, false, messageCallObj);
+    }
+
+    protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        this(preserveNames, preserveDimensions, preserveAttributes, false, null);
+    }
+
+    protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        this(preserveNames, preserveDimensions, preserveAttributes, forRFFI, null);
+    }
+
+    protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI, RBaseNode messageCallObj) {
         this.preserveNames = preserveNames;
         this.preserveDimensions = preserveDimensions;
         this.preserveAttributes = preserveAttributes;
+        this.forRFFI = forRFFI;
         if (preserveDimensions) {
             getDimNamesNode = GetDimNamesAttributeNode.create();
         }
         this.messageCallObj = messageCallObj == null ? this : messageCallObj;
     }
 
-    protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        this(preserveNames, preserveDimensions, preserveAttributes, null);
-    }
-
-    public boolean preserveNames() {
+    public final boolean preserveNames() {
         return preserveNames;
     }
 
@@ -84,7 +102,7 @@ public abstract class CastBaseNode extends CastNode {
         return preserveDimensions;
     }
 
-    public boolean preserveAttributes() {
+    public final boolean preserveAttributes() {
         return preserveAttributes;
     }
 
@@ -132,6 +150,10 @@ public abstract class CastBaseNode extends CastNode {
     @TruffleBoundary
     protected Object doOther(Object value) {
         Object mappedValue = RRuntime.asAbstractVector(value);
+        return forRFFI ? doOtherRFFI(mappedValue) : doOtherDefault(mappedValue);
+    }
+
+    protected Object doOtherDefault(Object mappedValue) {
         if (mappedValue instanceof REnvironment) {
             throw RError.error(RError.SHOW_CALLER, RError.Message.ENVIRONMENTS_COERCE);
         } else if (mappedValue instanceof RTypedValue) {
@@ -142,4 +164,13 @@ public abstract class CastBaseNode extends CastNode {
             throw RInternalError.shouldNotReachHere("unexpected value of type " + (mappedValue == null ? "null" : mappedValue.getClass()));
         }
     }
+
+    protected Object doOtherRFFI(Object mappedValue) {
+        if (mappedValue instanceof RTypedValue) {
+            RError.warning(RError.SHOW_CALLER2, Message.CANNOT_COERCE_RFFI, ((RTypedValue) mappedValue).getRType().getName(), getTargetType().getName());
+        } else if (mappedValue instanceof TruffleObject) {
+            throw RError.error(RError.SHOW_CALLER2, RError.Message.CANNOT_COERCE, "truffleobject", getTargetType().getName());
+        }
+        return RNull.instance;
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
index ac4c7257d2..3d8fb9edf3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
@@ -68,7 +68,11 @@ public abstract class CastComplexNode extends CastBaseNode {
     }
 
     protected CastComplexNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastComplexNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Child private CastComplexNode recursiveCastComplex;
@@ -253,7 +257,7 @@ public abstract class CastComplexNode extends CastBaseNode {
                 }
             }
         }
-        RComplexVector ret = RDataFactory.createComplexVector(result, !seenNA);
+        RComplexVector ret = RDataFactory.createComplexVector(result, !seenNA, getPreservedDimensions(list), getPreservedNames(list));
         if (preserveAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
@@ -264,6 +268,10 @@ public abstract class CastComplexNode extends CastBaseNode {
         return CastComplexNodeGen.create(true, true, true);
     }
 
+    public static CastComplexNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastComplexNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastComplexNode createNonPreserving() {
         return CastComplexNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java
index eee5c32934..6e1b66b740 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java
@@ -48,7 +48,11 @@ public abstract class CastDoubleBaseNode extends CastBaseNode {
     }
 
     protected CastDoubleBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        this(preserveNames, preserveDimensions, preserveAttributes, null);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastDoubleBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java
index 3b98bd3901..d937c07eef 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java
@@ -48,7 +48,11 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 public abstract class CastDoubleNode extends CastDoubleBaseNode {
 
     protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
@@ -211,6 +215,10 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
         return CastDoubleNodeGen.create(true, true, true);
     }
 
+    public static CastDoubleNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastDoubleNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastDoubleNode createNonPreserving() {
         return CastDoubleNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
index 1178f3762e..a5a4c01397 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -40,7 +40,11 @@ public abstract class CastExpressionNode extends CastBaseNode {
     public abstract Object executeExpression(Object o);
 
     protected CastExpressionNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastExpressionNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
@@ -104,6 +108,11 @@ public abstract class CastExpressionNode extends CastBaseNode {
         return RDataFactory.createExpression(new Object[]{obj});
     }
 
+    public static CastExpressionNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        // RFFI coercion to list unlike others does not preserve names it seems
+        return CastExpressionNodeGen.create(false, false, false, true);
+    }
+
     public static CastExpressionNode createNonPreserving() {
         return CastExpressionNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java
index 14766f8e64..5a26f6d198 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java
@@ -45,7 +45,11 @@ public abstract class CastIntegerBaseNode extends CastBaseNode {
     @Child private CastIntegerNode recursiveCastInteger;
 
     protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java
index 796d7b5569..b0310c602b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java
@@ -50,7 +50,11 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
     private final NAProfile naProfile = NAProfile.create();
 
     protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
@@ -229,6 +233,10 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
         return CastIntegerNodeGen.create(true, true, true, null);
     }
 
+    public static CastIntegerNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastIntegerNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastIntegerNode createNonPreserving() {
         return CastIntegerNodeGen.create(false, false, false, null);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
index 606b54d966..1fc21b1956 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -52,7 +52,11 @@ public abstract class CastListNode extends CastBaseNode {
     public abstract RList executeList(Object o);
 
     protected CastListNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastListNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
@@ -143,4 +147,8 @@ public abstract class CastListNode extends CastBaseNode {
     public static CastListNode create() {
         return CastListNodeGen.create(true, true, true);
     }
+
+    public static CastListNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastListNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java
index d9883e2f08..94f484b2fc 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java
@@ -35,7 +35,11 @@ public abstract class CastLogicalBaseNode extends CastBaseNode {
     protected final NACheck naCheck = NACheck.create();
 
     protected CastLogicalBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastLogicalBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     protected CastLogicalBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
index 7cd9f32a97..6f15ddd3fc 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
@@ -56,7 +56,11 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
     }
 
     protected CastLogicalNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastLogicalNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     protected Object castLogicalRecursive(Object o) {
@@ -176,7 +180,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
                 }
             }
         }
-        RLogicalVector ret = RDataFactory.createLogicalVector(result, !seenNA);
+        RLogicalVector ret = RDataFactory.createLogicalVector(result, !seenNA, getPreservedDimensions(list), getPreservedNames(list));
         if (preserveAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
@@ -197,6 +201,10 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
         return CastLogicalNodeGen.create(true, true, true);
     }
 
+    public static CastLogicalNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastLogicalNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastLogicalNode createNonPreserving() {
         return CastLogicalNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
index 6592eb1d59..9471d88d7a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
@@ -51,7 +51,11 @@ public abstract class CastRawNode extends CastBaseNode {
     private final BranchProfile warningBranch = BranchProfile.create();
 
     protected CastRawNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastRawNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Child private CastRawNode recursiveCastRaw;
@@ -295,13 +299,21 @@ public abstract class CastRawNode extends CastBaseNode {
     @Specialization
     protected RRawVector doList(RAbstractListVector value) {
         int length = value.getLength();
-        RRawVector result = RDataFactory.createRawVector(length);
+        byte[] data = new byte[length];
         for (int i = 0; i < length; i++) {
-            result.updateDataAt(i, (RRaw) castRawRecursive(value.getDataAt(i)));
+            data[i] = ((RRaw) castRawRecursive(value.getDataAt(i))).getValue();
+        }
+        RRawVector result = RDataFactory.createRawVector(data, getPreservedDimensions(value), getPreservedNames(value));
+        if (preserveAttributes()) {
+            result.copyRegAttributesFrom(value);
         }
         return result;
     }
 
+    public static CastRawNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastRawNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastRawNode createNonPreserving() {
         return CastRawNodeGen.create(false, false, false);
     }
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 e5d9f51ef3..8d3a0456e3 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -34,7 +34,11 @@ public abstract class CastStringBaseNode extends CastBaseNode {
     @Child private ToStringNode toString = ToStringNodeGen.create();
 
     protected CastStringBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastStringBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
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 2bdf51e02a..a59b45866a 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -35,7 +35,11 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 public abstract class CastStringNode extends CastStringBaseNode {
 
     protected CastStringNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastStringNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     public abstract Object executeString(int o);
@@ -85,6 +89,10 @@ public abstract class CastStringNode extends CastStringBaseNode {
         return CastStringNodeGen.create(true, true, true);
     }
 
+    public static CastStringNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastStringNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastStringNode createNonPreserving() {
         return CastStringNodeGen.create(false, false, false);
     }
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 b8cc2b7251..31b0fea74e 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -25,21 +25,28 @@ package com.oracle.truffle.r.nodes.unary;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public abstract class CastSymbolNode extends CastBaseNode {
 
     @Child private ToStringNode toString = ToStringNodeGen.create();
 
     protected CastSymbolNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastSymbolNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
@@ -121,6 +128,19 @@ public abstract class CastSymbolNode extends CastBaseNode {
         return RDataFactory.createSymbolInterned(s);
     }
 
+    @Override
+    protected Object doOtherRFFI(Object mappedValue) {
+        if (mappedValue instanceof RList) {
+            // to be compatible with GnuR
+            throw RError.error(RError.NO_CALLER, Message.INVALID_TYPE_LENGTH, "symbol", ((RList) mappedValue).getLength());
+        }
+        return super.doOtherRFFI(mappedValue);
+    }
+
+    public static CastSymbolNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastSymbolNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastSymbolNode createNonPreserving() {
         return CastSymbolNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java
index 92608cf7e3..790a649b00 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -38,7 +38,11 @@ public abstract class CastToAttributableNode extends CastBaseNode {
     public abstract Object executeObject(Object value);
 
     protected CastToAttributableNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastToAttributableNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java
index 6446fb5726..383e4adb83 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -36,7 +36,11 @@ public abstract class CastToContainerNode extends CastBaseNode {
     public abstract Object executeObject(Object value);
 
     protected CastToContainerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastToContainerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index c4bc15ba7f..da3597e880 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -455,6 +455,7 @@ public final class RError extends RuntimeException {
         INVALID_SUBSCRIPT_TYPE("invalid subscript type '%s'"),
         ARGUMENT_NOT_VECTOR("argument %d is not a vector"),
         CANNOT_COERCE("cannot coerce type '%s' to vector of type '%s'"),
+        CANNOT_COERCE_RFFI("(%s) object cannot be coerced to type '%s'"),
         ARGUMENT_ONLY_FIRST("argument '%s' has length > 1 and only the first element will be used"),
         ARGUMENT_ONLY_FIRST_1("only the first element of '%s' argument used"),
         ARGUMENT_WRONG_LENGTH("wrong length for argument"),
@@ -742,7 +743,6 @@ public final class RError extends RuntimeException {
         QUIT_INVALID_STATUS("invalid 'status', 0 assumed"),
         QUIT_INVALID_RUNLAST("invalid 'runLast', FALSE assumed"),
         ENVIRONMENTS_COERCE("environments cannot be coerced to other types"),
-        CLOSURE_COERCE("cannot coerce type 'closure' to vector of type 'integer'"),
         ROWSUM_NAMES_NOT_CHAR("row names are not character"),
         ROWSUM_NON_NUMERIC("non-numeric matrix in rowsum(): this should not happen"),
         ARGUMENTS_REQUIRED_COUNT("%d arguments to '%s' which requires %d"),
-- 
GitLab