From 87917c5e77bad3e0560297e9b211b6930341e46a Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Fri, 23 Feb 2018 12:13:36 +0100
Subject: [PATCH] RfEvalNode: environment may be (R_)NULL, use global in such
 case

---
 .../truffle/r/ffi/impl/nodes/RfEvalNode.java  | 37 +++++++++++++++----
 .../r/ffi/impl/upcalls/FFIUnwrapNode.java     |  6 +++
 .../truffle/r/runtime/env/REnvironment.java   |  9 ++++-
 3 files changed, 44 insertions(+), 8 deletions(-)

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
index 8a12776808..c94ad969ea 100644
--- 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
@@ -26,12 +26,15 @@ import static com.oracle.truffle.r.runtime.RError.Message.ARGUMENT_NOT_ENVIRONME
 import static com.oracle.truffle.r.runtime.RError.Message.ARGUMENT_NOT_FUNCTION;
 import static com.oracle.truffle.r.runtime.RError.Message.UNKNOWN_OBJECT;
 
+import org.graalvm.polyglot.Value;
+
 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.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
@@ -51,11 +54,18 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 public abstract class RfEvalNode extends FFIUpCallNode.Arg2 {
 
     @Child private PromiseHelperNode promiseHelper;
+    private final ConditionProfile envIsNullProfile = ConditionProfile.createBinaryProfile();
 
     public static RfEvalNode create() {
         return RfEvalNodeGen.create();
     }
 
+    @Specialization
+    @TruffleBoundary
+    Object handlePromise(RPromise expr, @SuppressWarnings("unused") RNull nulLEnv) {
+        return getPromiseHelper().evaluate(null, expr);
+    }
+
     @Specialization
     @TruffleBoundary
     Object handlePromise(RPromise expr, @SuppressWarnings("unused") REnvironment env) {
@@ -64,20 +74,21 @@ public abstract class RfEvalNode extends FFIUpCallNode.Arg2 {
 
     @Specialization
     @TruffleBoundary
-    Object handleExpression(RExpression expr, REnvironment env) {
-        return RContext.getEngine().eval(expr, env, null);
+    Object handleExpression(RExpression expr, Object envArg) {
+        return RContext.getEngine().eval(expr, getEnv(envArg), null);
     }
 
     @Specialization
     @TruffleBoundary
-    Object handleLanguage(RLanguage expr, REnvironment env) {
-        return RContext.getEngine().eval(expr, env, null);
+    Object handleLanguage(RLanguage expr, Object envArg) {
+        return RContext.getEngine().eval(expr, getEnv(envArg), null);
     }
 
     @Specialization
     @TruffleBoundary
-    Object handleSymbol(RSymbol expr, REnvironment env) {
-        Object result = ReadVariableNode.lookupAny(expr.getName(), env.getFrame(), false);
+    Object handleSymbol(RSymbol expr, Object envArg,
+                    @Cached("createClassProfile()") ValueProfile accessProfile) {
+        Object result = ReadVariableNode.lookupAny(expr.getName(), getEnv(envArg).getFrame(accessProfile), false);
         if (result == null) {
             throw RError.error(RError.NO_CALLER, UNKNOWN_OBJECT, expr.getName());
         }
@@ -85,7 +96,7 @@ public abstract class RfEvalNode extends FFIUpCallNode.Arg2 {
     }
 
     @Specialization
-    Object handlePairList(RPairList l, REnvironment env,
+    Object handlePairList(RPairList l, Object envArg,
                     @Cached("createBinaryProfile()") ConditionProfile isPromiseProfile,
                     @Cached("createBinaryProfile()") ConditionProfile noArgsProfile) {
         Object car = l.car();
@@ -101,6 +112,7 @@ public abstract class RfEvalNode extends FFIUpCallNode.Arg2 {
         }
 
         Object args = l.cdr();
+        REnvironment env = getEnv(envArg);
         if (noArgsProfile.profile(args == RNull.instance)) {
             return evalFunction(f, env, null);
         } else {
@@ -119,10 +131,21 @@ public abstract class RfEvalNode extends FFIUpCallNode.Arg2 {
         if (env instanceof REnvironment) {
             return expr;
         } else {
+            CompilerDirectives.transferToInterpreter();
             throw RError.error(RError.NO_CALLER, ARGUMENT_NOT_ENVIRONMENT);
         }
     }
 
+    private REnvironment getEnv(Object envArg) {
+        if (envIsNullProfile.profile(envArg == RNull.instance)) {
+            return REnvironment.globalEnv(RContext.getInstance());
+        } else if (envArg instanceof REnvironment) {
+            return (REnvironment) envArg;
+        }
+        CompilerDirectives.transferToInterpreter();
+        throw RError.error(RError.NO_CALLER, ARGUMENT_NOT_ENVIRONMENT);
+    }
+
     private PromiseHelperNode getPromiseHelper() {
         if (promiseHelper == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java
index 4d5aafa461..40a3f13e3f 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java
@@ -32,6 +32,7 @@ import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.NativeDataAccess;
+import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 
 /**
@@ -64,6 +65,11 @@ public final class FFIUnwrapNode extends Node {
                 }
                 try {
                     long address = ForeignAccess.sendAsPointer(asPointer, xTo);
+                    if (address == 0) {
+                        // Users are expected to use R_NULL, but at least when embedding, GNU R
+                        // seems to be tolerant to NULLs.
+                        return RNull.instance;
+                    }
                     return NativeDataAccess.lookup(address);
                 } catch (UnsupportedMessageException e) {
                     if (isPointerNode == null) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
index 6f6fc75678..1253a0a809 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
@@ -267,7 +267,14 @@ public abstract class REnvironment extends RAttributeStorage {
      * Value returned by {@code globalenv()}.
      */
     public static REnvironment globalEnv() {
-        return RContext.getInstance().stateREnvironment.getGlobalEnv();
+        return globalEnv(RContext.getInstance());
+    }
+
+    /**
+     * Value returned by {@code globalenv()}.
+     */
+    public static REnvironment globalEnv(RContext ctx) {
+        return ctx.stateREnvironment.getGlobalEnv();
     }
 
     /**
-- 
GitLab