From 041f6e54f00eedf51b9865cdfa88a28ea404cf57 Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Fri, 15 Sep 2017 17:59:38 +0200
Subject: [PATCH] Implement R_alloc as up-call & refactor all RFFI state from
 RContext to RFFIContext

---
 .../ffi/impl/common/JavaUpCallsRFFIImpl.java  |  14 +-
 .../llvm/TruffleLLVM_RFFIContextState.java    |   3 +-
 .../impl/llvm/TruffleLLVM_RFFIFactory.java    |   3 +-
 .../llvm/TruffleLLVM_UpCallsRFFIImpl.java     |   5 +
 .../ffi/impl/managed/Managed_RFFIFactory.java |   5 +-
 .../truffle/r/ffi/impl/nfi/NFIContext.java    |  62 ++++++
 .../ffi/impl/nfi/TruffleNFI_RFFIFactory.java  |  23 +-
 .../impl/nfi/TruffleNFI_UpCallsRFFIImpl.java  |  13 ++
 .../r/ffi/impl/upcalls/MemoryUpCallsRFFI.java |   2 +
 .../truffle/r/ffi/processor/FFIProcessor.java |  13 +-
 .../fficall/src/common/rffi_upcalls.h         |   2 +
 .../fficall/src/common/rffi_upcallsindex.h    | 205 +++++++++---------
 .../Rinternals_truffle_common.h               |   2 +-
 .../fficall/src/truffle_nfi/Memory.c          |  91 +++-----
 .../truffle/r/runtime/context/RContext.java   |  48 +---
 .../oracle/truffle/r/runtime/ffi/CRFFI.java   |   3 +-
 .../truffle/r/runtime/ffi/CallRFFI.java       |   6 +-
 .../truffle/r/runtime/ffi/RFFIContext.java    |  92 ++++++++
 .../truffle/r/runtime/ffi/RFFIFactory.java    |   2 +-
 19 files changed, 345 insertions(+), 249 deletions(-)
 create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIContext.java
 create mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.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 81405ffcd2..ef0a295fe5 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
@@ -108,6 +108,7 @@ import com.oracle.truffle.r.runtime.ffi.DLL.CEntry;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.ffi.RFFIContext;
 import com.oracle.truffle.r.runtime.ffi.UnsafeAdapter;
 import com.oracle.truffle.r.runtime.gnur.SA_TYPE;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
