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 8ab81d07892bad11c616121f38c557f08bda981c..f8776dbb218a5030515d5565857f811ebbcaa00a 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
@@ -48,7 +48,6 @@ import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
-import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RCleanUp;
@@ -70,7 +69,6 @@ import com.oracle.truffle.r.runtime.context.Engine.IncompleteSourceException;
 import com.oracle.truffle.r.runtime.context.Engine.ParseException;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.CharSXPWrapper;
-import com.oracle.truffle.r.runtime.data.Closure;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -791,55 +789,9 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         return result;
     }
 
-    private static final Object processResult(Object value) {
-        if (value instanceof Integer) {
-            int v = (int) value;
-            return RDataFactory.createIntVector(new int[]{v}, RRuntime.isNA(v));
-        } else if (value instanceof Double) {
-            double v = (double) value;
-            return RDataFactory.createDoubleVector(new double[]{v}, RRuntime.isNA(v));
-        } else if (value instanceof Byte) {
-            byte v = (byte) value;
-            return RDataFactory.createLogicalVector(new byte[]{v}, RRuntime.isNA(v));
-        } else if (value instanceof String) {
-            String v = (String) value;
-            return RDataFactory.createStringVector(new String[]{v}, RRuntime.isNA(v));
-        } else {
-            return value;
-        }
-    }
-
     @Override
