diff --git a/com.oracle.truffle.r.native/fficall/jni/src/rffiutils.c b/com.oracle.truffle.r.native/fficall/jni/src/rffiutils.c
index 346ba55cf2530c64bde446618e5c2525e4192932..a3e08bb2f228e61ed9c26a266c2d9384d2fdecad 100644
--- a/com.oracle.truffle.r.native/fficall/jni/src/rffiutils.c
+++ b/com.oracle.truffle.r.native/fficall/jni/src/rffiutils.c
@@ -73,7 +73,7 @@ void init_utils(JNIEnv *env) {
 	RRuntimeClass = checkFindClass(env, "com/oracle/truffle/r/runtime/RRuntime");
 	RInternalErrorClass = checkFindClass(env, "com/oracle/truffle/r/runtime/RInternalError");
 	unimplementedMethodID = checkGetMethodID(env, RInternalErrorClass, "unimplemented", "(Ljava/lang/String;)Ljava/lang/RuntimeException;", 1);
-	createSymbolMethodID = checkGetMethodID(env, RDataFactoryClass, "createSymbol", "(Ljava/lang/String;)Lcom/oracle/truffle/r/runtime/data/RSymbol;", 1);
+	createSymbolMethodID = checkGetMethodID(env, RDataFactoryClass, "createSymbolInterned", "(Ljava/lang/String;)Lcom/oracle/truffle/r/runtime/data/RSymbol;", 1);
     validateMethodID = checkGetMethodID(env, CallRFFIHelperClass, "validate", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
     for (int i = 0; i < CACHED_GLOBALREFS_TABLE_SIZE; i++) {
     	cachedGlobalRefs[i] = NULL;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
index fc335525efe7d395f444f2837b5f845fc7305297..1b79ed7583e633891e680452d84605ab8ce5aff7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
@@ -123,7 +123,9 @@ public abstract class AsVector extends RBuiltinNode {
     @Specialization(guards = "isSymbol(x, mode)")
     protected RSymbol asVectorSymbol(RSymbol x, @SuppressWarnings("unused") String mode) {
         controlVisibility();
-        return RDataFactory.createSymbol(x.getName());
+        String sName = x.getName();
+        assert sName == sName.intern();
+        return RDataFactory.createSymbol(sName);
     }
 
     protected boolean isSymbol(@SuppressWarnings("unused") RSymbol x, String mode) {
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 ed3f6262547bfb7a588e88efee4699fce36e3d35..a563a19e6f0bf7609e7d644e7e65d312a985a154 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
@@ -26,6 +26,7 @@ import static com.oracle.truffle.r.runtime.RBuiltinKind.*;
 
 import java.util.*;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
@@ -243,7 +244,9 @@ public class FrameFunctions {
                             if (n instanceof ConstantNode) {
                                 listValue = ((ConstantNode) n).getValue();
                             } else if (n instanceof ReadVariableNode) {
-                                listValue = RDataFactory.createSymbol(((ReadVariableNode) n).getIdentifier());
+                                String id = ((ReadVariableNode) n).getIdentifier();
+                                assert id == id.intern();
+                                listValue = RDataFactory.createSymbol(id);
                             } else if (n instanceof VarArgNode) {
                                 listValue = createVarArgSymbol((VarArgNode) n);
                             } else {
@@ -251,7 +254,7 @@ public class FrameFunctions {
                             }
                             pl.setCar(listValue);
                             if (varArgSignature.getName(i2) != null) {
-                                pl.setTag(RDataFactory.createSymbol(varArgSignature.getName(i2)));
+                                pl.setTag(RDataFactory.createSymbol(varArgSignature.getName(i2).intern()));
                             }
                             if (prev != null) {
                                 prev.setCdr(pl);
@@ -308,7 +311,9 @@ public class FrameFunctions {
 
         private static RSymbol createVarArgSymbol(VarArgNode varArgNode) {
             int vn = varArgNode.getIndex() + 1;
-            return RDataFactory.createSymbol((vn < 10 ? ".." : ".") + vn);
+            CompilerAsserts.neverPartOfCompilation(); // for string concatenation and interning
+            String varArgSymbol = (vn < 10 ? ".." : ".") + vn;
+            return RDataFactory.createSymbol(varArgSymbol.intern());
         }
 
         @Specialization
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 09c47e6c6c743689d9294ae49acc8b60c5d2507d..aafa26a098fd362cd92683408b15e7482f824d15 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
@@ -58,7 +58,9 @@ public abstract class Slot extends RBuiltinNode {
 
     @Specialization
     protected Object getSlot(RAttributable object, Object nameObj) {
-        return accessSlotNode.executeAccess(object, getName(nameObj));
+        String name = getName(nameObj);
+        assert name == name.intern();
+        return accessSlotNode.executeAccess(object, name);
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
index 208e4cb7ff517cc0f366c38e288d1458afbe3ad1..021eb25bbf834a0d8109f4e18e56bf79863abbf3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
@@ -84,7 +84,7 @@ public class ForeignFunctions {
         Object list = RNull.instance;
         for (int i = args.getLength() - 1; i >= 0; i--) {
             String name = args.getSignature().getName(i);
-            list = RDataFactory.createPairList(args.getArgument(i), list, name == null ? RNull.instance : RDataFactory.createSymbol(name));
+            list = RDataFactory.createPairList(args.getArgument(i), list, name == null ? RNull.instance : RDataFactory.createSymbol(name.intern()));
         }
         list = RDataFactory.createPairList(symbolName, list);
         return list;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java
index 5cf1c1e3459d9bccc80797c179a7c49995770a05..43a00cc2b87fb8e6f1d233b895e763a8aa037196 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.WrapperNode;
@@ -114,9 +115,11 @@ public class RASTUtils {
     public static RSymbol createRSymbol(Node readVariableNode) {
         if (readVariableNode instanceof ReadVariadicComponentNode) {
             ReadVariadicComponentNode rvcn = (ReadVariadicComponentNode) readVariableNode;
-            return RDataFactory.createSymbol(rvcn.getPrintForm());
+            return RDataFactory.createSymbol(rvcn.getPrintForm().intern());
         } else {
-            return RDataFactory.createSymbol(((ReadVariableNode) readVariableNode).getIdentifier());
+            String id = ((ReadVariableNode) readVariableNode).getIdentifier();
+            assert id == id.intern();
+            return RDataFactory.createSymbol(id);
         }
     }
 
@@ -229,25 +232,27 @@ public class RASTUtils {
      * or {@link GroupDispatchNode}.
      */
     public static Object findFunctionName(Node node) {
+        CompilerAsserts.neverPartOfCompilation(); // for string interning
         RNode child = (RNode) unwrap(getFunctionNode(node));
         if (child instanceof ConstantNode && ConstantNode.isFunction(child)) {
             return ((ConstantNode) child).getValue();
         } else if (child instanceof ReadVariableNode) {
             String name = ((ReadVariableNode) child).getIdentifier();
+            assert name == name.intern();
             return RDataFactory.createSymbol(name);
         } else if (child instanceof GroupDispatchNode) {
             GroupDispatchNode groupDispatchNode = (GroupDispatchNode) child;
             String gname = groupDispatchNode.getGenericName();
-            return RDataFactory.createSymbol(gname);
+            return RDataFactory.createSymbol(gname.intern());
         } else if (child instanceof RBuiltinNode) {
             RBuiltinNode builtinNode = (RBuiltinNode) child;
-            return RDataFactory.createSymbol((builtinNode.getBuiltin().getName()));
+            return RDataFactory.createSymbol((builtinNode.getBuiltin().getName().intern()));
         } else {
             // TODO This should really fail in some way as (clearly) this is not a "name"
             // some more complicated expression, just deparse it
             RDeparse.State state = RDeparse.State.createPrintableState();
             child.deparse(state);
-            return RDataFactory.createSymbol(state.toString());
+            return RDataFactory.createSymbol(state.toString().intern());
         }
     }
 
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 f709f8d3b7c68d59053aa9eb20d6223f16e2bfb2..2b23220db527a0367d76643c28a48f103e5dd4eb 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
@@ -41,7 +41,6 @@ public abstract class AccessSlotNode extends RNode {
     @Child private ClassHierarchyNode classHierarchy;
     @Child private TypeofNode typeofNode;
     private final BranchProfile noSlot = BranchProfile.create();
-    private final ConditionProfile nullSlot = ConditionProfile.createBinaryProfile();
 
     protected AttributeAccess createAttrAccess(String name) {
         return AttributeAccessNodeGen.create(name);
@@ -50,11 +49,8 @@ public abstract class AccessSlotNode extends RNode {
     private Object getSlotS4Internal(RAttributable object, String name, Object value) {
         if (value == null) {
             noSlot.enter();
+            assert name == name.intern();
             if (name == RRuntime.DOT_S3_CLASS) {
-                // TODO: this will not work if `@` function is called directly, as in:
-                // `@`(x, ".S3Class")
-                // in general, treatment of the name parameter has to be finessed to be
-                // fully compatible with GNU R on direct calls to `@` function
                 if (classHierarchy == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
                     classHierarchy = insert(ClassHierarchyNodeGen.create(true));
@@ -128,7 +124,7 @@ public abstract class AccessSlotNode extends RNode {
     }
 
     protected boolean isDotData(String name) {
-        // see comment on usinq object equality in getSlotS4()
+        assert name == name.intern();
         return name == RRuntime.DOT_DATA;
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
index 50d816413538f2139a7b136451049fd66b457c1d..bdda2e770a6bacca85405ef7e002876f43802df5 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
@@ -17,7 +17,6 @@ import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.r.nodes.attributes.PutAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.PutAttributeNodeGen;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
-import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.model.*;
 import com.oracle.truffle.r.runtime.nodes.*;
@@ -44,7 +43,8 @@ public abstract class UpdateSlotNode extends RNode {
 
     @Specialization(contains = "updateSlotS4Cached")
     protected Object updateSlotS4(RS4Object object, String name, Object value) {
-        object.setAttr(name.intern(), value);
+        assert name == name.intern();
+        object.setAttr(name, value);
         return object;
     }
 
@@ -57,7 +57,8 @@ public abstract class UpdateSlotNode extends RNode {
 
     @Specialization(contains = "updateSlotCached")
     protected Object updateSlot(RAbstractContainer object, String name, Object value) {
-        object.setAttr(name.intern(), value);
+        assert name == name.intern();
+        object.setAttr(name, value);
         return object;
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNodeSyntaxHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNodeSyntaxHelper.java
index 96ed55de7dc36180733addf2d67b9b9d2215fdbd..2809aeba1ccda4460330e042ef2641e7b7cb7b19 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNodeSyntaxHelper.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNodeSyntaxHelper.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.access;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -56,9 +57,11 @@ abstract class WriteVariableNodeSyntaxHelper extends WriteVariableNode {
     protected Object getRelementHelper(String op, int index) {
         switch (index) {
             case 0:
+                assert op == op.intern();
                 return RDataFactory.createSymbol(op);
             case 1:
-                return RDataFactory.createSymbol(getName().toString());
+                CompilerAsserts.neverPartOfCompilation();
+                return RDataFactory.createSymbol(getName().toString().intern());
             case 2:
                 return RASTUtils.createLanguageElement(getRhs());
             default:
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
index 673ac2dd79b4c606c29f5cc9968091e5c8288a12..329e4ca35f873c2502fcbdc5cf2a46f99d170356 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
@@ -137,7 +137,7 @@ public final class ReadVariableNode extends RNode implements RSyntaxNode, Visibi
 
     private ReadVariableNode(Object identifier, RType mode, ReadKind kind, boolean visibilityChange) {
         this.identifier = identifier;
-        this.identifierAsString = identifier.toString();
+        this.identifierAsString = identifier.toString().intern();
         this.mode = mode;
         this.kind = kind;
         this.visibilityChange = visibilityChange;
@@ -180,7 +180,9 @@ public final class ReadVariableNode extends RNode implements RSyntaxNode, Visibi
 
     @Override
     public Object getRelementImpl(int index) {
-        return RDataFactory.createSymbol(identifier.toString());
+        String id = identifier.toString();
+        assert id == id.intern();
+        return RDataFactory.createSymbol(id);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
index 4b00e38b6a61d58c31c14af94fbc1f0f8f69b45c..e90f8a8de94b5ee0a1947dea6bc061c72395177f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
@@ -57,9 +57,11 @@ public abstract class CastSymbolNode extends CastBaseNode {
         return backQuote(toString(value));
     }
 
+    @TruffleBoundary
     @Specialization
     protected RSymbol doString(String value) {
-        return RDataFactory.createSymbol(value);
+        // TODO: see if this is going to hit us performance-wise
+        return RDataFactory.createSymbol(value.intern());
     }
 
     @Specialization
@@ -85,7 +87,8 @@ public abstract class CastSymbolNode extends CastBaseNode {
 
     @TruffleBoundary
     private static RSymbol backQuote(String s) {
-        return RDataFactory.createSymbol("`" + s + "`");
+        String quotedString = "`" + s + "`";
+        return RDataFactory.createSymbol(quotedString.intern());
     }
 
     public static CastSymbolNode createNonPreserving() {
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/Constant.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/Constant.java
index 40f40c1a8815808e9061d7fe1e0e485c86ca0f4f..6177da34e174b3d6f8bff56e9519d6190ca73e60 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/Constant.java
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/Constant.java
@@ -30,8 +30,23 @@ public final class Constant extends ASTNode {
     private final String[] values;
     private final ConstantType type;
 
+    /*
+     * Used in case parameter is a single String value that should not be interned (e.g., NA)
+     */
+    private Constant(String value, SourceSection source) {
+        super(source);
+        this.values = new String[]{value};
+        this.type = ConstantType.STRING;
+    }
+
     private Constant(String[] values, ConstantType type, SourceSection source) {
         super(source);
+        if (type == ConstantType.STRING) {
+            assert values != null;
+            for (int i = 0; i < values.length; i++) {
+                values[i] = values[i].intern();
+            }
+        }
         this.values = values;
         this.type = type;
     }
@@ -95,7 +110,8 @@ public final class Constant extends ASTNode {
     }
 
     public static Constant createStringNA(SourceSection src) {
-        return new Constant(new String[]{RRuntime.STRING_NA}, ConstantType.STRING, src);
+        // don't intern NA value, otherwise each "NA" literal becomes an NA value
+        return new Constant(RRuntime.STRING_NA, src);
     }
 
     public void addNegativeSign() {
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/FieldAccess.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/FieldAccess.java
index 18b51191d2557a408eccda11e859fd837105e659..6dd48e261a87f09e92e482b9190989176a10b006 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/FieldAccess.java
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ast/FieldAccess.java
@@ -45,10 +45,7 @@ public final class FieldAccess extends ASTNode {
     public static ASTNode create(SourceSection src, FieldOperator op, ASTNode value, String fieldName) {
         switch (op) {
             case AT:
-                // these two names have special meaning for slot retrieval
-
-                String newName = fieldName.equals(RRuntime.DOT_DATA) ? RRuntime.DOT_DATA : (fieldName.equals(RRuntime.DOT_S3_CLASS) ? RRuntime.DOT_S3_CLASS : fieldName);
-                return new FieldAccess(src, value, newName, true);
+                return new FieldAccess(src, value, fieldName.intern(), true);
             case FIELD:
                 return new FieldAccess(src, value, fieldName, false);
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index 0bba416246db4c985a33177d3dc6c08c9cf6d033..ce0aaeb9c42edb9b0ed314c7d44c35f0f67a89d6 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -15,6 +15,7 @@ import java.io.*;
 import java.nio.charset.*;
 import java.util.*;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.source.*;
@@ -670,7 +671,7 @@ public class RSerialize {
 
                 case SYMSXP: {
                     String name = (String) readItem();
-                    result = RDataFactory.createSymbol(name);
+                    result = RDataFactory.createSymbol(name.intern());
                     addReadRef(result);
                     break;
                 }
@@ -1823,7 +1824,8 @@ public class RSerialize {
         RSymbol findSymbol(String name) {
             RSymbol symbol = symbolMap.get(name);
             if (symbol == null) {
-                symbol = RDataFactory.createSymbol(name);
+                CompilerAsserts.neverPartOfCompilation(); // for interning
+                symbol = RDataFactory.createSymbol(name.intern());
                 symbolMap.put(name, symbol);
             }
             return symbol;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
index 6acc3e48d498ad8afabf89b7cbabda69667ddb4d..56016b5b14cd1b02134448f33f0d6429a370be2c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
@@ -366,9 +366,17 @@ public final class RDataFactory {
     }
 
     public static RSymbol createSymbol(String name) {
+        assert name == name.intern();
         return traceDataCreated(new RSymbol(name));
     }
 
+    /*
+     * A version of {@link createSymbol} method used from native code.
+     */
+    public static RSymbol createSymbolInterned(String name) {
+        return createSymbol(name.intern());
+    }
+
     public static RLanguage createLanguage(RNode rep) {
         return traceDataCreated(new RLanguage(rep));
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
index 469e9f1c81743281b5f8e24d88eed0a7ff51c733..3fc09939fc4ef6d3f330dd977c41acd5a4c12762 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
@@ -16,6 +16,7 @@ import java.util.*;
 import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.RError.RErrorException;
 import com.oracle.truffle.r.runtime.context.*;
@@ -205,7 +206,8 @@ public class DLL {
     }
 
     public static RExternalPtr createExternalPtr(long value, RStringVector rClass) {
-        RExternalPtr result = RDataFactory.createExternalPtr(value, RDataFactory.createSymbol(rClass.getDataAt(0)));
+        CompilerAsserts.neverPartOfCompilation(); // for interning
+        RExternalPtr result = RDataFactory.createExternalPtr(value, RDataFactory.createSymbol(rClass.getDataAt(0).intern()));
         result.setClassAttr(rClass, false);
         return result;
     }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java
index 46e7b99886ea1873f8af7313995f6da09a56bd13..72532269a0ad6d8c74a90dee7fe06bc28905f495 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java
@@ -38,6 +38,8 @@ public class TestS4 extends TestBase {
         assertEval("{ getClass(\"ClassUnionRepresentation\")@virtual }");
         assertEval("{ getClass(\"ClassUnionRepresentation\")@.S3Class }");
         assertEval("{ c(42)@.Data }");
+        assertEval("{ x<-42; `@`(x, \".Data\") }");
+        assertEval("{ x<-42; `@`(x, .Data) }");
         assertEval(Output.ContainsError, "{ getClass(\"ClassUnionRepresentation\")@foo }");
         assertEval(Output.ContainsError, "{ c(42)@foo }");
         assertEval(Output.ContainsError, "{ x<-c(42); class(x)<-\"bar\"; x@foo }");