diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
index f8c9740e0670919634015cd2f65032f6d833872d..9c6878788b8834752ea58a49efe18da2e8c57e16 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
@@ -499,4 +499,23 @@ public final class NativeDataAccess {
         }
         return mirror.dataAddress;
     }
+
+    public static void setNativeContents(RObject obj, long address, int length) {
+        assert obj.getNativeMirror() != null;
+        if (noDoubleNative.isValid() && obj instanceof RDoubleVector) {
+            noDoubleNative.invalidate();
+        } else if (noComplexNative.isValid() && obj instanceof RComplexVector) {
+            noComplexNative.invalidate();
+        } else if (noIntNative.isValid() && obj instanceof RIntVector) {
+            noIntNative.invalidate();
+        } else if (noRawNative.isValid() && obj instanceof RRawVector) {
+            noRawNative.invalidate();
+        } else if (noLogicalNative.isValid() && obj instanceof RLogicalVector) {
+            noLogicalNative.invalidate();
+        }
+        NativeMirror mirror = (NativeMirror) obj.getNativeMirror();
+        mirror.dataAddress = address;
+        mirror.length = length;
+
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java
index 5aba159019d3194b3c76929e6bd35575d961e451..a3cedbc0057006849cc31cfcfe2c7b37561b7d37 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java
@@ -49,12 +49,23 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
         initDimsNamesDimNames(dims, names, dimNames);
     }
 
+    private RComplexVector() {
+        super(false);
+    }
+
+    static RComplexVector fromNative(long address, int length) {
+        RComplexVector result = new RComplexVector();
+        NativeDataAccess.asPointer(result);
+        NativeDataAccess.setNativeContents(result, address, length);
+        return result;
+    }
+
     @Override
     protected RComplexVector internalCopy() {
         if (data != null) {
             return new RComplexVector(Arrays.copyOf(data, data.length), this.isComplete());
         } else {
-            return new RComplexVector(NativeDataAccess.copyDoubleNativeData(getNativeMirror()), this.isComplete(), null);
+            return new RComplexVector(NativeDataAccess.copyDoubleNativeData(getNativeMirror()), this.isComplete());
         }
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
index 619bc2a75a2caff43fd491cb19def9571921693b..47e1c9d20c8c08cbce0b211a20673d7701fbd8a3 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
@@ -56,6 +56,10 @@ public final class RDataFactory {
     public static final boolean INCOMPLETE_VECTOR = false;
     public static final boolean COMPLETE_VECTOR = true;
 
+    public static RIntVector createIntVectorFromNative(long address, int length) {
+        return traceDataCreated(RIntVector.fromNative(address, length));
+    }
+
     public static RIntVector createIntVector(int length) {
         return createIntVector(length, false);
     }
@@ -88,6 +92,10 @@ public final class RDataFactory {
         return traceDataCreated(new RIntVector(data, complete, dims, names, dimNames));
     }
 
+    public static RDoubleVector createDoubleVectorFromNative(long address, int length) {
+        return traceDataCreated(RDoubleVector.fromNative(address, length));
+    }
+
     public static RDoubleVector createDoubleVector(int length) {
         return createDoubleVector(length, false);
     }
@@ -144,6 +152,10 @@ public final class RDataFactory {
         return traceDataCreated(new RRawVector(data, dims, names, dimNames));
     }
 
+    public static RComplexVector createComplexVectorFromNative(long address, int length) {
+        return traceDataCreated(RComplexVector.fromNative(address, length));
+    }
+
     public static RComplexVector createComplexVector(int length) {
         return createComplexVector(length, false);
     }
@@ -217,6 +229,10 @@ public final class RDataFactory {
         return traceDataCreated(new RStringVector(data, complete, dims, names, dimNames));
     }
 
+    public static RLogicalVector createLogicalVectorFromNative(long address, int length) {
+        return traceDataCreated(RLogicalVector.fromNative(address, length));
+    }
+
     public static RLogicalVector createLogicalVector(int length) {
         return createLogicalVector(length, false);
     }
@@ -317,6 +333,10 @@ public final class RDataFactory {
         return traceDataCreated(RComplex.valueOf(realPart, imaginaryPart));
     }
 
+    public static RRawVector createRawVectorFromNative(long address, int length) {
+        return traceDataCreated(RRawVector.fromNative(address, length));
+    }
+
     public static RRaw createRaw(byte value) {
         return traceDataCreated(new RRaw(value));
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java
index c5bfb51de748e6c643f1ae338c3ff02a26a07935..cc84373f42bcae0a9f153044ac545d4700966526 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java
@@ -48,6 +48,18 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
         initDimsNamesDimNames(dims, names, dimNames);
     }
 
+    private RDoubleVector() {
+        super(false);
+    }
+
+    static RDoubleVector fromNative(long address, int length) {
+        RDoubleVector result = new RDoubleVector();
+        NativeDataAccess.asPointer(result);
+        NativeDataAccess.setNativeContents(result, address, length);
+        assert result.data == null;
+        return result;
+    }
+
     @Override
     public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java
index a974ca745be12443883289e745d08a044b9efeb2..93d5547fc5ab9987b3dbae7d60c5ccc388ce8e47 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java
@@ -48,6 +48,17 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect
         initDimsNamesDimNames(dims, names, dimNames);
     }
 
+    private RIntVector() {
+        super(false);
+    }
+
+    static RIntVector fromNative(long address, int length) {
+        RIntVector result = new RIntVector();
+        NativeDataAccess.asPointer(result);
+        NativeDataAccess.setNativeContents(result, address, length);
+        return result;
+    }
+
     @Override
     public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java
index a96573dad51fa7e73df8b3f471c9b3453dfa84f7..8d87a76756d9dc101d4767d56b9be4051fd25f88 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java
@@ -48,6 +48,17 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo
         initDimsNamesDimNames(dims, names, dimNames);
     }
 
