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 cd6d41817b4d91f61a22c6ba51876a49930b52da..3def348e2a7995a765fc1cd53c40eac769360d26 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
@@ -31,13 +31,16 @@ 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.frame.Frame;
 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;
+import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -57,28 +60,36 @@ public abstract class RfEvalNode extends FFIUpCallNode.Arg2 {
         return RfEvalNodeGen.create();
     }
 
+    private static RCaller createCall(REnvironment env) {
+        Frame frame = Utils.getActualCurrentFrame();
+        RCaller originalCaller = RArguments.getCall(env.getFrame());
+        return RCaller.createForPromise(originalCaller, frame);
+    }
+
     @Specialization
     @TruffleBoundary
     Object handlePromise(RPromise expr, @SuppressWarnings("unused") RNull nulLEnv) {
-        return getPromiseHelper().evaluate(null, expr);
+        return getPromiseHelper().evaluate(Utils.getActualCurrentFrame().materialize(), expr);
     }
 
     @Specialization
     @TruffleBoundary
-    Object handlePromise(RPromise expr, @SuppressWarnings("unused") REnvironment env) {
-        return getPromiseHelper().evaluate(null, expr);
+    Object handlePromise(RPromise expr, REnvironment env) {
+        return getPromiseHelper().evaluate(env.getFrame(), expr);
     }
 
     @Specialization
     @TruffleBoundary
     Object handleExpression(RExpression expr, Object envArg) {
-        return RContext.getEngine().eval(expr, getEnv(envArg), null);
+        REnvironment env = getEnv(envArg);
+        return RContext.getEngine().eval(expr, env, createCall(env));
     }
 
     @Specialization(guards = "expr.isLanguage()")
     @TruffleBoundary
     Object handleLanguage(RPairList expr, Object envArg) {
-        return RContext.getEngine().eval(expr, getEnv(envArg), null);
+        REnvironment env = getEnv(envArg);
+        return RContext.getEngine().eval(expr, env, createCall(env));
     }
 
     @Specialization
@@ -124,7 +135,7 @@ public abstract class RfEvalNode extends FFIUpCallNode.Arg2 {
 
     @TruffleBoundary
     private static 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);
+        return RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : env.getFrame(), createCall(env), true, argsNames, args);
     }
 
     @Fallback
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java
index 63e827950501127a3a6c4a981b22a6bc8d71f19c..962eb99b04fcd2c1b15def407e8c91e728e2d0f3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java
@@ -149,6 +149,7 @@ public abstract class Assign extends RBuiltinNode.Arg4 {
         }
 
         protected final ValueProfile frameAccessProfile = ValueProfile.createClassProfile();
+        protected final ValueProfile frameProfile = ValueProfile.createClassProfile();
 
         public abstract void execute(VirtualFrame frame, REnvironment env, String name, Object value);
 
@@ -156,11 +157,15 @@ public abstract class Assign extends RBuiltinNode.Arg4 {
             return ResolvedWriteSuperFrameVariableNodeGen.create(name, Mode.REGULAR, null, null, FrameSlotNode.create(findOrAddFrameSlot(envDesc, name, FrameSlotKind.Illegal)));
         }
 
-        @Specialization(guards = {"env.getFrame(frameAccessProfile).getFrameDescriptor() == envDesc", "write.getName().equals(name)"})
+        protected FrameDescriptor getFrameDescriptor(REnvironment env) {
+            return frameProfile.profile(env.getFrame(frameAccessProfile)).getFrameDescriptor();
+        }
+
+        @Specialization(guards = {"getFrameDescriptor(env) == envDesc", "write.getName().equals(name)"})
         protected void assignCached(VirtualFrame frame, REnvironment env, @SuppressWarnings("unused") String name, Object value,
                         @Cached("env.getFrame().getFrameDescriptor()") @SuppressWarnings("unused") FrameDescriptor envDesc,
                         @Cached("createWrite(name, envDesc)") ResolvedWriteSuperFrameVariableNode write) {
-            write.execute(frame, value, env.getFrame(frameAccessProfile));
+            write.execute(frame, value, frameProfile.profile(env.getFrame(frameAccessProfile)));
         }
 
         @Specialization(replaces = "assignCached")
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
index c89561bf38828d6f30571f0cd98efd44e3cbef83..406d3eb5d20d3ec54199db9517ef1478bc52cf6d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
@@ -134,6 +134,8 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRStackTrace;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRStackTraceNodeGen;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRSyntaxTree;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRSyntaxTreeNodeGen;
+import com.oracle.truffle.r.nodes.builtin.fastr.FastRTestsTry;
+import com.oracle.truffle.r.nodes.builtin.fastr.FastRTestsTryNodeGen;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRThrowIt;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRThrowItNodeGen;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRTrace;
@@ -142,8 +144,6 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRTree;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRTreeNodeGen;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRTreeStats;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRTreeStatsNodeGen;
-import com.oracle.truffle.r.nodes.builtin.fastr.FastRTestsTry;
-import com.oracle.truffle.r.nodes.builtin.fastr.FastRTestsTryNodeGen;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrls;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrlsNodeGen;
 import com.oracle.truffle.r.nodes.builtin.fastr.memprof.FastRprofmem;
