diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
index a439a0b7db36dcd248ecc5f690dbac5da2861088..d0d48097d59d96b28d8e3770e37f6f31bb0d5131 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
@@ -92,6 +92,7 @@ import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder.Argument;
 import com.oracle.truffle.r.runtime.nodes.RInstrumentableNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
+import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction;
@@ -222,21 +223,27 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
 
     @Override
     @TruffleBoundary
-    public Object fromList(RList list, RLanguage.RepType repType) {
+    public Object createLanguageFromList(RList list, RLanguage.RepType repType) {
         int length = list.getLength();
         if (length == 0) {
             return RNull.instance;
         } else if (repType == RLanguage.RepType.CALL) {
             RStringVector formals = list.getNames();
-            RSyntaxNode[] arguments = new RSyntaxNode[length - 1];
-            String[] sigNames = new String[arguments.length];
+
+            List<RCodeBuilder.Argument<RSyntaxNode>> argList = new ArrayList<>(length - 1);
             for (int i = 1; i < length; i++) {
-                arguments[i - 1] = (RSyntaxNode) unwrapToRNode(list.getDataAtAsObject(i));
                 String formal = formals == null ? null : formals.getDataAt(i);
-                sigNames[i - 1] = formal != null && formal.length() > 0 ? formal : null;
+                RSyntaxNode syntaxArg = (RSyntaxNode) unwrapToRNode(list.getDataAtAsObject(i));
+                if (formal != null) {
+                    argList.add(RCodeBuilder.argument(RSourceSectionNode.LAZY_DEPARSE, formal, syntaxArg));
+                } else {
+                    argList.add(RCodeBuilder.argument(syntaxArg));
+                }
             }
+
             RNode fn = unwrapToRNode(list.getDataAtAsObject(0));
-            RLanguage result = RDataFactory.createLanguage(RASTUtils.createCall(fn, false, ArgumentsSignature.get(sigNames), arguments).asRNode());
+            RSyntaxNode call = RContext.getASTBuilder().call(RSourceSectionNode.LAZY_DEPARSE, fn.asRSyntaxNode(), argList);
+            RLanguage result = RDataFactory.createLanguage(call.asRNode());
             if (formals != null && formals.getLength() > 0 && formals.getDataAt(0).length() > 0) {
                 result.setCallLHSName(formals.getDataAt(0));
             }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
index 0fd2bf80d7febf8ed9d5b24c8dccc5a01cad255f..b459887c3e7b27730c2d4f2fb85fe16ba16a8d8b 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
@@ -136,7 +136,12 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
     private final Map<String, Object> nameSymbolCache = new ConcurrentHashMap<>();
 
     private static RuntimeException implementedAsNode() {
-        throw RInternalError.shouldNotReachHere("upcall function is implemented via a node");
+        // TODO: Exception handling over native boundaries is currently missing. Once this works,
+        // remove the following two lines.
+        System.err.println("upcall function is implemented via a node");
+        System.exit(1);
+
+        return RInternalError.shouldNotReachHere("upcall function is implemented via a node");
     }
 
     // Checkstyle: stop method name check
@@ -217,6 +222,13 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         return 0;
     }
 
+    @Override
+    public Object R_getClassDef(String clazz) {
+        String name = "getClassDef";
+        RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name));
+        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), true, null, clazz);
+    }
+
     @Override
     public Object R_do_MAKE_CLASS(String clazz) {
         String name = "getClass";
@@ -1678,4 +1690,15 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
     private static RFFIContext getContext() {
         return RContext.getInstance().getStateRFFI();
     }
+
+    @Override
+    public Object Rf_match(Object itables, Object ix, int nmatch) {
+        throw implementedAsNode();
+    }
+
+    @Override
+    public Object Rf_NonNullStringMatch(Object s, Object t) {
+        throw implementedAsNode();
+    }
+
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MatchNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MatchNodes.java
new file mode 100644
index 0000000000000000000000000000000000000000..fbd8025aaec2505b46256817a7c5437290878dfc
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MatchNodes.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.nodes;
+
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.dsl.TypeSystemReference;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RTypes;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+
+public final class MatchNodes {
+
+    @TypeSystemReference(RTypes.class)
+    public abstract static class MatchNode extends FFIUpCallNode.Arg3 {
+
+        @SuppressWarnings("unused")
+        @Specialization
+        Object match(Object itables, Object ix, int nmatch) {
+            throw RInternalError.unimplemented("Rf_match");
+        }
+
+        public static MatchNode create() {
+            return MatchNodesFactory.MatchNodeGen.create();
+        }
+    }
+
+    @TypeSystemReference(RTypes.class)
+    public abstract static class NonNullStringMatchNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization(guards = {"s.getLength() == 1", "t.getLength() == 1"})
+        Object matchSingle(RAbstractStringVector s, RAbstractStringVector t) {
+            if (s.getDataAt(0) == RRuntime.STRING_NA || t.getDataAt(0) == RRuntime.STRING_NA) {
+                return RRuntime.LOGICAL_FALSE;
+            }
+            return RRuntime.asLogical(s.getDataAt(0).equals(t.getDataAt(0)));
+        }
+
+        @Fallback
+        @SuppressWarnings("unused")
+        Object match(Object s, Object t) {
+            throw RInternalError.unimplemented("Rf_NonNullStringMatch");
+        }
+
+        public static NonNullStringMatchNode create() {
+            return MatchNodesFactory.NonNullStringMatchNodeGen.create();
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
index 6d7d2f2c571aa8bfcf848a11ae41e5e9bf295a12..515524a94b9a9918eb060ebca0e589d53b01d1ad 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
@@ -113,7 +113,7 @@ public final class MiscNodes {
     }
 
     @TypeSystemReference(RTypes.class)
-    abstract static class RDoSlotNode extends FFIUpCallNode.Arg2 {
+    public abstract static class RDoSlotNode extends FFIUpCallNode.Arg2 {
 
         @Child private AccessSlotNode accessSlotNode;
 
@@ -137,7 +137,7 @@ public final class MiscNodes {
     }
 
     @TypeSystemReference(RTypes.class)
-    abstract static class RDoSlotAssignNode extends FFIUpCallNode.Arg3 {
+    public abstract static class RDoSlotAssignNode extends FFIUpCallNode.Arg3 {
 
         @Child private UpdateSlotNode updateSlotNode;
 
@@ -150,6 +150,11 @@ public final class MiscNodes {
             return updateSlotNode.executeUpdate(o, name, value);
         }
 
+        @Specialization
+        Object doSlotAssign(Object o, RSymbol name, Object value) {
+            return updateSlotNode.executeUpdate(o, name.getName(), value);
+        }
+
         @Fallback
         Object doSlot(@SuppressWarnings("unused") Object o, Object name, @SuppressWarnings("unused") Object value) {
             throw RError.error(RError.SHOW_CALLER2, RError.Message.INVALID_ARGUMENT_OF_TYPE, "name", SEXPTYPE.gnuRTypeForObject(name).name());
@@ -161,7 +166,7 @@ public final class MiscNodes {
     }
 
     @TypeSystemReference(RTypes.class)
-    abstract static class RDoNewObjectNode extends FFIUpCallNode.Arg1 {
+    public abstract static class RDoNewObjectNode extends FFIUpCallNode.Arg1 {
 
         @Child private NewObject newObjectNode;
 
@@ -180,7 +185,7 @@ public final class MiscNodes {
     }
 
     @TypeSystemReference(RTypes.class)
-    abstract static class NamesGetsNode extends FFIUpCallNode.Arg2 {
+    public abstract static class NamesGetsNode extends FFIUpCallNode.Arg2 {
 
         @Child private SetNamesAttributeNode setNamesNode;
 
@@ -193,6 +198,10 @@ public final class MiscNodes {
             setNamesNode.execute(vec, val);
             return vec;
         }
+
+        public static NamesGetsNode create() {
+            return MiscNodesFactory.NamesGetsNodeGen.create();
+        }
     }
 
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RandFunctionsNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RandFunctionsNodes.java
index f168c1caeda218a4a7589d1e2a6edc979faa8fb8..a626970a7e77ca884c63f9dc0580fc8b6ef2d303 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RandFunctionsNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RandFunctionsNodes.java
@@ -24,13 +24,16 @@ package com.oracle.truffle.r.ffi.impl.nodes;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions;
+import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function3_1;
+import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function3_2;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandFunction2_Double;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandomNumberProvider;
+import com.oracle.truffle.r.runtime.nmath.distr.Unif;
 
 public final class RandFunctionsNodes {
 
-    public abstract static class RandFunction3_2Node extends FFIUpCallNode.Arg5 {
+    abstract static class RandFunction3_2Node extends FFIUpCallNode.Arg5 {
         private final MathFunctions.Function3_2 inner;
 
         protected RandFunction3_2Node(MathFunctions.Function3_2 inner) {
@@ -43,7 +46,7 @@ public final class RandFunctionsNodes {
         }
     }
 
-    public abstract static class RandFunction3_1Node extends FFIUpCallNode.Arg4 {
+    abstract static class RandFunction3_1Node extends FFIUpCallNode.Arg4 {
         private final MathFunctions.Function3_1 inner;
 
         protected RandFunction3_1Node(MathFunctions.Function3_1 inner) {
@@ -56,7 +59,7 @@ public final class RandFunctionsNodes {
         }
     }
 
-    public abstract static class RandFunction2Node extends FFIUpCallNode.Arg2 {
+    abstract static class RandFunction2Node extends FFIUpCallNode.Arg2 {
         @Child private RandomFunctions.RandFunction2_Double inner;
 
         protected RandFunction2Node(RandFunction2_Double inner) {
@@ -69,4 +72,51 @@ public final class RandFunctionsNodes {
         }
     }
 
+    public abstract static class RunifNode extends RandFunction2Node {
+
+        protected RunifNode(RandFunction2_Double inner) {
+            super(inner);
+        }
+
+        public static RunifNode create() {
+            return RandFunctionsNodesFactory.RunifNodeGen.create(new Unif.Runif());
+        }
+
+    }
+
+    public abstract static class DunifNode extends RandFunction3_1Node {
+
+        protected DunifNode(Function3_1 inner) {
+            super(inner);
+        }
+
+        public static DunifNode create() {
+            return RandFunctionsNodesFactory.DunifNodeGen.create(new Unif.DUnif());
+        }
+
+    }
+
+    public abstract static class QunifNode extends RandFunction3_2Node {
+
+        protected QunifNode(Function3_2 inner) {
+            super(inner);
+        }
+
+        public static QunifNode create() {
+            return RandFunctionsNodesFactory.QunifNodeGen.create(new Unif.QUnif());
+        }
+
+    }
+
+    public abstract static class PunifNode extends RandFunction3_2Node {
+
+        protected PunifNode(Function3_2 inner) {
+            super(inner);
+        }
+
+        public static PunifNode create() {
+            return RandFunctionsNodesFactory.PunifNodeGen.create(new Unif.PUnif());
+        }
+
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
index 4b7965ab318ddf4b53548d9d3036c4aaf72c2f52..d6dff9a1df3609c3548429a12a3b9e81b03ca595 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
@@ -36,7 +36,10 @@ import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CADRNode;
 import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CARNode;
 import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CDDRNode;
 import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CDRNode;
+import com.oracle.truffle.r.ffi.impl.nodes.MatchNodes;
+import com.oracle.truffle.r.ffi.impl.nodes.MiscNodes;
 import com.oracle.truffle.r.ffi.impl.nodes.MiscNodes.LENGTHNode;
+import com.oracle.truffle.r.ffi.impl.nodes.RandFunctionsNodes;
 import com.oracle.truffle.r.ffi.processor.RFFICstring;
 import com.oracle.truffle.r.ffi.processor.RFFIRunGC;
 import com.oracle.truffle.r.ffi.processor.RFFIUpCallNode;
@@ -93,8 +96,11 @@ public interface StdUpCallsRFFI {
 
     int /* void */ Rf_defineVar(Object symbolArg, Object value, Object envArg);
 
+    Object R_getClassDef(@RFFICstring String clazz);
+
     Object R_do_MAKE_CLASS(@RFFICstring String clazz);
 
+    @RFFIUpCallNode(MiscNodes.RDoNewObjectNode.class)
     Object R_do_new_object(Object classDef);
 
     /**
@@ -315,8 +321,10 @@ public interface StdUpCallsRFFI {
 
     boolean isSeekable(Object x);
 
+    @RFFIUpCallNode(MiscNodes.RDoSlotNode.class)
     Object R_do_slot(Object o, Object name);
 
+    @RFFIUpCallNode(MiscNodes.RDoSlotAssignNode.class)
     Object R_do_slot_assign(Object o, Object name, Object value);
 
     Object R_MethodsNamespace();
@@ -325,14 +333,19 @@ public interface StdUpCallsRFFI {
 
     int FASTR_getConnectionChar(Object obj);
 
+    @RFFIUpCallNode(RandFunctionsNodes.DunifNode.class)
     double Rf_dunif(double a, double b, double c, int d);
 
+    @RFFIUpCallNode(RandFunctionsNodes.QunifNode.class)
     double Rf_qunif(double a, double b, double c, int d, int e);
 
+    @RFFIUpCallNode(RandFunctionsNodes.PunifNode.class)
     double Rf_punif(double a, double b, double c, int d, int e);
 
+    @RFFIUpCallNode(RandFunctionsNodes.RunifNode.class)
     double Rf_runif(double a, double b);
 
+    @RFFIUpCallNode(MiscNodes.NamesGetsNode.class)
     Object Rf_namesgets(Object vec, Object val);
 
     @RFFIUpCallNode(CopyMostAttrib.class)
@@ -343,4 +356,10 @@ public interface StdUpCallsRFFI {
 
     @RFFIUpCallNode(CADDRNode.class)
     Object Rf_asCharacterFactor(Object x);
+
+    @RFFIUpCallNode(MatchNodes.MatchNode.class)
+    Object Rf_match(Object itables, Object ix, int nmatch);
+
+    @RFFIUpCallNode(MatchNodes.NonNullStringMatchNode.class)
+    Object Rf_NonNullStringMatch(Object s, Object t);
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/PPSum.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/PPSum.java
new file mode 100644
index 0000000000000000000000000000000000000000..6fd2053b204f3a7d2ec7b1df29a72e0ae1c5c74c
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/PPSum.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.library.stats;
+
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.library.stats.PPSumFactory.IntgrtVecNodeGen;
+import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+
+public abstract class PPSum {
+
+    /**
+     * Implementation of function 'intgrt_vec'.
+     */
+    public abstract static class IntgrtVecNode extends RExternalBuiltinNode.Arg3 {
+
+        private final ValueProfile profileArgX = ValueProfile.createClassProfile();
+        private final ValueProfile profileArgXi = ValueProfile.createClassProfile();
+
+        static {
+            Casts casts = new Casts(IntgrtVecNode.class);
+            casts.arg(0).asDoubleVector();
+            casts.arg(1).asDoubleVector();
+            casts.arg(2).asIntegerVector().findFirst();
+        }
+
+        @Specialization
+        protected RAbstractDoubleVector doIntegrateVector(RAbstractDoubleVector x, RAbstractDoubleVector xi, int lag) {
+            RAbstractDoubleVector profiledX = profileArgX.profile(x);
+            RAbstractDoubleVector profiledXi = profileArgXi.profile(xi);
+
+            int n = profiledX.getLength();
+            int nResult = n + lag;
+
+            RDoubleVector result = (RDoubleVector) profiledXi.copyResized(nResult, false);
+
+            double[] store = result.getInternalStore();
+            for (int i = 0; i < n; i++) {
+                store[i + lag] = profiledX.getDataAt(i) + store[i];
+            }
+            return result;
+        }
+
+        public static IntgrtVecNode create() {
+            return IntgrtVecNodeGen.create();
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R
index 37640f855ba9e0ec96d6831e6d6abb188f944f2c..2175ac8d653c38340f7b99f3a51baa4a5b5bf1b8 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R
@@ -582,14 +582,16 @@ termsform <- function (x.in, specials, data, keep.order, allowDotAsName) {
     varlist <<- list()
     ExtractVars(x)
     vars <- quote(list())
-    vars[2:(length(varlist) + 1L)] <- varlist
+    if(length(varlist)) {
+    	vars[2:(length(varlist) + 1L)] <- varlist
+    }
     attr(x, "variables") <- vars
     
     # Note: GnuR uses bitvector of integers and variable nwords to denote its size, we do not need that
     nvar <<- length(varlist) 
     formula <- EncodeVars(x)
     
-    # EncodeVars may have stretched varlist becuase it is a global variable (to reflect GnuR's implementation) 
+    # EncodeVars may have stretched varlist because it is a global variable (to reflect GnuR's implementation) 
     nvar <<- length(varlist)
     
     # Step 2a: Compute variable names 
@@ -611,24 +613,28 @@ termsform <- function (x.in, specials, data, keep.order, allowDotAsName) {
     
     # Step 3: Reorder the model terms by BitCount, otherwise
     # preserving their order. 
-    sCounts <- vapply(formula, BitCount, 0L)
-    bitmax <- max(sCounts)
-
-    if (keep.order) {
-        ord <- sCounts;
-    } else {
-      pattern <- formula # save original formula
-      callIdx <- 1L
-      ord <- integer(nterm)
-      for (i in 0:bitmax) {
-        for (n in 1:nterm) {
-          if (sCounts[[n]] == i) {
-            formula[[callIdx]] <- pattern[[n]]
-            ord[[callIdx]] <- i
-            callIdx <- callIdx + 1L
+    if(nterm) {
+        sCounts <- vapply(formula, BitCount, 0L)
+        bitmax <- max(sCounts)
+        
+        if (keep.order) {
+            ord <- sCounts;
+        } else {
+          pattern <- formula # save original formula
+          callIdx <- 1L
+          ord <- integer(nterm)
+          for (i in 0:bitmax) {
+            for (n in 1:nterm) {
+              if (sCounts[[n]] == i) {
+                formula[[callIdx]] <- pattern[[n]]
+                ord[[callIdx]] <- i
+                callIdx <- callIdx + 1L
+              }
+            }
           }
         }
-      }
+    } else {
+    	ord <- integer()
     }
     
     # Step 4: Compute the factor pattern for the model. 
@@ -996,7 +1002,7 @@ modelmatrix <- function(formula, modelframe) {
     # If there is no intercept we look through the factor pattern
     # matrix and adjust the code for the first factor found so that
     # it will be coded by dummy variables rather than contrasts.
-    if (!intercept) {
+    if (!intercept && nterms > 0L) {
         # Note/TODO: in GnuR response is retrieved using asLogical, 
         # but here it is used as an index, is this intended?
         done <- FALSE
@@ -1034,7 +1040,7 @@ modelmatrix <- function(formula, modelframe) {
     # By convention, an rhs term identical to the response generates nothing
     # in the model matrix (but interactions involving the response do).
     rhs_response = -1;
-    if (response > 0) {
+    if (response > 0 && nterms > 0L) {
         for (j in 1:nterms) {
             if (factors[response, j] != 0L && sum(factors[,j] > 0L) == 1L) {
                 rhs_response = j
@@ -1052,36 +1058,38 @@ modelmatrix <- function(formula, modelframe) {
     if (intercept) {
         dnc <- 1
     }
-    for (j in 1:nterms) {
-        if (j == rhs_response) {
-            warning("the response appeared on the right-hand side and was dropped")
-            count[[j]] <- 0L
-        }
-        
-        dk <- 1L
-        for (i in 1:nvar) {
-            factors_ij <- factors[i,j]
-            if (factors_ij == 0L) {
-                next
+    if(nterms > 0L) {
+        for (j in 1:nterms) {
+            if (j == rhs_response) {
+                warning("the response appeared on the right-hand side and was dropped")
+                count[[j]] <- 0L
             }
             
-            if (nlevs[[i]] != 0L) {
-                if (factors_ij == 1L) {
-                    dk <- dk * ncols(contr1[[i]])
-                } else if (factors_ij == 2L) {
-                    dk <- dk * ncols(contr2[[i]])
+            dk <- 1L
+            for (i in 1:nvar) {
+                factors_ij <- factors[i,j]
+                if (factors_ij == 0L) {
+                    next
+                }
+                
+                if (nlevs[[i]] != 0L) {
+                    if (factors_ij == 1L) {
+                        dk <- dk * ncols(contr1[[i]])
+                    } else if (factors_ij == 2L) {
+                        dk <- dk * ncols(contr2[[i]])
+                    }
+                } else {
+                    dk <- dk * columns[[i]]
                 }
-            } else {
-                dk <- dk * columns[[i]]
             }
-        }
-        
-        if (typeof(dk) == "double") {
-            error(paste0("term ", j, " would require ", dk, " columns"))
-        }
-        count[[j]] <- dk
-        dnc <- dnc + dk
-    }    
+            
+            if (typeof(dk) == "double") {
+                error(paste0("term ", j, " would require ", dk, " columns"))
+            }
+            count[[j]] <- dk
+            dnc <- dnc + dk
+        }    
+    }
     
     # Record which columns of the design matrix are associated with which model terms
     assign <- integer(dnc)
@@ -1090,15 +1098,17 @@ modelmatrix <- function(formula, modelframe) {
         assign[[k]] <- 0L
         k <- k + 1
     }
-    for (j in 1:nterms) {
-        if (count[[j]] <= 0L) {
-            warning(paste0("problem with term ", j, " in model.matrix: no columns are assigned"))
+    if(nterms > 0L) {
+        for (j in 1:nterms) {
+            if (count[[j]] <= 0L) {
+                warning(paste0("problem with term ", j, " in model.matrix: no columns are assigned"))
+            }
+            
+            # idx.seq covers columns that are associated with term 'j'
+            idx.seq <- seq(k, length.out = count[[j]])
+            assign[idx.seq] <- j
+            k <- k + count[[j]]
         }
-        
-        # idx.seq covers columns that are associated with term 'j'
-        idx.seq <- seq(k, length.out = count[[j]])
-        assign[idx.seq] <- j
-        k <- k + count[[j]]
     }
     
     # Create column labels for the matrix columns.
@@ -1122,58 +1132,60 @@ modelmatrix <- function(formula, modelframe) {
     # append them together with ':', this gives us 'x', 'q', 'x:q'. Plus 
     # some special handling that makes it less straightforward
     
-    for (j in 1:nterms) {
-        if (j == rhs_response) {
-            next
-        }
-        for (kk in 1:count[j]) {
-            first <- TRUE
-            indx <- kk - 1 # zero base like in GnuR C code
-            buffer <- ""
-            for (i in 1:nvar) {
-                ll <- factors[i,j]
-                if (ll != 0L) {
-                    var_i <- variable[[i]]
-                    if (!first) {
-                        buffer  <- paste0(buffer, ":")
-                    }
-                    first <- FALSE
-                    if (is.factor(var_i) || is.logical(var_i)) {
-                        if (ll == 1) {
-                            x = ColumnNames(contr1[[i]])
-                            ll <- ncols(contr1[[i]])
-                        } else {
-                            x = ColumnNames(contr2[[i]])
-                            ll <- ncols(contr2[[i]])
-                        }
-                        buffer <- paste0(buffer, vnames[[i]])
-                        if (is.null(x)) {
-                            buffer <- paste0(buffer, indx %% ll + 1)
-                        } else {
-                            buffer <- paste0(buffer, x[[indx %% ll + 1]])
+    if(nterms > 0L) {
+        for (j in 1:nterms) {
+            if (j == rhs_response) {
+                next
+            }
+            for (kk in 1:count[j]) {
+                first <- TRUE
+                indx <- kk - 1 # zero base like in GnuR C code
+                buffer <- ""
+                for (i in 1:nvar) {
+                    ll <- factors[i,j]
+                    if (ll != 0L) {
+                        var_i <- variable[[i]]
+                        if (!first) {
+                            buffer  <- paste0(buffer, ":")
                         }
-                    } else if (is.complex(var_i)) {
-                        error("complex variables are not currently allowed in model matrices");
-                    } else if (is.numeric(var_i)) {
-                        x = ColumnNames(var_i)
-                        ll = ncols(var_i)
-                        buffer = paste0(buffer, vnames[[i]])
-                        if (ll > 1L) {
+                        first <- FALSE
+                        if (is.factor(var_i) || is.logical(var_i)) {
+                            if (ll == 1) {
+                                x = ColumnNames(contr1[[i]])
+                                ll <- ncols(contr1[[i]])
+                            } else {
+                                x = ColumnNames(contr2[[i]])
+                                ll <- ncols(contr2[[i]])
+                            }
+                            buffer <- paste0(buffer, vnames[[i]])
                             if (is.null(x)) {
                                 buffer <- paste0(buffer, indx %% ll + 1)
                             } else {
                                 buffer <- paste0(buffer, x[[indx %% ll + 1]])
                             }
+                        } else if (is.complex(var_i)) {
+                            error("complex variables are not currently allowed in model matrices");
+                        } else if (is.numeric(var_i)) {
+                            x = ColumnNames(var_i)
+                            ll = ncols(var_i)
+                            buffer = paste0(buffer, vnames[[i]])
+                            if (ll > 1L) {
+                                if (is.null(x)) {
+                                    buffer <- paste0(buffer, indx %% ll + 1)
+                                } else {
+                                    buffer <- paste0(buffer, x[[indx %% ll + 1]])
+                                }
+                            }
+                        } else {
+                            error(paste0("variables of type '", typeof(var_i), "' are not allowed in model matrices"))
                         }
-                    } else {
-                        error(paste0("variables of type '", typeof(var_i), "' are not allowed in model matrices"))
+                        indx <- indx %/% ll;
                     }
-                    indx <- indx %/% ll;
                 }
+                
+                xnames[[k]] <- buffer
+                k <- k + 1
             }
-            
-            xnames[[k]] <- buffer
-            k <- k + 1
         }
     }
     
@@ -1202,54 +1214,56 @@ modelmatrix <- function(formula, modelframe) {
     jnext <- as.integer(intercept) + 1
     jstart <- jnext
     contrast <- NULL
-    for (k in 1:nterms) {
-        if (k == rhs_response) { next }
-        # for each term we go through the rows in corresponding column in 'factor'
-        for (i in 1:nvar) {
-            if (columns[[i]] == 0L) { next } # num of cols == 0
-            var_i <- variable[[i]]
-            factor_ik <- factors[i,k]
-            
-            # if factor for this variable is != 0 we do some action with it, resulting 
-            # into putting new columns into the result 'x'. This moves jnext by the 
-            # number of new columns, jstart tells us the first column that was copied 
-            # within this innermost loop
-            if (factor_ik == 0L) { next }
-            if (factor_ik == 1L) {
-                contrast <- contr1[[i]]
-            } else {
-                contrast <- contr2[[i]]
-            }
-            
-            # is this the first non-zero factor in this factor column?
-            if (jnext == jstart) {
-                if (nlevs[[i]] > 0L) {
-                    for (j in 1:ncols(contrast)) {
-                        x[,jstart + j - 1] = get.col(contrast,j)[var_i]
-                    }
-                    jnext = jnext + ncols(contrast)
+    if(nterms > 0L) {
+        for (k in 1:nterms) {
+            if (k == rhs_response) { next }
+            # for each term we go through the rows in corresponding column in 'factor'
+            for (i in 1:nvar) {
+                if (columns[[i]] == 0L) { next } # num of cols == 0
+                var_i <- variable[[i]]
+                factor_ik <- factors[i,k]
+                
+                # if factor for this variable is != 0 we do some action with it, resulting 
+                # into putting new columns into the result 'x'. This moves jnext by the 
+                # number of new columns, jstart tells us the first column that was copied 
+                # within this innermost loop
+                if (factor_ik == 0L) { next }
+                if (factor_ik == 1L) {
+                    contrast <- contr1[[i]]
                 } else {
-                    # first variable in this term is simply copied, note that it can 
-                    # be a matrix or a vector, this assignment handles both: 
-                    # vector is treated as a single column matrix
-                    x[, seq(jstart, length.out = ncols(var_i))] <- var_i
-                    jnext = jnext + ncols(var_i)
+                    contrast <- contr2[[i]]
                 }
-            } else {
-                if (nlevs[[i]] > 0L) {
-                    cont.var = matrix(0L, nrows(var_i), ncols(contrast))
-                    for (j in 1:ncols(contrast)) {
-                        cont.var[,j] = get.col(contrast,j)[var_i]
-                    }                    
-                    x <- addvar(x, jstart, jnext - jstart, cont.var)
-                    jnext <- jnext + (jnext - jstart) * (ncols(contrast) - 1);
+                
+                # is this the first non-zero factor in this factor column?
+                if (jnext == jstart) {
+                    if (nlevs[[i]] > 0L) {
+                        for (j in 1:ncols(contrast)) {
+                            x[,jstart + j - 1] = get.col(contrast,j)[var_i]
+                        }
+                        jnext = jnext + ncols(contrast)
+                    } else {
+                        # first variable in this term is simply copied, note that it can 
+                        # be a matrix or a vector, this assignment handles both: 
+                        # vector is treated as a single column matrix
+                        x[, seq(jstart, length.out = ncols(var_i))] <- var_i
+                        jnext = jnext + ncols(var_i)
+                    }
                 } else {
-                    x <- addvar(x, jstart, jnext - jstart, var_i)
-                    jnext <- jnext + (jnext - jstart) * (ncols(var_i) - 1);
+                    if (nlevs[[i]] > 0L) {
+                        cont.var = matrix(0L, nrows(var_i), ncols(contrast))
+                        for (j in 1:ncols(contrast)) {
+                            cont.var[,j] = get.col(contrast,j)[var_i]
+                        }                    
+                        x <- addvar(x, jstart, jnext - jstart, cont.var)
+                        jnext <- jnext + (jnext - jstart) * (ncols(contrast) - 1);
+                    } else {
+                        x <- addvar(x, jstart, jnext - jstart, var_i)
+                        jnext <- jnext + (jnext - jstart) * (ncols(var_i) - 1);
+                    }
                 }
             }
+            jstart <- jnext
         }
-        jstart <- jnext
     }
     
     dimnames(x) <- list(row.names(modelframe), xnames)
diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
index 3d29cb9f88548f2536114d3b2b9e893a6499d498..e48fc20e3ce43ba1249164d1c78ab328bd6df01d 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
+++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
@@ -275,6 +275,8 @@ typedef double (*call_Rf_qunif)(double a, double b, double c, int d, int e);
 typedef double (*call_Rf_dunif)(double a, double b, double c, int d);
 typedef double (*call_Rf_punif)(double a, double b, double c, int d, int e);
 typedef double (*call_Rf_runif)(double x, double y);
+typedef SEXP (*call_Rf_match)(SEXP itable, SEXP ix, int nmatch);
+typedef Rboolean (*call_Rf_NonNullStringMatch)(SEXP s, SEXP t);
 
 typedef SEXP (*call_getvar)();
 
diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h
index e028d1c383ec401a6d1307c87ad3aa41b295b6c0..a86b1d5693b84d22db836eb98851b7078a19216d 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h
+++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h
@@ -67,103 +67,106 @@
 #define R_do_new_object_x 62
 #define R_do_slot_x 63
 #define R_do_slot_assign_x 64
-#define R_getContextCall_x 65
-#define R_getContextEnv_x 66
-#define R_getContextFun_x 67
-#define R_getContextSrcRef_x 68
-#define R_getGlobalFunctionContext_x 69
-#define R_getParentFunctionContext_x 70
-#define R_insideBrowser_x 71
-#define R_isEqual_x 72
-#define R_isGlobal_x 73
-#define R_lsInternal3_x 74
-#define R_new_custom_connection_x 75
-#define R_tryEval_x 76
-#define Rf_GetOption1_x 77
-#define Rf_PairToVectorList_x 78
-#define Rf_ScalarDouble_x 79
-#define Rf_ScalarInteger_x 80
-#define Rf_ScalarLogical_x 81
-#define Rf_ScalarString_x 82
-#define Rf_VectorToPairList_x 83
-#define Rf_allocArray_x 84
-#define Rf_allocMatrix_x 85
-#define Rf_allocVector_x 86
-#define Rf_any_duplicated_x 87
-#define Rf_asChar_x 88
-#define Rf_asCharacterFactor_x 89
-#define Rf_asInteger_x 90
-#define Rf_asLogical_x 91
-#define Rf_asReal_x 92
-#define Rf_classgets_x 93
-#define Rf_coerceVector_x 94
-#define Rf_cons_x 95
-#define Rf_copyListMatrix_x 96
-#define Rf_copyMatrix_x 97
-#define Rf_copyMostAttrib_x 98
-#define Rf_defineVar_x 99
-#define Rf_dunif_x 100
-#define Rf_duplicate_x 101
-#define Rf_error_x 102
-#define Rf_errorcall_x 103
-#define Rf_eval_x 104
-#define Rf_findFun_x 105
-#define Rf_findVar_x 106
-#define Rf_findVarInFrame_x 107
-#define Rf_findVarInFrame3_x 108
-#define Rf_getAttrib_x 109
-#define Rf_gsetVar_x 110
-#define Rf_inherits_x 111
-#define Rf_install_x 112
-#define Rf_installChar_x 113
-#define Rf_isNull_x 114
-#define Rf_isString_x 115
-#define Rf_lengthgets_x 116
-#define Rf_mkCharLenCE_x 117
-#define Rf_namesgets_x 118
-#define Rf_ncols_x 119
-#define Rf_nrows_x 120
-#define Rf_protect_x 121
-#define Rf_punif_x 122
-#define Rf_qunif_x 123
-#define Rf_runif_x 124
-#define Rf_setAttrib_x 125
-#define Rf_str2type_x 126
-#define Rf_unprotect_x 127
-#define Rf_unprotect_ptr_x 128
-#define Rf_warning_x 129
-#define Rf_warningcall_x 130
-#define Rprintf_x 131
-#define SETCADR_x 132
-#define SETCAR_x 133
-#define SETCDR_x 134
-#define SET_NAMED_FASTR_x 135
-#define SET_RDEBUG_x 136
-#define SET_RSTEP_x 137
-#define SET_S4_OBJECT_x 138
-#define SET_STRING_ELT_x 139
-#define SET_SYMVALUE_x 140
-#define SET_TAG_x 141
-#define SET_TYPEOF_FASTR_x 142
-#define SET_VECTOR_ELT_x 143
-#define STRING_ELT_x 144
-#define SYMVALUE_x 145
-#define TAG_x 146
-#define TYPEOF_x 147
-#define UNSET_S4_OBJECT_x 148
-#define VECTOR_ELT_x 149
-#define forceSymbols_x 150
-#define getCCallable_x 151
-#define getConnectionClassString_x 152
-#define getOpenModeString_x 153
-#define getSummaryDescription_x 154
-#define isSeekable_x 155
-#define registerCCallable_x 156
-#define registerRoutines_x 157
-#define setDotSymbolValues_x 158
-#define unif_rand_x 159
-#define useDynamicSymbols_x 160
+#define R_getClassDef_x 65
+#define R_getContextCall_x 66
+#define R_getContextEnv_x 67
+#define R_getContextFun_x 68
+#define R_getContextSrcRef_x 69
+#define R_getGlobalFunctionContext_x 70
+#define R_getParentFunctionContext_x 71
+#define R_insideBrowser_x 72
+#define R_isEqual_x 73
+#define R_isGlobal_x 74
+#define R_lsInternal3_x 75
+#define R_new_custom_connection_x 76
+#define R_tryEval_x 77
+#define Rf_GetOption1_x 78
+#define Rf_NonNullStringMatch_x 79
+#define Rf_PairToVectorList_x 80
+#define Rf_ScalarDouble_x 81
+#define Rf_ScalarInteger_x 82
+#define Rf_ScalarLogical_x 83
+#define Rf_ScalarString_x 84
+#define Rf_VectorToPairList_x 85
+#define Rf_allocArray_x 86
+#define Rf_allocMatrix_x 87
+#define Rf_allocVector_x 88
+#define Rf_any_duplicated_x 89
+#define Rf_asChar_x 90
+#define Rf_asCharacterFactor_x 91
+#define Rf_asInteger_x 92
+#define Rf_asLogical_x 93
+#define Rf_asReal_x 94
+#define Rf_classgets_x 95
+#define Rf_coerceVector_x 96
+#define Rf_cons_x 97
+#define Rf_copyListMatrix_x 98
+#define Rf_copyMatrix_x 99
+#define Rf_copyMostAttrib_x 100
+#define Rf_defineVar_x 101
+#define Rf_dunif_x 102
+#define Rf_duplicate_x 103
+#define Rf_error_x 104
+#define Rf_errorcall_x 105
+#define Rf_eval_x 106
+#define Rf_findFun_x 107
+#define Rf_findVar_x 108
+#define Rf_findVarInFrame_x 109
+#define Rf_findVarInFrame3_x 110
+#define Rf_getAttrib_x 111
+#define Rf_gsetVar_x 112
+#define Rf_inherits_x 113
+#define Rf_install_x 114
+#define Rf_installChar_x 115
+#define Rf_isNull_x 116
+#define Rf_isString_x 117
+#define Rf_lengthgets_x 118
+#define Rf_match_x 119
+#define Rf_mkCharLenCE_x 120
+#define Rf_namesgets_x 121
+#define Rf_ncols_x 122
+#define Rf_nrows_x 123
+#define Rf_protect_x 124
+#define Rf_punif_x 125
+#define Rf_qunif_x 126
+#define Rf_runif_x 127
+#define Rf_setAttrib_x 128
+#define Rf_str2type_x 129
+#define Rf_unprotect_x 130
+#define Rf_unprotect_ptr_x 131
+#define Rf_warning_x 132
+#define Rf_warningcall_x 133
+#define Rprintf_x 134
+#define SETCADR_x 135
+#define SETCAR_x 136
+#define SETCDR_x 137
+#define SET_NAMED_FASTR_x 138
+#define SET_RDEBUG_x 139
+#define SET_RSTEP_x 140
+#define SET_S4_OBJECT_x 141
+#define SET_STRING_ELT_x 142
+#define SET_SYMVALUE_x 143
+#define SET_TAG_x 144
+#define SET_TYPEOF_FASTR_x 145
+#define SET_VECTOR_ELT_x 146
+#define STRING_ELT_x 147
+#define SYMVALUE_x 148
+#define TAG_x 149
+#define TYPEOF_x 150
+#define UNSET_S4_OBJECT_x 151
+#define VECTOR_ELT_x 152
+#define forceSymbols_x 153
+#define getCCallable_x 154
+#define getConnectionClassString_x 155
+#define getOpenModeString_x 156
+#define getSummaryDescription_x 157
+#define isSeekable_x 158
+#define registerCCallable_x 159
+#define registerRoutines_x 160
+#define setDotSymbolValues_x 161
+#define unif_rand_x 162
+#define useDynamicSymbols_x 163
 
-#define UPCALLS_TABLE_SIZE 161
+#define UPCALLS_TABLE_SIZE 164
 
 #endif // RFFI_UPCALLSINDEX_H
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
index 583fee9348251042d78bd2bcb00ff56c65674652..a02784c1a830733cbbc6fc698410e357676b13d5 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h
@@ -1316,8 +1316,8 @@ SEXP R_do_MAKE_CLASS(const char *what) {
 }
 
 SEXP R_getClassDef (const char *what) {
-    TRACE0();
-    return unimplemented("R_getClassDef");
+    TRACE(TARGs, what);
+    return ((call_R_getClassDef) callbacks[R_getClassDef_x])(what);
 }
 
 SEXP R_do_new_object(SEXP class_def) {
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Utils.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/Utils.c
index 6c0a8d482cb9556b55b8475a0cd61c8c016d41b7..7b3a17dfc2a2dbd3fccb08d5040d491df232d83e 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Utils.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Utils.c
@@ -41,3 +41,10 @@ void Rf_onintr() {
     // TODO: implement interrupt handling, signal errors
     // ignored
 }
+
+Rboolean isOrdered(SEXP s)
+{
+    return (TYPEOF(s) == INTSXP
+	    && inherits(s, "factor")
+	    && inherits(s, "ordered"));
+}
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/match.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/match.c
new file mode 100644
index 0000000000000000000000000000000000000000..9a5d46d50c869f5e9fe00e6f214e34dc3a9c2387
--- /dev/null
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/match.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+#include "../truffle_nfi/rffiutils.h"
+#include "rffi_upcalls.h"
+
+Rboolean Rf_NonNullStringMatch(SEXP s, SEXP t)
+{
+	return ((call_Rf_NonNullStringMatch) callbacks[Rf_NonNullStringMatch_x])(s, t);
+}
+
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/unique.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/unique.c
new file mode 100644
index 0000000000000000000000000000000000000000..bfbe23c5f82fc85abce5a9e272bc5a7c9bbc93b2
--- /dev/null
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/unique.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+#include "../truffle_nfi/rffiutils.h"
+#include "rffi_upcalls.h"
+
+SEXP Rf_matchE(SEXP itable, SEXP ix, int nmatch, SEXP env)
+{
+	unimplemented("Rf_matchE");
+}
+
+/* used from other code, not here: */
+SEXP Rf_match(SEXP itable, SEXP ix, int nmatch)
+{
+	return ((call_Rf_match) callbacks[Rf_match_x])(itable, ix, nmatch);
+}
+
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Memory.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Memory.c
index 4f2042988b31bef3a8ac79452ddd45ca2e7cfaf6..9aa78ee7998c9dcc0cd21c9f8b39bcb9b7a9fee8 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Memory.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Memory.c
@@ -88,3 +88,9 @@ SEXP Rf_allocS4Object() {
     return NULL;
 }
 
+SEXP do_address(SEXP call, SEXP op, SEXP args, SEXP rho)
+{
+    checkArity(op, args);
+    return R_MakeExternalPtr((void *) CAR(args), R_NilValue, R_NilValue);
+}
+
diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source
index 81b5c5d06cc0b8290c264b408abb32cc0986e8f2..a2720097dccb441015beb4f75766b9908ad46f5a 100644
--- a/com.oracle.truffle.r.native/version.source
+++ b/com.oracle.truffle.r.native/version.source
@@ -1 +1 @@
-37
+39
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
index 33b9f53eb2bcc6da41a102539f92b1e8d6ca6f2e..33364751766bc9dd9cd61da732615d77464bd0bb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
@@ -36,6 +36,7 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
+import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
@@ -79,6 +80,7 @@ import com.oracle.truffle.r.runtime.data.RTypes;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
@@ -435,11 +437,14 @@ public abstract class Bind extends RBaseNode {
     @Specialization(guards = {"precedence != NO_PRECEDENCE", "args.length == 1"})
     protected Object allOneElem(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence,
                     @Cached("create()") GetNamesAttributeNode getNamesNode) {
+
         RAbstractVector vec = vectorProfile.profile(castVector(args[0]));
-        int[] rawDimensions = getVectorDimensions(vec);
+        int[] rawDimensions = null;
+        rawDimensions = getVectorDimensions(vec);
         if (GetDimAttributeNode.isMatrix(rawDimensions)) {
             return vec;
         }
+
         // for cbind dimNamesA is names for the 1st dim and dimNamesB is names for 2nd dim; for
         // rbind the other way around
         Object dimNamesA = getNamesNode.getNames(vec);
@@ -574,7 +579,7 @@ public abstract class Bind extends RBaseNode {
 
         @Specialization
         protected Object bind(VirtualFrame frame, int deparseLevel, RArgsValuesAndNames args) {
-            RFunction dispatchFunction = createDispatchFunction(frame, args.getArguments());
+            RFunction dispatchFunction = createDispatchFunction(frame, args.getArguments(), deparseLevel);
             if (hasDispatchFunction.profile(dispatchFunction != null)) {
                 if (dispatchCallNode == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -607,9 +612,20 @@ public abstract class Bind extends RBaseNode {
             return precedence;
         }
 
-        private RFunction createDispatchFunction(VirtualFrame frame, Object[] args) {
+        private RFunction createDispatchFunction(VirtualFrame frame, Object[] args, int deparseLevel) {
+
+            // S4 dispatch is only considered if deparseLevel is non-negative
+            boolean tryS4 = deparseLevel >= 0;
+
+            // indicating if any of the arguments is an S4 object
+            boolean anyS4 = false;
+
             Result result = null;
             for (Object arg : args) {
+                if (tryS4 && !anyS4 && RRuntime.isS4Object(arg)) {
+                    anyS4 = true;
+                }
+
                 RStringVector clazz = classHierarchy.execute(arg);
                 if (hasClassProfile.profile(clazz != null)) {
                     if (lookup == null) {
@@ -630,7 +646,17 @@ public abstract class Bind extends RBaseNode {
                     }
                 }
             }
-            return result != null ? result.function : null;
+
+            RFunction dispatchFunction = result != null ? result.function : null;
+
+            // TODO class compatibility: record if S3 classes were compatible, if not, do S4
+            // dispatch
+            // In this case, call function 'methods::cbind' or 'methods::rbind'.
+            if (dispatchFunction == null && anyS4) {
+                REnvironment methodsEnv = REnvironment.getRegisteredNamespace("methods");
+                dispatchFunction = ReadVariableNode.lookupFunction(type.name(), methodsEnv.getFrame(), true, true);
+            }
+            return dispatchFunction;
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
index 14cc631717cbcc5bcf1db61d9a08a405b3432d25..9c105a0af64c45af2c5b086f125805916f891f3a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
@@ -168,6 +168,7 @@ public class EnvFunctions {
         }
 
         @Specialization
+        @TruffleBoundary
         protected REnvironment asEnvironment(RList list,
                         @Cached("new()") RList2EnvNode list2Env) {
             REnvironment env = RDataFactory.createNewEnv(null);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
index ea9010d63eb5986035bdaf2631fd9772d243f1c1..45aa94bc53f72db3833e6658748a32c94382e84e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
@@ -925,7 +925,14 @@ public class GrepFunctions {
 
         @TruffleBoundary
         private static Matcher getPatternMatcher(String pattern, String text, boolean ignoreCase) {
-            return Pattern.compile(pattern, ignoreCase ? Pattern.CASE_INSENSITIVE : 0).matcher(text);
+            String actualPattern = pattern;
+
+            // If a pattern starts with a '*', GnuR virtually prepends an empty string literal to
+            // the star. This won't match anything, so just remove '*' from the pattern.
+            if (pattern.length() > 0 && pattern.charAt(0) == '*') {
+                actualPattern = pattern.substring(1);
+            }
+            return Pattern.compile(actualPattern, ignoreCase ? Pattern.CASE_INSENSITIVE : 0).matcher(text);
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
index 53a2fe0007ca4e46b1486dddb6a8a4aa6dd8fd86..286ed49c6b59006cfbce45ef2992eb83e971dd03 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode.isMatrix;
+import static com.oracle.truffle.r.runtime.RDispatch.OPS_GROUP_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
@@ -62,7 +63,7 @@ import com.oracle.truffle.r.runtime.data.nodes.GetReadonlyData;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
-@RBuiltin(name = "%*%", kind = PRIMITIVE, parameterNames = {"", ""}, behavior = PURE)
+@RBuiltin(name = "%*%", kind = PRIMITIVE, parameterNames = {"", ""}, behavior = PURE, dispatch = OPS_GROUP_GENERIC)
 public abstract class MatMult extends RBuiltinNode.Arg2 {
 
     private static final int BLOCK_SIZE = 64;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IsElementFastPath.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IsElementFastPath.java
index c211bb753ea774dc4e87c6f5e7e69554bbd9067b..b4b9c2b17c39951b94199db27ce9e3f712a5dbaa 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IsElementFastPath.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IsElementFastPath.java
@@ -57,7 +57,7 @@ public abstract class IsElementFastPath extends RFastPathNode {
         return RRuntime.LOGICAL_FALSE;
     }
 
-    @Specialization(replaces = "iselementOneCachedString")
+    @Specialization(guards = "elIn.getLength() == 1", replaces = "iselementOneCachedString")
     protected Byte iselementOne(RAbstractStringVector elIn, RAbstractStringVector setIn,
                     @Cached("create()") BranchProfile trueProfile,
                     @Cached("create()") BranchProfile falseProfile) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
index 704efdd2428bf484eaa6f68d93543e322ce81b28..647e0140bbf6faecbe62e14a6d897253acc45e6b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
@@ -42,6 +42,7 @@ import com.oracle.truffle.r.library.stats.CompleteCases;
 import com.oracle.truffle.r.library.stats.CovcorNodeGen;
 import com.oracle.truffle.r.library.stats.CutreeNodeGen;
 import com.oracle.truffle.r.library.stats.DoubleCentreNodeGen;
+import com.oracle.truffle.r.library.stats.PPSum;
 import com.oracle.truffle.r.library.stats.RMultinomNode;
 import com.oracle.truffle.r.library.stats.RandFunctionsNodes;
 import com.oracle.truffle.r.library.stats.RandFunctionsNodes.RandFunction1Node;
@@ -84,6 +85,7 @@ import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.nodes.MaterializeNode;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
@@ -222,6 +224,7 @@ public class CallAndExternalFunctions {
     public abstract static class DotCall extends LookupAdapter {
 
         @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getCallRFFI().createInvokeCallNode();
+        @Child MaterializeNode materializeNode = MaterializeNode.create();
 
         static {
             Casts.noCasts(DotCall.class);
@@ -232,6 +235,14 @@ public class CallAndExternalFunctions {
             return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY, RMissing.instance};
         }
 
+        private Object[] materializeArgs(VirtualFrame frame, Object[] args) {
+            Object[] materializedArgs = new Object[args.length];
+            for (int i = 0; i < args.length; i++) {
+                materializedArgs[i] = materializeNode.execute(frame, args[i]);
+            }
+            return materializedArgs;
+        }
+
         @Override
         @TruffleBoundary
         public RExternalBuiltinNode lookupBuiltin(RList symbol) {
@@ -570,6 +581,7 @@ public class CallAndExternalFunctions {
                 case "ar2ma":
                 case "Burg":
                 case "intgrt_vec":
+                    return PPSum.IntgrtVecNode.create();
                 case "pp_sum":
                 case "Fexact":
                 case "Fisher_sim":
@@ -653,12 +665,12 @@ public class CallAndExternalFunctions {
          */
         @SuppressWarnings("unused")
         @Specialization(limit = "2", guards = {"cached == symbol", "builtin == null"})
-        protected Object callNamedFunction(RList symbol, RArgsValuesAndNames args, Object packageName,
+        protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName,
                         @Cached("symbol") RList cached,
                         @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin,
                         @Cached("new()") ExtractNativeCallInfoNode extractSymbolInfo,
                         @Cached("extractSymbolInfo.execute(symbol)") NativeCallInfo nativeCallInfo) {
-            return callRFFINode.dispatch(nativeCallInfo, args.getArguments());
+            return callRFFINode.dispatch(nativeCallInfo, materializeArgs(frame, args.getArguments()));
         }
 
         /**
@@ -667,24 +679,24 @@ public class CallAndExternalFunctions {
          */
         @SuppressWarnings("unused")
         @Specialization(replaces = {"callNamedFunction", "doExternal"})
-        protected Object callNamedFunctionGeneric(RList symbol, RArgsValuesAndNames args, Object packageName,
+        protected Object callNamedFunctionGeneric(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName,
                         @Cached("new()") ExtractNativeCallInfoNode extractSymbolInfo) {
             RExternalBuiltinNode builtin = lookupBuiltin(symbol);
             if (builtin != null) {
                 throw RInternalError.shouldNotReachHere("Cache for .Calls with FastR reimplementation (lookupBuiltin(...) != null) exceeded the limit");
             }
             NativeCallInfo nativeCallInfo = extractSymbolInfo.execute(symbol);
-            return callRFFINode.dispatch(nativeCallInfo, args.getArguments());
+            return callRFFINode.dispatch(nativeCallInfo, materializeArgs(frame, args.getArguments()));
         }
 
         /**
          * {@code .NAME = string}, no package specified.
          */
         @Specialization
-        protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName,
+        protected Object callNamedFunction(VirtualFrame frame, String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName,
                         @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns,
                         @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
-            return callNamedFunctionWithPackage(symbol, args, null, rns, findSymbolNode);
+            return callNamedFunctionWithPackage(frame, symbol, args, null, rns, findSymbolNode);
         }
 
         /**
@@ -692,19 +704,19 @@ public class CallAndExternalFunctions {
          * define that symbol.
          */
         @Specialization
-        protected Object callNamedFunctionWithPackage(String symbol, RArgsValuesAndNames args, String packageName,
+        protected Object callNamedFunctionWithPackage(VirtualFrame frame, String symbol, RArgsValuesAndNames args, String packageName,
                         @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns,
                         @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
             DLL.SymbolHandle func = findSymbolNode.execute(symbol, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 throw error(RError.Message.SYMBOL_NOT_IN_TABLE, symbol, "Call", packageName);
             }
-            return callRFFINode.dispatch(new NativeCallInfo(symbol, func, rns.getDllInfo()), args.getArguments());
+            return callRFFINode.dispatch(new NativeCallInfo(symbol, func, rns.getDllInfo()), materializeArgs(frame, args.getArguments()));
         }
 
         @Specialization
-        protected Object callNamedFunctionWithPackage(RExternalPtr symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName) {
-            return callRFFINode.dispatch(new NativeCallInfo("", symbol.getAddr(), null), args.getArguments());
+        protected Object callNamedFunctionWithPackage(VirtualFrame frame, RExternalPtr symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName) {
+            return callRFFINode.dispatch(new NativeCallInfo("", symbol.getAddr(), null), materializeArgs(frame, args.getArguments()));
         }
 
         @SuppressWarnings("unused")
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
index 7ce6f47b092713c0e5503f85b28e24f883381c98..f6e1fdd15a338630359f8e342e595a831ae2df34 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
@@ -274,7 +274,7 @@ final class CachedExtractVectorNode extends CachedVectorNode {
 
     @TruffleBoundary
     private static Object materializeLanguage(RAbstractVector extractedVector) {
-        return RContext.getRRuntimeASTAccess().fromList((RList) extractedVector, RLanguage.RepType.CALL);
+        return RContext.getRRuntimeASTAccess().createLanguageFromList((RList) extractedVector, RLanguage.RepType.CALL);
     }
 
     private Object extract(int dimensionIndex, RAbstractStringVector vector, Object pos, PositionProfile profile) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
index 71a7e7c7183b7deb12ec8bcccd4e06d9167c3026..73b47fda388a25673352a3f2d033143354008629 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
@@ -318,7 +318,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
     private Object wrapResult(RAbstractVector vector, RLanguage.RepType repType) {
         switch (vectorType) {
             case Language:
-                return RContext.getRRuntimeASTAccess().fromList((RList) vector, repType);
+                return RContext.getRRuntimeASTAccess().createLanguageFromList((RList) vector, repType);
             default:
                 return vector;
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToVectorNode.java
index f645d23f52d00e855f51b0d7c639e3258d8755b5..7e916de094572174a6c4088fa2f33f694366a7c2 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToVectorNode.java
@@ -23,10 +23,12 @@
 package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public abstract class CastToVectorNode extends CastNode {
@@ -73,6 +75,12 @@ public abstract class CastToVectorNode extends CastNode {
         return vector;
     }
 
+    @Specialization
+    protected RAbstractVector cast(@SuppressWarnings("unused") RS4Object s4obj) {
+        // TODO implement according to function 'R_getS4DataSlot' in 'attrib.c'
+        throw error(RError.Message.CANNOT_COERCE_S4_TO_VECTOR);
+    }
+
     public static CastToVectorNode create() {
         return CastToVectorNodeGen.create(false);
     }
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 dd4aaab8b46974711c0040fa695013a13b086015..a23208b85715f53cc7e1d68eb2e53fe2cab517f1 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
@@ -633,6 +633,7 @@ public final class RError extends RuntimeException implements TruffleException {
         POS_NOT_ALLOWED_WITH_NUMERIC("pos argument not allowed with a numeric value"),
         OBJ_CANNOT_BE_ATTRIBUTED("external object cannot be attributed"),
         CANNOT_COERCE_EXTERNAL_OBJECT_TO_VECTOR("no method for coercing this external object to a %s"),
+        CANNOT_COERCE_S4_TO_VECTOR("no method for coercing this S4 class to a vector"),
         // the following list is incomplete (but like GNU-R)
         INVALID_FORMAT_DOUBLE("invalid format '%s'; use format %%f, %%e, %%g or %%a for numeric objects"),
         INVALID_LOGICAL("'%s' must be TRUE or FALSE"),
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 144cb8f2ac25ace0926f56dce84638b94b966c50..a1c5c0a19fb2ad08e6e77f39bb5e5444dedf544b 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
@@ -945,4 +945,8 @@ public class RRuntime {
     private static boolean hasDims(RAbstractContainer xa) {
         return xa.hasDimensions();
     }
+
+    public static boolean isS4Object(Object o) {
+        return o instanceof RTypedValue && ((RTypedValue) o).isS4();
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
index fe78327aeb55db9317feefacba162cdefeb53f8e..cda344489795bd1c53400e6741bf16cb43d66dfc 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
@@ -73,7 +73,7 @@ public interface RRuntimeASTAccess {
      * object whose rep is a {@code RCallNode} with the first list element as the function and the
      * remainder as the arguments, or a {@code RFunction} (as determined by repType).
      */
-    Object fromList(RList list, RLanguage.RepType repType);
+    Object createLanguageFromList(RList list, RLanguage.RepType repType);
 
     /**
      * Get the "names" attribute for an {@link RLanguage} object, or {@code null} if none.
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
index 9c2e312f17d16967ac88b13b55f18ba26b0bc23e..de9ff2b821a97f48a5dc9189edde8caa77b27dd2 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
@@ -193,19 +193,26 @@ public final class NativeDataAccess {
             RObject obj = (RObject) arg;
             NativeMirror mirror = (NativeMirror) obj.getNativeMirror();
             if (mirror == null) {
-                obj.setNativeMirror(mirror = arg instanceof CustomNativeMirror ? new NativeMirror(((CustomNativeMirror) arg).getCustomMirrorAddress()) : new NativeMirror());
-                // System.out.println(String.format("adding %16x = %s", mirror.id,
-                // obj.getClass().getSimpleName()));
-                nativeMirrors.put(mirror.id, new WeakReference<>(obj));
-                if (TRACE_MIRROR_ALLOCATION_SITES) {
-                    registerAllocationSite(arg, mirror);
-                }
+                mirror = putMirrorObject(arg, obj);
             }
             return mirror.id;
         }
         throw UnsupportedMessageException.raise(Message.AS_POINTER);
     }
 
+    @TruffleBoundary
+    private static NativeMirror putMirrorObject(Object arg, RObject obj) {
+        NativeMirror mirror;
+        obj.setNativeMirror(mirror = arg instanceof CustomNativeMirror ? new NativeMirror(((CustomNativeMirror) arg).getCustomMirrorAddress()) : new NativeMirror());
+        // System.out.println(String.format("adding %16x = %s", mirror.id,
+        // obj.getClass().getSimpleName()));
+        nativeMirrors.put(mirror.id, new WeakReference<>(obj));
+        if (TRACE_MIRROR_ALLOCATION_SITES) {
+            registerAllocationSite(arg, mirror);
+        }
+        return mirror;
+    }
+
     @TruffleBoundary
     private static void registerAllocationSite(Object arg, NativeMirror mirror) {
         nativeMirrorInfo.put(mirror.id, new RuntimeException(arg.getClass().getSimpleName() + " " + arg));
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
index aa46ff8da7eb3ac5072177291084578551044f86..9595b1723d5c17dcc0d31deb33a7ee1db2fd77e5 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
@@ -84,7 +84,7 @@ public final class RLanguage extends RSharingAttributeStorage implements RAbstra
         } else {
             l = (RList) o;
         }
-        return RContext.getRRuntimeASTAccess().fromList(l, type);
+        return RContext.getRRuntimeASTAccess().createLanguageFromList(l, type);
     }
 
     public RBaseNode getRep() {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/MaterializeNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/MaterializeNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..67f641bca46d4247ce9de3b0bbe5433c9c90c7e9
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/MaterializeNode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.data.nodes;
+
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+
+public abstract class MaterializeNode extends Node {
+
+    protected static final int LIMIT = 10;
+
+    public abstract Object execute(VirtualFrame frame, Object arg);
+
+    @Specialization(limit = "LIMIT", guards = {"vec.getClass() == cachedClass"})
+    protected RAbstractContainer doAbstractContainerCached(RAbstractContainer vec,
+                    @SuppressWarnings("unused") @Cached("vec.getClass()") Class<?> cachedClass) {
+        return vec.materialize();
+    }
+
+    @Specialization(replaces = "doAbstractContainerCached")
+    protected RAbstractContainer doAbstractContainer(RAbstractContainer vec) {
+        return vec.materialize();
+    }
+
+    @Fallback
+    protected Object doGeneric(Object o) {
+        return o;
+    }
+
+    public static MaterializeNode create() {
+        return MaterializeNodeGen.create();
+    }
+
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index c2bfbac1b9ae02f97a2bd5912071e6303b647bfb..4d659845e40e4825ac4a691c081af846975cc15c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -26029,6 +26029,14 @@ integer(0)
 #grep('))', '))')
 [1] 1
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#
+#grep('*', c('prefix.lsmc', 'arm'), value = TRUE)
+[1] "prefix.lsmc" "arm"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#
+#grep('*.lsmc', c('prefix.lsmc', 'arm'), value = TRUE)
+[1] "prefix.lsmc"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#
 #grep('[(]', ')')
 integer(0)
@@ -47152,6 +47160,10 @@ y2  2  4
 y1  1  3
 y2  2  4
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#Output.IgnoreErrorContext#
+#{ setClass('fooo', slots = c(a='numeric')); obj <- new('fooo'); rbind(obj) }
+Error in rbind2(..1) : no method for coercing this S4 class to a vector
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
 #{ v <- 1; class(v) <- 'foo'; assign('rbind.foo', function(x) {'foo'}, envir=.__S3MethodsTable__.); result <- rbind(v) ; rm('rbind.foo', envir=.__S3MethodsTable__.); result;}
 [1] "foo"
@@ -80242,6 +80254,41 @@ Error in get("x") : object 'x' not found
 #{ x <- function(){3} ; gg <- function() { assign("x", 4) ; g <- function() { if (FALSE) { x <- 2 } ; f <- function() { h <- function() { x() } ; h() } ; f() } ; g() } ; gg() }
 [1] 3
 
+##com.oracle.truffle.r.test.library.base.TestIsElement.testIsElement#
+#{ is.element('b', c('a', 'b', 'b')) }
+[1] TRUE
+
+##com.oracle.truffle.r.test.library.base.TestIsElement.testIsElement#
+#{ is.element(c('a', 'b', 'b'), 'b') }
+[1] FALSE  TRUE  TRUE
+
+##com.oracle.truffle.r.test.library.base.TestIsElement.testIsElement#
+#{ is.element(c(1:10,rep(11,10)), 1) }
+ [1]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
+[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
+
+##com.oracle.truffle.r.test.library.base.TestIsElement.testIsElement#
+#{ is.element(c(1:10,rep(11,10)), 11) }
+ [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
+[13]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
+
+##com.oracle.truffle.r.test.library.base.TestIsElement.testIsElement#
+#{ is.element(c(1:10,rep(11,10)), c(1:10,rep(11,10))) }
+ [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
+[16] TRUE TRUE TRUE TRUE TRUE
+
+##com.oracle.truffle.r.test.library.base.TestIsElement.testIsElement#
+#{ is.element(paste0('a', 1:10), 'a0') }
+ [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
+
+##com.oracle.truffle.r.test.library.base.TestIsElement.testIsElement#
+#{ is.element(paste0('a', 1:10), 'a1') }
+ [1]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
+
+##com.oracle.truffle.r.test.library.base.TestIsElement.testIsElement#
+#{ is.element(paste0('a', c(1:10, rep(11,2))), 'a11') }
+ [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
+
 ##com.oracle.truffle.r.test.library.base.TestPromiseOptimizations.testDeoptimization#
 #{ delayedAssign('x', c(1,2,3)); x/180; x }
 [1] 1 2 3
@@ -152299,6 +152346,10 @@ list(cyl, hp, mpg, disp, drat, wt, qsec, vs, am, gear, carb)
 9  8  9
 10 9 10
 
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelFrame#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;; model.frame(terms.formula(~1)) }
+data frame with 0 columns and 0 rows
+
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelFrame#
 #{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;; model.frame(terms.formula(~k+y+z)) }
     k y  z
@@ -152523,6 +152574,10 @@ list(cyl, hp, mpg, disp, drat, wt, qsec, vs, am, gear, carb)
 9  8 c
 10 9 c
 
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelFrame#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.frame(terms.formula(~1)) }
+data frame with 0 columns and 0 rows
+
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelFrame#
 #{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.frame(terms.formula(~k+y+z)) }
    k y z
@@ -152777,6 +152832,11 @@ attr(,"assign")
 attr(,"assign")
 [1] 0 1
 
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;; model.matrix(model.frame(terms.formula(~1))) }
+Error in formula.data.frame(object, env = baseenv()) :
+  cannot create a formula from a zero-column data frame
+
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
 #{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;; model.matrix(model.frame(terms.formula(~k+y+z))) }
    (Intercept)  k y  z
@@ -153107,6 +153167,11 @@ attr(,"contrasts")$z
 [1] "contr.treatment"
 
 
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(~1))) }
+Error in formula.data.frame(object, env = baseenv()) :
+  cannot create a formula from a zero-column data frame
+
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
 #{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(~k+y+z))) }
    (Intercept) km y zb zc
@@ -153626,6 +153691,33 @@ $variables
 list(y, z)
 
 
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testTermsform#
+#f <- terms.formula(~1); attrs <- attributes(f); envIdx <- which(names(attrs)=='.Environment'); print(attrs[envIdx]); attrs[sort(names(attrs[-envIdx]))]
+$.Environment
+<environment: R_GlobalEnv>
+
+$class
+[1] "terms"   "formula"
+
+$factors
+integer(0)
+
+$intercept
+[1] 1
+
+$order
+integer(0)
+
+$response
+[1] 0
+
+$term.labels
+character(0)
+
+$variables
+list()
+
+
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testTermsform#
 #f <- terms.formula(~k+y+z); attrs <- attributes(f); envIdx <- which(names(attrs)=='.Environment'); print(attrs[envIdx]); attrs[sort(names(attrs[-envIdx]))]
 $.Environment
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java
index d5c5148e5700bf77b247ef7607dab95add6a7a71..36a3bd4f1f3d6cf5fd2defd05d41942532c389b4 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java
@@ -107,6 +107,8 @@ public class TestBuiltin_grep extends TestBase {
         assertEval(Output.IgnoreErrorMessage, "grep('([)]', ')')");
         assertEval(Output.IgnoreErrorMessage, "grep('([(]', ')')");
         assertEval(Output.IgnoreErrorMessage, "grep('(()', ')')");
+        assertEval("grep('*.lsmc', c('prefix.lsmc', 'arm'), value = TRUE)");
+        assertEval("grep('*', c('prefix.lsmc', 'arm'), value = TRUE)");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rbind.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rbind.java
index 558032e94439942a684f70b658f4e5392f6cc237..ccf9cc0a6af505c946cd22616e20791a9619997e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rbind.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rbind.java
@@ -111,6 +111,9 @@ public class TestBuiltin_rbind extends TestBase {
         assertEval("{ v1 <- 1; class(v1) <- 'foo1'; rbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; rbind.foo2 <- function(...) 'foo2'; rbind(v1, v2) }");
         assertEval("{ v1 <- 1; class(v1) <- 'foo1'; rbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; rbind(v1, v2) }");
         assertEval("{ v1 <- 1; class(v1) <- 'foo1'; v2 <- 2; class(v2) <- 'foo2'; rbind.foo2 <- function(...) 'foo2'; rbind(v1, v2) }");
+
+        // S4
+        assertEval(Output.IgnoreErrorContext, "{ setClass('fooo', slots = c(a='numeric')); obj <- new('fooo'); rbind(obj) }");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestIsElement.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestIsElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec27ac1989d18ed27bcb3aa637022e37904f87e4
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestIsElement.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.library.base;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.test.TestBase;
+
+public class TestIsElement extends TestBase {
+
+    @Test
+    public void testIsElement() {
+        assertEval("{ is.element(c('a', 'b', 'b'), 'b') }");
+        assertEval("{ is.element('b', c('a', 'b', 'b')) }");
+        assertEval("{ is.element(paste0('a', 1:10), 'a1') }");
+        assertEval("{ is.element(paste0('a', 1:10), 'a0') }");
+        assertEval("{ is.element(paste0('a', c(1:10, rep(11,2))), 'a11') }");
+        assertEval("{ is.element(c(1:10,rep(11,10)), 1) }");
+        assertEval("{ is.element(c(1:10,rep(11,10)), 11) }");
+        assertEval("{ is.element(c(1:10,rep(11,10)), c(1:10,rep(11,10))) }");
+    }
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java
index c2d7be4e0b73e889737f4a424536c3a14a7ba03e..76faa10ddb6f317796b42ff353e03a8aee98c84d 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java
@@ -60,7 +60,7 @@ public class TestFormulae extends TestBase {
                     "y~z", "y~1+z", "y~0+z", "y~-1+z", "y~z*k", "y~z*k+w*m", "u~z*k+w*m",
                     "y~z:k", "y~z^2", "y~(z+k)^2", "y~z*((m+w)^3)",
                     "y~(z+k)*(w+u)", "y~w%in%v", "y~w/k", "y~(1 + w/k)",
-                    "~k+y+z"
+                    "~k+y+z", "~1"
     };
 
     /**