+    private RLogicalVector() {
+        super(false);
+    }
+
+    static RLogicalVector fromNative(long address, int length) {
+        RLogicalVector result = new RLogicalVector();
+        NativeDataAccess.asPointer(result);
+        NativeDataAccess.setNativeContents(result, address, length);
+        return result;
+    }
+
     @Override
     public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java
index 8e12c79aab3b58aa77d22c69cd248f678434a241..1bd4e1e70c5ef768f5993f0f60e56e204d934ba5 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java
@@ -48,6 +48,17 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec
         initDimsNamesDimNames(dims, names, dimNames);
     }
 
+    private RRawVector() {
+        super(true);
+    }
+
+    static RRawVector fromNative(long address, int length) {
+        RRawVector result = new RRawVector();
+        NativeDataAccess.asPointer(result);
+        NativeDataAccess.setNativeContents(result, address, length);
+        return result;
+    }
+
     @Override
     public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) {
         switch (type) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
index 16e53cf26ee6b3014a75e21ccc4c48369289a3bf..27ad924f7b5e9d8e71877be62886206c25a54d7d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
@@ -94,6 +94,10 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
      */
     public abstract ArrayT getInternalManagedData();
 
+    public boolean hasNativeMemoryData() {
+        return getInternalManagedData() == null;
+    }
+
     /**
      * Intended for external calls where a mutable copy is needed.
      */
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
index 37e2afc0d46ce0a0e101c3cdb02cd334b9916bca..13bb121163eed6b1467ba03786b12851a5dca641 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
@@ -36,6 +36,7 @@ import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.NativeDataAccess;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
@@ -54,6 +55,7 @@ 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.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 import sun.misc.Unsafe;
@@ -75,7 +77,7 @@ class TemporaryWrapperMR {
         protected Object access(TemporaryWrapper receiver) {
             long address = receiver.address;
             if (profile.profile(address == 0)) {
-                receiver.address = address = receiver.allocate();
+                return receiver.asPointer();
             }
             return address;
         }
@@ -117,13 +119,12 @@ abstract class TemporaryWrapper implements TruffleObject {
 
     protected long address;
     protected RAbstractAtomicVector vector;
+    protected boolean reuseVector = false;
 
     TemporaryWrapper(RAbstractAtomicVector vector) {
         this.vector = vector;
     }
 
-    public abstract long allocate();
-
     public Object read(long index) {
         throw RInternalError.unimplemented("read at " + index);
     }
@@ -137,34 +138,64 @@ abstract class TemporaryWrapper implements TruffleObject {
         return TemporaryWrapperMRForeign.ACCESS;
     }
 
+    public long asPointer() {
+        // if the vector is temporary, we can re-use it. We turn it into native memory backed
+        // vector, keep it so and reuse it as the result.
+        if (vector instanceof RVector<?> && ((RVector<?>) vector).isTemporary()) {
+            NativeDataAccess.asPointer(vector);
+            reuseVector = true;
+            address = allocateNative((RVector<?>) vector);
+        } else {
+            reuseVector = false;
+            address = allocate(vector);
+        }
+        return address;
+    }
+
     public final RAbstractAtomicVector cleanup() {
-        if (address == 0) {
+        if (address == 0 || reuseVector) {
             return vector;
         } else {
-            return copyBack();
+            return copyBack(address, vector);
         }
     }
 
-    protected abstract RAbstractAtomicVector copyBack();
+    protected abstract long allocate(RAbstractVector vector);
 
-    protected static <ArrayT> ArrayT reuseData(RVector<ArrayT> vec) {
-        // Note: maybe we can reuse non-shared vectors too?
-        return vec.isTemporary() ? vec.getInternalManagedData() : null;
-    }
+    protected abstract long allocateNative(RVector<?> vector);
+
+    protected abstract RAbstractAtomicVector copyBack(long address, RAbstractVector vector);
 }
 
+// TODO: fortran only takes a pointer to the first string
 final class StringWrapper extends TemporaryWrapper {
 
     StringWrapper(RAbstractStringVector vector) {
         super(vector);
     }
 
+    @Override
+    public long asPointer() {
+        address = allocate(vector);
+        return address;
+    }
+
+    @Override
+    protected long allocateNative(RVector<?> vector) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
     @Override
     @TruffleBoundary
-    public long allocate() {
+    public long allocate(RAbstractVector vector) {
+        // We allocate contiguous memory that we'll use to store both the array of pointers (char**)
+        // and the arrays of characters (char*). Given vector of size N, we allocate memory for N
+        // adresses (long) and after those we put individual strings character by character, the
+        // pointers from the first segment of this memory will be pointing to the starts of those
+        // strings.
         RAbstractStringVector v = (RAbstractStringVector) vector;
         int length = v.getLength();
-        int size = length * 8;
+        int size = length * Long.BYTES;
         byte[][] bytes = new byte[length][];
         for (int i = 0; i < length; i++) {
             String element = v.getDataAt(i);
@@ -172,7 +203,7 @@ final class StringWrapper extends TemporaryWrapper {
             size += bytes[i].length + 1;
         }
         long memory = UnsafeAdapter.UNSAFE.allocateMemory(size);
-        long ptr = memory + length * 8; // start of the actual character data
+        long ptr = memory + length * Long.BYTES; // start of the actual character data
         for (int i = 0; i < length; i++) {
             UnsafeAdapter.UNSAFE.putLong(memory + i * 8, ptr);
             UnsafeAdapter.UNSAFE.copyMemory(bytes[i], Unsafe.ARRAY_BYTE_BASE_OFFSET, null, ptr, bytes[i].length);
@@ -185,12 +216,10 @@ final class StringWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    protected RStringVector copyBack() {
+    protected RStringVector copyBack(long address, RAbstractVector vector) {
         RStringVector result = ((RAbstractStringVector) vector).materialize();
-        String[] data = reuseData(result);
-        if (data == null) {
-            data = new String[result.getLength()];
-        }
+        boolean reuseResult = result.isTemporary() && !result.hasNativeMemoryData();
+        String[] data = reuseResult ? result.getInternalManagedData() : new String[result.getLength()];
         for (int i = 0; i < data.length; i++) {
             long ptr = UnsafeAdapter.UNSAFE.getLong(address + i * 8);
             int length = 0;
@@ -202,7 +231,13 @@ final class StringWrapper extends TemporaryWrapper {
             data[i] = new String(bytes, StandardCharsets.US_ASCII);
         }
         UnsafeAdapter.UNSAFE.freeMemory(address);
-        return RDataFactory.createStringVector(data, true);
+        if (reuseResult) {
+            return result;
+        } else {
+            RStringVector newResult = RDataFactory.createStringVector(data, true);
+            newResult.copyAttributesFrom(result);
+            return newResult;
+        }
     }
 }
 
@@ -214,7 +249,7 @@ final class IntWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    public long allocate() {
+    public long allocate(RAbstractVector vector) {
         RAbstractIntVector v = (RAbstractIntVector) vector;
         int length = v.getLength();
         long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_INT_INDEX_SCALE);
@@ -226,15 +261,16 @@ final class IntWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    protected RIntVector copyBack() {
-        RIntVector result = ((RAbstractIntVector) vector).materialize();
-        int[] data = reuseData(result);
-        if (data == null) {
-            data = new int[vector.getLength()];
-        }
-        UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_INT_BASE_OFFSET, vector.getLength() * Unsafe.ARRAY_INT_INDEX_SCALE);
-        UnsafeAdapter.UNSAFE.freeMemory(address);
-        return RDataFactory.createIntVector(data, false);
+    protected long allocateNative(RVector<?> vector) {
+        return ((RIntVector) vector).allocateNativeContents();
+    }
+
+    @Override
+    @TruffleBoundary
+    protected RIntVector copyBack(long address, RAbstractVector vector) {
+        RIntVector result = RDataFactory.createIntVectorFromNative(address, vector.getLength());
+        result.copyAttributesFrom(vector);
+        return result;
     }
 }
 
@@ -246,7 +282,7 @@ final class LogicalWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    public long allocate() {
+    public long allocate(RAbstractVector vector) {
         RAbstractLogicalVector v = (RAbstractLogicalVector) vector;
         int length = v.getLength();
         long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_INT_INDEX_SCALE);
@@ -258,18 +294,16 @@ final class LogicalWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    protected RLogicalVector copyBack() {
-        RLogicalVector result = ((RAbstractLogicalVector) vector).materialize();
-        byte[] data = reuseData(result);
-        if (data == null) {
-            data = new byte[result.getLength()];
-        }
-        int length = vector.getLength();
-        for (int i = 0; i < length; i++) {
-            data[i] = RRuntime.int2logical(UnsafeAdapter.UNSAFE.getInt(address + (i * Unsafe.ARRAY_INT_INDEX_SCALE)));
-        }
-        UnsafeAdapter.UNSAFE.freeMemory(address);
-        return RDataFactory.createLogicalVector(data, false);
+    protected long allocateNative(RVector<?> vector) {
+        return ((RLogicalVector) vector).allocateNativeContents();
+    }
+
+    @Override
+    @TruffleBoundary
+    protected RLogicalVector copyBack(long address, RAbstractVector vector) {
+        RLogicalVector result = RDataFactory.createLogicalVectorFromNative(address, vector.getLength());
+        result.copyAttributesFrom(vector);
+        return result;
     }
 }
 
@@ -281,7 +315,7 @@ final class DoubleWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    public long allocate() {
+    public long allocate(RAbstractVector vector) {
         RAbstractDoubleVector v = (RAbstractDoubleVector) vector;
         int length = v.getLength();
         long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
@@ -293,15 +327,16 @@ final class DoubleWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    protected RDoubleVector copyBack() {
-        RDoubleVector result = ((RAbstractDoubleVector) vector).materialize();
-        double[] data = reuseData(result);
-        if (data == null) {
-            data = new double[vector.getLength()];
-        }
-        UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_DOUBLE_BASE_OFFSET, vector.getLength() * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
-        UnsafeAdapter.UNSAFE.freeMemory(address);
-        return RDataFactory.createDoubleVector(data, false);
+    protected long allocateNative(RVector<?> vector) {
+        return ((RDoubleVector) vector).allocateNativeContents();
+    }
+
+    @Override
+    @TruffleBoundary
+    protected RDoubleVector copyBack(long address, RAbstractVector vector) {
+        RDoubleVector result = RDataFactory.createDoubleVectorFromNative(address, vector.getLength());
+        result.copyAttributesFrom(vector);
+        return result;
     }
 }
 
@@ -313,7 +348,7 @@ final class ComplexWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    public long allocate() {
+    public long allocate(RAbstractVector vector) {
         RAbstractComplexVector v = (RAbstractComplexVector) vector;
         int length = v.getLength();
         long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE * 2);
@@ -327,15 +362,16 @@ final class ComplexWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    protected RComplexVector copyBack() {
-        RComplexVector result = ((RAbstractComplexVector) vector).materialize();
-        double[] data = reuseData(result);
-        if (data == null) {
-            data = new double[result.getLength() * 2];
-        }
-        UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_DOUBLE_BASE_OFFSET, vector.getLength() * 2 * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
-        UnsafeAdapter.UNSAFE.freeMemory(address);
-        return RDataFactory.createComplexVector(data, false);
+    protected long allocateNative(RVector<?> vector) {
+        return ((RComplexVector) vector).allocateNativeContents();
+    }
+
+    @Override
+    @TruffleBoundary
+    protected RComplexVector copyBack(long address, RAbstractVector vector) {
+        RComplexVector result = RDataFactory.createComplexVectorFromNative(address, vector.getLength());
+        result.copyAttributesFrom(vector);
+        return result;
     }
 }
 
@@ -347,7 +383,7 @@ final class RawWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    public long allocate() {
+    public long allocate(RAbstractVector vector) {
         RAbstractRawVector v = (RAbstractRawVector) vector;
         int length = v.getLength();
         long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_BYTE_INDEX_SCALE);
@@ -359,20 +395,30 @@ final class RawWrapper extends TemporaryWrapper {
 
     @Override
     @TruffleBoundary
-    protected RRawVector copyBack() {
-        RRawVector result = ((RAbstractRawVector) vector).materialize();
-        byte[] data = reuseData(result);
-        if (data == null) {
-            data = new byte[result.getLength()];
-        }
-        UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_BYTE_BASE_OFFSET, vector.getLength() * Unsafe.ARRAY_BYTE_INDEX_SCALE);
-        UnsafeAdapter.UNSAFE.freeMemory(address);
-        return RDataFactory.createRawVector(data);
+    protected long allocateNative(RVector<?> vector) {
+        return ((RRawVector) vector).allocateNativeContents();
+    }
+
+    @Override
+    @TruffleBoundary
+    protected RRawVector copyBack(long address, RAbstractVector vector) {
+        RRawVector result = RDataFactory.createRawVectorFromNative(address, vector.getLength());
+        result.copyAttributesFrom(vector);
+        return result;
     }
 }
 
 /**
- * Support for the {.C} and {.Fortran} calls.
+ * Support for the {.C} and {.Fortran} calls. Arguments of these calls are only arrays of primitive
+ * types, in the case character vectors, only the first string. The vectors coming from the R side
+ * are duplicated (if not temporary) with all their attributes and then the pointer to the data of
+ * the new fresh vectors is passed to the function. The result is a list of all those new vectors
+ * (or the original vectors if they are temporary).
+ *
+ * Note: seems that symbols in GnuR may declare: expected types of their args (and other types
+ * should be coerced), whether an argument is only input (RNull is in its place in the result list)
+ * and whether the argument value must always be copied. We do not implement those as they do not
+ * seem necessary?
  */
 public interface CRFFI {