@@ -1490,26 +1491,26 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
     @Override
     public void R_PreserveObject(Object obj) {
         guaranteeInstanceOf(obj, RObject.class);
-        HashSet<RObject> list = RContext.getInstance().preserveList;
+        HashSet<RObject> list = getContext().preserveList;
         list.add((RObject) obj);
     }
 
     @Override
     public void R_ReleaseObject(Object obj) {
         guaranteeInstanceOf(obj, RObject.class);
-        HashSet<RObject> list = RContext.getInstance().preserveList;
+        HashSet<RObject> list = getContext().preserveList;
         list.remove(obj);
     }
 
     @Override
     public Object Rf_protect(Object x) {
-        RContext.getInstance().protectStack.add(guaranteeInstanceOf(x, RObject.class));
+        getContext().protectStack.add(guaranteeInstanceOf(x, RObject.class));
         return x;
     }
 
     @Override
     public void Rf_unprotect(int x) {
-        RContext context = RContext.getInstance();
+        RFFIContext context = getContext();
         ArrayList<RObject> stack = context.protectStack;
         for (int i = 0; i < x; i++) {
             context.registerReferenceUsedInNative(stack.remove(stack.size() - 1));
@@ -1528,7 +1529,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     public void Rf_unprotect_ptr(Object x) {
-        RContext context = RContext.getInstance();
+        RFFIContext context = getContext();
         ArrayList<RObject> stack = context.protectStack;
         for (int i = stack.size() - 1; i >= 0; i--) {
             if (stack.get(i) == x) {
@@ -1673,4 +1674,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         throw implementedAsNode();
     }
 
+    private static RFFIContext getContext() {
+        return RContext.getInstance().getStateRFFI();
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIContextState.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIContextState.java
index 2201a8f2c0..c42c35cb01 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIContextState.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIContextState.java
@@ -26,12 +26,13 @@ import com.oracle.truffle.r.ffi.impl.common.LibPaths;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.RFFIContext;
 
 /**
  * A facade for the context state for the Truffle LLVM factory. Delegates to the various
  * module-specific pieces of state.
  */
-class TruffleLLVM_RFFIContextState implements ContextState {
+class TruffleLLVM_RFFIContextState extends RFFIContext {
     TruffleLLVM_DLL.ContextStateImpl dllState;
     TruffleLLVM_Call.ContextStateImpl callState;
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIFactory.java
index b15ebf8a65..e7bd3e199c 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIFactory.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIFactory.java
@@ -34,6 +34,7 @@ import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
 import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFI;
+import com.oracle.truffle.r.runtime.ffi.RFFIContext;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
 import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
@@ -43,7 +44,7 @@ import com.oracle.truffle.r.runtime.ffi.ZipRFFI;
 public class TruffleLLVM_RFFIFactory extends RFFIFactory {
 
     @Override
-    public ContextState newContextState() {
+    public RFFIContext newContextState() {
         return new TruffleLLVM_RFFIContextState();
     }
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java
index 5c1923299b..d4a5792760 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java
@@ -162,4 +162,9 @@ public class TruffleLLVM_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
             throw RInternalError.shouldNotReachHere(ex);
         }
     }
+
+    @Override
+    public Object R_alloc(int n, int size) {
+        throw RInternalError.unimplemented("R_alloc for LLVM");
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java
index 2bd86ac7f2..1b660805e2 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java
@@ -37,6 +37,7 @@ import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
 import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFI;
+import com.oracle.truffle.r.runtime.ffi.RFFIContext;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
 import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
@@ -213,8 +214,8 @@ public class Managed_RFFIFactory extends RFFIFactory {
     }
 
     @Override
-    public ContextState newContextState() {
-        return new ContextState() {
+    public RFFIContext newContextState() {
+        return new RFFIContext() {
             @Override
             public ContextState initialize(RContext context) {
                 return this;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIContext.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIContext.java
new file mode 100644
index 0000000000..7122102401
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIContext.java
@@ -0,0 +1,62 @@
+/*
+ * 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.nfi;
+
+import java.util.ArrayList;
+
+import com.oracle.truffle.r.ffi.impl.common.LibPaths;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.context.RContext.ContextState;
+import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
+import com.oracle.truffle.r.runtime.ffi.RFFIContext;
+import com.oracle.truffle.r.runtime.ffi.UnsafeAdapter;
+
+class NFIContext extends RFFIContext {
+    /**
+     * Memory allocated using Rf_alloc, which should be reclaimed at every down-call exit. Note:
+     * this is less efficient than GNUR's version, we may need to implement it properly should the
+     * performance be a problem.
+     */
+    public final ArrayList<Long> transientAllocations = new ArrayList<>();
+
+    @Override
+    public ContextState initialize(RContext context) {
+        String librffiPath = LibPaths.getBuiltinLibPath("R");
+        if (context.isInitial()) {
+            DLL.loadLibR(librffiPath);
+        } else {
+            // force initialization of NFI
+            DLLRFFI.DLOpenRootNode.create(context).call(librffiPath, false, false);
+        }
+        return this;
+    }
+
+    @Override
+    public void afterDowncall() {
+        for (Long ptr : transientAllocations) {
+            UnsafeAdapter.UNSAFE.freeMemory(ptr);
+        }
+        transientAllocations.clear();
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_RFFIFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_RFFIFactory.java
index 5de7192a15..bbac164014 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_RFFIFactory.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_RFFIFactory.java
@@ -24,19 +24,16 @@ package com.oracle.truffle.r.ffi.impl.nfi;
 
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.r.ffi.impl.common.LibPaths;
-import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
-import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
 import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
 import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFI;
+import com.oracle.truffle.r.runtime.ffi.RFFIContext;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
 import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
@@ -45,23 +42,9 @@ import com.oracle.truffle.r.runtime.ffi.ZipRFFI;
 
 public class TruffleNFI_RFFIFactory extends RFFIFactory {
 
-    private static class ContextStateImpl implements RContext.ContextState {
-        @Override
-        public ContextState initialize(RContext context) {
-            String librffiPath = LibPaths.getBuiltinLibPath("R");
-            if (context.isInitial()) {
-                DLL.loadLibR(librffiPath);
-            } else {
-                // force initialization of NFI
-                DLLRFFI.DLOpenRootNode.create(context).call(librffiPath, false, false);
-            }
-            return this;
-        }
-    }
-
     @Override
-    public ContextState newContextState() {
-        return new ContextStateImpl();
+    public RFFIContext newContextState() {
+        return new NFIContext();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java
index 29aeb45671..b9f38b7afb 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java
@@ -41,6 +41,7 @@ import com.oracle.truffle.r.ffi.impl.nfi.TruffleNFI_UpCallsRFFIImplFactory.Vecto
 import com.oracle.truffle.r.ffi.impl.upcalls.FFIUnwrapNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.CharSXPWrapper;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
@@ -53,6 +54,7 @@ import com.oracle.truffle.r.runtime.ffi.DLL.CEntry;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.ffi.UnsafeAdapter;
 
 public class TruffleNFI_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
 
@@ -84,6 +86,13 @@ public class TruffleNFI_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
         return CharSXPWrapper.create(TruffleNFI_Utils.getString(address, len));
     }
 
+    @Override
+    public Object R_alloc(int n, int size) {
+        long result = UnsafeAdapter.UNSAFE.allocateMemory(n * size);
+        getContext().transientAllocations.add(result);
+        return result;
+    }
+
     @MessageResolution(receiverType = VectorWrapper.class)
     public static class VectorWrapperMR {
 
@@ -219,4 +228,8 @@ public class TruffleNFI_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
             throw RInternalError.shouldNotReachHere(ex);
         }
     }
+
+    private static NFIContext getContext() {
+        return (NFIContext) RContext.getInstance().getStateRFFI();
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/MemoryUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/MemoryUpCallsRFFI.java
index 7a4a9a3109..662c864c47 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/MemoryUpCallsRFFI.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/MemoryUpCallsRFFI.java
@@ -45,4 +45,6 @@ public interface MemoryUpCallsRFFI {
 
     @RFFINoGC
     void Rf_unprotect_ptr(Object x);
+
+    Object R_alloc(int n, int size);
 }
diff --git a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
index 6a662215f8..e70d4d915a 100644
--- a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
+++ b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
@@ -167,7 +167,7 @@ public final class FFIProcessor extends AbstractProcessor {
 
     private void generateCallClass(ExecutableElement m) throws IOException {
         RFFIUpCallNode nodeAnnotation = m.getAnnotation(RFFIUpCallNode.class);
-        RFFINoGC noGCAnnotation = m.getAnnotation(RFFINoGC.class);
+        String canRunGc = m.getAnnotation(RFFINoGC.class) == null ? "true" : "false";
         String nodeClassName = null;
         TypeElement nodeClass = null;
         if (nodeAnnotation != null) {
@@ -236,6 +236,7 @@ public final class FFIProcessor extends AbstractProcessor {
         w.append("import com.oracle.truffle.api.interop.TruffleObject;\n");
         w.append("import com.oracle.truffle.api.nodes.RootNode;\n");
         w.append("import com.oracle.truffle.r.runtime.context.RContext;\n");
+        w.append("import com.oracle.truffle.r.runtime.ffi.RFFIContext;\n");
         w.append("import com.oracle.truffle.r.ffi.impl.common.RFFIUtils;\n");
         w.append("import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;\n");
         w.append("import com.oracle.truffle.r.runtime.data.RTruffleObject;\n");
@@ -294,6 +295,8 @@ public final class FFIProcessor extends AbstractProcessor {
         w.append("                    if (RFFIUtils.traceEnabled) {\n");
         w.append("                        RFFIUtils.traceUpCall(\"" + name + "\", arguments);\n");
         w.append("                    }\n");
+        w.append("                    RFFIContext ctx = RContext.getInstance().getStateRFFI();\n");
+        w.append("                    ctx.beforeUpcall(" + canRunGc + ");\n");
         if (returnKind == TypeKind.VOID) {
             w.append("                    ");
         } else {
@@ -313,14 +316,12 @@ public final class FFIProcessor extends AbstractProcessor {
         } else {
             w.append(";\n");
         }
-        if (noGCAnnotation == null) {
-            w.append("                    RContext.getInstance().runNativeCollector(); // we could have run cooperative GC at this point \n");
-        }
+        w.append("                    ctx.afterUpcall(" + canRunGc + ");\n");
         if (returnKind == TypeKind.VOID) {
             w.append("                    return 0; // void return type\n");
         } else {
-            w.append("                    RContext.getInstance().registerReferenceUsedInNative(resultRObj); \n");
-            w.append("                    return resultRObj; // void return type\n");
+            w.append("                    ctx.registerReferenceUsedInNative(resultRObj); \n");
+            w.append("                    return resultRObj;\n");
         }
         w.append("                }\n");
         w.append("            });\n");
diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
index 9c61534e99..07299d0366 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
+++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
@@ -314,5 +314,7 @@ typedef void (*call_Rf_unprotect_ptr)(SEXP x);
 typedef void (*call_R_PreserveObject)(SEXP x);
 typedef void (*call_R_ReleaseObject)(SEXP x);
 
+typedef void* (*call_R_alloc)(int n, int size);
+
 #endif
 
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 a9c6a9db78..e028d1c383 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
@@ -61,108 +61,109 @@
 #define R_TempDir_x 56
 #define R_ToplevelExec_x 57
 #define R_WriteConnection_x 58
-#define R_compute_identical_x 59
-#define R_do_MAKE_CLASS_x 60
-#define R_do_new_object_x 61
-#define R_do_slot_x 62
-#define R_do_slot_assign_x 63
-#define R_getContextCall_x 64
-#define R_getContextEnv_x 65
-#define R_getContextFun_x 66
-#define R_getContextSrcRef_x 67
-#define R_getGlobalFunctionContext_x 68
-#define R_getParentFunctionContext_x 69
-#define R_insideBrowser_x 70
-#define R_isEqual_x 71
-#define R_isGlobal_x 72
-#define R_lsInternal3_x 73
-#define R_new_custom_connection_x 74
-#define R_tryEval_x 75
-#define Rf_GetOption1_x 76
-#define Rf_PairToVectorList_x 77
-#define Rf_ScalarDouble_x 78
-#define Rf_ScalarInteger_x 79
-#define Rf_ScalarLogical_x 80
-#define Rf_ScalarString_x 81
-#define Rf_VectorToPairList_x 82
-#define Rf_allocArray_x 83
-#define Rf_allocMatrix_x 84
-#define Rf_allocVector_x 85
-#define Rf_any_duplicated_x 86
-#define Rf_asChar_x 87
-#define Rf_asCharacterFactor_x 88
-#define Rf_asInteger_x 89
-#define Rf_asLogical_x 90
-#define Rf_asReal_x 91
-#define Rf_classgets_x 92
-#define Rf_coerceVector_x 93
-#define Rf_cons_x 94
-#define Rf_copyListMatrix_x 95
-#define Rf_copyMatrix_x 96
-#define Rf_copyMostAttrib_x 97
-#define Rf_defineVar_x 98
-#define Rf_dunif_x 99
-#define Rf_duplicate_x 100
-#define Rf_error_x 101
-#define Rf_errorcall_x 102
-#define Rf_eval_x 103
-#define Rf_findFun_x 104
-#define Rf_findVar_x 105
-#define Rf_findVarInFrame_x 106
-#define Rf_findVarInFrame3_x 107
-#define Rf_getAttrib_x 108
-#define Rf_gsetVar_x 109
-#define Rf_inherits_x 110
-#define Rf_install_x 111
-#define Rf_installChar_x 112
-#define Rf_isNull_x 113
-#define Rf_isString_x 114
-#define Rf_lengthgets_x 115
-#define Rf_mkCharLenCE_x 116
-#define Rf_namesgets_x 117
-#define Rf_ncols_x 118
-#define Rf_nrows_x 119
-#define Rf_protect_x 120
-#define Rf_punif_x 121
-#define Rf_qunif_x 122
-#define Rf_runif_x 123
-#define Rf_setAttrib_x 124
-#define Rf_str2type_x 125
-#define Rf_unprotect_x 126
-#define Rf_unprotect_ptr_x 127
-#define Rf_warning_x 128
-#define Rf_warningcall_x 129
-#define Rprintf_x 130
-#define SETCADR_x 131
-#define SETCAR_x 132
-#define SETCDR_x 133
-#define SET_NAMED_FASTR_x 134
-#define SET_RDEBUG_x 135
-#define SET_RSTEP_x 136
-#define SET_S4_OBJECT_x 137
-#define SET_STRING_ELT_x 138
-#define SET_SYMVALUE_x 139
-#define SET_TAG_x 140
-#define SET_TYPEOF_FASTR_x 141
-#define SET_VECTOR_ELT_x 142
-#define STRING_ELT_x 143
-#define SYMVALUE_x 144
-#define TAG_x 145
-#define TYPEOF_x 146
-#define UNSET_S4_OBJECT_x 147
-#define VECTOR_ELT_x 148
-#define forceSymbols_x 149
-#define getCCallable_x 150
-#define getConnectionClassString_x 151
-#define getOpenModeString_x 152
-#define getSummaryDescription_x 153
-#define isSeekable_x 154
-#define registerCCallable_x 155
-#define registerRoutines_x 156
-#define setDotSymbolValues_x 157
-#define unif_rand_x 158
-#define useDynamicSymbols_x 159
+#define R_alloc_x 59
+#define R_compute_identical_x 60
+#define R_do_MAKE_CLASS_x 61
+#define R_do_new_object_x 62
+#define R_do_slot_x 63
+#define R_do_slot_assign_x 64
+#define R_getContextCall_x 65
+#define R_getContextEnv_x 66
+#define R_getContextFun_x 67
+#define R_getContextSrcRef_x 68
+#define R_getGlobalFunctionContext_x 69
+#define R_getParentFunctionContext_x 70
+#define R_insideBrowser_x 71
+#define R_isEqual_x 72
+#define R_isGlobal_x 73
+#define R_lsInternal3_x 74
+#define R_new_custom_connection_x 75
+#define R_tryEval_x 76
+#define Rf_GetOption1_x 77
+#define Rf_PairToVectorList_x 78
+#define Rf_ScalarDouble_x 79
+#define Rf_ScalarInteger_x 80
+#define Rf_ScalarLogical_x 81
+#define Rf_ScalarString_x 82
+#define Rf_VectorToPairList_x 83
+#define Rf_allocArray_x 84
+#define Rf_allocMatrix_x 85
+#define Rf_allocVector_x 86
+#define Rf_any_duplicated_x 87
+#define Rf_asChar_x 88
+#define Rf_asCharacterFactor_x 89
+#define Rf_asInteger_x 90
+#define Rf_asLogical_x 91
+#define Rf_asReal_x 92
+#define Rf_classgets_x 93
+#define Rf_coerceVector_x 94
+#define Rf_cons_x 95
+#define Rf_copyListMatrix_x 96
+#define Rf_copyMatrix_x 97
+#define Rf_copyMostAttrib_x 98
+#define Rf_defineVar_x 99
+#define Rf_dunif_x 100
+#define Rf_duplicate_x 101
+#define Rf_error_x 102
+#define Rf_errorcall_x 103
+#define Rf_eval_x 104
+#define Rf_findFun_x 105
+#define Rf_findVar_x 106
+#define Rf_findVarInFrame_x 107
+#define Rf_findVarInFrame3_x 108
+#define Rf_getAttrib_x 109
+#define Rf_gsetVar_x 110
+#define Rf_inherits_x 111
+#define Rf_install_x 112
+#define Rf_installChar_x 113
+#define Rf_isNull_x 114
+#define Rf_isString_x 115
+#define Rf_lengthgets_x 116
+#define Rf_mkCharLenCE_x 117
+#define Rf_namesgets_x 118
+#define Rf_ncols_x 119
+#define Rf_nrows_x 120
+#define Rf_protect_x 121
+#define Rf_punif_x 122
+#define Rf_qunif_x 123
+#define Rf_runif_x 124
+#define Rf_setAttrib_x 125
+#define Rf_str2type_x 126
+#define Rf_unprotect_x 127
+#define Rf_unprotect_ptr_x 128
+#define Rf_warning_x 129
+#define Rf_warningcall_x 130
+#define Rprintf_x 131
+#define SETCADR_x 132
+#define SETCAR_x 133
+#define SETCDR_x 134
+#define SET_NAMED_FASTR_x 135
+#define SET_RDEBUG_x 136
+#define SET_RSTEP_x 137
+#define SET_S4_OBJECT_x 138
+#define SET_STRING_ELT_x 139
+#define SET_SYMVALUE_x 140
+#define SET_TAG_x 141
+#define SET_TYPEOF_FASTR_x 142
+#define SET_VECTOR_ELT_x 143
+#define STRING_ELT_x 144
+#define SYMVALUE_x 145
+#define TAG_x 146
+#define TYPEOF_x 147
+#define UNSET_S4_OBJECT_x 148
+#define VECTOR_ELT_x 149
+#define forceSymbols_x 150
+#define getCCallable_x 151
+#define getConnectionClassString_x 152
+#define getOpenModeString_x 153
+#define getSummaryDescription_x 154
+#define isSeekable_x 155
+#define registerCCallable_x 156
+#define registerRoutines_x 157
+#define setDotSymbolValues_x 158
+#define unif_rand_x 159
+#define useDynamicSymbols_x 160
 
-#define UPCALLS_TABLE_SIZE 160
+#define UPCALLS_TABLE_SIZE 161
 
 #endif // RFFI_UPCALLSINDEX_H
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 396ece126b..77e736ddb0 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
@@ -218,7 +218,7 @@ void Rf_error(const char *format, ...) {
     va_end(ap);
     ((call_Rf_error) callbacks[Rf_error_x])(ensure_string(buf));
     // Should not reach here
-    UNIMPLEMENTED;
+    unimplemented("Unexpected return from Rf_error, should be no return function");
 }
 
 /*
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Memory.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Memory.c
index 5d123026a1..4f2042988b 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Memory.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Memory.c
@@ -9,103 +9,68 @@
  *
  * All rights reserved.
  */
-#include <rffiutils.h>
+#include "rffiutils.h"
 #include <stdlib.h>
 #include <string.h>
+#include <rffi_upcalls.h>
 
-#define T_MEM_TABLE_INITIAL_SIZE 0
-// The table of transient objects that have been allocated dur the current FFI call
-static void **tMemTable;
-// hwm of tMemTable
-static int tMemTableIndex;
-static int tMemTableLength;
-
-void init_memory() {
-    tMemTable = malloc(sizeof(void*) * T_MEM_TABLE_INITIAL_SIZE);
-    tMemTableLength = T_MEM_TABLE_INITIAL_SIZE;
-    tMemTableIndex = 0;
-}
-
-void *R_chk_calloc(size_t nelem, size_t elsize);
-
-// Memory that is auto-reclaimed across FFI calls
+// R_alloc should allocate memory that is auto-reclaimed across FFI calls.
+// In FastR this memory is managed by RContext to avoid race conditions.
+// FastR frees this memory in Java at the end of every FFI call (down-call).
 char *R_alloc(size_t n, int size) {
-    unimplemented("R_alloc should be implementd as UpCall functions to be thread safe");
-
-    void *p = R_chk_calloc(n, size);
-    if (tMemTableIndex >= tMemTableLength) {
-	int newLength = 2 * tMemTableLength;
-	void *newtMemTable = malloc(sizeof(void*) * newLength);
-	if (newtMemTable == NULL) {
-	    fatalError("malloc failure");
-	}
-	memcpy(newtMemTable, tMemTable, tMemTableLength * sizeof(void*));
-	free(tMemTable);
-	tMemTable = newtMemTable;
-	tMemTableLength = newLength;
-    }
-    tMemTable[tMemTableIndex] = p;
-    return (char*) p;
+    return (char *) ((call_R_alloc) callbacks[R_alloc_x])(n, size);
 }
 
-char* S_alloc(long n, int size) {
-	char *p = R_alloc(n, size);
-	memset(p, 0, n);
-	return p;
+// This is S compatible version of R_alloc
+char *S_alloc(long n, int size) {
+    char *p = R_alloc(n, size);
+    memset(p, 0, n);
+    return p;
 }
 
-char* S_realloc(char *p, long a, long b, int size) {
-	return unimplemented("S_realloc");
-}
-
-void allocExit() {
-    int i;
-    for (i = 0; i < tMemTableIndex; i++) {
-	free(tMemTable[i]);
-    }
+char *S_realloc(char *p, long a, long b, int size) {
+    return unimplemented("S_realloc");
 }
 
 void *R_chk_calloc(size_t nelem, size_t elsize) {
     void *p;
 #ifndef HAVE_WORKING_CALLOC
     if (nelem == 0)
-	return (NULL);
+        return (NULL);
 #endif
     p = calloc(nelem, elsize);
     if (!p) /* problem here is that we don't have a format for size_t. */
-	error("'Calloc' could not allocate memory (%.0f of %u bytes)",
-		(double) nelem, elsize);
+        error("'Calloc' could not allocate memory (%.0f of %u bytes)",
+              (double) nelem, elsize);
     return (p);
 }
 
 void *R_chk_realloc(void *ptr, size_t size) {
     void *p;
     /* Protect against broken realloc */
-    if(ptr) p = realloc(ptr, size); else p = malloc(size);
-    if(!p)
-	error("'Realloc' could not re-allocate memory (%.0f bytes)",
-	      (double) size);
-    return(p);
+    if (ptr) p = realloc(ptr, size); else p = malloc(size);
+    if (!p)
+        error("'Realloc' could not re-allocate memory (%.0f bytes)",
+              (double) size);
+    return (p);
 }
 
 void R_chk_free(void *ptr) {
-    if(ptr) {
-	    free(ptr);
+    if (ptr) {
+        free(ptr);
     }
 }
 
 int VMAX_MAGIC = 1234;
 
-void* vmaxget(void) {
-//    unimplemented("vmaxget");
+void *vmaxget(void) {
     // ignored
     return &VMAX_MAGIC;
 }
 
-void vmaxset(const void * x) {
-//    unimplemented("vmaxget");
+void vmaxset(const void *x) {
     if (x != &VMAX_MAGIC) {
-	unimplemented("vmaxset with different value");
+        unimplemented("vmaxset with different value");
     }
 }
 
@@ -119,7 +84,7 @@ int R_gc_running() {
 }
 
 SEXP Rf_allocS4Object() {
-	unimplemented("Rf_allocS4Object unimplemented");
-	return NULL;
+    unimplemented("Rf_allocS4Object unimplemented");
+    return NULL;
 }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
index 8c3fd5fd14..265f759518 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
@@ -42,7 +42,6 @@ import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.TimeZone;
@@ -94,11 +93,11 @@ import com.oracle.truffle.r.runtime.conn.ConnectionSupport;
 import com.oracle.truffle.r.runtime.conn.StdConnections;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RObject;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.RFFIContext;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.instrument.InstrumentationState;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
@@ -348,9 +347,9 @@ public final class RContext implements RTruffleObject {
     public final DLL.ContextStateImpl stateDLL;
     /**
      * RFFI implementation state. Cannot be final as choice of FFI implementation is not made at the
-     * time the constructor is called.
+     * time the constructor is called. TODO: any reason for it not being @CompilationFinal?
      */
-    private ContextState stateRFFI;
+    private RFFIContext stateRFFI;
 
     public final WeakHashMap<String, WeakReference<String>> stringMap = new WeakHashMap<>();
     public final WeakHashMap<Source, REnvironment> sourceRefEnvironments = new WeakHashMap<>();
@@ -358,45 +357,6 @@ public final class RContext implements RTruffleObject {
     public final List<String> libraryPaths = new ArrayList<>(1);
     public final Map<Integer, Thread> threads = new ConcurrentHashMap<>();
 
-    /**
-     * Stack used by RFFI to implement the PROTECT/UNPROTECT functions. Objects registered on this
-     * stack do necessarily not have to be {@linke #registerReferenceUsedInNative}, but once popped
-     * off, they must be put into that list.
-     */
-    public final ArrayList<RObject> protectStack = new ArrayList<>();
-
-    public final ArrayList<Object> protectedNativeReferences = new ArrayList<>();
-
-    /**
-     * @see #runNativeCollector()
-     */
-    public void registerReferenceUsedInNative(Object obj) {
-        protectedNativeReferences.add(obj);
-    }
-
-    /**
-     * The GC in GNUR is cooperative, which means that unless native code calls back to the R engine
-     * (GNUR/FastR) it may assume (and unfortunately people do that) that GC will not run and will
-     * not collect anything that may be not reachable anymore, including the result of the last
-     * up-call and including the objects popped off the PROTECT/UNPROTECT stack! Moreover, some
-     * R-API functions are known to be not calling GC, therefore people may (and do) count on them
-     * not removing unreachable references, this is specifically true for {@code UPROTECT} and its
-     * variants and for macros like {@code INTEGER}. This behaviour is required e.g. for
-     * {@code C_parseRd}. We keep a list of all the objects that may not be reachable anymore, but
-     * must not be collected, because no garbagge collecting R-API function has been called since
-     * they became unreachable. This method clears this list so that Java GC can collect the
-     * objects.
-     */
-    public void runNativeCollector() {
-        protectedNativeReferences.clear();
-    }
-
-    /**
-     * FastR equivalent of GNUR's special dedicated global list that is GC root and so any vectors
-     * added to it will be guaranteed to be preserved.
-     */
-    public final HashSet<RObject> preserveList = new HashSet<>();
-
     private final AllocationReporter allocationReporter;
 
     private ContextState[] contextStates() {
@@ -797,7 +757,7 @@ public final class RContext implements RTruffleObject {
         return language;
     }
 
-    public ContextState getStateRFFI() {
+    public RFFIContext getStateRFFI() {
         assert stateRFFI != null;
         return stateRFFI;
     }
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 e63c2245d0..3f96e6fb35 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
@@ -472,6 +472,7 @@ public interface CRFFI {
                 array[i] = getNativeArgument(i, args.getArgument(i));
             }
 
+            RContext.getInstance().getStateRFFI().beforeDowncall();
             execute(nativeCallInfo, array);
 
             // we have to assume that the native method updated everything
@@ -480,7 +481,7 @@ public interface CRFFI {
                 results[i] = ((TemporaryWrapper) array[i]).cleanup();
             }
 
-            RContext.getInstance().runNativeCollector();
+            RContext.getInstance().getStateRFFI().afterDowncall();
             return RDataFactory.createList(results, validateArgNames(array.length, args.getSignature()));
         }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
index f56278f27f..23a301b431 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
@@ -34,8 +34,9 @@ public interface CallRFFI {
     interface InvokeCallNode extends NodeInterface {
 
         default Object dispatch(NativeCallInfo nativeCallInfo, Object[] args) {
+            RContext.getInstance().getStateRFFI().beforeDowncall();
             Object result = execute(nativeCallInfo, args);
-            RContext.getInstance().runNativeCollector();
+            RContext.getInstance().getStateRFFI().afterDowncall();
             return result;
         }
 
@@ -49,8 +50,9 @@ public interface CallRFFI {
 
     interface InvokeVoidCallNode extends NodeInterface {
         default void dispatch(NativeCallInfo nativeCallInfo, Object[] args) {
+            RContext.getInstance().getStateRFFI().beforeDowncall();
             execute(nativeCallInfo, args);
-            RContext.getInstance().runNativeCollector();
+            RContext.getInstance().getStateRFFI().afterDowncall();
         }
 
         /**
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java
new file mode 100644
index 0000000000..188397b1f7
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java
@@ -0,0 +1,92 @@
+/*
+ * 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.runtime.ffi;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+import com.oracle.truffle.r.runtime.context.RContext.ContextState;
+import com.oracle.truffle.r.runtime.data.RObject;
+
+/**
+ * Holds per RContext specific state of the RFFI. RFFI implementation agnostic data and methods are
+ * implemented here, RFFI implementations may add their specifics.
+ */
+public abstract class RFFIContext implements ContextState {
+
+    /**
+     * @see #registerReferenceUsedInNative(Object)
+     */
+    private final ArrayList<Object> protectedNativeReferences = new ArrayList<>();
+
+    /**
+     * Stack used by RFFI to implement the PROTECT/UNPROTECT functions. Objects registered on this
+     * stack do necessarily not have to be {@linke #registerReferenceUsedInNative}, but once popped
+     * off, they must be put into that list.
+     */
+    public final ArrayList<RObject> protectStack = new ArrayList<>();
+
+    /**
+     * The GC in GNUR is cooperative, which means that unless native code calls back to the R engine
+     * (GNUR/FastR) it may assume (and unfortunately people do that) that GC will not run and will
+     * not collect anything that may be not reachable anymore, including the result of the last
+     * up-call and including the objects popped off the PROTECT/UNPROTECT stack! Moreover, some
+     * R-API functions are known to be not calling GC, therefore people may (and do) count on them
+     * not removing unreachable references, this is specifically true for {@code UPROTECT} and its
+     * variants and for macros like {@code INTEGER}. This behaviour is required e.g. for
+     * {@code C_parseRd}. We keep a list of all the objects that may not be reachable anymore, but
+     * must not be collected, because no garbagge collecting R-API function has been called since
+     * they became unreachable. This method clears this list so that Java GC can collect the
+     * objects.
+     */
+    public final void registerReferenceUsedInNative(Object obj) {
+        protectedNativeReferences.add(obj);
+    }
+
+    /**
+     * FastR equivalent of GNUR's special dedicated global list that is GC root and so any vectors
+     * added to it will be guaranteed to be preserved.
+     */
+    public final HashSet<RObject> preserveList = new HashSet<>();
+
+    public void beforeUpcall(boolean canRunGc) {
+    }
+
+    public void afterUpcall(boolean canRunGc) {
+        if (canRunGc) {
+            cooperativeGc();
+        }
+    }
+
+    public void beforeDowncall() {
+    }
+
+    public void afterDowncall() {
+        cooperativeGc();
+    }
+
+    // this emulates the GNUR's cooperative GC
+    private void cooperativeGc() {
+        protectedNativeReferences.clear();
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
index f0ae3fa3a1..ddd7a23208 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
@@ -170,5 +170,5 @@ public abstract class RFFIFactory {
      */
     protected abstract RFFI createRFFI();
 
-    public abstract ContextState newContextState();
+    public abstract RFFIContext newContextState();
 }
-- 
GitLab