diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java
index c6a44575fbe04e3278328db0b434fb5601f18f72..57f9b36dad911f2e1f2f9f03980b7bc0dc2118e3 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java
@@ -22,8 +22,8 @@
  */
 package com.oracle.truffle.r.ffi.impl.nfi;
 
+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.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.InteropException;
@@ -44,77 +44,37 @@ public class TruffleNFI_C implements CRFFI {
         @Specialization(guards = "args.length == 0")
         protected void invokeCall0(NativeCallInfo nativeCallInfo, @SuppressWarnings("unused") Object[] args, @SuppressWarnings("unused") boolean hasStrings,
                         @Cached("createExecute(args.length)") Node executeNode) {
-            try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(): void");
-                ForeignAccess.sendExecute(executeNode, callFunction);
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
+            synchronized (TruffleNFI_Call.class) {
+                try {
+                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode, nativeCallInfo.address.asTruffleObject(), "bind", "(): void");
+                    ForeignAccess.sendExecute(executeNode, callFunction);
+                } catch (InteropException ex) {
+                    throw RInternalError.shouldNotReachHere(ex);
+                }
             }
         }
 
-        @Specialization(guards = "args.length == 1")
+        @Specialization(limit = "99", guards = "args.length == cachedArgsLength")
         protected void invokeCall1(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean hasStrings,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            try {
-                Object[] nargs = new Object[args.length];
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
-                ForeignAccess.sendExecute(executeNode, callFunction, nargs[0]);
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            }
-        }
-
-        @Specialization(guards = "args.length == 2")
-        protected void invokeCall2(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean hasStrings,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            try {
-                Object[] nargs = new Object[args.length];
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
-                ForeignAccess.sendExecute(executeNode, callFunction, nargs[0], nargs[1]);
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
+                        @Cached("args.length") int cachedArgsLength,
+                        @Cached("createExecute(cachedArgsLength)") Node executeNode) {
+            synchronized (TruffleNFI_Call.class) {
+                try {
+                    Object[] nargs = new Object[cachedArgsLength];
+                    TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode, nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
+                    ForeignAccess.sendExecute(executeNode, callFunction, nargs);
+                } catch (InteropException ex) {
+                    throw RInternalError.shouldNotReachHere(ex);
+                }
             }
         }
 
-        @Specialization(guards = "args.length == 3")
-        protected void invokeCall3(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean hasStrings,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            try {
-                Object[] nargs = new Object[args.length];
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
-                ForeignAccess.sendExecute(executeNode, callFunction, nargs[0], nargs[1], nargs[2]);
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            }
-        }
-
-        @Specialization(guards = "args.length == 4")
-        protected void invokeCall4(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean hasStrings,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            try {
-                Object[] nargs = new Object[args.length];
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", getSignature(args, nargs));
-                ForeignAccess.sendExecute(executeNode, callFunction, nargs[0], nargs[1], nargs[2], nargs[3]);
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            }
-        }
-
-        @Fallback
-        protected void invokeCallN(@SuppressWarnings("unused") NativeCallInfo nativeCallInfo, @SuppressWarnings("unused") Object[] args, @SuppressWarnings("unused") boolean hasStrings) {
-            throw RInternalError.unimplemented(".C (too many args)");
-        }
-
         public static Node createExecute(int n) {
             return Message.createExecute(n).createNode();
         }
     }
 