-    @TruffleBoundary
     public Object Rf_eval(Object expr, Object env) {
-        guaranteeInstanceOf(env, REnvironment.class);
-        Object result;
-        if (expr instanceof RPromise) {
-            result = RContext.getRRuntimeASTAccess().forcePromise(null, expr);
-        } else if (expr instanceof RExpression) {
-            result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, RCaller.topLevel);
-        } else if (expr instanceof RLanguage) {
-            result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, RCaller.topLevel);
-        } else if (expr instanceof RPairList) {
-            RPairList l = (RPairList) expr;
-            RFunction f = (RFunction) l.car();
-            Object args = l.cdr();
-            if (args == RNull.instance) {
-                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, true, null, new Object[0]);
-            } else {
-                RList argsList = ((RPairList) args).toRList();
-                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, true,
-                                ArgumentsSignature.fromNamesAttribute(argsList.getNames()),
-                                argsList.getDataTemp());
-            }
-        } else if (expr instanceof RSymbol) {
-            RSyntaxNode lookup = RContext.getASTBuilder().lookup(RSyntaxNode.LAZY_DEPARSE, ((RSymbol) expr).getName(), false);
-            result = RContext.getEngine().eval(RDataFactory.createLanguage(Closure.createLanguageClosure(lookup.asRNode())), (REnvironment) env, RCaller.topLevel);
-        } else {
-            // just return value
-            result = expr;
-        }
-        return processResult(result);
+        throw implementedAsNode();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ed5333a7a15aa662b393b56384c94a3cd66d16b
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.nodes;
+
+import static com.oracle.truffle.r.runtime.RError.Message.ARGUMENT_NOT_ENVIRONMENT;
+import static com.oracle.truffle.r.runtime.RError.Message.ARGUMENT_NOT_FUNCTION;
+import static com.oracle.truffle.r.runtime.RError.Message.UNKNOWN_OBJECT;
+
+import com.oracle.truffle.api.CompilerDirectives;
+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.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
+import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.runtime.RCaller;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RExpression;
+import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.data.RLanguage;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.RPromise;
+import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.env.REnvironment;
+
+public abstract class RfEvalNode extends FFIUpCallNode.Arg2 {
+
+    @Child private PromiseHelperNode promiseHelper;
+
+    public static RfEvalNode create() {
+        return RfEvalNodeGen.create();
+    }
+
+    @Specialization
+    @TruffleBoundary
+    Object handlePromise(RPromise expr, @SuppressWarnings("unused") REnvironment env) {
+        return getPromiseHelper().evaluate(null, expr);
+    }
+
+    @Specialization
+    @TruffleBoundary
+    Object handleExpression(RExpression expr, REnvironment env) {
+        return RContext.getEngine().eval(expr, env, RCaller.topLevel);
+    }
+
+    @Specialization
+    @TruffleBoundary
+    Object handleLanguage(RLanguage expr, REnvironment env) {
+        return RContext.getEngine().eval(expr, env, RCaller.topLevel);
+    }
+
+    @Specialization
+    @TruffleBoundary
+    Object handleSymbol(RSymbol expr, REnvironment env) {
+        Object result = ReadVariableNode.lookupAny(expr.getName(), env.getFrame(), false);
+        if (result == null) {
+            throw RError.error(RError.NO_CALLER, UNKNOWN_OBJECT, expr.getName());
+        }
+        return result;
+    }
+
+    @Specialization
+    Object handlePairList(RPairList l, REnvironment env,
+                    @Cached("createBinaryProfile()") ConditionProfile isPromiseProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile noArgsProfile) {
+        Object car = l.car();
+        RFunction f;
+        if (isPromiseProfile.profile(car instanceof RPromise)) {
+            car = getPromiseHelper().evaluate(null, (RPromise) car);
+        }
+
+        if (car instanceof RFunction) {
+            f = (RFunction) car;
+        } else {
+            throw RError.error(RError.NO_CALLER, ARGUMENT_NOT_FUNCTION);
+        }
+
+        Object args = l.cdr();
+        if (noArgsProfile.profile(args == RNull.instance)) {
+            return evalFunction(f, env, null);
+        } else {
+            RList argsList = ((RPairList) args).toRList();
+            return evalFunction(f, env, ArgumentsSignature.fromNamesAttribute(argsList.getNames()), argsList.getDataTemp());
+        }
+    }
+
+    @TruffleBoundary
+    private Object evalFunction(RFunction f, REnvironment env, ArgumentsSignature argsNames, Object... args) {
+        return RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : env.getFrame(), RCaller.topLevel, true, argsNames, args);
+    }
+
+    @Fallback
+    Object handleOthers(Object expr, Object env) {
+        if (env instanceof REnvironment) {
+            return expr;
+        } else {
+            throw RError.error(RError.NO_CALLER, ARGUMENT_NOT_ENVIRONMENT);
+        }
+    }
+
+    private PromiseHelperNode getPromiseHelper() {
+        if (promiseHelper == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            promiseHelper = insert(new PromiseHelperNode());
+        }
+        return promiseHelper;
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
index a26fa2347b0f22e96558002764ce2c776b4ce37d..70dbd8d13a804fb8b7b1a3a095a449573f3aa841 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
@@ -50,6 +50,7 @@ import com.oracle.truffle.r.ffi.impl.nodes.MatchNodes;
 import com.oracle.truffle.r.ffi.impl.nodes.MiscNodes;
 import com.oracle.truffle.r.ffi.impl.nodes.MiscNodes.LENGTHNode;
 import com.oracle.truffle.r.ffi.impl.nodes.RandFunctionsNodes;
+import com.oracle.truffle.r.ffi.impl.nodes.RfEvalNode;
 import com.oracle.truffle.r.ffi.processor.RFFICstring;
 import com.oracle.truffle.r.ffi.processor.RFFIRunGC;
 import com.oracle.truffle.r.ffi.processor.RFFIUpCallNode;
@@ -253,6 +254,7 @@ public interface StdUpCallsRFFI {
     Object R_FindNamespace(Object name);
 
     @RFFIRunGC
+    @RFFIUpCallNode(RfEvalNode.class)
     Object Rf_eval(Object expr, Object env);
 
     Object Rf_findFun(Object symbolObj, Object envObj);
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 19e6f1d16a4c89b89f4fd647d639159d309f5a7d..ef15cc0dbd5cacdf878afcbe124123320488decb 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
@@ -304,7 +304,7 @@ public final class FFIProcessor extends AbstractProcessor {
         w.append("                    }\n");
         w.append("                    RFFIContext ctx = RContext.getInstance().getStateRFFI();\n");
         if (returnKind != TypeKind.VOID) {
-            w.append("                Object resultRObj;");
+            w.append("                    Object resultRObj;\n");
         }
         w.append("                    ctx.beforeUpcall(" + canRunGc + ");\n");
         w.append("                    try {\n");
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/TruffleRLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/TruffleRLanguage.java
index b7f120bf34bf4374b9209411baafbf05f697e303..93004fa0a9c32454acced25fe8579994214a9ca4 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/TruffleRLanguage.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/TruffleRLanguage.java
@@ -31,4 +31,10 @@ public abstract class TruffleRLanguage extends TruffleLanguage<RContext> {
 
     public abstract HashMap<String, RFunction> getBuiltinFunctionCache();
 
+    @Override
+    protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) {
+        // FastR does not support access to a single context from multiple threads, mainly because
+        // it has to maintain thread local variables on the native side.
+        return Thread.currentThread() == thread;
+    }
 }
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
index b4e7c16b80117cd3d128c809319d4f0170b720cf..214488fecfa13c364a9eddaf364dc30970e62758 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
@@ -192,3 +192,7 @@ rffi.createNativeConnection <- function() {
 rffi.parseVector <- function(x) {
     .Call('test_ParseVector', x);
 }
+
+rffi.RfEvalWithPromiseInPairList <- function() {
+    .Call('test_RfEvalWithPromiseInPairList')
+}
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
index 51107ad6a2b6e86f848f60a4238b2378d0235bb5..8e711c3bbd1b3bc16fe9264e0bf64c1de5528238 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
@@ -81,6 +81,7 @@ static const R_CallMethodDef CallEntries[] = {
         CALLDEF(test_readConnection, 1),
         CALLDEF(test_createNativeConnection, 0),
         CALLDEF(test_ParseVector, 1),
+        CALLDEF(test_RfEvalWithPromiseInPairList, 0),
         {NULL, NULL, 0}
 };
 
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
index 3a2abf0fd5eea5e7051f7b1027c1f0d59467e8c5..3e6edb7ee6e8f2879ee3a141e89a384faa3fab82 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
@@ -540,3 +540,17 @@ SEXP test_ParseVector(SEXP src) {
     UNPROTECT(2);
     return result;
 }
+
+SEXP test_RfEvalWithPromiseInPairList() {
+    SEXP fun = Rf_findVarInFrame(R_FindNamespace(ScalarString(mkChar("stats"))), Rf_install("runif"));
+    if (TYPEOF(fun) != PROMSXP) {
+        printf("ERROR: Rf_findVarInFrame evaluated the promise!");
+    }
+    SEXP e, ptr;
+    PROTECT(e = Rf_allocVector(LANGSXP, 2));
+    SETCAR(e, fun); ptr = CDR(e);
+    SETCAR(ptr, ScalarInteger(5));
+    SEXP result = Rf_eval(e, R_GlobalEnv);
+    UNPROTECT(1);
+    return result;
+}
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
index 48b2e53621cdbebfa0803079dd2930272781068d..2fbab660b916bb16973f4340025af10b5b585646 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
@@ -105,3 +105,5 @@ extern SEXP test_readConnection(SEXP conn);
 extern SEXP test_createNativeConnection(void);
 
 extern SEXP test_ParseVector(SEXP src);
+
+extern SEXP test_RfEvalWithPromiseInPairList(void);
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R
index c01e673ea3dfe0f557fa4ebf5e9e4cbf28b08bd1..e1fea9c3ccf24afc755177189c3ff422497f0e28 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R
@@ -92,3 +92,8 @@ for(i in seq(5000)) {
     obj <- preserved_objects[[i]]
     rffi.release_object(obj)
 }
+
+# Note: runif must not be used before this test so that it is still a promise!!!
+# Following code calls Rf_eval with a language object that contains a promise instead of the expected function
+set.seed(42)
+rffi.RfEvalWithPromiseInPairList()