@@ -638,7 +638,6 @@ public class BasePackage extends RBuiltinPackage {
         add(MatMult.class, MatMult::create);
         add(Match.class, MatchNodeGen::create);
         add(MatchFun.class, MatchFunNodeGen::create);
-        add(MatchArg.class, MatchArgNodeGen::create);
         add(Matrix.class, MatrixNodeGen::create);
         add(Max.class, MaxNodeGen::create);
         add(Mean.class, MeanNodeGen::create);
@@ -876,6 +875,7 @@ public class BasePackage extends RBuiltinPackage {
         addFastPath(baseFrame, "rbind", FastPathFactory.FORCED_EAGER_ARGS);
         addFastPath(baseFrame, "seq.default", SeqFunctionsFactory.SeqDefaultFastPathNodeGen::create, RVisibility.ON);
         addFastPath(baseFrame, "seq", SeqFunctionsFactory.SeqFastPathNodeGen::create, RVisibility.ON);
+        addFastPath(baseFrame, "match.arg", MatchArgFastPathNodeGen::create, MatchArgFastPath.class);
 
         setContainsDispatch(baseFrame, "eval", "[.data.frame", "[[.data.frame", "[<-.data.frame", "[[<-.data.frame");
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
index 5d56afcee2c928d467ea8394658de6d6351dd47c..49d139a0ebf9c5d9f25306b6e77863190784dff9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
@@ -127,6 +127,7 @@ public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSynta
         @Child private GetNamesAttributeNode getNamesNode;
         @Child private SetVisibilityNode setVisibilityNode;
         private final ValueProfile frameAccessProfile = ValueProfile.createClassProfile();
+        private final ValueProfile frameProfile = ValueProfile.createClassProfile();
         private final RNodeClosureCache languagesClosureCache = new RNodeClosureCache();
         private final SymbolClosureCache symbolsClosureCache = new SymbolClosureCache();
 
@@ -137,7 +138,7 @@ public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSynta
         public abstract Object execute(VirtualFrame virtualFrame, String funcName, RFunction func, RList argsAsList, boolean quote, REnvironment env);
 
         protected FrameDescriptor getFrameDescriptor(REnvironment env) {
-            return env.getFrame(frameAccessProfile).getFrameDescriptor();
+            return frameProfile.profile(env.getFrame(frameAccessProfile)).getFrameDescriptor();
         }
 
         /**
@@ -152,7 +153,7 @@ public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSynta
                         @Cached("create()") GetVisibilityNode getVisibilityNode,
                         @Cached("createBinaryProfile()") ConditionProfile quoteProfile,
                         @Cached("create()") BranchProfile containsRSymbolProfile) {
-            MaterializedFrame promiseFrame = env.getFrame(frameAccessProfile).materialize();
+            MaterializedFrame promiseFrame = frameProfile.profile(env.getFrame(frameAccessProfile)).materialize();
             RArgsValuesAndNames args = getArguments(promiseFrame, quote, quoteProfile, containsRSymbolProfile, argsAsList);
             RCaller caller = getExplicitCaller(virtualFrame, promiseFrame, funcName, func, args);
             MaterializedFrame evalFrame = getEvalFrame(virtualFrame, promiseFrame);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
index 324249e38dd0faea4957f0c13ce9ccb2e940f4f1..70e06d1a1aa32c642169ba05311a2a54ef7a1e2b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
@@ -349,7 +349,7 @@ public class EnvFunctions {
             MaterializedFrame matFrame = callerFrame.execute(frame);
 
             matFrame = matFrame instanceof VirtualEvalFrame ? ((VirtualEvalFrame) matFrame).getOriginalFrame() : matFrame;
-            deoptFrameNode.deoptimizeFrame(matFrame);
+            deoptFrameNode.deoptimizeFrame(RArguments.getArguments(matFrame));
             return REnvironment.frameToEnvironment(matFrame);
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
index 9cc46a846c6409de9e221fff7a041e45ddc4c7ac..418fd51854110fa8e0a83ae1382fb5b290ffc833 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
@@ -444,7 +444,7 @@ public class FrameFunctions {
             }
 
             // Deoptimize every promise which is now in this frame, as it might leave it's stack
-            deoptFrameNode.deoptimizeFrame(result.getFrame());
+            deoptFrameNode.deoptimizeFrame(RArguments.getArguments(result.getFrame()));
             return result;
         }
     }
@@ -465,7 +465,7 @@ public class FrameFunctions {
                 RPairList next = result;
                 for (int i = 1; i < depth; i++) {
                     MaterializedFrame mf = helper.getNumberedFrame(frame, i).materialize();
-                    deoptFrameNode.deoptimizeFrame(mf);
+                    deoptFrameNode.deoptimizeFrame(RArguments.getArguments(mf));
                     next.setCar(REnvironment.frameToEnvironment(mf));
                     if (i != depth - 1) {
                         RPairList pl = RDataFactory.createPairList();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
index d13b44e5c9c3c93526c95a9cc2a1eaffe2b81e77..ddb5992e1f16d27b82bd93efb3a6239157c4d389 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
@@ -48,6 +48,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.nodes.InternalRSyntaxNodeChildren;
@@ -84,10 +85,11 @@ public abstract class Lapply extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected Object lapply(VirtualFrame frame, RAbstractVector vec, RFunction fun,
-                    @Cached("create()") ExtractNamesAttributeNode extractNamesNode) {
+                    @Cached("create()") ExtractNamesAttributeNode extractNamesNode,
+                    @Cached("create()") VectorFactory factory) {
         Object[] result = lapply.execute(frame, vec, fun);
         // set here else it gets overridden by the iterator evaluation
-        return RDataFactory.createList(result, extractNamesNode.execute(vec));
+        return factory.createList(result, extractNamesNode.execute(vec));
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
index dc16026b21480763d246b606c21b49e00d356ee1..4b22d2a7e57ac45fd84b0eba60df7f48a5e7fc89 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, 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
@@ -41,6 +41,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
 
 @RBuiltin(name = "list", kind = PRIMITIVE, parameterNames = {"..."}, behavior = PURE)
 public abstract class ListBuiltin extends RBuiltinNode.Arg1 {
@@ -48,6 +49,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 {
     protected static final int CACHE_LIMIT = 2;
     protected static final int MAX_SHARE_OBJECT_NODES = 16;
 
+    @Child private VectorFactory factory = VectorFactory.create();
     @Children private final ShareObjectNode[] shareObjectNodes = new ShareObjectNode[MAX_SHARE_OBJECT_NODES];
     private final ConditionProfile namesNull = ConditionProfile.createBinaryProfile();
 
@@ -78,8 +80,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 {
             String orgName = signature.getName(i);
             names[i] = (orgName == null ? RRuntime.NAMES_ATTR_EMPTY_VALUE : orgName);
         }
-        RStringVector result = RDataFactory.createStringVector(names, RDataFactory.COMPLETE_VECTOR);
-        return result;
+        return factory.createStringVector(names, RDataFactory.COMPLETE_VECTOR);
     }
 
     /**
@@ -99,7 +100,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 {
         for (int i = 0; i < cachedLength; i++) {
             getShareObjectNode(i).execute(argArray[i]);
         }
-        return RDataFactory.createList(argArray, cachedArgNames);
+        return factory.createList(argArray, cachedArgNames);
     }
 
     @Specialization(guards = "!args.isEmpty()")
@@ -109,7 +110,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 {
         for (int i = 0; i < argArray.length; i++) {
             shareObjectNode.execute(argArray[i]);
         }
-        return RDataFactory.createList(argArray, argNameVector(args.getSignature()));
+        return factory.createList(argArray, argNameVector(args.getSignature()));
     }
 
     @Specialization(guards = "args.isEmpty()")
@@ -119,7 +120,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 {
 
     @Specialization
     protected RList listMissing(@SuppressWarnings("unused") RMissing missing) {
-        return RDataFactory.createList(new Object[]{});
+        return factory.createList(new Object[]{});
     }
 
     @Specialization(guards = {"!isRArgsValuesAndNames(value)", "!isRMissing(value)"})
@@ -130,7 +131,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             suppliedSignatureArgNames = argNameVector(ArgumentsSignature.empty(1));
         }
-        return RDataFactory.createList(new Object[]{value}, suppliedSignatureArgNames);
+        return factory.createList(new Object[]{value}, suppliedSignatureArgNames);
     }
 
     private ShareObjectNode getShareObjectNode(int index) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArgFastPath.java
similarity index 96%
rename from com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java
rename to com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArgFastPath.java
index f58283148d64ef914a001351d4363ed2c8423d36..fa1c53e1df78b1696a37b1eab76625b78b965cf6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArgFastPath.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
@@ -39,9 +40,7 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.RRootNode;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
-import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.nodes.builtin.base.MatchArgNodeGen.MatchArgInternalNodeGen;
+import com.oracle.truffle.r.nodes.builtin.base.MatchArgFastPathNodeGen.MatchArgInternalNodeGen;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.nodes.unary.CastNode;
@@ -59,20 +58,12 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RTypes;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.nodes.RFastPathNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 @RBuiltin(name = "match.arg", kind = SUBSTITUTE, parameterNames = {"arg", "choices", "several.ok"}, nonEvalArgs = {0}, behavior = COMPLEX)
-public abstract class MatchArg extends RBuiltinNode.Arg3 {
-
-    static {
-        Casts.noCasts(MatchArg.class);
-    }
-
-    @Override
-    public Object[] getDefaultParameterValues() {
-        return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
-    }
+public abstract class MatchArgFastPath extends RFastPathNode {
 
     @TypeSystemReference(RTypes.class)
     protected abstract static class MatchArgInternal extends Node {
@@ -225,7 +216,7 @@ public abstract class MatchArg extends RBuiltinNode.Arg3 {
     @Specialization(limit = "1", guards = "cache.choicesValue.isSupported(frame, arg)")
     protected Object matchArg(VirtualFrame frame, RPromise arg, @SuppressWarnings("unused") RMissing choices, Object severalOK,
                     @Cached("new(frame, arg)") MatchArgNode cache) {
-        return cache.internal.castAndExecute(cache.promiseHelper.evaluate(frame, arg), cache.choicesValue.execute(frame), severalOK);
+        return cache.internal.castAndExecute(cache.promiseHelper.evaluate(frame, arg), cache.choicesValue.execute(frame), severalOK == RMissing.instance ? RRuntime.LOGICAL_FALSE : severalOK);
     }
 
     public static final class MatchArgNode extends Node {
@@ -248,7 +239,7 @@ public abstract class MatchArg extends RBuiltinNode.Arg3 {
     protected Object matchArg(VirtualFrame frame, RPromise arg, Object choices, Object severalOK,
                     @Cached("createInternal()") MatchArgInternal internal,
                     @Cached("new()") PromiseHelperNode promiseHelper) {
-        return internal.castAndExecute(promiseHelper.evaluate(frame, arg), choices, severalOK);
+        return internal.castAndExecute(promiseHelper.evaluate(frame, arg), choices, severalOK == RMissing.instance ? RRuntime.LOGICAL_FALSE : severalOK);
     }
 
     @SuppressWarnings("unused")
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
index 6194da9a6cd385a21cac054592523df563b7df4f..806b73434a170c7cfef7077594fb58f726253810 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -72,6 +72,8 @@ public abstract class StandardGeneric extends RBuiltinNode.Arg2 {
 
     private final BranchProfile noGenFunFound = BranchProfile.create();
     private final ConditionProfile sameNamesProfile = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile isBuiltinProfile = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile isDeferredProfile = ConditionProfile.createBinaryProfile();
 
     static {
         Casts casts = new Casts(StandardGeneric.class);
@@ -83,9 +85,9 @@ public abstract class StandardGeneric extends RBuiltinNode.Arg2 {
 
     private Object stdGenericInternal(VirtualFrame frame, String fname, RFunction fdef) {
         RFunction def = fdef;
-        if (def.isBuiltin()) {
+        if (isBuiltinProfile.profile(def.isBuiltin())) {
             def = RContext.getInstance().getPrimitiveMethodsInfo().getPrimGeneric(def.getRBuiltin().getPrimMethodIndex());
-            if (def == null) {
+            if (isDeferredProfile.profile(def == null)) {
                 return RRuntime.DEFERRED_DEFAULT_MARKER;
             }
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java
index f67c254ce6760e5525ff1ef194c5455be9f1c515..533db2210151c99af8b2518e8367a45846453b9a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java
@@ -51,6 +51,7 @@ public final class LocalReadVariableNode extends Node {
 
     private final Object identifier;
     private final boolean forceResult;
+    @CompilationFinal private boolean firstExecution = true;
 
     @CompilationFinal(dimensions = 1) private boolean[] seenValueKinds;
     @CompilationFinal private ValueProfile valueProfile;
@@ -144,6 +145,13 @@ public final class LocalReadVariableNode extends Node {
                 isPromiseProfile = ConditionProfile.createBinaryProfile();
             }
             if (isPromiseProfile.profile(result instanceof RPromise)) {
+                if (firstExecution) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    firstExecution = false;
+                    if (identifier instanceof String) {
+                        return ReadVariableNode.evalPromiseSlowPathWithName((String) identifier, frame, (RPromise) result);
+                    }
+                }
                 if (promiseHelper == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
                     promiseHelper = insert(new PromiseHelperNode());
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java
index f677a2ecfd1eafa8d83508c7a005c345d7ae131d..9c46ea23e765f8d32b78a6df739c19d75b859573 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.r.nodes.function.opt.EagerEvalHelper;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
@@ -68,7 +69,7 @@ public final class FunctionExpressionNode extends RSourceSectionNode implements
         MaterializedFrame matFrame = frame.materialize();
         if (deoptFrameNode != null) {
             // Deoptimize every promise which is now in this frame, as it might leave it's stack
-            deoptFrameNode.deoptimizeFrame(matFrame);
+            deoptFrameNode.deoptimizeFrame(RArguments.getArguments(matFrame));
         }
         if (!initialized) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java
index 934265d3025a5bfeac28d296ede2b8cc06bf5a5a..104121b451716238ff88773c4d589aa3d2bbcb2c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, 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
@@ -33,6 +33,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
  */
 public final class GetBaseEnvFrameNode extends Node {
     private final ValueProfile frameAccessProfile = ValueProfile.createClassProfile();
+    private final ValueProfile frameProfile = ValueProfile.createClassProfile();
     private final ValueProfile baseEnvProfile = ValueProfile.createIdentityProfile();
 
     public static GetBaseEnvFrameNode create() {
@@ -41,6 +42,6 @@ public final class GetBaseEnvFrameNode extends Node {
 
     public MaterializedFrame execute() {
         REnvironment baseEnv = baseEnvProfile.profile(REnvironment.baseEnv());
-        return baseEnv.getFrame(frameAccessProfile);
+        return frameProfile.profile(baseEnv.getFrame(frameAccessProfile));
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
index 71968032f21c367cc1e6fedd27b6f6997aff8f04..018515b742e3bcddefa873886878fa119959c481 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
@@ -28,9 +28,6 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.Frame;
-import com.oracle.truffle.api.frame.FrameSlot;
-import com.oracle.truffle.api.frame.FrameSlotKind;
-import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
@@ -45,13 +42,11 @@ import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.VirtualEvalFrame;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RPromise.EagerPromise;
 import com.oracle.truffle.r.runtime.data.RPromise.PromiseState;
 import com.oracle.truffle.r.runtime.data.RShareable;
-import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
@@ -88,32 +83,19 @@ public final class PromiseHelperNode extends RBaseNode {
          * Guarantees, that all {@link RPromise}s in frame are deoptimized and thus are safe to
          * leave it's stack-branch.
          *
-         * @param frame The frame to check for {@link RPromise}s to deoptimize
+         * @param arguments The frame's arguments, which will be checked for {@link RPromise}s to
+         *            deoptimize
          * @return Whether there was at least on {@link RPromise} which needed to be deoptimized.
          */
-        @TruffleBoundary
-        public boolean deoptimizeFrame(MaterializedFrame frame) {
+        public boolean deoptimizeFrame(Object[] arguments) {
             boolean deoptOne = false;
-            for (FrameSlot slot : frame.getFrameDescriptor().getSlots().toArray(new FrameSlot[0])) {
-                // We're only interested in RPromises
-                if (slot.getKind() != FrameSlotKind.Object || !(slot.getIdentifier() instanceof String)) {
-                    continue;
-                }
-
-                // Try to read it...
-                try {
-                    Object value = FrameSlotChangeMonitor.getObject(slot, frame);
-
-                    // If it's a promise, deoptimize it!
-                    if (value instanceof RPromise) {
-                        RPromise promise = (RPromise) value;
-                        if (!promise.isEvaluated()) {
-                            deoptOne |= deoptimize(promise);
-                        }
+            for (Object value : arguments) {
+                // If it's a promise, deoptimize it!
+                if (value instanceof RPromise) {
+                    RPromise promise = (RPromise) value;
+                    if (!promise.isEvaluated()) {
+                        deoptOne |= deoptimize(promise);
                     }
-                } catch (FrameSlotTypeException err) {
-                    // Should not happen after former check on FrameSlotKind!
-                    throw RInternalError.shouldNotReachHere();
                 }
             }
             return deoptOne;
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 84fb2f06e21b2fb8e65bcec9db896f3cce97e87f..6f987abcbbe6212c1ee3d90b6fcc47c37eebc22d 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
@@ -1202,4 +1202,9 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
     public static Object createDeferredMemberAccess(TruffleObject object, String name) {
         return new DeferredFunctionValue(object, name);
     }
+
+    @Override
+    public String toString() {
+        return "call: " + RDeparse.deparseSyntaxElement(this);
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
index 7b425b9f8fac56ae5a24ce3e17564e472dd0e378..4bdd3dbe455a9a9eac21eb2c5ac7b3d5bf70259a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -38,6 +38,7 @@ public abstract class DispatchGeneric extends RBaseNode {
     public abstract Object executeObject(VirtualFrame frame, REnvironment mtable, RStringVector classes, RFunction fdef, String fname);
 
     private final ConditionProfile singleStringProfile = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile isDeferredProfile = ConditionProfile.createBinaryProfile();
     private final BranchProfile equalsMethodRequired = BranchProfile.create();
     @Child private LoadMethod loadMethod = LoadMethodNodeGen.create();
     @Child private ExecuteMethod executeMethod = new ExecuteMethod();
@@ -78,7 +79,7 @@ public abstract class DispatchGeneric extends RBaseNode {
             RFunction currentFunction = ReadVariableNode.lookupFunction(".InheritForDispatch", methodsEnv.getFrame(), true, true);
             method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), true, null, classes, fdef, mtable);
         }
-        if (method.isBuiltin() || getInheritsInternalDispatchCheckNode().execute(method)) {
+        if (isDeferredProfile.profile(method.isBuiltin() || getInheritsInternalDispatchCheckNode().execute(method))) {
             return RRuntime.DEFERRED_DEFAULT_MARKER;
         }
         method = loadMethod.executeRFunction(frame, method, fname);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
index 1803e88efbfda4b92f6f6c4b95f1097ec6477f8b..89b24089184494e10c033092b70fa966baf41598 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -68,6 +68,7 @@ abstract class LoadMethod extends RBaseNode {
     @Specialization
     protected RFunction loadMethod(VirtualFrame frame, RFunction fdef, String fname,
                     @Cached("createClassProfile()") ValueProfile regFrameAccessProfile,
+                    @Cached("createClassProfile()") ValueProfile regFrameProfile,
                     @Cached("createClassProfile()") ValueProfile methodsFrameAccessProfile) {
         DynamicObject attributes = fdef.getAttributes();
         assert fdef.isBuiltin() || attributes != null;
@@ -115,7 +116,7 @@ abstract class LoadMethod extends RBaseNode {
         RFunction ret;
         if (fdef.getAttributes() != null && moreAttributes.profile(found < fdef.getAttributes().size())) {
             RFunction currentFunction;
-            REnvironment methodsEnv = (REnvironment) methodsEnvRead.execute(frame, REnvironment.getNamespaceRegistry().getFrame(regFrameAccessProfile));
+            REnvironment methodsEnv = (REnvironment) methodsEnvRead.execute(frame, regFrameProfile.profile(REnvironment.getNamespaceRegistry().getFrame(regFrameAccessProfile)));
             if (loadMethodFind == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 loadMethodFind = insert(ReadVariableNode.createFunctionLookup(RRuntime.R_LOAD_METHOD_NAME));
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
index 2d17f16cb44ee8dc2a0e892eab4b31168e17540a..c54448034f70222006046e7952cb8762e17034b6 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
@@ -97,6 +97,7 @@ public class ParserGeneration {
         "allow greek characters in identifiers",
         "allow everything but newlines in %<ident>% operators",
         "allow strings in :: and :::",
-        "use file for interactive single-line source"
+        "use file for interactive single-line source",
+        ":: and ::: do not set argument names"
     };
 }
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
index a86d1728d7e0fd16b916f60228ab2a974b939586..daab0541ae8da9e5eb327ad196c7950d7165a873 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
@@ -578,17 +578,17 @@ simple_expr returns [T v]
     | cstr=conststring                          { $v = $cstr.v; }
     | pkg=id op=(NS_GET|NS_GET_INT) n_          {
         SourceSection pkgSource = src($pkg.v);
-        args.add(RCodeBuilder.argument(pkgSource, "pkg", builder.lookup(pkgSource, $pkg.text, false)));
+        args.add(RCodeBuilder.argument(pkgSource, (String) null, builder.lookup(pkgSource, $pkg.text, false)));
         }
       ( compId=id                               {
         SourceSection compSource = src($compId.v);
         compToken = $compId.v;
-        args.add(RCodeBuilder.argument(compSource, "name", builder.lookup(compSource, $compId.text, false)));
+        args.add(RCodeBuilder.argument(compSource, (String) null, builder.lookup(compSource, $compId.text, false)));
         }
       | compString=STRING                       { 
         SourceSection compSource = src($compString);
         compToken = $compString;
-        args.add(RCodeBuilder.argument(compSource, "name", builder.constant(compSource, $compString.text)));
+        args.add(RCodeBuilder.argument(compSource, (String) null, builder.constant(compSource, $compString.text)));
         }
         )                                       { $v = builder.call(src($pkg.v, compToken), operator($op), args); }
     | op=LPAR n_ ea=expr_or_assign n_ y=RPAR    { $v = builder.call(src($op, $y), operator($op), $ea.v); }
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 bd968fce28658fa6a8960386888877b6d8a88099..dfdf08646513d442ee3f2cf655b81cc45fe3453d 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
@@ -279,7 +279,7 @@ public final class RContext {
 
     private EnumSet<State> state = EnumSet.noneOf(State.class);
 
-    private PrimitiveMethodsInfo primitiveMethodsInfo;
+    @CompilationFinal private PrimitiveMethodsInfo primitiveMethodsInfo;
 
     /** Class loader for Java interop. */
     private ClassLoader interopClassLoader = FastRConfig.InternalGridAwtSupport ? getClass().getClassLoader() : null;
@@ -691,7 +691,6 @@ public final class RContext {
         s4ExtendsTable.put(key, value);
     }
 
-    @TruffleBoundary
     public PrimitiveMethodsInfo getPrimitiveMethodsInfo() {
         if (primitiveMethodsInfo == null) {
             // shared contexts do not run concurrently with their parent and re-use primitive
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java
index 90cafa94aaac3d440f351bf0a8a81d448c5536b9..de16d7697a903ae5896c8b1d42abe732c7a8a338 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, 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
@@ -22,6 +22,16 @@
  */
 package com.oracle.truffle.r.runtime.nodes;
 
+import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.env.REnvironment;
+
+/**
+ * Currently, this visitor is only necessary because we don't treat the body of an RFunction as a
+ * pairlist. It's slightly inaccurate in how it treats constants, attributes, etc.
+ */
 public final class IdenticalVisitor extends RSyntaxArgVisitor<Boolean, RSyntaxElement> {
 
     @Override
@@ -41,7 +51,65 @@ public final class IdenticalVisitor extends RSyntaxArgVisitor<Boolean, RSyntaxEl
         if (!(arg instanceof RSyntaxConstant)) {
             return false;
         }
-        return element.getValue().equals(((RSyntaxConstant) arg).getValue());
+        return identicalValue(element.getValue(), ((RSyntaxConstant) arg).getValue());
+    }
+
+    private Boolean identicalValue(Object value, Object otherValue) {
+        if (value instanceof Number || value instanceof String) {
+            return value.equals(otherValue);
+        }
+        if (value instanceof RAttributable) {
+            if (!(otherValue instanceof RAttributable)) {
+                return false;
+            }
+            if (!identicalAttributes((RAttributable) value, (RAttributable) otherValue)) {
+                return false;
+            }
+            if (!identicalAttributes((RAttributable) otherValue, (RAttributable) value)) {
+                return false;
+            }
+        }
+        if (value instanceof RAbstractVector) {
+            RAbstractVector vector = (RAbstractVector) value;
+            if (!(otherValue instanceof RAbstractVector)) {
+                return false;
+            }
+            RAbstractVector otherVector = (RAbstractVector) otherValue;
+            if (vector.getLength() != otherVector.getLength() || vector.getRType() != otherVector.getRType()) {
+                return false;
+            }
+            for (int i = 0; i < vector.getLength(); i++) {
+                if (!identicalValue(vector.getDataAtAsObject(i), otherVector.getDataAtAsObject(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        if (value instanceof RPairList && ((RPairList) value).isLanguage()) {
+            if (!(otherValue instanceof RPairList && ((RPairList) otherValue).isLanguage())) {
+                return false;
+            }
+            return accept(((RPairList) value).getSyntaxElement(), ((RPairList) otherValue).getSyntaxElement());
+        }
+        if (value instanceof REnvironment) {
+            return value == otherValue;
+        }
+        return value == otherValue;
+    }
+
+    private boolean identicalAttributes(RAttributable attributable, RAttributable otherAttributable) {
+        DynamicObject attributes = attributable.getAttributes();
+        if (attributes != null) {
+            DynamicObject otherAttributes = otherAttributable.getAttributes();
+            for (Object key : attributes.getShape().getKeys()) {
+                Object attributeValue = attributes.get(key);
+                Object otherAttributeValue = otherAttributes == null ? null : otherAttributes.get(key);
+                if ((attributeValue == null) != (otherAttributeValue == null) || !identicalValue(attributeValue, otherAttributeValue)) {
+                    return false;
+                }
+            }
+        }
+        return true;
     }
 
     @Override
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 28e719055c235dd5c8ca7d1063e7c0edaeee97f6..963736621e0a6dc556d5a01aad82615d703a87df 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -29927,6 +29927,13 @@ attr(,"Rd_tag")
 #a <- quote(a(100)); b <- quote(a(101)); identical(a,b)
 [1] FALSE
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical#
+#e1 <- quote(a+1); e2 <- quote(a+2); identical(e1, e2); e2[[3]] <- c(1,2,3); identical(e1, e2); e1[[3]] <- c(1,2,3); identical(e1, e2); attr(e2[[3]], 'foo') <- 'bar'; identical(e1, e2)
+[1] FALSE
+[1] FALSE
+[1] TRUE
+[1] FALSE
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical#
 #identical(pairlist(1, pairlist('foo')), pairlist(1, pairlist('bar')))
 [1] FALSE
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java
index d9e8d9df8e8cf413e2485220111a7a477c76ab2a..9aa604764d5d92769baab83b8004a012fb2ccdef 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java
@@ -271,6 +271,7 @@ public class TestBuiltin_identical extends TestBase {
         assertEval("a <- quote(a(100)); b <- quote(a(100)); attr(a[[2]], 'foo') <- 'bar'; b[[2]] <- a[[2]]; identical(a,b)");
         assertEval("a <- quote(a(100)); b <- quote(a(100)); attr(b[[2]], 'foo') <- 'baz'; attr(a[[2]], 'foo') <- 'bar'; identical(a,b)");
         assertEval("a <- quote(a(100)); b <- quote(a(100)); attr(b[[2]], 'foo') <- 'bar'; attr(a[[2]], 'foo') <- 'bar'; identical(a,b)");
+        assertEval("e1 <- quote(a+1); e2 <- quote(a+2); identical(e1, e2); e2[[3]] <- c(1,2,3); identical(e1, e2); e1[[3]] <- c(1,2,3); identical(e1, e2); attr(e2[[3]], 'foo') <- 'bar'; identical(e1, e2)");
     }
 
     @Test