+    @TruffleBoundary
     private static String getSignature(Object[] args, Object[] nargs) {
         StringBuilder sb = new StringBuilder();
         sb.append('(');
@@ -124,8 +84,8 @@ public class TruffleNFI_C implements CRFFI {
                 sb.append("[sint32]");
             } else if (arg instanceof double[]) {
                 sb.append("[double]");
-            } else if (arg instanceof byte[]) {
-                sb.append("[uint8]");
+            } else if (arg instanceof byte[][]) {
+                sb.append("[pointer]");
             } else {
                 throw RInternalError.unimplemented(".C type: " + arg.getClass().getSimpleName());
             }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
index 0efd2c10b1fab6696a0bd2f5b603c85cfeaf2a21..6caf24cf5804b525ce207305cd4e9815311fd655 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
@@ -26,6 +26,7 @@ import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.traceDownCall;
 import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.traceDownCallReturn;
 import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.traceEnabled;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.interop.ForeignAccess;
@@ -231,165 +232,69 @@ public class TruffleNFI_Call implements CallRFFI {
     }
 
     public abstract static class TruffleNFI_InvokeCallNode extends Node implements InvokeCallNode {
-        @Child private Node bindNode = Message.createInvoke(1).createNode();
-
-        @Specialization(guards = "args.length == 0")
-        protected Object invokeCall0(NativeCallInfo nativeCallInfo, Object[] args,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            Object result = null;
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-            try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(): object");
-                result = ForeignAccess.sendExecute(executeNode, callFunction);
-                return result;
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, result, isNullSetting);
-            }
-        }
+        private static final String[] SIGNATURES = new String[32];
 
-        @Specialization(guards = "args.length == 1")
-        protected Object invokeCall1(NativeCallInfo nativeCallInfo, Object[] args,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            Object result = null;
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-            try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(object): object");
-                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0]);
-                return result;
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, result, isNullSetting);
-            }
-        }
-
-        @Specialization(guards = "args.length == 2")
-        protected Object invokeCall2(NativeCallInfo nativeCallInfo, Object[] args,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            Object result = null;
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-            try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object): object");
-                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1]);
-                return result;
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, result, isNullSetting);
-            }
-        }
-
-        @Specialization(guards = "args.length == 3")
-        protected Object invokeCall3(NativeCallInfo nativeCallInfo, Object[] args,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            Object result = null;
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-            try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object): object");
-                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1], args[2]);
-                return result;
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, result, isNullSetting);
-            }
-        }
-
-        @Specialization(guards = "args.length == 4")
-        protected Object invokeCall4(NativeCallInfo nativeCallInfo, Object[] args,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            Object result = null;
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-            try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object): object");
-                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1], args[2],
-                                args[3]);
-                return result;
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, result, isNullSetting);
-            }
-        }
+        @Child private Node bindNode = Message.createInvoke(1).createNode();
 
-        @Specialization(guards = "args.length == 5")
-        protected Object invokeCall5(NativeCallInfo nativeCallInfo, Object[] args,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            Object result = null;
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-            try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object): object");
-                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
-                                args[2], args[3], args[4]);
-                return result;
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, result, isNullSetting);
+        @TruffleBoundary
+        protected TruffleObject getFunction(TruffleObject address, int arity) {
+            // cache signatures
+            String signature;
+            if (arity >= SIGNATURES.length || SIGNATURES[arity] == null) {
+                StringBuilder str = new StringBuilder().append('(');
+                for (int i = 0; i < arity; i++) {
+                    str.append(i > 0 ? ", object" : "object");
+                }
+                str.append("): object");
+                signature = str.toString();
+                if (arity < SIGNATURES.length) {
+                    SIGNATURES[arity] = signature;
+                }
+            } else {
+                signature = SIGNATURES[arity];
             }
-        }
-
-        @Specialization(guards = "args.length == 6")
-        protected Object invokeCall6(NativeCallInfo nativeCallInfo, Object[] args,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            Object result = null;
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
             try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object, object): object");
-                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
-                                args[2], args[3], args[4], args[5]);
-                return result;
+                return (TruffleObject) ForeignAccess.sendInvoke(bindNode, address, "bind", signature);
             } catch (InteropException ex) {
                 throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, result, isNullSetting);
             }
         }
 
