From 2e6f11206b097549928af4050d150f43d8991c0f Mon Sep 17 00:00:00 2001
From: Florian Angerer <florian.angerer@oracle.com>
Date: Wed, 15 Nov 2017 15:58:44 +0100
Subject: [PATCH] Refactored slot node to detect if its LHS of a call.

---
 .../truffle/r/nodes/builtin/base/Slot.java    | 37 +++++++++++++------
 .../r/nodes/access/AccessSlotNode.java        |  8 ++++
 .../truffle/r/nodes/builtin/RBuiltinNode.java |  4 --
 .../truffle/r/nodes/function/RCallNode.java   |  3 --
 4 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java
index 2ef8f6aa55..e58454418a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java
@@ -17,16 +17,19 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.foreign;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.RCallNode;
+import com.oracle.truffle.r.nodes.function.RCallNode.BuiltinCallNode;
 import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -34,11 +37,13 @@ import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.Closure;
 import com.oracle.truffle.r.runtime.data.RPromise;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 @RBuiltin(name = "@", kind = PRIMITIVE, parameterNames = {"", ""}, nonEvalArgs = 1, behavior = COMPLEX)
 public abstract class Slot extends RBuiltinNode.Arg2 {
 
-    @CompilationFinal private boolean isLhsOfCall;
     @Child private UpdateShareableChildValueNode sharedAttrUpdate = UpdateShareableChildValueNode.create();
     @Child private AccessSlotNode accessSlotNode = AccessSlotNodeGen.create(true);
 
@@ -61,14 +66,29 @@ public abstract class Slot extends RBuiltinNode.Arg2 {
         throw error(RError.Message.GENERIC, "invalid type or length for slot name");
     }
 
-    protected boolean isLhsOfForeignCall(Object o) {
-        return isLhsOfCall && RRuntime.isForeignObject(o);
+    private static boolean isLhsOfSyntaxCall(RSyntaxNode n) {
+        Node unwrapParent = RASTUtils.unwrapParent(n.asNode());
+        return unwrapParent instanceof RSyntaxCall && ((RSyntaxCall) unwrapParent).getSyntaxLHS() == n;
     }
 
-    @Specialization(guards = {"isLhsOfForeignCall(object)"})
+    protected boolean isForeignObject(Object obj) {
+        return RRuntime.isForeignObject(obj);
+    }
+
+    protected boolean isLhsOfCall() {
+        CompilerAsserts.neverPartOfCompilation();
+        Node unwrapParent = RASTUtils.unwrapParent(this);
+        assert ((BuiltinCallNode) unwrapParent).getBuiltin() == this;
+        return unwrapParent instanceof BuiltinCallNode && isLhsOfSyntaxCall(((RBaseNode) unwrapParent).asRSyntaxNode());
+    }
+
+    @Specialization(guards = {"isForeignObject(object)", "lhsOfCall"})
     protected Object getSlot(TruffleObject object, Object nameObj,
+                    @Cached("isLhsOfCall()") boolean lhsOfCall,
                     @Cached("createClassProfile()") ValueProfile nameObjProfile) {
 
+        assert lhsOfCall;
+
         String name = getName(nameObjProfile.profile(nameObj));
         assert Utils.isInterned(name);
 
@@ -76,7 +96,7 @@ public abstract class Slot extends RBuiltinNode.Arg2 {
         return RCallNode.createDeferredMemberAccess(object, name);
     }
 
-    @Specialization(guards = "!isLhsOfForeignCall(object)")
+    @Specialization
     protected Object getSlot(Object object, Object nameObj,
                     @Cached("createClassProfile()") ValueProfile nameObjProfile) {
         String name = getName(nameObjProfile.profile(nameObj));
@@ -88,9 +108,4 @@ public abstract class Slot extends RBuiltinNode.Arg2 {
         return result;
     }
 
-    @Override
-    public void setLhsOfCall(boolean value) {
-        CompilerDirectives.transferToInterpreterAndInvalidate();
-        this.isLhsOfCall = value;
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
index 182e05aa0f..c8d8a6c3f1 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
@@ -13,6 +13,7 @@
 package com.oracle.truffle.r.nodes.access;
 
 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.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.attributes.GetAttributeNode;
@@ -21,6 +22,7 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClass
 import com.oracle.truffle.r.nodes.function.ImplicitClassHierarchyNode;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributable;
@@ -80,4 +82,10 @@ public abstract class AccessSlotNode extends BaseAccessSlotNode {
             throw error(RError.Message.SLOT_NON_S4, name, classAttr.getDataAt(0));
         }
     }
+
+    @Fallback
+    protected Object getSlot(Object object, String name) {
+        throw error(RError.Message.SLOT_CANNOT_GET, name, RRuntime.getRTypeName(object));
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java
index 26cb852738..11315ae997 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java
@@ -148,10 +148,6 @@ public abstract class RBuiltinNode extends RBuiltinBaseNode implements NodeWithA
         }
     }
 
-    public void setLhsOfCall(@SuppressWarnings("unused") boolean value) {
-        // default: do nothing
-    }
-
     public abstract static class Arg0 extends RBuiltinNode {
 
         public abstract Object execute(VirtualFrame frame);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
index d8746d02f3..c4fe686b5f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
@@ -886,9 +886,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             varArgSeen = new boolean[formals.getLength()];
             nonWrapSeen = new boolean[formals.getLength()];
             wrapSeen = new boolean[formals.getLength()];
-
-            // Tell this builtin that it is LHS of a call which might imply different behavior.
-            builtin.setLhsOfCall(true);
         }
 
         @Override
-- 
GitLab