From e1b4fd3da6f15328e037479a0fde1a986cb4e439 Mon Sep 17 00:00:00 2001
From: Florian Angerer <florian.angerer@oracle.com>
Date: Tue, 27 Jun 2017 18:01:11 +0200
Subject: [PATCH] Changed interop behavior of promises.

---
 .../truffle/r/engine/interop/RPromiseMR.java  | 103 ++++++++++++++++--
 .../truffle/r/runtime/data/RPromise.java      |  10 ++
 2 files changed, 104 insertions(+), 9 deletions(-)

diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java
index 269143e33d..589fd7f8c7 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java
@@ -22,40 +22,125 @@
  */
 package com.oracle.truffle.r.engine.interop;
 
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.MessageResolution;
 import com.oracle.truffle.api.interop.Resolve;
 import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnknownIdentifierException;
+import com.oracle.truffle.api.interop.UnsupportedTypeException;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.engine.TruffleRLanguageImpl;
+import com.oracle.truffle.r.ffi.impl.interop.NativePointer;
+import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.context.RContext.RCloseable;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPromise;
 
 @MessageResolution(receiverType = RPromise.class)
 public class RPromiseMR {
+
+    private static final String PROP_VALUE = "value";
+    private static final String PROP_IS_EVALUATED = "isEvaluated";
+    private static final String PROP_IS_EAGER = "isEager";
+
     @Resolve(message = "IS_BOXED")
     public abstract static class RPromiseIsBoxedNode extends Node {
         protected Object access(@SuppressWarnings("unused") RPromise receiver) {
-            return true;
+            return false;
         }
     }
 
-    @Resolve(message = "HAS_SIZE")
-    public abstract static class RPromiseHasSizeNode extends Node {
+    @Resolve(message = "IS_NULL")
+    public abstract static class RPromiseIsNullNode extends Node {
         protected Object access(@SuppressWarnings("unused") RPromise receiver) {
             return false;
         }
     }
 
-    @Resolve(message = "IS_NULL")
-    public abstract static class RPromiseIsNullNode extends Node {
+    @Resolve(message = "READ")
+    public abstract static class RPromiseReadNode extends Node {
+
+        protected Object access(@SuppressWarnings("unused") VirtualFrame frame, RPromise receiver, String field) {
+            if (PROP_IS_EAGER.equals(field)) {
+                return RRuntime.asLogical(RPromise.PromiseState.isEager(receiver.getState()));
+            }
+            if (PROP_IS_EVALUATED.equals(field)) {
+                return RRuntime.asLogical(receiver.isEvaluated());
+            }
+            if (PROP_VALUE.equals(field)) {
+                // only read value if evaluated
+                if (receiver.isEvaluated()) {
+                    return receiver.getValue();
+                }
+                return RNull.instance;
+            }
+            throw UnknownIdentifierException.raise(field);
+        }
+    }
+
+    @Resolve(message = "WRITE")
+    public abstract static class RPromiseWriteNode extends Node {
+
+        @SuppressWarnings("try")
+        protected Object access(@SuppressWarnings("unused") VirtualFrame frame, RPromise receiver, String field, Object valueObj) {
+            if (PROP_IS_EVALUATED.equals(field)) {
+                if (!(valueObj instanceof Boolean)) {
+                    throw UnsupportedTypeException.raise(new Object[]{valueObj});
+                }
+
+                boolean newVal = (boolean) valueObj;
+
+                if (!receiver.isEvaluated() && newVal) {
+                    try (RCloseable c = RContext.withinContext(TruffleRLanguageImpl.getCurrentContext())) {
+                        PromiseHelperNode.evaluateSlowPath(receiver);
+                    }
+                } else if (receiver.isEvaluated() && !newVal) {
+                    try (RCloseable c = RContext.withinContext(TruffleRLanguageImpl.getCurrentContext())) {
+                        receiver.resetValue();
+                    }
+
+                }
+                return RRuntime.asLogical(receiver.isEvaluated());
+            }
+            throw UnknownIdentifierException.raise(field);
+        }
+    }
+
+    @Resolve(message = "KEYS")
+    public abstract static class RPromiseKeysNode extends Node {
+
         protected Object access(@SuppressWarnings("unused") RPromise receiver) {
-            return false;
+            return RDataFactory.createStringVector(new String[]{PROP_VALUE, PROP_IS_EVALUATED, PROP_IS_EAGER}, true);
+        }
+    }
+
+    @Resolve(message = "KEY_INFO")
+    public abstract static class RPromiseKeyInfoNode extends Node {
+
+        private static final int READABLE = 1 << 1;
+        private static final int WRITABLE = 1 << 2;
+
+        @SuppressWarnings("try")
+        protected Object access(@SuppressWarnings("unused") VirtualFrame frame, @SuppressWarnings("unused") RPromise receiver, String identifier) {
+            if (PROP_IS_EAGER.equals(identifier) || PROP_VALUE.equals(identifier)) {
+                return READABLE;
+            }
+
+            if (PROP_IS_EVALUATED.equals(identifier)) {
+                return READABLE + WRITABLE;
+            }
+            return 0;
         }
     }
 
-    @Resolve(message = "UNBOX")
-    public abstract static class RPromiseUnboxNode extends Node {
+    @Resolve(message = "TO_NATIVE")
+    public abstract static class RPromiseToNativeNode extends Node {
         protected Object access(RPromise receiver) {
-            return receiver.getValue();
+            return new NativePointer(receiver);
         }
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
index cdb65dbbb9..2f7d1004bd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
@@ -203,6 +203,16 @@ public class RPromise implements RTypedValue {
         return value;
     }
 
+    /**
+     * Discards any previously evaluated value if this is not an eager promise.
+     */
+    public final void resetValue() {
+        // Only non-eager promises can be reset.
+        if (!PromiseState.isEager(state)) {
+            value = null;
+        }
+    }
+
     /**
      * Used in case the {@link RPromise} is evaluated outside.
      *
-- 
GitLab