-        @Specialization(guards = "args.length == 7")
-        protected Object invokeCall7(NativeCallInfo nativeCallInfo, Object[] args,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            Object result = null;
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-            try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object, object, object): object");
-                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
-                                args[2], args[3], args[4], args[5],
-                                args[6]);
-                return result;
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, result, isNullSetting);
+        @Specialization(guards = {"args.length == cachedArgsLength", "nativeCallInfo.address.asTruffleObject() == cachedAddress"})
+        protected Object invokeCallCached(NativeCallInfo nativeCallInfo, Object[] args,
+                        @SuppressWarnings("unused") @Cached("args.length") int cachedArgsLength,
+                        @Cached("createExecute(cachedArgsLength)") Node executeNode,
+                        @SuppressWarnings("unused") @Cached("nativeCallInfo.address.asTruffleObject()") TruffleObject cachedAddress,
+                        @Cached("getFunction(cachedAddress, cachedArgsLength)") TruffleObject cachedFunction) {
+            synchronized (TruffleNFI_Call.class) {
+                Object result = null;
+                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+                try {
+                    result = ForeignAccess.sendExecute(executeNode, cachedFunction, args);
+                    return result;
+                } catch (InteropException ex) {
+                    throw RInternalError.shouldNotReachHere(ex);
+                } finally {
+                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
+                }
             }
         }
 
-        @Specialization(guards = "args.length == 8")
-        protected Object invokeCall8(NativeCallInfo nativeCallInfo, Object[] args,
-                        @Cached("createExecute(args.length)") Node executeNode) {
-            Object result = null;
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-            try {
-                TruffleObject callFunction = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                nativeCallInfo.address.asTruffleObject(), "bind", "(object, object, object, object, object, object, object, object): object");
-                result = ForeignAccess.sendExecute(executeNode, callFunction, args[0], args[1],
-                                args[2], args[3], args[4], args[5],
-                                args[6], args[7]);
-                return result;
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, result, isNullSetting);
+        @Specialization(limit = "99", guards = "args.length == cachedArgsLength")
+        protected Object invokeCallCachedLength(NativeCallInfo nativeCallInfo, Object[] args,
+                        @Cached("args.length") int cachedArgsLength,
+                        @Cached("createExecute(cachedArgsLength)") Node executeNode) {
+            synchronized (TruffleNFI_Call.class) {
+                Object result = null;
+                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+                try {
+                    result = ForeignAccess.sendExecute(executeNode, getFunction(nativeCallInfo.address.asTruffleObject(), cachedArgsLength), args);
+                    return result;
+                } catch (InteropException ex) {
+                    throw RInternalError.shouldNotReachHere(ex);
+                } finally {
+                    prepareReturn(nativeCallInfo.name, result, isNullSetting);
+                }
             }
         }
 
@@ -407,24 +312,26 @@ public class TruffleNFI_Call implements CallRFFI {
 
         @Override
         public void execute(NativeCallInfo nativeCallInfo, Object[] args) {
-            boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
-            try {
-                switch (args.length) {
-                    case 0:
-                        TruffleObject callVoid0Function = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                        nativeCallInfo.address.asTruffleObject(), "bind", CallVoid0Sig);
-                        ForeignAccess.sendExecute(execute0Node, callVoid0Function);
-                        break;
-                    case 1:
-                        TruffleObject callVoid1Function = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
-                                        nativeCallInfo.address.asTruffleObject(), "bind", CallVoid1Sig);
-                        ForeignAccess.sendExecute(execute1Node, callVoid1Function, args[0]);
-                        break;
+            synchronized (TruffleNFI_Call.class) {
+                boolean isNullSetting = prepareCall(nativeCallInfo.name, args);
+                try {
+                    switch (args.length) {
+                        case 0:
+                            TruffleObject callVoid0Function = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                            nativeCallInfo.address.asTruffleObject(), "bind", CallVoid0Sig);
+                            ForeignAccess.sendExecute(execute0Node, callVoid0Function);
+                            break;
+                        case 1:
+                            TruffleObject callVoid1Function = (TruffleObject) ForeignAccess.sendInvoke(bindNode,
+                                            nativeCallInfo.address.asTruffleObject(), "bind", CallVoid1Sig);
+                            ForeignAccess.sendExecute(execute1Node, callVoid1Function, args[0]);
+                            break;
+                    }
+                } catch (InteropException ex) {
+                    throw RInternalError.shouldNotReachHere(ex);
+                } finally {
+                    prepareReturn(nativeCallInfo.name, null, isNullSetting);
                 }
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            } finally {
-                prepareReturn(nativeCallInfo.name, null, isNullSetting);
             }
         }
     }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
