diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index 0bcde47bd516ecb2ae9371b672abc9d07dce3440..1d1eab31ccaad035899ede359b5ba5529b639c69 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -76,7 +76,7 @@ public final class REngine implements RContext.Engine {
      * @param crashOnFatalErrorArg if {@code true} any unhandled exception will terminate the
      *            process.
      * @return a {@link VirtualFrame} that can be passed to
-     *         {@link #parseAndEval(String, String, VirtualFrame, REnvironment, boolean, boolean)}
+     *         {@link #parseAndEval(String, String, MaterializedFrame, REnvironment, boolean, boolean)}
      */
     public static VirtualFrame initialize(String[] commandArgs, ConsoleHandler consoleHandler, boolean crashOnFatalErrorArg, boolean headless) {
         singleton.startTime = System.nanoTime();
@@ -101,16 +101,16 @@ public final class REngine implements RContext.Engine {
         ROptions.initialize();
         RProfile.initialize();
         // eval the system profile
-        singleton.parseAndEval("<system_profile>", RProfile.systemProfile(), baseFrame, REnvironment.baseEnv(), false, false);
+        singleton.parseAndEval("<system_profile>", RProfile.systemProfile(), baseFrame.materialize(), REnvironment.baseEnv(), false, false);
         REnvironment.packagesInitialize(RPackages.initialize());
         RPackageVariables.initialize(); // TODO replace with R code
         String siteProfile = RProfile.siteProfile();
         if (siteProfile != null) {
-            singleton.parseAndEval("<site_profile>", siteProfile, baseFrame, REnvironment.baseEnv(), false, false);
+            singleton.parseAndEval("<site_profile>", siteProfile, baseFrame.materialize(), REnvironment.baseEnv(), false, false);
         }
         String userProfile = RProfile.userProfile();
         if (userProfile != null) {
-            singleton.parseAndEval("<user_profile>", userProfile, globalFrame, REnvironment.globalEnv(), false, false);
+            singleton.parseAndEval("<user_profile>", userProfile, globalFrame.materialize(), REnvironment.globalEnv(), false, false);
         }
         return globalFrame;
     }
@@ -119,7 +119,7 @@ public final class REngine implements RContext.Engine {
         return singleton;
     }
 
-    public void loadDefaultPackage(String name, VirtualFrame frame, REnvironment envForFrame) {
+    public void loadDefaultPackage(String name, MaterializedFrame frame, REnvironment envForFrame) {
         RBuiltinPackages.load(name, frame, envForFrame);
     }
 
@@ -135,14 +135,14 @@ public final class REngine implements RContext.Engine {
         return childTimes;
     }
 
-    public Object parseAndEval(String sourceDesc, String rscript, VirtualFrame frame, REnvironment envForFrame, boolean printResult, boolean allowIncompleteSource) {
+    public Object parseAndEval(String sourceDesc, String rscript, MaterializedFrame frame, REnvironment envForFrame, boolean printResult, boolean allowIncompleteSource) {
         return parseAndEvalImpl(new ANTLRStringStream(rscript), Source.asPseudoFile(rscript, sourceDesc), frame, printResult, allowIncompleteSource);
     }
 
     public Object parseAndEvalTest(String rscript, boolean printResult) {
         VirtualFrame frame = RRuntime.createNonFunctionFrame();
         REnvironment.resetForTest(frame);
-        return parseAndEvalImpl(new ANTLRStringStream(rscript), Source.asPseudoFile(rscript, "<test_input>"), frame, printResult, false);
+        return parseAndEvalImpl(new ANTLRStringStream(rscript), Source.asPseudoFile(rscript, "<test_input>"), frame.materialize(), printResult, false);
     }
 
     public class ParseException extends Exception {
@@ -188,7 +188,7 @@ public final class REngine implements RContext.Engine {
         return eval(ffunction, (RNode) expr.getRep(), envir, enclos);
     }
 
-    public Object eval(RExpression expr, VirtualFrame frame) {
+    public Object eval(RExpression expr, MaterializedFrame frame) {
         Object result = null;
         for (int i = 0; i < expr.getLength(); i++) {
             result = expr.getDataAt(i);
@@ -202,7 +202,7 @@ public final class REngine implements RContext.Engine {
 
     private static final String EVAL_FUNCTION_NAME = "<eval wrapper>";
 
-    public Object eval(RLanguage expr, VirtualFrame frame) {
+    public Object eval(RLanguage expr, MaterializedFrame frame) {
         RNode n = expr.getType() == RLanguage.Type.RNODE ? (RNode) expr.getRep() : makeCallNode(expr);
         RootCallTarget callTarget = doMakeCallTarget(n, EVAL_FUNCTION_NAME);
         return runCall(callTarget, frame, false, false);
@@ -219,7 +219,7 @@ public final class REngine implements RContext.Engine {
         for (int i = 0; i < argLength; i++) {
             Object a = expr.getDataAt(i + 1);
             if (a instanceof RSymbol) {
-                args[i] = ReadVariableNode.create(((RSymbol) a).getName(), RRuntime.TYPE_ANY, false, true, false, true);
+                args[i] = ReadVariableNode.create(((RSymbol) a).getName(), RType.Any, false, true, false, true);
             } else if (a instanceof RLanguage) {
                 RLanguage l = (RLanguage) a;
                 if (l.getType() == RLanguage.Type.RNODE) {
@@ -245,7 +245,7 @@ public final class REngine implements RContext.Engine {
         if (expr.getDataAt(0) instanceof RSymbol) {
             RSymbol funcName = (RSymbol) expr.getDataAt(0);
             // TODO: source section?
-            return RCallNode.createCall(null, ReadVariableNode.create(funcName.getName(), RRuntime.TYPE_FUNCTION, false, true, false, true), callArgsNode);
+            return RCallNode.createCall(null, ReadVariableNode.create(funcName.getName(), RType.Function, false, true, false, true), callArgsNode);
         } else {
             return RCallNode.createStaticCall(null, (RFunction) expr.getDataAt(0), callArgsNode);
         }
@@ -281,12 +281,12 @@ public final class REngine implements RContext.Engine {
     private static Object eval(RFunction function, RootCallTarget callTarget, SourceSection callSrc, REnvironment envir, REnvironment enclos) throws PutException {
         MaterializedFrame envFrame = envir.getFrame();
         // Here we create fake frame that wraps the original frame's context and has an only
-        // slightly changed arguments array (functio and callSrc).
-        VirtualFrame vFrame = VirtualEvalFrame.create(envFrame, function, callSrc);
+        // slightly changed arguments array (function and callSrc).
+        MaterializedFrame vFrame = VirtualEvalFrame.create(envFrame, function, callSrc);
         return runCall(callTarget, vFrame, false, false);
     }
 
-    public Object evalPromise(RPromise promise, VirtualFrame frame) throws RError {
+    public Object evalPromise(RPromise promise, MaterializedFrame frame) throws RError {
         return runCall(promise.getClosure().getCallTarget(), frame, false, false);
     }
 
@@ -304,7 +304,7 @@ public final class REngine implements RContext.Engine {
         }
     }
 
-    private static Object parseAndEvalImpl(ANTLRStringStream stream, Source source, VirtualFrame frame, boolean printResult, boolean allowIncompleteSource) {
+    private static Object parseAndEvalImpl(ANTLRStringStream stream, Source source, MaterializedFrame frame, boolean printResult, boolean allowIncompleteSource) {
         try {
             RootCallTarget callTarget = doMakeCallTarget(parseToRNode(stream, source), "<repl wrapper>");
             Object result = runCall(callTarget, frame, printResult, true);
@@ -393,12 +393,12 @@ public final class REngine implements RContext.Engine {
      * {@code frame} will be accessible via {@code newFrame.getArguments()[0]}, and the execution
      * will continue using {@code frame}.
      */
-    private static Object runCall(RootCallTarget callTarget, VirtualFrame frame, boolean printResult, boolean topLevel) {
+    private static Object runCall(RootCallTarget callTarget, MaterializedFrame frame, boolean printResult, boolean topLevel) {
         Object result = null;
         try {
             try {
                 // FIXME: callTargets should only be called via Direct/IndirectCallNode
-                result = callTarget.call(frame.materialize());
+                result = callTarget.call(frame);
             } catch (ControlFlowException cfe) {
                 throw RError.error(RError.Message.NO_LOOP_FOR_BREAK_NEXT);
             }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java
index bf5a5edc9eb0b96da3e592cfd45a4e5ef149cb9b..fcae1da1dd65e5a620ac08624aa57b1b77c4b553 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackage.java
@@ -128,7 +128,7 @@ public abstract class RBuiltinPackage {
     /**
      * Runtime component of the package initialization process.
      */
-    public void loadSources(VirtualFrame frame, REnvironment envForFrame) {
+    public void loadSources(MaterializedFrame frame, REnvironment envForFrame) {
         this.env = envForFrame;
         for (RBuiltinFactory factory : builtins.values()) {
             if (factory.getPackage() == this) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java
index b44c78ab5ae8697b6aeb445ee56cbb696609266e..fee2b189759d8b3fdda6d13a4fcab366d6246889 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java
@@ -67,7 +67,7 @@ public final class RBuiltinPackages implements RBuiltinLookup {
         return packages;
     }
 
-    public static void load(String name, VirtualFrame frame, REnvironment envForFrame) {
+    public static void load(String name, MaterializedFrame frame, REnvironment envForFrame) {
         RBuiltinPackage pkg = packages.get(name);
         if (pkg == null) {
             Utils.fail("unknown default package: " + name);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java
index 80fbba27d9a538679f3f7d724996d66af8fcd62e..b5bb706592adc1819d1d7a4195aff788a0dad312 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java
@@ -30,7 +30,7 @@ import com.oracle.truffle.r.runtime.data.model.*;
 public abstract class AnyDuplicated extends RBuiltinNode {
 
     @Child private CastTypeNode castTypeNode;
-    @Child private Typeof typeof;
+    @Child private TypeofNode typeof;
 
     @Override
     public RNode[] getParameterValues() {
@@ -60,7 +60,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     protected int anyDuplicatedTrueIncomparablesFromStart(VirtualFrame frame, RAbstractVector x, byte incomparables, byte fromLast) {
         initTypeof();
         initCastTypeNode();
-        final String xType = typeof.execute(frame, x);
+        RType xType = typeof.execute(frame, x);
         return getIndexFromStart(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType)));
     }
 
@@ -69,7 +69,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     protected int anyDuplicatedTrueIncomparablesFromLast(VirtualFrame frame, RAbstractVector x, byte incomparables, byte fromLast) {
         initTypeof();
         initCastTypeNode();
-        String xType = typeof.execute(frame, x);
+        RType xType = typeof.execute(frame, x);
         return getIndexFromLast(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType)));
     }
 
@@ -77,7 +77,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     protected int anyDuplicatedFromStart(VirtualFrame frame, RAbstractVector x, RAbstractVector incomparables, @SuppressWarnings("unused") byte fromLast) {
         initTypeof();
         initCastTypeNode();
-        String xType = typeof.execute(frame, x);
+        RType xType = typeof.execute(frame, x);
         return getIndexFromStart(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType)));
     }
 
@@ -85,7 +85,7 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     protected int anyDuplicatedFromLast(VirtualFrame frame, RAbstractVector x, RAbstractVector incomparables, @SuppressWarnings("unused") byte fromLast) {
         initTypeof();
         initCastTypeNode();
-        String xType = typeof.execute(frame, x);
+        RType xType = typeof.execute(frame, x);
         return getIndexFromLast(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType)));
     }
 
@@ -186,14 +186,14 @@ public abstract class AnyDuplicated extends RBuiltinNode {
     private void initCastTypeNode() {
         if (castTypeNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castTypeNode = insert(CastTypeNodeFactory.create(new RNode[2], this.getBuiltin(), this.getSuppliedArgsNames()));
+            castTypeNode = insert(CastTypeNodeFactory.create(null, null));
         }
     }
 
     private void initTypeof() {
         if (typeof == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            typeof = insert(TypeofFactory.create(new RNode[1], this.getBuiltin(), this.getSuppliedArgsNames()));
+            typeof = insert(TypeofNodeFactory.create(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 385b33ba782d31ddd475bd9f840e436d2636cef4..bf50a878b6f3cc2789a9dfb76897f5acc7b013de 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
@@ -113,7 +113,7 @@ public abstract class AsVector extends RBuiltinNode {
 
     @Override
     public RNode[] getParameterValues() {
-        return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(RRuntime.TYPE_ANY)};
+        return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(RType.Any.getName())};
     }
 
     @Specialization
@@ -220,27 +220,27 @@ public abstract class AsVector extends RBuiltinNode {
     }
 
     protected boolean castToInt(RAbstractVector x, String mode) {
-        return x.getElementClass() != RInt.class && RRuntime.TYPE_INTEGER.equals(mode);
+        return x.getElementClass() != RInt.class && RType.Integer.getName().equals(mode);
     }
 
     protected boolean castToDouble(RAbstractVector x, String mode) {
-        return x.getElementClass() != RDouble.class && (RRuntime.TYPE_NUMERIC.equals(mode) || RRuntime.TYPE_DOUBLE.equals(mode));
+        return x.getElementClass() != RDouble.class && (RType.Numeric.getName().equals(mode) || RType.Double.getName().equals(mode));
     }
 
     protected boolean castToComplex(RAbstractVector x, String mode) {
-        return x.getElementClass() != RComplex.class && RRuntime.TYPE_COMPLEX.equals(mode);
+        return x.getElementClass() != RComplex.class && RType.Complex.getName().equals(mode);
     }
 
     protected boolean castToLogical(RAbstractVector x, String mode) {
-        return x.getElementClass() != RLogical.class && RRuntime.TYPE_LOGICAL.equals(mode);
+        return x.getElementClass() != RLogical.class && RType.Logical.getName().equals(mode);
     }
 
     protected boolean castToString(RAbstractVector x, String mode) {
-        return x.getElementClass() != RString.class && RRuntime.TYPE_CHARACTER.equals(mode);
+        return x.getElementClass() != RString.class && RType.Character.getName().equals(mode);
     }
 
     protected boolean castToRaw(RAbstractVector x, String mode) {
-        return x.getElementClass() != RRaw.class && RRuntime.TYPE_RAW.equals(mode);
+        return x.getElementClass() != RRaw.class && RType.Raw.getName().equals(mode);
     }
 
     protected boolean castToList(RAbstractVector x, String mode) {
@@ -264,13 +264,31 @@ public abstract class AsVector extends RBuiltinNode {
     }
 
     protected boolean modeIsAnyOrMatches(RAbstractVector x, String mode) {
-        return RRuntime.TYPE_ANY.equals(mode) || RRuntime.classToString(x.getElementClass()).equals(mode) || x.getElementClass() == RDouble.class && RRuntime.TYPE_DOUBLE.equals(mode);
+        return RType.Any.getName().equals(mode) || RRuntime.classToString(x.getElementClass()).equals(mode) || x.getElementClass() == RDouble.class &&
+                        RType.Double.getName().equals(mode);
     }
 
     protected boolean invalidMode(@SuppressWarnings("unused") RAbstractVector x, String mode) {
-        return !RRuntime.TYPE_ANY.equals(mode) && !RRuntime.TYPE_ARRAY.equals(mode) && !RRuntime.TYPE_CHARACTER.equals(mode) && !RRuntime.TYPE_COMPLEX.equals(mode) &&
-                        !RRuntime.TYPE_DOUBLE.equals(mode) && !RRuntime.TYPE_INTEGER.equals(mode) && !RRuntime.TYPE_LIST.equals(mode) && !RRuntime.TYPE_LOGICAL.equals(mode) &&
-                        !RRuntime.TYPE_MATRIX.equals(mode) && !RRuntime.TYPE_NUMERIC.equals(mode) && !RRuntime.TYPE_RAW.equals(mode) && !RRuntime.TYPE_SYMBOL.equals(mode);
+        RType modeType = RType.fromString(mode);
+        if (modeType == null) {
+            return true;
+        }
+        switch (modeType) {
+            case Any:
+            case Array:
+            case Character:
+            case Complex:
+            case Double:
+            case Integer:
+            case List:
+            case Logical:
+            case Matrix:
+            case Numeric:
+            case Raw:
+            case Symbol:
+                return false;
+            default:
+                return true;
+        }
     }
-
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
index 22203436681c78187f1050d0a52386f5650b8044..c944e1ba0bf7e538663b4ab1a3284115ccb7b5e6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
@@ -116,7 +116,7 @@ public class BrowserFunctions {
                         }
 
                         default:
-                            RContext.getEngine().parseAndEval("<browser_input>", input, frame, callerEnv, true, false);
+                            RContext.getEngine().parseAndEval("<browser_input>", input, frame.materialize(), callerEnv, true, false);
                             break;
                     }
                 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ClassHierarchyNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ClassHierarchyNode.java
index d531c6cbbec956996407382339272c5eea40b5a9..f370150ec0687b0b68c8342ce2b02dd8fc2fc5ff 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ClassHierarchyNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ClassHierarchyNode.java
@@ -39,17 +39,17 @@ public abstract class ClassHierarchyNode extends UnaryNode {
 
     @Specialization
     protected RStringVector getClassHr(@SuppressWarnings("unused") byte arg) {
-        return RDataFactory.createStringVector(RRuntime.TYPE_LOGICAL);
+        return RDataFactory.createStringVector(RType.Logical.getName());
     }
 
     @Specialization
     protected RStringVector getClassHr(@SuppressWarnings("unused") String arg) {
-        return RDataFactory.createStringVector(RRuntime.TYPE_CHARACTER);
+        return RDataFactory.createStringVector(RType.Character.getName());
     }
 
     @Specialization
     protected RStringVector getClassHr(@SuppressWarnings("unused") int arg) {
-        return RDataFactory.createStringVector(RRuntime.TYPE_INTEGER);
+        return RDataFactory.createStringVector(RType.Integer.getName());
     }
 
     @Specialization
@@ -59,17 +59,17 @@ public abstract class ClassHierarchyNode extends UnaryNode {
 
     @Specialization
     protected RStringVector getClassHr(@SuppressWarnings("unused") RComplex arg) {
-        return RDataFactory.createStringVector(RRuntime.TYPE_COMPLEX);
+        return RDataFactory.createStringVector(RType.Complex.getName());
     }
 
     @Specialization
     protected RStringVector getClassHr(@SuppressWarnings("unused") RFunction arg) {
-        return RDataFactory.createStringVector(RRuntime.TYPE_FUNCTION);
+        return RDataFactory.createStringVector(RType.Function.getName());
     }
 
     @Specialization
     protected RStringVector getClassHr(@SuppressWarnings("unused") RNull arg) {
-        return RDataFactory.createStringVector(RRuntime.NULL);
+        return RDataFactory.createStringVector(RType.Null.getName());
     }
 
     @Specialization
@@ -79,12 +79,12 @@ public abstract class ClassHierarchyNode extends UnaryNode {
 
     @Specialization
     protected RStringVector getClassHr(@SuppressWarnings("unused") REnvironment arg) {
-        return RDataFactory.createStringVector(RRuntime.TYPE_ENVIRONMENT);
+        return RDataFactory.createStringVector(RType.Environment.getName());
     }
 
     @Specialization
     protected RStringVector getClassHr(@SuppressWarnings("unused") RPairList arg) {
-        return RDataFactory.createStringVector(RRuntime.TYPE_PAIR_LIST);
+        return RDataFactory.createStringVector(RType.PairList.getName());
     }
 
     @Specialization
@@ -94,7 +94,7 @@ public abstract class ClassHierarchyNode extends UnaryNode {
 
     @Specialization
     protected RStringVector getClassHr(@SuppressWarnings("unused") RFormula arg) {
-        return RDataFactory.createStringVector(RRuntime.TYPE_FORMULA);
+        return RDataFactory.createStringVector(RType.Formula.getName());
     }
 
     @Specialization
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 2afa5567910fcc655244c33a4f46d53ea5965eb3..3e309d464875ae00eff10b3d608c1aabc66d3a3c 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
@@ -53,7 +53,7 @@ public abstract class DoCall extends RBuiltinNode {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 getNode = insert(GetFactory.create(new RNode[5], this.getBuiltin(), getSuppliedArgsNames()));
             }
-            func = (RFunction) getNode.execute(frame, fname.getDataAt(0), 0, RMissing.instance, RRuntime.TYPE_FUNCTION, RRuntime.LOGICAL_TRUE);
+            func = (RFunction) getNode.execute(frame, fname.getDataAt(0), 0, RMissing.instance, RType.Function.getName(), RRuntime.LOGICAL_TRUE);
         }
         Object[] argValues = argsAsList.getDataNonShared();
         Object n = argsAsList.getNames();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EvalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EvalFunctions.java
index 161b1a6d802a37076b0f89db3a3fe38ef770990f..60c52224695001b2fcfa626763825d68cb2f62ba 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EvalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EvalFunctions.java
@@ -109,9 +109,9 @@ public class EvalFunctions {
             Object expr = checkConvertSymbol(exprArg);
 
             if (expr instanceof RExpression) {
-                return RContext.getEngine().eval((RExpression) exprArg, frame);
+                return RContext.getEngine().eval((RExpression) exprArg, frame.materialize());
             } else if (expr instanceof RLanguage) {
-                return RContext.getEngine().eval((RLanguage) exprArg, frame);
+                return RContext.getEngine().eval((RLanguage) exprArg, frame.materialize());
             } else {
                 // just return value
                 return expr;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java
index 5d53dec7ca57eed9b2b9934b5784a66b4e407e21..0cb48cce274cffe1052d4f5bbb5ee46a990d5a2b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java
@@ -46,7 +46,7 @@ public abstract class Exists extends RBuiltinNode {
     @Override
     public RNode[] getParameterValues() {
         return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(-1), ConstantNode.create(RMissing.instance), ConstantNode.create(RMissing.instance),
-                        ConstantNode.create(RRuntime.TYPE_ANY), ConstantNode.create(RRuntime.LOGICAL_TRUE)};
+                        ConstantNode.create(RType.Any.getName()), ConstantNode.create(RRuntime.LOGICAL_TRUE)};
     }
 
     @Specialization(guards = "noEnv")
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Get.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Get.java
index 4039904c06ba2d908833c3afbc432e3f17b7de37..de61197f9840fb65bcfb1fd92b15a85ecb6a7077 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Get.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Get.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.access.*;
 import com.oracle.truffle.r.nodes.builtin.*;
@@ -48,11 +49,13 @@ public abstract class Get extends RBuiltinNode {
     @Child private ReadVariableNode lookUpNoInherit;
 
     @CompilationFinal private String lastX;
-    @CompilationFinal private String lastMode;
+    @CompilationFinal private RType lastMode;
+
+    private final ValueProfile modeProfile = ValueProfile.createIdentityProfile();
 
     @Override
     public RNode[] getParameterValues() {
-        return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(-1), ConstantNode.create(RMissing.instance), ConstantNode.create(RRuntime.TYPE_ANY),
+        return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(-1), ConstantNode.create(RMissing.instance), ConstantNode.create(RType.Any.getName()),
                         ConstantNode.create(RRuntime.LOGICAL_TRUE)};
     }
 
@@ -64,10 +67,11 @@ public abstract class Get extends RBuiltinNode {
         controlVisibility();
         boolean doesInherit = inherits == RRuntime.LOGICAL_TRUE;
         ReadVariableNode lookup = null;
+        RType modeType = RType.fromString(modeProfile.profile(mode));
         if (doesInherit) {
-            lookup = lookUpInherit = setLookUp(lookUpInherit, x, mode, doesInherit);
+            lookup = lookUpInherit = setLookUp(lookUpInherit, x, modeType, doesInherit);
         } else {
-            lookup = lookUpNoInherit = setLookUp(lookUpNoInherit, x, mode, doesInherit);
+            lookup = lookUpNoInherit = setLookUp(lookUpNoInherit, x, modeType, doesInherit);
         }
         try {
             // FIXME: this will not compile, since lookup is not compilation final
@@ -77,7 +81,7 @@ public abstract class Get extends RBuiltinNode {
         }
     }
 
-    private ReadVariableNode setLookUp(ReadVariableNode lookup, final String x, final String mode, boolean inherits) {
+    private ReadVariableNode setLookUp(ReadVariableNode lookup, String x, RType mode, boolean inherits) {
         if (lookup == null || !lastX.equals(x) || !lastMode.equals(mode)) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             lastX = x;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java
index ed43d6d3c73ed2fdac3e3ecf1c737ae114b8629c..ce1a8f5c759fee1c9cd2cfd5c75592d485ab9588 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java
@@ -33,8 +33,8 @@ public abstract class GetClass extends RBuiltinNode {
     protected Object getClass(RAbstractContainer arg) {
         controlVisibility();
         final String klass = arg.getClassHierarchy().getDataAt(0);
-        if (klass.equals(RRuntime.TYPE_DOUBLE)) {
-            return RRuntime.TYPE_NUMERIC;
+        if (klass.equals(RType.Double.getName())) {
+            return RType.Numeric.getName();
         }
         return klass;
     }
@@ -42,19 +42,19 @@ public abstract class GetClass extends RBuiltinNode {
     @Specialization
     protected Object getClass(@SuppressWarnings("unused") RFunction arg) {
         controlVisibility();
-        return RRuntime.TYPE_FUNCTION;
+        return RType.Function.getName();
     }
 
     @Specialization
     protected Object getClass(@SuppressWarnings("unused") RFormula arg) {
         controlVisibility();
-        return RRuntime.TYPE_FORMULA;
+        return RType.Formula.getName();
     }
 
     @Specialization
     protected Object getClass(@SuppressWarnings("unused") RNull arg) {
         controlVisibility();
-        return RRuntime.NULL;
+        return RType.Null.getName();
     }
 
     @Specialization
@@ -66,13 +66,13 @@ public abstract class GetClass extends RBuiltinNode {
     @Specialization
     protected Object getClass(@SuppressWarnings("unused") REnvironment arg) {
         controlVisibility();
-        return RRuntime.TYPE_ENVIRONMENT;
+        return RType.Environment.getName();
     }
 
     @Specialization
     protected Object getClass(@SuppressWarnings("unused") RPairList arg) {
         controlVisibility();
-        return RRuntime.TYPE_PAIR_LIST;
+        return RType.PairList.getName();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Inherits.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Inherits.java
index ee76945f9a6c339a9a0b0db782beca17c3ca7261..ace4a566e42167ccaa76df6f7186d025b669e3a3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Inherits.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Inherits.java
@@ -40,7 +40,7 @@ public abstract class Inherits extends RBuiltinNode {
 
     private InheritsNode initInheritsNode() {
         if (inheritsNode == null) {
-            inheritsNode = insert(InheritsNodeFactory.create(new RNode[3], getBuiltin(), getSuppliedArgsNames()));
+            inheritsNode = insert(InheritsNodeFactory.create(null, null));
         }
         return inheritsNode;
     }
@@ -83,5 +83,4 @@ public abstract class Inherits extends RBuiltinNode {
         }
         return RDataFactory.createIntVector(result, true);
     }
-
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsVector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsVector.java
index 43cddc24f05d25e709632d11708f56546e7a9755..2d4e3038719f2a7d18367427f2bb80ac16de0950 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsVector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsVector.java
@@ -38,7 +38,7 @@ public abstract class IsVector extends RBuiltinNode {
     @Override
     public RNode[] getParameterValues() {
         // x, mode = "any"
-        return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(RRuntime.TYPE_ANY)};
+        return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(RType.Any.getName())};
     }
 
     @SuppressWarnings("unused")
@@ -108,8 +108,8 @@ public abstract class IsVector extends RBuiltinNode {
     }
 
     protected boolean modeIsAnyOrMatches(RAbstractVector x, String mode) {
-        return RRuntime.TYPE_ANY.equals(mode) || RRuntime.classToString(x.getElementClass()).equals(mode) || (x.getElementClass() == RDouble.class && RRuntime.TYPE_DOUBLE.equals(mode)) ||
-                        (x.getElementClass() == Object.class && mode.equals("list"));
+        return RType.Any.getName().equals(mode) || RRuntime.classToString(x.getElementClass()).equals(mode) ||
+                        (x.getElementClass() == RDouble.class && RType.Double.getName().equals(mode)) || (x.getElementClass() == Object.class && mode.equals("list"));
     }
 
 }
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 08df1920aec58784595a6839647ae19240f7eba5..bf9aed45827e3bce6416faa06f21952fe6c3e129 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
@@ -61,7 +61,7 @@ public abstract class MatchFun extends RBuiltinNode {
         if (lookup == null || !fun.equals(lastFun)) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             lastFun = fun;
-            ReadVariableNode rvn = ReadVariableNode.create(fun, RRuntime.TYPE_FUNCTION, false);
+            ReadVariableNode rvn = ReadVariableNode.create(fun, RType.Function, false);
             lookup = lookup == null ? insert(rvn) : lookup.replace(rvn);
         }
         Object r = lookup.execute(frame);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
index 11ae34c61c7d1e1b56019b1b1b4420f6117c6578..46d851c7e3bbceb2b53c4de85b35251ca315f8a9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
@@ -52,7 +52,7 @@ public abstract class Order extends RBuiltinNode {
     @Child private BooleanOperation ge = BinaryCompare.GREATER_EQUAL.create();
     @Child private BooleanOperation gt = BinaryCompare.GREATER_THAN.create();
 
-    // specialisations for one parameter
+    // specializations for one parameter
 
     @SuppressWarnings("unused")
     @Specialization(guards = "empty")
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java
index 7a3f604e6a088676f8c8bd67d518b3c4c98ba437..d0abc49bdc61b8380aac1814e83e492e0f543e1b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java
@@ -42,7 +42,7 @@ public abstract class Typeof extends RBuiltinNode {
         if (typeofNode == null) {
             typeofNode = insert(TypeofNodeFactory.create(null));
         }
-        return typeofNode.execute(frame, obj);
+        return typeofNode.execute(frame, obj).getName();
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
index a827d3ec661d9b73a4fdaea2ba5f84d6efdf6a96..757ab8996c4ef6ce69cf1c00845e72484b778a72 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
@@ -16,7 +16,7 @@ import static com.oracle.truffle.r.runtime.RBuiltinKind.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.r.nodes.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.r.nodes.binary.*;
 import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.nodes.unary.*;
@@ -30,7 +30,9 @@ public abstract class UpdateClass extends RBuiltinNode {
 
     @Child private CastTypeNode castTypeNode;
     @Child private CastStringNode castStringNode;
-    @Child private Typeof typeof;
+    @Child private TypeofNode typeof;
+
+    private final ValueProfile modeProfile = ValueProfile.createIdentityProfile();
 
     public abstract Object execute(VirtualFrame frame, RAbstractContainer vector, Object o);
 
@@ -60,19 +62,22 @@ public abstract class UpdateClass extends RBuiltinNode {
         controlVisibility();
         initTypeof();
         if (!arg.isObject()) {
-            final String argType = this.typeof.execute(frame, arg);
-            if (argType.equals(className) || (className.equals(RRuntime.TYPE_NUMERIC) && (argType.equals(RRuntime.TYPE_INTEGER) || (argType.equals(RRuntime.TYPE_DOUBLE))))) {
+            RType argType = this.typeof.execute(frame, arg);
+            if (argType.equals(className) || (RType.Numeric.getName().equals(className) && (argType == RType.Integer || argType == RType.Double))) {
                 // "explicit" attribute might have been set (e.g. by oldClass<-)
                 return setClass(arg, RNull.instance);
             }
         }
         initCastTypeNode();
-        Object result = castTypeNode.execute(frame, arg, className);
-        if (result != null) {
-            return setClass((RAbstractVector) result, RNull.instance);
+        RType mode = RType.fromString(modeProfile.profile(className));
+        if (mode != null) {
+            Object result = castTypeNode.execute(frame, arg, mode);
+            if (result != null) {
+                return setClass((RAbstractVector) result, RNull.instance);
+            }
         }
         RVector resultVector = arg.materializeNonSharedVector();
-        if (className.equals(RRuntime.TYPE_MATRIX)) {
+        if (RType.Matrix.getName().equals(className)) {
             if (resultVector.isMatrix()) {
                 return setClass(resultVector, RNull.instance);
             }
@@ -83,7 +88,7 @@ public abstract class UpdateClass extends RBuiltinNode {
             }
             throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_A_MATRIX_UPDATE_CLASS, dimLength);
         }
-        if (className.equals(RRuntime.TYPE_ARRAY)) {
+        if (RType.Array.getName().equals(className)) {
             if (resultVector.isArray()) {
                 return setClass(resultVector, RNull.instance);
             }
@@ -108,14 +113,14 @@ public abstract class UpdateClass extends RBuiltinNode {
     private void initCastTypeNode() {
         if (castTypeNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castTypeNode = insert(CastTypeNodeFactory.create(new RNode[2], this.getBuiltin(), getSuppliedArgsNames()));
+            castTypeNode = insert(CastTypeNodeFactory.create(null, null));
         }
     }
 
     private void initTypeof() {
         if (typeof == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            typeof = insert(TypeofFactory.create(new RNode[1], this.getBuiltin(), getSuppliedArgsNames()));
+            typeof = insert(TypeofNodeFactory.create(null));
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
index ff6ea8301fbe18bf624c2c642f0aac5fd03c0d97..d012a8377d630e8a07870ee7cda9855d81e1fd02 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
@@ -42,7 +42,6 @@ public abstract class UpdateOldClass extends RInvisibleBuiltinNode {
 
     @Child private CastTypeNode castTypeNode;
     @Child private CastStringNode castStringNode;
-    @Child private Typeof typeof;
 
     public abstract Object execute(VirtualFrame frame, RAbstractContainer vector, Object o);
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
index 7d20af25894fe8afef70ed3e09b0fa27d718bdfc..04fd3d3bd5efaf088da9fe841f9bc274410b5a84 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
@@ -16,7 +16,7 @@ import static com.oracle.truffle.r.runtime.RBuiltinKind.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.r.nodes.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.r.nodes.binary.*;
 import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.nodes.unary.*;
@@ -28,19 +28,27 @@ import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute;
 // 2nd parameter is "value", but should not be matched against, so ""
 public abstract class UpdateStorageMode extends RBuiltinNode {
 
-    @Child private Typeof typeof;
+    @Child private TypeofNode typeof;
     @Child private CastTypeNode castTypeNode;
     @Child private IsFactorNode isFactor;
 
-    @Specialization(guards = {"!isReal", "!isSingle"})
-    protected Object update(VirtualFrame frame, final Object x, final String value) {
+    private final ValueProfile modeProfile = ValueProfile.createIdentityProfile();
+    private final BranchProfile errorProfile = new BranchProfile();
+
+    @Specialization
+    protected Object update(VirtualFrame frame, Object x, String value) {
         controlVisibility();
+        RType mode = RType.fromString(modeProfile.profile(value));
+        if (mode == RType.DefunctReal || mode == RType.DefunctSingle) {
+            errorProfile.enter();
+            throw RError.error(getEncapsulatingSourceSection(), RError.Message.USE_DEFUNCT, mode.getName(), mode == RType.DefunctSingle ? "mode<-" : "double");
+        }
         if (typeof == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            typeof = insert(TypeofFactory.create(new RNode[1], this.getBuiltin(), getSuppliedArgsNames()));
+            typeof = insert(TypeofNodeFactory.create(null));
         }
-        String typeX = typeof.execute(frame, x);
-        if (typeX.equals(value)) {
+        RType typeX = typeof.execute(frame, x);
+        if (typeX == mode) {
             return x;
         }
         if (isFactor == null) {
@@ -48,59 +56,37 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
             isFactor = insert(IsFactorNodeFactory.create(null));
         }
         if (isFactor.execute(frame, x) == RRuntime.LOGICAL_TRUE) {
+            errorProfile.enter();
             throw RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_STORAGE_MODE_UPDATE);
         }
         if (castTypeNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castTypeNode = insert(CastTypeNodeFactory.create(new RNode[2], this.getBuiltin(), getSuppliedArgsNames()));
+            castTypeNode = insert(CastTypeNodeFactory.create(null, null));
         }
-        Object result = castTypeNode.execute(frame, x, value);
-        if (result == null) {
-            throw RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_UNNAMED_VALUE);
-        } else {
-            if (x instanceof RAttributable && result instanceof RAttributable) {
-                RAttributable rx = (RAttributable) x;
-                RAttributes attrs = rx.getAttributes();
-                if (attrs != null) {
-                    RAttributable rresult = (RAttributable) result;
-                    for (RAttribute attr : attrs) {
-                        rresult.setAttr(attr.getName(), attr.getValue());
+        if (mode != null) {
+            Object result = castTypeNode.execute(frame, x, mode);
+            if (result != null) {
+                if (x instanceof RAttributable && result instanceof RAttributable) {
+                    RAttributable rx = (RAttributable) x;
+                    RAttributes attrs = rx.getAttributes();
+                    if (attrs != null) {
+                        RAttributable rresult = (RAttributable) result;
+                        for (RAttribute attr : attrs) {
+                            rresult.setAttr(attr.getName(), attr.getValue());
+                        }
                     }
                 }
+                return result;
             }
-            return result;
         }
-    }
-
-    @SuppressWarnings("unused")
-    @Specialization(guards = "isReal")
-    protected Object updateReal(final Object x, final String value) {
-        controlVisibility();
-        throw RError.error(getEncapsulatingSourceSection(), RError.Message.USE_DEFUNCT, RRuntime.REAL, RRuntime.TYPE_DOUBLE);
-    }
-
-    @SuppressWarnings("unused")
-    @Specialization(guards = "isSingle")
-    protected Object updateSingle(final Object x, final String value) {
-        controlVisibility();
-        throw RError.error(getEncapsulatingSourceSection(), RError.Message.USE_DEFUNCT, RRuntime.SINGLE, "mode<-");
+        errorProfile.enter();
+        throw RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_UNNAMED_VALUE);
     }
 
     @SuppressWarnings("unused")
     @Specialization
-    protected Object update(final Object x, final Object value) {
+    protected Object update(Object x, Object value) {
         controlVisibility();
         throw RError.error(getEncapsulatingSourceSection(), RError.Message.NULL_VALUE);
     }
-
-    @SuppressWarnings("unused")
-    protected static boolean isReal(VirtualFrame frame, final Object x, final String value) {
-        return value.equals(RRuntime.REAL);
-    }
-
-    @SuppressWarnings("unused")
-    protected static boolean isSingle(VirtualFrame frame, final Object x, final String value) {
-        return value.equals(RRuntime.SINGLE);
-    }
-
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
index c9aefe05deb50857b46ba0671613d06905f0ad87..a86cc41c076bb2d8b3d2560e9848cce0b913b807 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
@@ -41,7 +41,7 @@ public abstract class Vector extends RBuiltinNode {
     @Override
     public RNode[] getParameterValues() {
         // mode = "logical", length = 0
-        return new RNode[]{ConstantNode.create(RRuntime.TYPE_LOGICAL), ConstantNode.create(0)};
+        return new RNode[]{ConstantNode.create(RType.Logical.getName()), ConstantNode.create(0)};
     }
 
     @CreateCast("arguments")
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RNode.java
index 71dc38c262cff8bbeb7693240728322b875e8a85..261a69b958f4e6f901aa0b54e1cc0bc0194b5bac 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RNode.java
@@ -186,6 +186,10 @@ public abstract class RNode extends Node {
         return RTypesGen.RTYPES.expectRArgsValuesAndNames(execute(frame));
     }
 
+    public RType executeType(VirtualFrame frame) throws UnexpectedResultException {
+        return RTypesGen.RTYPES.expectRType(execute(frame));
+    }
+
     public static boolean areSameLength(RAbstractVector a, RAbstractVector b) {
         return a.getLength() == b.getLength();
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java
index 0f9380af67ba62f9494ad673ba2050909cd71778..80abf3dc166203103feda17ca0f92647654f75c8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTruffleVisitor.java
@@ -125,7 +125,7 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> {
             if (!FastROptions.DisableGroupGenerics.getValue() && RGroupGenerics.getGroup(functionName) != null) {
                 return DispatchedCallNode.create(functionName, RGroupGenerics.RDotGroup, callSource, aCallArgNode);
             }
-            return RCallNode.createCall(callSource, ReadVariableNode.create(functionName, RRuntime.TYPE_FUNCTION, false, true, false, true), aCallArgNode);
+            return RCallNode.createCall(callSource, ReadVariableNode.create(functionName, RType.Function, false, true, false, true), aCallArgNode);
         } else {
             RNode lhs = call.getLhsNode().accept(this);
             return RCallNode.createCall(callSource, lhs, aCallArgNode);
@@ -408,12 +408,12 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> {
             String vSymbol = RRuntime.toString(varAST.getVariable());
 
             RNode[] seq = createReplacementSequence();
-            ReadVariableNode v = isSuper ? ReadVariableSuperMaterializedNode.create(varAST.getSource(), vSymbol, RRuntime.TYPE_ANY) : ReadVariableNode.create(varAST.getSource(), vSymbol,
-                            RRuntime.TYPE_ANY, varAST.shouldCopyValue());
+            ReadVariableNode v = isSuper ? ReadVariableSuperMaterializedNode.create(varAST.getSource(), vSymbol, RType.Any) : ReadVariableNode.create(varAST.getSource(), vSymbol,
+                            RType.Any, varAST.shouldCopyValue());
             final Object rhsSymbol = constructReplacementPrefix(seq, rhs, v, WriteVariableNode.Mode.INVISIBLE);
             String rhsSymbolString = RRuntime.toString(rhsSymbol);
-            RNode rhsAccess = ReadVariableNode.create(null, rhsSymbolString, RRuntime.TYPE_ANY, false);
-            RNode tmpVarAccess = ReadVariableNode.create(null, varSymbol, RRuntime.TYPE_ANY, false);
+            RNode rhsAccess = ReadVariableNode.create(null, rhsSymbolString, RType.Any, false);
+            RNode tmpVarAccess = ReadVariableNode.create(null, varSymbol, RType.Any, false);
 
             RNode positions = createPositions(a.getArguments(), argLength, a.isSubset(), true);
             CoerceVector coerceVector = CoerceVectorFactory.create(null, null, null);
@@ -430,8 +430,8 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> {
             String vSymbol = RRuntime.toString(varAST.getVariable());
             RNode[] seq = new RNode[3];
 
-            ReadVariableNode v = isSuper ? ReadVariableSuperMaterializedNode.create(varAST.getSource(), vSymbol, RRuntime.TYPE_ANY) : ReadVariableNode.create(varAST.getSource(), vSymbol,
-                            RRuntime.TYPE_ANY, varAST.shouldCopyValue());
+            ReadVariableNode v = isSuper ? ReadVariableSuperMaterializedNode.create(varAST.getSource(), vSymbol, RType.Any) : ReadVariableNode.create(varAST.getSource(), vSymbol,
+                            RType.Any, varAST.shouldCopyValue());
             final Object rhsSymbol = constructReplacementPrefix(seq, rhs, v, WriteVariableNode.Mode.INVISIBLE);
 
             RNode rhsAccess = AccessVariable.create(null, rhsSymbol).accept(this);
@@ -447,12 +447,12 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> {
 
             String vSymbol = RRuntime.toString(varAST.getVariable());
             RNode[] seq = createReplacementSequence();
-            ReadVariableNode v = isSuper ? ReadVariableSuperMaterializedNode.create(varAST.getSource(), vSymbol, RRuntime.TYPE_ANY) : ReadVariableNode.create(varAST.getSource(), vSymbol,
-                            RRuntime.TYPE_ANY, varAST.shouldCopyValue());
+            ReadVariableNode v = isSuper ? ReadVariableSuperMaterializedNode.create(varAST.getSource(), vSymbol, RType.Any) : ReadVariableNode.create(varAST.getSource(), vSymbol,
+                            RType.Any, varAST.shouldCopyValue());
             final Object rhsSymbol = constructReplacementPrefix(seq, rhs, v, WriteVariableNode.Mode.INVISIBLE);
             String rhsSymbolString = RRuntime.toString(rhsSymbol);
-            RNode rhsAccess = ReadVariableNode.create(null, rhsSymbolString, RRuntime.TYPE_ANY, false);
-            RNode tmpVarAccess = ReadVariableNode.create(null, varSymbol, RRuntime.TYPE_ANY, false);
+            RNode rhsAccess = ReadVariableNode.create(null, rhsSymbolString, RType.Any, false);
+            RNode tmpVarAccess = ReadVariableNode.create(null, varSymbol, RType.Any, false);
             UpdateFieldNode ufn = UpdateFieldNodeFactory.create(tmpVarAccess, rhsAccess, RRuntime.toString(accessAST.getFieldName()));
             RNode assignFromTemp = WriteVariableNode.create(vSymbol, ufn, false, isSuper, WriteVariableNode.Mode.TEMP);
             return constructReplacementSuffix(seq, assignFromTemp, rhsSymbol, source);
@@ -560,21 +560,21 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> {
         SourceSection argSourceSection = simpleAccessVariable.getSource();
         boolean replacementInSuperEnvironment = replacement.isSuper();
         if (replacementInSuperEnvironment) {
-            return ReadVariableSuperMaterializedNode.create(argSourceSection, variableSymbol, RRuntime.TYPE_ANY);
+            return ReadVariableSuperMaterializedNode.create(argSourceSection, variableSymbol, RType.Any);
         } else {
-            return ReadVariableNode.create(argSourceSection, variableSymbol, RRuntime.TYPE_ANY, simpleAccessVariable.shouldCopyValue());
+            return ReadVariableNode.create(argSourceSection, variableSymbol, RType.Any, simpleAccessVariable.shouldCopyValue());
         }
     }
 
     @Override
     public RNode visit(SimpleAccessVariable n) {
-        return ReadVariableNode.create(n.getSource(), RRuntime.toString(n.getVariable()), RRuntime.TYPE_ANY, n.shouldCopyValue());
+        return ReadVariableNode.create(n.getSource(), RRuntime.toString(n.getVariable()), RType.Any, n.shouldCopyValue());
     }
 
     @Override
     public RNode visit(SimpleAccessTempVariable n) {
         String symbol = RRuntime.toString(n.getSymbol());
-        return ReadVariableNode.create(n.getSource(), symbol, RRuntime.TYPE_ANY, false);
+        return ReadVariableNode.create(n.getSource(), symbol, RType.Any, false);
     }
 
     @Override
@@ -639,12 +639,12 @@ public final class RTruffleVisitor extends BasicVisitor<RNode> {
         String vSymbol = RRuntime.toString(varAST.getVariable());
 
         RNode[] seq = createReplacementSequence();
-        ReadVariableNode v = isSuper ? ReadVariableSuperMaterializedNode.create(varAST.getSource(), vSymbol, RRuntime.TYPE_ANY) : ReadVariableNode.create(varAST.getSource(), vSymbol,
-                        RRuntime.TYPE_ANY, varAST.shouldCopyValue());
+        ReadVariableNode v = isSuper ? ReadVariableSuperMaterializedNode.create(varAST.getSource(), vSymbol, RType.Any) : ReadVariableNode.create(varAST.getSource(), vSymbol,
+                        RType.Any, varAST.shouldCopyValue());
         final Object rhsSymbol = constructReplacementPrefix(seq, rhs, v, WriteVariableNode.Mode.INVISIBLE);
         String rhsSymbolString = RRuntime.toString(rhsSymbol);
-        RNode rhsAccess = ReadVariableNode.create(null, rhsSymbolString, RRuntime.TYPE_ANY, false);
-        RNode tmpVarAccess = ReadVariableNode.create(null, varSymbol, RRuntime.TYPE_ANY, false);
+        RNode rhsAccess = ReadVariableNode.create(null, rhsSymbolString, RType.Any, false);
+        RNode tmpVarAccess = ReadVariableNode.create(null, varSymbol, RType.Any, false);
         UpdateFieldNode ufn = UpdateFieldNodeFactory.create(tmpVarAccess, rhsAccess, RRuntime.toString(a.getFieldName()));
         RNode assignFromTemp = WriteVariableNode.create(vSymbol, ufn, false, isSuper, WriteVariableNode.Mode.TEMP);
         return constructReplacementSuffix(seq, assignFromTemp, rhsSymbol, source);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTypes.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTypes.java
index 6eeb3dba4e13a0a62de5769200ae70ec89e4bfca..d0821bb7656b96ab4b153cf6d08ffcb9c180c96d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTypes.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RTypes.java
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.env.*;
                 RRawVector.class, RComplexVector.class, RStringVector.class, RLogicalVector.class, RFunction.class, RNull.class, RMissing.class, REnvironment.class, RExpression.class,
                 RConnection.class, MaterializedFrame.class, FrameSlot.class, RAbstractIntVector.class, RAbstractDoubleVector.class, RAbstractLogicalVector.class, RAbstractComplexVector.class,
                 RAbstractStringVector.class, RAbstractRawVector.class, RList.class, RAbstractVector.class, RDataFrame.class, RSymbol.class, RPromise.class, RLanguage.class, RPairList.class,
-                RFormula.class, RAbstractContainer.class, RArgsValuesAndNames.class, Object[].class})
+                RFormula.class, RAbstractContainer.class, RArgsValuesAndNames.class, RType.class, Object[].class})
 public class RTypes {
 
     @TypeCheck
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java
index d5e176d410190949345ff917c51fbe0685ed9ce9..459d561dd67f22015688df781b5bfd49566061d3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java
@@ -54,10 +54,10 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
     /**
      * Convenience method
      *
-     * @return {@link #create(String, String, boolean, boolean)}
+     * @return {@link #create(String, RType, boolean, boolean)}
      */
     public static ReadVariableNode create(String symbol, boolean shouldCopyValue) {
-        return create(symbol, RRuntime.TYPE_ANY, shouldCopyValue);
+        return create(symbol, RType.Any, shouldCopyValue);
     }
 
     /**
@@ -72,9 +72,9 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
     /**
      * Convenience method
      *
-     * @return {@link #create(String, String, boolean, boolean)}
+     * @return {@link #create(String, RType, boolean, boolean)}
      */
-    public static ReadVariableNode create(SourceSection src, String symbol, String mode, boolean shouldCopyValue) {
+    public static ReadVariableNode create(SourceSection src, String symbol, RType mode, boolean shouldCopyValue) {
         ReadVariableNode rvn = create(symbol, mode, shouldCopyValue);
         rvn.assignSourceSection(src);
         return rvn;
@@ -83,9 +83,9 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
     /**
      * Convenience method
      *
-     * @return {@link #create(String, String, boolean, boolean)}
+     * @return {@link #create(String, RType, boolean, boolean)}
      */
-    public static ReadVariableNode create(String symbol, String mode, boolean shouldCopyValue) {
+    public static ReadVariableNode create(String symbol, RType mode, boolean shouldCopyValue) {
         return create(symbol, mode, shouldCopyValue, true);
     }
 
@@ -93,7 +93,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
      * @return #create(String, String, boolean, boolean, boolean, boolean), where readMissing and
      *         forcePromise are set to {@code false}
      */
-    public static ReadVariableNode create(String symbolStr, String mode, boolean shouldCopyValue, boolean isSuper) {
+    public static ReadVariableNode create(String symbolStr, RType mode, boolean shouldCopyValue, boolean isSuper) {
         return create(symbolStr, mode, shouldCopyValue, isSuper, false, false);
     }
 
@@ -109,7 +109,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
      * @param forcePromise Whether to force {@link RPromise} for type-checking or not
      * @return The appropriate implementation of {@link ReadVariableNode}
      */
-    public static ReadVariableNode create(String symbolStr, String mode, boolean shouldCopyValue, boolean isSuper, boolean readMissing, boolean forcePromise) {
+    public static ReadVariableNode create(String symbolStr, RType mode, boolean shouldCopyValue, boolean isSuper, boolean readMissing, boolean forcePromise) {
         Symbol symbol = Symbol.create(symbolStr);
 
         ReadVariableNode rvn = null;
@@ -144,13 +144,13 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
      * @param forcePromise Whether a promise should be forced to check its type or not
      * @return see above
      */
-    protected boolean checkType(VirtualFrame frame, Object objArg, String type, boolean readMissing, boolean forcePromise) {
+    protected boolean checkType(VirtualFrame frame, Object objArg, RType type, boolean readMissing, boolean forcePromise) {
         Object obj = objArg;
         if (obj == RMissing.instance && !readMissing && !getSymbol().isVarArg()) {
             SourceSection callSrc = RArguments.getCallSourceSection(frame);
             throw RError.error(callSrc, RError.Message.ARGUMENT_MISSING, getSymbol());
         }
-        if (type.equals(RRuntime.TYPE_ANY)) {
+        if (type == RType.Any) {
             return true;
         }
         if (obj instanceof RPromise) {
@@ -167,16 +167,16 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
                 obj = promise.getValue();
             }
         }
-        if (type.equals(RRuntime.TYPE_FUNCTION) || type.equals(RRuntime.TYPE_CLOSURE) || type.equals(RRuntime.TYPE_BUILTIN) || type.equals(RRuntime.TYPE_SPECIAL)) {
+        if (type == RType.Function || type == RType.Closure || type == RType.Builtin || type == RType.Special) {
             return obj instanceof RFunction;
         }
-        if (type.equals(RRuntime.TYPE_CHARACTER)) {
+        if (type == RType.Character) {
             return obj instanceof String;
         }
-        if (type.equals(RRuntime.TYPE_LOGICAL)) {
+        if (type == RType.Logical) {
             return obj instanceof Byte;
         }
-        if (type.equals(RRuntime.TYPE_INTEGER) || type.equals(RRuntime.TYPE_DOUBLE) || type.equals(RRuntime.TYPE_NUMERIC)) {
+        if (type == RType.Integer || type == RType.Double || type == RType.Numeric) {
             return obj instanceof Integer || obj instanceof Double;
         }
         return false;
@@ -243,7 +243,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
     }
 
     private interface HasMode {
-        String getMode();
+        RType getMode();
     }
 
     public static final class UnresolvedReadVariableNode extends ReadVariableNode implements HasMode {
@@ -252,7 +252,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         // readMissing, forcePromise, copyValue) into a single class to reduce clutter and
         // repetition throughout RVN hierarchy
         private final Symbol symbol;
-        private final String mode;
+        private final RType mode;
         private final boolean readMissing;
         private final boolean forcePromise;
 
@@ -267,7 +267,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
             copyValue = c;
         }
 
-        public UnresolvedReadVariableNode(Symbol symbol, String mode, boolean readMissing, boolean forcePromise, boolean copyValue) {
+        public UnresolvedReadVariableNode(Symbol symbol, RType mode, boolean readMissing, boolean forcePromise, boolean copyValue) {
             this.symbol = symbol;
             this.mode = mode;
             this.readMissing = readMissing;
@@ -335,7 +335,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         }
 
         @Override
-        public String getMode() {
+        public RType getMode() {
             return mode;
         }
     }
@@ -384,11 +384,11 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
 
         @Child private ReadLocalVariableNode readNode;
         @Child private ReadVariableNode nextNode;
-        private final String mode;
+        private final RType mode;
         private final boolean readMissing;
         private final boolean forcePromise;
 
-        ReadVariableVirtualNode(ReadLocalVariableNode readNode, ReadVariableNode nextNode, String mode, boolean readMissing, boolean forcePromise) {
+        ReadVariableVirtualNode(ReadLocalVariableNode readNode, ReadVariableNode nextNode, RType mode, boolean readMissing, boolean forcePromise) {
             this.readNode = readNode;
             this.nextNode = nextNode;
             this.mode = mode;
@@ -420,19 +420,19 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         }
 
         @Override
-        public String getMode() {
+        public RType getMode() {
             return mode;
         }
     }
 
     public static final class UnResolvedReadLocalVariableNode extends ReadVariableNode implements HasMode {
         private final Symbol symbol;
-        private final String mode;
+        private final RType mode;
         private final boolean readMissing;
         private final boolean forcePromise;
         @Child private ReadLocalVariableNode node;
 
-        UnResolvedReadLocalVariableNode(final Symbol symbol, final String mode, boolean readMissing, boolean forcePromise) {
+        UnResolvedReadLocalVariableNode(Symbol symbol, RType mode, boolean readMissing, boolean forcePromise) {
             this.symbol = symbol;
             this.mode = mode;
             this.readMissing = readMissing;
@@ -466,7 +466,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         }
 
         @Override
-        public String getMode() {
+        public RType getMode() {
             return mode;
         }
     }
@@ -491,7 +491,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
             throw new UnsupportedOperationException();
         }
 
-        public static ReadVariableNode create(SourceSection src, String symbolStr, String mode) {
+        public static ReadVariableNode create(SourceSection src, String symbolStr, RType mode) {
             Symbol symbol = Symbol.create(symbolStr);
             ReadVariableNode rvn = new UnresolvedReadVariableNode(symbol, mode, false, false, false);
             rvn.assignSourceSection(src);
@@ -508,13 +508,13 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
 
         @Child private ReadSuperVariableNode readNode;
         @Child private ReadVariableNode nextNode;
-        private final String mode;
+        private final RType mode;
         private final boolean readMissing;
         private final boolean forcePromise;
 
         private final ValueProfile frameTypeProfile = ValueProfile.createClassProfile();
 
-        ReadVariableMaterializedNode(ReadSuperVariableNode readNode, ReadVariableNode nextNode, boolean readMissing, boolean forcePromise, String mode) {
+        ReadVariableMaterializedNode(ReadSuperVariableNode readNode, ReadVariableNode nextNode, boolean readMissing, boolean forcePromise, RType mode) {
             this.readNode = readNode;
             this.nextNode = nextNode;
             this.mode = mode;
@@ -547,7 +547,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         }
 
         @Override
-        public String getMode() {
+        public RType getMode() {
             return mode;
         }
     }
@@ -663,7 +663,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         }
     }
 
-    @NodeFields({@NodeField(name = "symbol", type = Symbol.class), @NodeField(name = "mode", type = String.class), @NodeField(name = "readMissing", type = Boolean.class),
+    @NodeFields({@NodeField(name = "symbol", type = Symbol.class), @NodeField(name = "mode", type = RType.class), @NodeField(name = "readMissing", type = Boolean.class),
                     @NodeField(name = "forcePromise", type = Boolean.class)})
     public abstract static class UnknownVariableNode extends ReadVariableNode implements HasMode {
 
@@ -671,7 +671,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         public abstract Symbol getSymbol();
 
         @Override
-        public abstract String getMode();
+        public abstract RType getMode();
 
         public abstract boolean getReadMissing();
 
@@ -680,7 +680,7 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         @Specialization
         protected Object doObject() {
             controlVisibility();
-            throw RError.error(getMode() == RRuntime.TYPE_FUNCTION ? RError.Message.UNKNOWN_FUNCTION : RError.Message.UNKNOWN_OBJECT, getSymbol());
+            throw RError.error(getMode() == RType.Function ? RError.Message.UNKNOWN_FUNCTION : RError.Message.UNKNOWN_OBJECT, getSymbol());
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java
index 8a5296ec23edec3a0cccff747f0238fc3512111f..6711cdc79a344fc0b816fe7305bd91eeadc635e3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.RPromise.*;
  */
 public class ReadVariadicComponentNode extends RNode {
 
-    @Child private ReadVariableNode lookup = ReadVariableNode.create("...", RRuntime.TYPE_ANY, false, true);
+    @Child private ReadVariableNode lookup = ReadVariableNode.create("...", RType.Any, false, true);
     @Child private ExpressionExecutorNode exprExecNode = ExpressionExecutorNode.create();
 
     private final int index;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
index 3f156700b10968077f72e85522efc19057044ffe..9f5eef1e4d9160c69a98a19c568cb21feaeee92d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.r.nodes.*;
+import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.nodes.unary.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
@@ -36,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.model.*;
 import com.oracle.truffle.r.runtime.ops.*;
 import com.oracle.truffle.r.runtime.ops.na.*;
 
-public abstract class BinaryArithmeticNode extends BinaryNode {
+public abstract class BinaryArithmeticNode extends RBuiltinNode {
 
     @Child private BinaryArithmetic arithmetic;
     @Child private UnaryArithmeticNode unaryNode;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
index f0dfc1d9964493fcfb6687c0348de7d2f854cc12..1ef4eead4650f4e1fd7522071b78e11975077b21 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
@@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.binary;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.closures.*;
@@ -35,7 +36,7 @@ import com.oracle.truffle.r.runtime.ops.na.*;
 import static com.oracle.truffle.r.runtime.RRuntime.*;
 
 @SuppressWarnings("unused")
-public abstract class BinaryBooleanNode extends BinaryNode {
+public abstract class BinaryBooleanNode extends RBuiltinNode {
 
     private final BooleanOperationFactory factory;
     @Child private BooleanOperation logic;
@@ -60,6 +61,18 @@ public abstract class BinaryBooleanNode extends BinaryNode {
 
     // empty raw vectors
 
+    public static boolean isEmpty(RAbstractVector left, Object right) {
+        return left.getLength() == 0;
+    }
+
+    public static boolean isEmpty(Object left, RAbstractVector right) {
+        return right.getLength() == 0;
+    }
+
+    public static boolean isEmpty(RAbstractVector left, RAbstractVector right) {
+        return left.getLength() == 0 || right.getLength() == 0;
+    }
+
     @Specialization(guards = {"isEmpty", "expectLogical"})
     protected RLogicalVector doEmptyLogical(RRawVector left, RRaw right) {
         return RDataFactory.createLogicalVector(0);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNonVectorizedNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNonVectorizedNode.java
index 84a1f96d36046b766f8d95f8200aaa6679b085b9..6d26719a154f47cb7314cf6d449051a1617f0e98 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNonVectorizedNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNonVectorizedNode.java
@@ -30,6 +30,7 @@ import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.unary.*;
 import com.oracle.truffle.r.nodes.binary.BinaryArithmeticNodeFactory.*;
 import com.oracle.truffle.r.nodes.binary.BinaryBooleanNonVectorizedNodeFactory.LeftOpToLogicalScalarCastFactory;
+import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.model.*;
@@ -39,7 +40,7 @@ import com.oracle.truffle.r.runtime.ops.na.*;
 import static com.oracle.truffle.r.runtime.RRuntime.*;
 
 @SuppressWarnings("unused")
-public abstract class BinaryBooleanNonVectorizedNode extends BinaryNode {
+public abstract class BinaryBooleanNonVectorizedNode extends RBuiltinNode {
 
     private final BooleanOperationFactory factory;
     @Child private BooleanOperation logic;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryNode.java
index 5dc53bd455edce90c76b22a609833c3dd26e52b6..9f9ed34ccc3e9f85a32b9d63da589c0754bc9b32 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryNode.java
@@ -22,21 +22,18 @@
  */
 package com.oracle.truffle.r.nodes.binary;
 
+import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.r.nodes.*;
-import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.model.*;
 
-public abstract class BinaryNode extends RBuiltinNode {
+@NodeChildren({@NodeChild(value = "left", type = RNode.class), @NodeChild(value = "right", type = RNode.class)})
+public abstract class BinaryNode extends RNode {
 
-    public final RNode getLeft() {
-        return getArguments()[0];
-    }
+    protected abstract RNode getLeft();
 
-    public final RNode getRight() {
-        return getArguments()[1];
-    }
+    protected abstract RNode getRight();
 
     public static boolean isEmpty(RAbstractVector left, @SuppressWarnings("unused") Object right) {
         return left.getLength() == 0;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
index ffeacff88ce1b1aed7cbbac63c6de23b99eaae62..facf67fe88f69062a1065ea7b445b25642c32762 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
@@ -14,13 +14,13 @@ package com.oracle.truffle.r.nodes.binary;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.nodes.unary.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.model.*;
 
-public abstract class CastTypeNode extends RInvisibleBuiltinNode {
+public abstract class CastTypeNode extends BinaryNode {
+
     @Child private CastStringNode castStringNode;
     @Child private CastComplexNode castComplexNode;
     @Child private CastDoubleNode castDoubleNode;
@@ -31,108 +31,108 @@ public abstract class CastTypeNode extends RInvisibleBuiltinNode {
     @Child private CastToVectorNode castToVectorNode;
     @Child private TypeofNode typeof;
 
-    public abstract Object execute(VirtualFrame frame, final Object value, final String type);
+    public abstract Object execute(VirtualFrame frame, Object value, RType type);
 
     @SuppressWarnings("unused")
     @Specialization(guards = "isSameType")
-    protected RAbstractVector doCast(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected RAbstractVector doCast(VirtualFrame frame, RAbstractVector value, RType type) {
         return value;
     }
 
     @SuppressWarnings("unused")
     @Specialization(guards = {"!isSameType", "isString"})
-    protected Object doCastString(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected Object doCastString(VirtualFrame frame, RAbstractVector value, RType type) {
         initCastString();
         return castStringNode.executeString(frame, value);
     }
 
     @SuppressWarnings("unused")
     @Specialization(guards = {"!isSameType", "isComplex"})
-    protected Object doCastComplex(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected Object doCastComplex(VirtualFrame frame, RAbstractVector value, RType type) {
         initCastComplex();
         return castComplexNode.executeComplex(frame, value);
     }
 
     @SuppressWarnings("unused")
     @Specialization(guards = {"!isSameType", "isDouble"})
-    protected Object doCastDouble(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected Object doCastDouble(VirtualFrame frame, RAbstractVector value, RType type) {
         initCastDouble();
         return castDoubleNode.executeDouble(frame, value);
     }
 
     @SuppressWarnings("unused")
     @Specialization(guards = {"!isSameType", "isInteger"})
-    protected Object doCastInteger(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected Object doCastInteger(VirtualFrame frame, RAbstractVector value, RType type) {
         initCastInteger();
         return castIntegerNode.executeInt(frame, value);
     }
 
     @SuppressWarnings("unused")
     @Specialization(guards = {"!isSameType", "isLogical"})
-    protected Object doCastLogical(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected Object doCastLogical(VirtualFrame frame, RAbstractVector value, RType type) {
         initCastLogical();
         return castLogicalNode.executeLogical(frame, value);
     }
 
     @SuppressWarnings("unused")
     @Specialization(guards = {"!isSameType", "isRaw"})
-    protected Object doCastRaw(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected Object doCastRaw(VirtualFrame frame, RAbstractVector value, RType type) {
         initCastRaw();
         return castRawNode.executeRaw(frame, value);
     }
 
     @SuppressWarnings("unused")
     @Specialization(guards = {"!isSameType", "isList"})
-    protected RList doCastList(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected RList doCastList(VirtualFrame frame, RAbstractVector value, RType type) {
         initCastList();
         return castListNode.executeList(frame, value);
     }
 
     @SuppressWarnings("unused")
     @Specialization
-    protected Object doCastUnknown(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected Object doCastUnknown(RAbstractVector value, RType type) {
         return null;
     }
 
     @SuppressWarnings("unused")
-    protected static boolean isString(VirtualFrame frame, final RAbstractVector value, final String type) {
-        return type.equals(RRuntime.TYPE_CHARACTER);
+    protected static boolean isString(RAbstractVector value, RType type) {
+        return type == RType.Character;
     }
 
     @SuppressWarnings("unused")
-    protected static boolean isComplex(VirtualFrame frame, final RAbstractVector value, final String type) {
-        return type.equals(RRuntime.TYPE_COMPLEX);
+    protected static boolean isComplex(RAbstractVector value, RType type) {
+        return type == RType.Complex;
     }
 
     @SuppressWarnings("unused")
-    protected static boolean isDouble(VirtualFrame frame, final RAbstractVector value, final String type) {
-        return type.equals(RRuntime.TYPE_DOUBLE) || type.equals(RRuntime.TYPE_NUMERIC);
+    protected static boolean isDouble(final RAbstractVector value, RType type) {
+        return type == RType.Double || type == RType.Numeric;
     }
 
     @SuppressWarnings("unused")
-    protected static boolean isInteger(VirtualFrame frame, final RAbstractVector value, final String type) {
-        return type.equals(RRuntime.TYPE_INTEGER);
+    protected static boolean isInteger(RAbstractVector value, RType type) {
+        return type == RType.Integer;
     }
 
     @SuppressWarnings("unused")
-    protected static boolean isLogical(VirtualFrame frame, final RAbstractVector value, final String type) {
-        return type.equals(RRuntime.TYPE_LOGICAL);
+    protected static boolean isLogical(RAbstractVector value, RType type) {
+        return type == RType.Logical;
     }
 
     @SuppressWarnings("unused")
-    protected static boolean isRaw(VirtualFrame frame, final RAbstractVector value, final String type) {
-        return type.equals(RRuntime.TYPE_RAW);
+    protected static boolean isRaw(RAbstractVector value, RType type) {
+        return type == RType.Raw;
     }
 
     @SuppressWarnings("unused")
-    protected static boolean isList(VirtualFrame frame, final RAbstractVector value, final String type) {
-        return type.equals(RRuntime.TYPE_LIST);
+    protected static boolean isList(RAbstractVector value, RType type) {
+        return type == RType.List;
     }
 
-    protected boolean isSameType(VirtualFrame frame, final RAbstractVector value, final String type) {
+    protected boolean isSameType(VirtualFrame frame, RAbstractVector value, RType type) {
         initTypeof();
-        String givenType = typeof.execute(frame, value);
-        return givenType.equals(type);
+        RType givenType = typeof.execute(frame, value);
+        return givenType.getName().equals(type);
     }
 
     private void initTypeof() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CbindFoldOperationNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CbindFoldOperationNode.java
index a9cf4cac72acf55f9be2f108252cbffb00c3f94d..0519b6feb8b04214b4542c6dabde02b7fbfaee28 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CbindFoldOperationNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CbindFoldOperationNode.java
@@ -23,14 +23,13 @@
 package com.oracle.truffle.r.nodes.binary;
 
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.r.nodes.*;
 
 public final class CbindFoldOperationNode extends FoldOperationNode {
 
     @Child private CbindBinaryNode cbind;
 
     public CbindFoldOperationNode() {
-        this.cbind = CbindBinaryNodeFactory.create(new RNode[2], null, null);
+        this.cbind = CbindBinaryNodeFactory.create(null, null);
     }
 
     private Object executeCbind(VirtualFrame frame, Object left, Object right) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CombineFoldOperationNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CombineFoldOperationNode.java
index 1dab85108bdce20a4580c69cd380712fc447c288..c85dfd9ebbf2ad9b16093849858c3d4ad67f0042 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CombineFoldOperationNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CombineFoldOperationNode.java
@@ -24,7 +24,6 @@ package com.oracle.truffle.r.nodes.binary;
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.r.nodes.*;
 
 public final class CombineFoldOperationNode extends FoldOperationNode {
 
@@ -40,7 +39,7 @@ public final class CombineFoldOperationNode extends FoldOperationNode {
     public Object executeComplex(VirtualFrame frame, Object left, Object right) {
         if (combineComplex == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            combineComplex = insert(CombineBinaryComplexNodeFactory.create(new RNode[2], null, null));
+            combineComplex = insert(CombineBinaryComplexNodeFactory.create(null, null));
         }
         return combineComplex.executeCombine(frame, left, right);
     }
@@ -49,7 +48,7 @@ public final class CombineFoldOperationNode extends FoldOperationNode {
     public Object executeDouble(VirtualFrame frame, Object left, Object right) {
         if (combineDouble == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            combineDouble = insert(CombineBinaryDoubleNodeFactory.create(new RNode[2], null, null));
+            combineDouble = insert(CombineBinaryDoubleNodeFactory.create(null, null));
         }
         return combineDouble.executeCombine(frame, left, right);
     }
@@ -58,7 +57,7 @@ public final class CombineFoldOperationNode extends FoldOperationNode {
     public Object executeInteger(VirtualFrame frame, Object left, Object right) {
         if (combineInteger == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            combineInteger = insert(CombineBinaryIntegerNodeFactory.create(new RNode[2], null, null));
+            combineInteger = insert(CombineBinaryIntegerNodeFactory.create(null, null));
         }
         return combineInteger.executeCombine(frame, left, right);
     }
@@ -67,7 +66,7 @@ public final class CombineFoldOperationNode extends FoldOperationNode {
     public Object executeString(VirtualFrame frame, Object left, Object right) {
         if (combineString == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            combineString = insert(CombineBinaryStringNodeFactory.create(new RNode[2], null, null));
+            combineString = insert(CombineBinaryStringNodeFactory.create(null, null));
         }
         return combineString.executeCombine(frame, left, right);
     }
@@ -76,7 +75,7 @@ public final class CombineFoldOperationNode extends FoldOperationNode {
     public Object executeLogical(VirtualFrame frame, Object left, Object right) {
         if (combineLogical == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            combineLogical = insert(CombineBinaryLogicalNodeFactory.create(new RNode[2], null, null));
+            combineLogical = insert(CombineBinaryLogicalNodeFactory.create(null, null));
         }
         return combineLogical.executeCombine(frame, left, right);
     }
@@ -85,7 +84,7 @@ public final class CombineFoldOperationNode extends FoldOperationNode {
     public Object executeRaw(VirtualFrame frame, Object left, Object right) {
         if (combineRaw == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            combineRaw = insert(CombineBinaryRawNodeFactory.create(new RNode[2], null, null));
+            combineRaw = insert(CombineBinaryRawNodeFactory.create(null, null));
         }
         return combineRaw.executeCombine(frame, left, right);
     }
@@ -94,7 +93,7 @@ public final class CombineFoldOperationNode extends FoldOperationNode {
     public Object executeList(VirtualFrame frame, Object left, Object right) {
         if (combineList == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            combineList = insert(CombineBinaryListNodeFactory.create(new RNode[2], null, null));
+            combineList = insert(CombineBinaryListNodeFactory.create(null, null));
         }
         return combineList.executeCombine(frame, left, right);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/RbindFoldOperationNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/RbindFoldOperationNode.java
index 4da606f7b0f8e9b540eb1cd0372937ed4a93eede..1ae54b8e3198673465c5817d57c514892d7724f8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/RbindFoldOperationNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/RbindFoldOperationNode.java
@@ -23,14 +23,13 @@
 package com.oracle.truffle.r.nodes.binary;
 
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.r.nodes.*;
 
 public final class RbindFoldOperationNode extends FoldOperationNode {
 
     @Child private RbindBinaryNode rbind;
 
     public RbindFoldOperationNode() {
-        this.rbind = RbindBinaryNodeFactory.create(new RNode[2], null, null);
+        this.rbind = RbindBinaryNodeFactory.create(null, null);
     }
 
     private Object executeRbind(VirtualFrame frame, Object left, Object right) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/expressions/ExpressionExecutorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/expressions/ExpressionExecutorNode.java
index 13c41236c6f577815d57dec55f3fb5d4f45ee39b..5d263f6566b458ee4b88de7ea4b6662bd61ad3da 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/expressions/ExpressionExecutorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/expressions/ExpressionExecutorNode.java
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.*;
  * {@link RNode}. This in essence bridges the gap between code as runtime data and executed code. To
  * make this as efficient as possible, it creates a PIC (polymorphic inline cache) for a certain
  * number of known expressions before delegating to a generic version which uses the
- * {@link Engine#eval(RLanguage, VirtualFrame)} functionality.
+ * {@link Engine#eval(RLanguage, MaterializedFrame)} functionality.
  */
 public abstract class ExpressionExecutorNode extends Node {
 
@@ -58,7 +58,7 @@ public abstract class ExpressionExecutorNode extends Node {
             // Specialize below
             ExpressionExecutorNode replacement;
             if (picDepth < INLINE_CACHE_SIZE) {
-                this.incPicDepth();
+                incPicDepth();
                 replacement = new DirectExpressionExecutorNode(node, this);
             } else {
                 replacement = new GenericExpressionExecutorNode();
@@ -96,7 +96,7 @@ public abstract class ExpressionExecutorNode extends Node {
     private static final class GenericExpressionExecutorNode extends ExpressionExecutorNode {
         @Override
         public Object execute(VirtualFrame frame, RNode node) {
-            return RContext.getEngine().eval(new RLanguage(node), frame);
+            return RContext.getEngine().eval(new RLanguage(node), frame.materialize());
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java
index 093ade7e68ebcefd5dc5af161c0ff58118d1632c..24d3d91f1f4b130d6e9ecf522056ba454a45f903 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java
@@ -45,7 +45,7 @@ import com.oracle.truffle.r.runtime.data.RPromise.Closure;
  */
 public final class CallArgumentsNode extends ArgumentsNode implements UnmatchedArguments {
 
-    @Child private ReadVariableNode varArgsSlotNode = ReadVariableNode.create(ArgumentsTrait.VARARG_NAME, RRuntime.TYPE_ANY, false, false, true, false);
+    @Child private ReadVariableNode varArgsSlotNode = ReadVariableNode.create(ArgumentsTrait.VARARG_NAME, RType.Any, false, false, true, false);
 
     /**
      * If a supplied argument is a {@link ReadVariableNode} whose {@link Symbol} is "...", this
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java
index f3f1a671d2ed92b3214ef8cedf58f43c8be2bb0e..03bca37b13a40bf99cff1c7a8971af5803207654 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java
@@ -152,7 +152,7 @@ public class GroupDispatchNode extends S3DispatchNode {
         this.typeLast = null;
         if (builtInNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            builtInNode = insert(ReadVariableNode.create(this.genericName, RRuntime.TYPE_FUNCTION, false));
+            builtInNode = insert(ReadVariableNode.create(this.genericName, RType.Function, false));
         }
         RFunction builtinFunc = null;
         try {
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 3faef1fa51cf274acff388d140af5cbb59415e10..b6a04d075f71a506bfda7b5647d8dab4f0682c13 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
@@ -74,13 +74,13 @@ import com.oracle.truffle.r.runtime.data.*;
  *  U = {@link UninitializedCallNode}: Forms the uninitialized end of the function PIC
  *  D = {@link DispatchedCallNode}: Function fixed, no varargs
  *  G = {@link GenericCallNode}: Function arbitrary, no varargs (generic case)
- *
+ * 
  *  UV = {@link UninitializedCallNode} with varargs,
  *  UVC = {@link UninitializedVarArgsCacheCallNode} with varargs, for varargs cache
  *  DV = {@link DispatchedVarArgsCallNode}: Function fixed, with cached varargs
  *  DGV = {@link DispatchedGenericVarArgsCallNode}: Function fixed, with arbitrary varargs (generic case)
  *  GV = {@link GenericVarArgsCallNode}: Function arbitrary, with arbitrary varargs (generic case)
- *
+ * 
  * (RB = {@link RBuiltinNode}: individual functions that are builtins are represented by this node
  * which is not aware of caching). Due to {@link CachedCallNode} (see below) this is transparent to
  * the cache and just behaves like a D/DGV)
@@ -93,11 +93,11 @@ import com.oracle.truffle.r.runtime.data.*;
  * non varargs, max depth:
  * |
  * D-D-D-U
- *
+ * 
  * no varargs, generic (if max depth is exceeded):
  * |
  * D-D-D-D-G
- *
+ * 
  * varargs:
  * |
  * DV-DV-UV         <- function call target identity level cache
@@ -105,7 +105,7 @@ import com.oracle.truffle.r.runtime.data.*;
  *    DV
  *    |
  *    UVC           <- varargs signature level cache
- *
+ * 
  * varargs, max varargs depth exceeded:
  * |
  * DV-DV-UV
@@ -117,7 +117,7 @@ import com.oracle.truffle.r.runtime.data.*;
  *    DV
  *    |
  *    DGV
- *
+ * 
  * varargs, max function depth exceeded:
  * |
  * DV-DV-DV-DV-GV
@@ -175,7 +175,7 @@ public abstract class RCallNode extends RNode {
     }
 
     public static RCallNode createStaticCall(SourceSection src, String function, CallArgumentsNode arguments) {
-        return RCallNode.createCall(src, ReadVariableNode.create(function, RRuntime.TYPE_FUNCTION, false), arguments);
+        return RCallNode.createCall(src, ReadVariableNode.create(function, RType.Function, false), arguments);
     }
 
     public static RCallNode createStaticCall(SourceSection src, RFunction function, CallArgumentsNode arguments) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3DispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3DispatchNode.java
index 712ac37a05800a349c62bba4f93515839f12b73b..a4de964dc0416bc715b7f41ace5032669ae5084e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3DispatchNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3DispatchNode.java
@@ -42,7 +42,7 @@ public abstract class S3DispatchNode extends DispatchNode {
         if (lookup == null || !functionName.equals(lastFun)) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             lastFun = functionName;
-            ReadVariableNode rvn = ReadVariableNode.create(functionName, RRuntime.TYPE_FUNCTION, false, true);
+            ReadVariableNode rvn = ReadVariableNode.create(functionName, RType.Function, false, true);
             lookup = lookup == null ? insert(rvn) : lookup.replace(rvn);
         }
         Object func = targetFunction = null;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/InheritsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/InheritsNode.java
index 26e5720dfe9e2686c31b976e2f051cb285225358..fe4bb37712add0f4fbd099d5fc875af54d94345e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/InheritsNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/InheritsNode.java
@@ -13,10 +13,10 @@ package com.oracle.truffle.r.nodes.unary;
 
 import java.util.*;
 
-import com.oracle.truffle.api.CompilerDirectives.*;
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.r.nodes.builtin.*;
+import com.oracle.truffle.r.nodes.binary.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.model.*;
@@ -25,7 +25,7 @@ import com.oracle.truffle.r.runtime.env.*;
 /**
  * Basic support for "inherits" that is used by the {@code inherits} builtin and others.
  */
-public abstract class InheritsNode extends RBuiltinNode {
+public abstract class InheritsNode extends BinaryNode {
     public abstract byte execute(VirtualFrame frame, Object x, Object what);
 
     @SuppressWarnings("unused")
@@ -64,5 +64,4 @@ public abstract class InheritsNode extends RBuiltinNode {
         }
         return classToPos;
     }
-
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/IsFactorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/IsFactorNode.java
index f59571d8a3b5e11ed58c60ccbe79c1511458c66a..a4a18a2cfac9bfe0cda6f30c79874da4d5c041fb 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/IsFactorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/IsFactorNode.java
@@ -14,7 +14,6 @@ package com.oracle.truffle.r.nodes.unary;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 
@@ -30,13 +29,13 @@ public abstract class IsFactorNode extends UnaryNode {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             typeofNode = insert(TypeofNodeFactory.create(null));
         }
-        if (!typeofNode.execute(frame, x).equals(RRuntime.TYPE_INTEGER)) {
+        if (typeofNode.execute(frame, x) != RType.Integer) {
             return RRuntime.LOGICAL_FALSE;
         }
         if (inheritsNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            inheritsNode = insert(InheritsNodeFactory.create(new RNode[3], null, null));
+            inheritsNode = insert(InheritsNodeFactory.create(null, null));
         }
-        return inheritsNode.execute(frame, x, RDataFactory.createStringVector(RRuntime.TYPE_FACTOR));
+        return inheritsNode.execute(frame, x, RDataFactory.createStringVector(RType.Factor.getName()));
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java
index bea0fd332efe7edffd0ec72ec463d5efc465ca97..0e3bee3e6ce819f942c882787c52fc59e47dcf04 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java
@@ -26,6 +26,7 @@ import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
@@ -34,126 +35,126 @@ import com.oracle.truffle.r.runtime.env.*;
 @SuppressWarnings("unused")
 public abstract class TypeofNode extends UnaryNode {
 
-    public abstract String execute(VirtualFrame frame, Object x);
+    public abstract RType execute(VirtualFrame frame, Object x);
 
     @Specialization
-    protected String typeof(RNull vector) {
-        return "NULL";
+    protected RType typeof(RNull vector) {
+        return RType.Null;
     }
 
     @Specialization
-    protected String typeof(byte x) {
-        return "logical";
+    protected RType typeof(byte x) {
+        return RType.Logical;
     }
 
     @Specialization
-    protected String typeof(int s) {
-        return "integer";
+    protected RType typeof(int s) {
+        return RType.Integer;
     }
 
     @Specialization
-    protected String typeof(double x) {
-        return "double";
+    protected RType typeof(double x) {
+        return RType.Double;
     }
 
     @Specialization
-    protected String typeof(RComplex x) {
-        return "complex";
+    protected RType typeof(RComplex x) {
+        return RType.Complex;
     }
 
     @Specialization
-    protected String typeof(RRaw x) {
-        return "raw";
+    protected RType typeof(RRaw x) {
+        return RType.Raw;
     }
 
     @Specialization
-    protected String typeof(String x) {
-        return "character";
+    protected RType typeof(String x) {
+        return RType.Character;
     }
 
     @Specialization
-    protected String typeof(RIntSequence vector) {
-        return "integer";
+    protected RType typeof(RIntSequence vector) {
+        return RType.Integer;
     }
 
     @Specialization
-    protected String typeof(RLogicalVector vector) {
-        return "logical";
+    protected RType typeof(RLogicalVector vector) {
+        return RType.Logical;
     }
 
     @Specialization
-    protected String typeof(RIntVector vector) {
-        return "integer";
+    protected RType typeof(RIntVector vector) {
+        return RType.Integer;
     }
 
     @Specialization
-    protected String typeof(RDoubleVector vector) {
-        return "double";
+    protected RType typeof(RDoubleVector vector) {
+        return RType.Double;
     }
 
     @Specialization
-    protected String typeof(RStringVector vector) {
-        return "character";
+    protected RType typeof(RStringVector vector) {
+        return RType.Character;
     }
 
     @Specialization
-    protected String typeof(RComplexVector vector) {
-        return "complex";
+    protected RType typeof(RComplexVector vector) {
+        return RType.Complex;
     }
 
     @Specialization
-    protected String typeof(RRawVector vector) {
-        return "raw";
+    protected RType typeof(RRawVector vector) {
+        return RType.Raw;
     }
 
     @Specialization
-    protected String typeof(RList list) {
-        return "list";
+    protected RType typeof(RList list) {
+        return RType.List;
     }
 
     @Specialization
-    protected String typeof(REnvironment env) {
-        return RRuntime.TYPE_ENVIRONMENT;
+    protected RType typeof(REnvironment env) {
+        return RType.Environment;
     }
 
     @Specialization
-    protected String typeof(RSymbol symbol) {
-        return "symbol";
+    protected RType typeof(RSymbol symbol) {
+        return RType.Symbol;
     }
 
     @Specialization
-    protected String typeof(RLanguage language) {
-        return "language";
+    protected RType typeof(RLanguage language) {
+        return RType.Language;
     }
 
     @Specialization
-    protected String typeof(RPromise promise) {
-        return "promise";
+    protected RType typeof(RPromise promise) {
+        return RType.Promise;
     }
 
     @Specialization
-    protected String typeof(RExpression symbol) {
-        return "expression";
+    protected RType typeof(RExpression symbol) {
+        return RType.Expression;
     }
 
     @Specialization
-    protected String typeof(RPairList pairlist) {
-        return RRuntime.TYPE_PAIR_LIST;
+    protected RType typeof(RPairList pairlist) {
+        return RType.PairList;
     }
 
     @Specialization(guards = "isFunctionBuiltin")
-    protected String typeofBuiltin(RFunction obj) {
-        return "builtin";
+    protected RType typeofBuiltin(RFunction obj) {
+        return RType.Builtin;
     }
 
     @Specialization(guards = "!isFunctionBuiltin")
-    protected String typeofClosure(RFunction obj) {
-        return "closure";
+    protected RType typeofClosure(RFunction obj) {
+        return RType.Closure;
     }
 
     @Specialization
-    protected String typeofFormula(RFormula f) {
-        return "language";
+    protected RType typeofFormula(RFormula f) {
+        return RType.Language;
     }
 
     public static boolean isFunctionBuiltin(RFunction fun) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RContext.java
index cca44faf66dcb7184931c45ad535138f624b0959..886b1681d864939d95d162906331073b651490c6 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RContext.java
@@ -152,7 +152,7 @@ public final class RContext extends ExecutionContext {
          * @param frame for evaluating any associated R code
          * @param envForFrame the namespace environment associated with the package.
          */
-        void loadDefaultPackage(String name, VirtualFrame frame, REnvironment envForFrame);
+        void loadDefaultPackage(String name, MaterializedFrame frame, REnvironment envForFrame);
 
         /**
          * Return the {@link RFunction} for the builtin {@code name}.
@@ -173,7 +173,7 @@ public final class RContext extends ExecutionContext {
          * @param envForFrame the environment that {@code frame} is bound to.
          * @return the object returned by the evaluation or {@code null} if an error occurred.
          */
-        Object parseAndEval(String sourceDesc, String rscript, VirtualFrame frame, REnvironment envForFrame, boolean printResult, boolean allowIncompleteSource);
+        Object parseAndEval(String sourceDesc, String rscript, MaterializedFrame frame, REnvironment envForFrame, boolean printResult, boolean allowIncompleteSource);
 
         static final Object INCOMPLETE_SOURCE = new Object();
 
@@ -219,18 +219,18 @@ public final class RContext extends ExecutionContext {
         /**
          * Evaluate {@code expr} in {@code frame}.
          */
-        Object eval(RExpression expr, VirtualFrame frame);
+        Object eval(RExpression expr, MaterializedFrame frame);
 
         /**
-         * Variant of {@link #eval(RExpression, VirtualFrame)} for a single language element.
+         * Variant of {@link #eval(RExpression, MaterializedFrame)} for a single language element.
          */
-        Object eval(RLanguage expr, VirtualFrame frame);
+        Object eval(RLanguage expr, MaterializedFrame frame);
 
         /**
-         * Evaluate a promise in the given frame, where we can use the {@link VirtualFrame}) of the
-         * caller directly). This should <b>only</b> be called by the {@link RPromise} class.
+         * Evaluate a promise in the given frame, where we can use the {@link MaterializedFrame}) of
+         * the caller directly). This should <b>only</b> be called by the {@link RPromise} class.
          */
-        Object evalPromise(RPromise expr, VirtualFrame frame) throws RError;
+        Object evalPromise(RPromise expr, MaterializedFrame frame) throws RError;
 
         /**
          * Evaluate a promise in the {@link MaterializedFrame} stored with the promise. This should
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index 72bea8eaefdfec9f11be4ab1b25d640e6d69fc64..e73169627cbd7b2ac88eb3e878301cb38555f037 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -141,9 +141,9 @@ public final class RError extends RuntimeException {
             if (errorExpr instanceof RLanguage || errorExpr instanceof RExpression) {
                 VirtualFrame frame = Utils.getActualCurrentFrame();
                 if (errorExpr instanceof RLanguage) {
-                    RContext.getEngine().eval((RLanguage) errorExpr, frame);
+                    RContext.getEngine().eval((RLanguage) errorExpr, frame.materialize());
                 } else if (errorExpr instanceof RExpression) {
-                    RContext.getEngine().eval((RExpression) errorExpr, frame);
+                    RContext.getEngine().eval((RExpression) errorExpr, frame.materialize());
                 }
             } else {
                 // GnuR checks this earlier when the option is set
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
index 39f52ec6c8bd8fc72a5f1f3a1c1b4f7ebdd56fbe..76099c23bef0a550709b9c1b7d1890169e9028ff 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
@@ -73,42 +73,9 @@ public class RRuntime {
     public static final byte LOGICAL_FALSE = 0;
     public static final byte LOGICAL_NA = -1;
 
-    public static final String TYPE_ANY = new String("any");
-    public static final String TYPE_NUMERIC = new String("numeric");
-    public static final String TYPE_DOUBLE = new String("double");
-    public static final String TYPE_INTEGER = new String("integer");
-    public static final String TYPE_COMPLEX = new String("complex");
-    public static final String TYPE_CHARACTER = new String("character");
-    public static final String TYPE_LOGICAL = new String("logical");
-    public static final String TYPE_RAW = new String("raw");
-    public static final String TYPE_LIST = new String("list");
-    public static final String TYPE_FORMULA = new String("formula");
-    public static final String TYPE_FUNCTION = new String("function");
-    public static final String TYPE_MATRIX = new String("matrix");
-    public static final String TYPE_ARRAY = new String("array");
-    public static final String TYPE_CLOSURE = new String("closure");
-    public static final String TYPE_BUILTIN = new String("builtin");
-    public static final String TYPE_SPECIAL = new String("special");
-    public static final String TYPE_DATA_FRAME = new String("data.frame");
-    public static final String TYPE_FACTOR = new String("factor");
-    public static final String TYPE_SYMBOL = new String("symbol");
     public static final String CLASS_SYMBOL = new String("name");
-    public static final String TYPE_ENVIRONMENT = new String("environment");
-    public static final String TYPE_PAIR_LIST = new String("pairlist");
     public static final String CLASS_LANGUAGE = new String("call");
     public static final String CLASS_EXPRESSION = new String("expression");
-    public static final String TYPE_CALL = new String("call");
-
-    // Defunct types
-    public static final String REAL = new String("real");
-    public static final String SINGLE = new String("single");
-
-    public static final String TYPE_NUMERIC_CAP = new String("Numeric");
-    public static final String TYPE_INTEGER_CAP = new String("Integer");
-    public static final String TYPE_COMPLEX_CAP = new String("Complex");
-    public static final String TYPE_CHARACTER_CAP = new String("Character");
-    public static final String TYPE_LOGICAL_CAP = new String("Logical");
-    public static final String TYPE_RAW_CAP = new String("Raw");
 
     public static final String[] STRING_ARRAY_SENTINEL = new String[0];
     public static final String DEFAULT = "default";
@@ -129,8 +96,8 @@ public class RRuntime {
     public static final String PREVIOUS_ATTR_KEY = "previous";
     public static final String ROWNAMES_ATTR_KEY = "row.names";
 
-    public static final String[] CLASS_INTEGER = new String[]{TYPE_INTEGER, TYPE_NUMERIC};
-    public static final String[] CLASS_DOUBLE = new String[]{TYPE_DOUBLE, TYPE_NUMERIC};
+    public static final String[] CLASS_INTEGER = new String[]{"integer", "numeric"};
+    public static final String[] CLASS_DOUBLE = new String[]{"double", "numeric"};
 
     public static final String WHICH = "which";
 
@@ -186,17 +153,17 @@ public class RRuntime {
     @SlowPath
     public static String classToString(Class<?> c, boolean numeric) {
         if (c == RLogical.class) {
-            return TYPE_LOGICAL;
+            return RType.Logical.getName();
         } else if (c == RInt.class) {
-            return TYPE_INTEGER;
+            return RType.Integer.getName();
         } else if (c == RDouble.class) {
-            return numeric ? TYPE_NUMERIC : TYPE_DOUBLE;
+            return numeric ? RType.Numeric.getName() : RType.Double.getName();
         } else if (c == RComplex.class) {
-            return TYPE_COMPLEX;
+            return RType.Complex.getName();
         } else if (c == RRaw.class) {
-            return TYPE_RAW;
+            return RType.Raw.getName();
         } else if (c == RString.class) {
-            return TYPE_CHARACTER;
+            return RType.Character.getName();
         } else {
             throw new RuntimeException("internal error, unknown class: " + c);
         }
@@ -210,17 +177,17 @@ public class RRuntime {
     @SlowPath
     public static String classToStringCap(Class<?> c) {
         if (c == RLogical.class) {
-            return TYPE_LOGICAL_CAP;
+            return "Logical";
         } else if (c == RInt.class) {
-            return TYPE_INTEGER_CAP;
+            return "Integer";
         } else if (c == RDouble.class) {
-            return TYPE_NUMERIC_CAP;
+            return "Numeric";
         } else if (c == RComplex.class) {
-            return TYPE_COMPLEX_CAP;
+            return "Complex";
         } else if (c == RRaw.class) {
-            return TYPE_RAW_CAP;
+            return "Raw";
         } else if (c == RString.class) {
-            return TYPE_CHARACTER_CAP;
+            return "Character";
         } else {
             throw new RuntimeException("internal error, unknown class: " + c);
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java
new file mode 100644
index 0000000000000000000000000000000000000000..49ebe44a918f90b147ed21b9629214e625394235
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java
@@ -0,0 +1,74 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 1995-2012, The R Core Team
+ * Copyright (c) 2003, The R Foundation
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.runtime;
+
+import com.oracle.truffle.api.CompilerDirectives.*;
+
+public enum RType {
+    Any("any"),
+    Null("NULL"),
+    Numeric("numeric"),
+    Double("double"),
+    Integer("integer"),
+    Complex("complex"),
+    Character("character"),
+    Logical("logical"),
+    Raw("raw"),
+    List("list"),
+    Formula("formula"),
+    Function("function"),
+    Matrix("matrix"),
+    Array("array"),
+    Closure("closure"),
+    Builtin("builtin"),
+    Special("special"),
+    DataFrame("data.frame"),
+    Factor("factor"),
+    Symbol("symbol"),
+    Environment("environment"),
+    PairList("pairlist"),
+    Language("language"),
+    Promise("promise"),
+    Expression("expression"),
+    DefunctReal("real"),
+    DefunctSingle("single");
+
+    private final String name;
+
+    private RType(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public static RType fromString(String mode) {
+        if (mode == Any.getName()) {
+            return Any;
+        } else if (mode == Function.getName()) {
+            return Function;
+        } else {
+            return lookup(mode);
+        }
+    }
+
+    @SlowPath
+    private static RType lookup(String mode) {
+        for (RType type : values()) {
+            if (type.getName().equals(mode)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java
index ea7278af4f731edfcf9c3c4cb55358aa1534cbf3..03cf4b7ea3e50585b4a5fdb4b7326d4199426833 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java
@@ -33,7 +33,7 @@ public final class RComplexVector extends RVector implements RAbstractComplexVec
 
     private double[] data;
 
-    private static final String[] implicitClassHrDyn = new String[]{"", RRuntime.TYPE_COMPLEX};
+    private static final String[] implicitClassHrDyn = new String[]{"", RType.Complex.getName()};
 
     RComplexVector(double[] data, boolean complete, int[] dims, Object names) {
         super(complete, data.length >> 1, dims, names);
@@ -201,6 +201,6 @@ public final class RComplexVector extends RVector implements RAbstractComplexVec
 
     @Override
     protected RStringVector getImplicitClassHr() {
-        return getClassHierarchyHelper(new String[]{RRuntime.TYPE_COMPLEX}, implicitClassHrDyn);
+        return getClassHierarchyHelper(new String[]{RType.Complex.getName()}, implicitClassHrDyn);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
index ae3b659f8bbbcf665799310623909daa3849a488..c1c9a527c8d52bf0bb297350adda08e4a44801ab 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
@@ -34,7 +34,7 @@ public final class RList extends RVector implements RAbstractVector {
 
     private Object[] data;
 
-    private static final String[] implicitClassHrDyn = {"", RRuntime.TYPE_LIST};
+    private static final String[] implicitClassHrDyn = {"", RType.List.getName()};
 
     @CompilationFinal public String elementNamePrefix;
 
@@ -212,6 +212,6 @@ public final class RList extends RVector implements RAbstractVector {
 
     @Override
     protected RStringVector getImplicitClassHr() {
-        return getClassHierarchyHelper(new String[]{RRuntime.TYPE_LIST}, implicitClassHrDyn);
+        return getClassHierarchyHelper(new String[]{RType.List.getName()}, implicitClassHrDyn);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java
index 753a8f1da5db9118792c013d5d5a274bff1862e3..4f02a17937fa8ddc8bf2e0f89f1d581e8f46b11b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java
@@ -33,7 +33,7 @@ public final class RLogicalVector extends RVector implements RAbstractLogicalVec
 
     private byte[] data;
 
-    private static final String[] implicitClassHrDyn = new String[]{"", RRuntime.TYPE_LOGICAL};
+    private static final String[] implicitClassHrDyn = new String[]{"", RType.Logical.getName()};
 
     RLogicalVector(byte[] data, boolean complete, int[] dims, Object names) {
         super(complete, data.length, dims, names);
@@ -199,6 +199,6 @@ public final class RLogicalVector extends RVector implements RAbstractLogicalVec
 
     @Override
     protected RStringVector getImplicitClassHr() {
-        return getClassHierarchyHelper(new String[]{RRuntime.TYPE_LOGICAL}, implicitClassHrDyn);
+        return getClassHierarchyHelper(new String[]{RType.Logical.getName()}, implicitClassHrDyn);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
index 32afc25f79d16e2c74f68c282a21992fd3f110b1..f3228cb2f304f4bc5589f3300a8014558de477ff 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
@@ -220,7 +220,7 @@ public final class RPromise extends RLanguageRep {
                 newValue = doEvalArgument(callSrc);
             } else {
                 assert isInOriginFrame(frame, profile);
-                newValue = doEvalArgument(frame);
+                newValue = doEvalArgument(frame.materialize());
             }
 
             setValue(newValue);
@@ -255,7 +255,7 @@ public final class RPromise extends RLanguageRep {
         return result;
     }
 
-    protected Object doEvalArgument(VirtualFrame frame) {
+    protected Object doEvalArgument(MaterializedFrame frame) {
         Object result = null;
         try {
             result = RContext.getEngine().evalPromise(this, frame);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java
index f864137d306fa4b8afaa563b1bfdb2eecef82d1a..1e5a1a84309926144e8e49460b3aaed9d8db4891 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java
@@ -32,7 +32,7 @@ public final class RRawVector extends RVector implements RAbstractRawVector {
 
     private byte[] data;
 
-    private static final String[] implicitClassHrDyn = new String[]{"", RRuntime.TYPE_RAW};
+    private static final String[] implicitClassHrDyn = new String[]{"", RType.Raw.getName()};
 
     RRawVector(byte[] data, int[] dims, Object names) {
         super(true, data.length, dims, names);
@@ -181,6 +181,6 @@ public final class RRawVector extends RVector implements RAbstractRawVector {
 
     @Override
     protected RStringVector getImplicitClassHr() {
-        return getClassHierarchyHelper(new String[]{RRuntime.TYPE_RAW}, implicitClassHrDyn);
+        return getClassHierarchyHelper(new String[]{RType.Raw.getName()}, implicitClassHrDyn);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java
index d6a11580c42292dad7d3a26bd35f070c5e5c00da..a2c2aa510a437248ae9412ce8e8b850f996932db 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.ops.na.*;
 public final class RStringVector extends RVector implements RAbstractStringVector {
 
     private String[] data;
-    private static final String[] implicitClassHrDyn = new String[]{"", RRuntime.TYPE_CHARACTER};
+    private static final String[] implicitClassHrDyn = new String[]{"", RType.Character.getName()};
 
     RStringVector(String[] data, boolean complete, int[] dims, Object names) {
         super(complete, data.length, dims, names);
@@ -185,6 +185,6 @@ public final class RStringVector extends RVector implements RAbstractStringVecto
 
     @Override
     protected RStringVector getImplicitClassHr() {
-        return getClassHierarchyHelper(new String[]{RRuntime.TYPE_CHARACTER}, implicitClassHrDyn);
+        return getClassHierarchyHelper(new String[]{RType.Character.getName()}, implicitClassHrDyn);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
index 16e2391d7597c0c59b9bbf9654ecbd0bba474b8c..56cf5dc21143600f3c00ce9b8a529d1106e0d627 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
@@ -400,7 +400,7 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
             return vector;
         } else if (classAttr != null && classAttr.getLength() != 0) {
             for (int i = 0; i < classAttr.getLength(); i++) {
-                if (classAttr.getDataAt(i).equals(RRuntime.TYPE_DATA_FRAME)) {
+                if (RType.DataFrame.getName().equals(classAttr.getDataAt(i))) {
                     vector.putAttribute(RRuntime.CLASS_ATTR_KEY, classAttr);
                     if (enclosingDataFrame != null) {
                         // was a frame and still is a frame
@@ -620,11 +620,11 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV
     // class hierarchy on the fly.
     protected final RStringVector getClassHierarchyHelper(final String[] classHr, final String[] classHrDyn) {
         if (isMatrix()) {
-            classHrDyn[0] = RRuntime.TYPE_MATRIX;
+            classHrDyn[0] = RType.Matrix.getName();
             return RDataFactory.createStringVector(classHrDyn, true);
         }
         if (isArray()) {
-            classHrDyn[0] = RRuntime.TYPE_ARRAY;
+            classHrDyn[0] = RType.Array.getName();
             return RDataFactory.createStringVector(classHrDyn, true);
         }
         return RDataFactory.createStringVector(classHr, true);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
index 0f5bac28793418a2356c9c9f6271988679f7a8a3..110dd38fe1e1b97e820f8d4b902930c3cfce2d3a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
@@ -231,7 +231,7 @@ public abstract class REnvironment implements RAttributable {
         initSearchList();
 
         // load base package first
-        RContext.getEngine().loadDefaultPackage("base", baseFrame, baseEnv);
+        RContext.getEngine().loadDefaultPackage("base", baseFrame.materialize(), baseEnv);
     }
 
     public static void packagesInitialize(ArrayList<RPackage> rPackages) {
@@ -240,7 +240,7 @@ public abstract class REnvironment implements RAttributable {
         for (RPackage rPackage : rPackages) {
             VirtualFrame pkgFrame = RRuntime.createNonFunctionFrame();
             Package pkgEnv = new Package(pkgParent, rPackage.name, pkgFrame, rPackage.path);
-            RContext.getEngine().loadDefaultPackage(rPackage.name, pkgFrame, pkgEnv);
+            RContext.getEngine().loadDefaultPackage(rPackage.name, pkgFrame.materialize(), pkgEnv);
             attach(2, pkgEnv);
             pkgParent = pkgEnv;
         }
diff --git a/com.oracle.truffle.r.shell/src/com/oracle/truffle/r/shell/RCommand.java b/com.oracle.truffle.r.shell/src/com/oracle/truffle/r/shell/RCommand.java
index d728bebcfb48db833d5bef93a008e33c8c9d4b46..bcf15f2f0b37158033138982ca25344d20fd3029 100644
--- a/com.oracle.truffle.r.shell/src/com/oracle/truffle/r/shell/RCommand.java
+++ b/com.oracle.truffle.r.shell/src/com/oracle/truffle/r/shell/RCommand.java
@@ -155,7 +155,7 @@ public class RCommand {
             String content = new String(bytes);
             JLineConsoleHandler consoleHandler = new JLineConsoleHandler(false, new ConsoleReader(null, System.out));
             VirtualFrame frame = REngine.initialize(commandArgs, consoleHandler, true, true);
-            REngine.getInstance().parseAndEval(filePath, content, frame, REnvironment.globalEnv(), false, false);
+            REngine.getInstance().parseAndEval(filePath, content, frame.materialize(), REnvironment.globalEnv(), false, false);
         } catch (IOException ex) {
             Utils.fail("unexpected error reading file input");
         }
@@ -180,7 +180,7 @@ public class RCommand {
                     continue;
                 }
 
-                while (REngine.getInstance().parseAndEval("<shell_input>", input, globalFrame, REnvironment.globalEnv(), true, true) == Engine.INCOMPLETE_SOURCE) {
+                while (REngine.getInstance().parseAndEval("<shell_input>", input, globalFrame.materialize(), REnvironment.globalEnv(), true, true) == Engine.INCOMPLETE_SOURCE) {
                     console.setPrompt(SLAVE.getValue() ? "" : "+ ");
                     String additionalInput = console.readLine();
                     if (additionalInput == null) {
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index 404b6887966e31abbc2d64cb9b6cf91312bcf2ed..2fc370c18b81ebaf6ea853a5cad3d0b0abc866a1 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -133,6 +133,7 @@ com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RNGInitAdapter
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/mt/MersenneTwister.java,hiroshima.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/mm/MarsagliaMulticarry.java,gnu_r.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java,gnu_r.copyright
+com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java,gnu_r.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RAccuracyInfo.java,gnu_r.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RGroupGenerics.java,purdue.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java,gnu_r.copyright