diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java
index 30fe74af0a997c9fdd179f41e46abe25824f42ef..ad1b25a74de3cda9cbc664347f7ca255b1fa4200 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java
@@ -229,8 +229,7 @@ public abstract class Identical extends RBuiltinNode.Arg8 {
     @SuppressWarnings("unused")
     @Specialization
     protected byte doInternalIdentical(RSymbol x, RSymbol y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment, boolean ignoreSrcref) {
-        assert Utils.isInterned(x.getName()) && Utils.isInterned(y.getName());
-        return RRuntime.asLogical(x.getName() == y.getName());
+        return RRuntime.asLogical(x == y);
     }
 
     @Specialization
@@ -343,10 +342,7 @@ public abstract class Identical extends RBuiltinNode.Arg8 {
                         return RRuntime.LOGICAL_FALSE;
                     } else {
                         if (xSubList.getTag() instanceof RSymbol && ySubList.getTag() instanceof RSymbol) {
-                            String xTagName = ((RSymbol) xSubList.getTag()).getName();
-                            String yTagName = ((RSymbol) ySubList.getTag()).getName();
-                            assert Utils.isInterned(xTagName) && Utils.isInterned(yTagName);
-                            if (xTagName != yTagName) {
+                            if (xSubList.getTag() != ySubList.getTag()) {
                                 return RRuntime.LOGICAL_FALSE;
                             }
                         } else {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java
index c368686daf1bcc444c4c2148d12a59b7549d893f..8a74878b896b8e360b137a09d6a95ba0e66ae5c0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java
@@ -112,10 +112,6 @@ public abstract class MatchFun extends RBuiltinNode.Arg2 {
             return vec.getDataAt(0);
         }
 
-        protected static String firstString(RSymbol symbol) {
-            return symbol.getName();
-        }
-
         private RFunction checkResult(Object result) {
             if (result instanceof RFunction) {
                 return (RFunction) result;
@@ -140,11 +136,11 @@ public abstract class MatchFun extends RBuiltinNode.Arg2 {
         }
 
         @SuppressWarnings("unused")
-        @Specialization(limit = "LIMIT", guards = {"funValue.getName() == cachedName", "getCallerFrameDescriptor(frame) == cachedCallerFrameDescriptor"})
+        @Specialization(limit = "LIMIT", guards = {"funValue == cachedFunValue", "getCallerFrameDescriptor(frame) == cachedCallerFrameDescriptor"})
         protected RFunction matchfunCached(VirtualFrame frame, RPromise funPromise, RSymbol funValue, boolean descend,
-                        @Cached("firstString(funValue)") String cachedName,
+                        @Cached("funValue") RSymbol cachedFunValue,
                         @Cached("getCallerFrameDescriptor(frame)") FrameDescriptor cachedCallerFrameDescriptor,
-                        @Cached("createLookup(cachedName, descend)") ReadVariableNode lookup) {
+                        @Cached("createLookup(cachedFunValue.getName(), descend)") ReadVariableNode lookup) {
             return checkResult(lookup.execute(frame, getCallerFrame.execute(frame)));
         }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseAccessSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseAccessSlotNode.java
index e53a1687a3a21f55dd2c8995eff4f036b9b26211..ffd83c138f3835cb97e8c28458e194e4651d752f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseAccessSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseAccessSlotNode.java
@@ -96,7 +96,7 @@ public abstract class BaseAccessSlotNode extends RBaseNode {
         }
         if (value instanceof RSymbol) {
             symbolValue.enter();
-            if (((RSymbol) value).getName() == RRuntime.PSEUDO_NULL.getName()) {
+            if (value == RRuntime.PSEUDO_NULL) {
                 return RNull.instance;
             }
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapper.java
index 1d292d32d89b0bf3178cd714c612b6402c906928..d4d8e4ac01187840d116c45b6467f89c058c0e08 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapper.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapper.java
@@ -46,12 +46,12 @@ import java.util.WeakHashMap;
  */
 public final class CharSXPWrapper extends RObject implements RTruffleObject {
     private static final CharSXPWrapper NA = new CharSXPWrapper(RRuntime.STRING_NA);
-    private final String contents;
+    private String contents;
     private byte[] bytes;
     private static final Map<CharSXPWrapper, WeakReference<CharSXPWrapper>> instances = new WeakHashMap<>(2048);
 
     private CharSXPWrapper(String contents) {
-        this.contents = Utils.intern(contents);
+        this.contents = contents;
     }
 
     @TruffleBoundary
@@ -96,6 +96,16 @@ public final class CharSXPWrapper extends RObject implements RTruffleObject {
     }
 
     public static CharSXPWrapper create(String contents) {
+        return create(contents, false);
+    }
+
+    public static CharSXPWrapper createInterned(String contents) {
+        assert Utils.isInterned(contents);
+        return create(contents, true);
+    }
+
+    private static CharSXPWrapper create(String contents, boolean intern) {
+        assert !intern || Utils.isInterned(contents);
         if (contents == RRuntime.STRING_NA) {
             return NA;
         } else {
@@ -106,6 +116,9 @@ public final class CharSXPWrapper extends RObject implements RTruffleObject {
                 if (wr != null) {
                     cachedWrapper = wr.get();
                     if (cachedWrapper != null) {
+                        if (intern) {
+                            cachedWrapper.contents = contents;
+                        }
                         return cachedWrapper;
                     }
                 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSymbol.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSymbol.java
index 84a6d232a4c6393a497df9a1746165184f130546..715b8cd6d3292fd9d5ccb40a14c0573674862874 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSymbol.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSymbol.java
@@ -22,11 +22,13 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
+import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.Utils;
 
 /**
  * Denotes an R "symbol" or "name". Its rep is a {@code String} but it's a different type in the
@@ -39,14 +41,15 @@ public final class RSymbol extends RAttributeStorage {
      * Note: GnuR caches all symbols and some packages rely on their identity. Moreover, the cached
      * symbols are never garbage collected. This table corresponds to {@code R_SymbolTable} in GNUR.
      */
-    private static final ConcurrentHashMap<String, RSymbol> symbolTable = new ConcurrentHashMap<>(1024);
+    private static final ConcurrentHashMap<String, RSymbol> symbolTable = new ConcurrentHashMap<>(2551);
 
     public static final RSymbol MISSING = RDataFactory.createSymbol("");
 
-    private final CharSXPWrapper name;
+    private final String name;
+    private CharSXPWrapper nameWrapper;
 
     private RSymbol(String name) {
-        this.name = CharSXPWrapper.create(name);
+        this.name = Utils.intern(name);
     }
 
     @TruffleBoundary
@@ -60,11 +63,14 @@ public final class RSymbol extends RAttributeStorage {
     }
 
     public String getName() {
-        return name.getContents();
+        return name;
     }
 
     public CharSXPWrapper getWrappedName() {
-        return name;
+        if (nameWrapper == null) {
+            nameWrapper = CharSXPWrapper.createInterned(name);
+        }
+        return nameWrapper;
     }
 
     @Override
@@ -78,7 +84,7 @@ public final class RSymbol extends RAttributeStorage {
 
     @Override
     public int hashCode() {
-        return this.getName().hashCode();
+        return System.identityHashCode(this.getName());
     }
 
     @Override
@@ -86,7 +92,7 @@ public final class RSymbol extends RAttributeStorage {
         if (obj == this) {
             return true;
         } else if (obj instanceof RSymbol) {
-            return ((RSymbol) obj).getName().equals(this.getName());
+            return ((RSymbol) obj).getName() == this.name;
         }
         return false;
     }