index 662dcfd26b378c93d55fa5883f2dca1cbf8f56ae..2ae0b803e372d6040849900704aa52227a2efc0f 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
@@ -22,16 +22,48 @@
  */
 package com.oracle.truffle.r.ffi.impl.upcalls;
 
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RObject;
 
-public final class FFIWrapNode extends Node {
+public abstract class FFIWrapNode extends Node {
 
-    @SuppressWarnings("static-method")
-    public Object execute(Object value) {
+    public abstract Object execute(Object value);
+
+    @Specialization
+    protected static Object wrap(int value) {
+        return wrap(RDataFactory.createIntVectorFromScalar(value));
+    }
+
+    @Specialization
+    protected static Object wrap(double value) {
+        return wrap(RDataFactory.createDoubleVectorFromScalar(value));
+    }
+
+    @Specialization
+    protected static Object wrap(byte value) {
+        return wrap(RDataFactory.createLogicalVectorFromScalar(value));
+    }
+
+    @Specialization
+    protected static Object wrap(String value) {
+        return wrap(RDataFactory.createStringVectorFromScalar(value));
+    }
+
+    @Specialization
+    protected static Object wrap(RObject value) {
+        return value;
+    }
+
+    @Fallback
+    protected static Object wrap(Object value) {
+        System.out.println("invalid wrapping: " + value.getClass().getSimpleName());
         return value;
     }
 
     public static FFIWrapNode create() {
-        return new FFIWrapNode();
+        return FFIWrapNodeGen.create();
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RBaseObject.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RBaseObject.java
index 52e181b7b495afc5e697ff40bff8347e407e17ff..b918df63e05ee7f040c2bed474b88bfe750fe094 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RBaseObject.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RBaseObject.java
@@ -22,7 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
-abstract class RBaseObject implements RTypedValue {
+abstract class RBaseObject extends RObject implements RTypedValue {
 
     private int typedValueInfo;
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b3555e35bade73c1fea251848d3169a5205df5d
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java
@@ -0,0 +1,36 @@
+/*
+ * 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
+ * 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.runtime.data;
+
+public abstract class RObject {
+
+    private Object nativeMirror;
+
+    public final void setNativeMirror(Object mirror) {
+        this.nativeMirror = mirror;
+    }
+
+    public final Object getNativeMirror() {
+        return nativeMirror;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalar.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalar.java
index 9bfb531713c0f5371afb487a77fc86a0e3fdf978..e5fd6e43c40d9a6cd62b7b72c546c6fd18e6a6c4 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalar.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalar.java
@@ -26,7 +26,7 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.r.runtime.RInternalError;
 
 @ValueType
-public abstract class RScalar implements RTypedValue {
+public abstract class RScalar extends RObject implements RTypedValue {
 
     @Override
     public final int getTypedValueInfo() {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CharSXPWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CharSXPWrapper.java
index 62f5679c8c57b19df52ece5bb3f5ffcff0a08ffc..92763196ffc5a7d1515017bdf8db8fa535778c91 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CharSXPWrapper.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CharSXPWrapper.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.r.runtime.data.RObject;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 
 /**
@@ -32,9 +33,8 @@ import com.oracle.truffle.r.runtime.data.RTruffleObject;
  * represent a {@code CHARSXP}, so this class exists to do so.
  *
  * N.B. Use limited to RFFI implementations.
- *
  */
-public final class CharSXPWrapper implements RTruffleObject {
+public final class CharSXPWrapper extends RObject implements RTruffleObject {
     private final String contents;
 
     private CharSXPWrapper(String contents) {