diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
index da39fe9bdec0bf28a7259cf9f31fb90fe5b65302..2ca65bc6427b9c391f9faf31de90e40cd2c9bb8e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
@@ -14,33 +14,30 @@ import static com.oracle.truffle.r.runtime.RDispatch.SUMMARY_GROUP_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE_SUMMARY;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
-import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
+import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
-import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
+@ImportStatic(RType.class)
 @RBuiltin(name = "prod", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE_SUMMARY)
 public abstract class Prod extends RBuiltinNode.Arg2 {
 
-    // TODO: handle multiple arguments, handle na.rm
-
     static {
-        Casts.noCasts(Prod.class);
+        Casts casts = new Casts(Prod.class);
+        casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(Predef.toBoolean());
     }
 
     @Override
@@ -48,139 +45,154 @@ public abstract class Prod extends RBuiltinNode.Arg2 {
         return new Object[]{RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE};
     }
 
-    @Child private Prod prodRecursive;
-
-    public abstract Object executeObject(Object x);
-
     @Child private BinaryArithmetic prod = BinaryArithmetic.MULTIPLY.createOperation();
 
-    @Specialization
-    protected Object prod(RArgsValuesAndNames args) {
-        int argsLen = args.getLength();
-        if (argsLen == 0) {
-            return 1d;
+    @ExplodeLoop
+    protected static boolean supports(RArgsValuesAndNames args, VectorAccess[] argAccess) {
+        if (args.getLength() != argAccess.length) {
+            return false;
         }
-        if (prodRecursive == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            prodRecursive = insert(ProdNodeGen.create());
+        for (int i = 0; i < argAccess.length; i++) {
+            if (!argAccess[i].supports(args.getArgument(i))) {
+                return false;
+            }
         }
-        Object ret = 1d;
-        if (argsLen > 0) {
-            double prodReal;
-            double prodImg;
-            boolean complex;
-            if (ret instanceof RComplex) {
-                RComplex c = (RComplex) ret;
-                prodReal = c.getRealPart();
-                prodImg = c.getImaginaryPart();
-                complex = true;
-            } else {
-                prodReal = (Double) ret;
-                prodImg = 0d;
-                complex = false;
+        return true;
+    }
+
+    protected static VectorAccess[] createAccess(RArgsValuesAndNames args, RType topmostType) {
+        VectorAccess[] result = new VectorAccess[args.getLength()];
+        for (int i = 0; i < result.length; i++) {
+            VectorAccess access = VectorAccess.create(args.getArgument(i));
+            if (access == null) {
+                return null;
             }
-            for (int i = 0; i < argsLen; i++) {
-                Object aProd = prodRecursive.executeObject(args.getArgument(i));
-                double aProdReal;
-                double aProdImg;
-                if (aProd instanceof RComplex) {
-                    RComplex c = (RComplex) aProd;
-                    if (RRuntime.isNA(c)) {
-                        return c;
-                    }
-                    aProdReal = c.getRealPart();
-                    aProdImg = c.getImaginaryPart();
-                    complex = true;
-                } else {
-                    aProdReal = (Double) aProd;
-                    aProdImg = 0d;
-                    if (RRuntime.isNA(aProdReal)) {
-                        return aProd;
-                    }
-                }
-                if (complex) {
-                    RComplex c = prod.op(prodReal, prodImg, aProdReal, aProdImg);
-                    prodReal = c.getRealPart();
-                    prodImg = c.getImaginaryPart();
-                } else {
-                    prodReal = prod.op(prodReal, aProdReal);
-                }
+            RType type = access.getType();
+            if (type != RType.Null && type != RType.Logical && type != RType.Integer && type != RType.Double && type != topmostType) {
+                return null;
             }
-            ret = complex ? RComplex.valueOf(prodReal, prodImg) : prodReal;
+            result[i] = access;
         }
-        return ret;
+        return result;
     }
 
-    private final ValueProfile intVecProfile = ValueProfile.createClassProfile();
-    private final NACheck naCheck = NACheck.create();
-
-    @Specialization
-    protected double prod(RAbstractDoubleVector x) {
-        RAbstractDoubleVector profiledVec = intVecProfile.profile(x);
-        double product = 1;
-        naCheck.enable(x);
-        for (int k = 0; k < profiledVec.getLength(); k++) {
-            double value = profiledVec.getDataAt(k);
-            if (naCheck.check(value)) {
-                return RRuntime.DOUBLE_NA;
+    @Specialization(guards = {"argAccess != null", "supports(args, argAccess)", "naRm == cachedNaRm"})
+    @ExplodeLoop
+    protected double prodDoubleCached(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean naRm,
+                    @Cached("naRm") boolean cachedNaRm,
+                    @Cached("createAccess(args, Double)") VectorAccess[] argAccess) {
+        double value = 1;
+        for (int i = 0; i < argAccess.length; i++) {
+            VectorAccess access = argAccess[i];
+            double element = prodDouble(args.getArgument(i), access, cachedNaRm);
+            if (!cachedNaRm && access.na.check(element)) {
+                return element;
             }
-            product = prod.op(product, value);
+            value *= element;
         }
-        return product;
+        return value;
     }
 
-    @Specialization
-    protected double prod(RAbstractIntVector x) {
-        RAbstractIntVector profiledVec = intVecProfile.profile(x);
-        double product = 1;
-        naCheck.enable(x);
-        for (int k = 0; k < profiledVec.getLength(); k++) {
-            int data = profiledVec.getDataAt(k);
-            if (naCheck.check(data)) {
-                return RRuntime.DOUBLE_NA;
+    @Specialization(guards = {"argAccess != null", "supports(args, argAccess)", "naRm == cachedNaRm"})
+    @ExplodeLoop
+    protected RComplex prodComplexCached(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean naRm,
+                    @Cached("naRm") boolean cachedNaRm,
+                    @Cached("createAccess(args, Complex)") VectorAccess[] argAccess) {
+        RComplex value = RComplex.valueOf(1, 0);
+        for (int i = 0; i < argAccess.length; i++) {
+            VectorAccess access = argAccess[i];
+            RComplex element = prodComplex(args.getArgument(i), access, cachedNaRm);
+            if (!cachedNaRm && access.na.check(element)) {
+                return element;
             }
-            product = prod.op(product, data);
+            value = prod.op(value.getRealPart(), value.getImaginaryPart(), element.getRealPart(), element.getImaginaryPart());
         }
-        return product;
+        return value;
     }
 
-    @Specialization
-    protected double prod(RAbstractLogicalVector x) {
-        RAbstractLogicalVector profiledVec = intVecProfile.profile(x);
-        double product = 1;
-        naCheck.enable(x);
-        for (int k = 0; k < profiledVec.getLength(); k++) {
-            byte value = profiledVec.getDataAt(k);
-            if (naCheck.check(value)) {
-                return RRuntime.DOUBLE_NA;
+    @Specialization(replaces = {"prodDoubleCached", "prodComplexCached"})
+    protected Object prodGeneric(RArgsValuesAndNames args, boolean naRm) {
+        int length = args.getLength();
+        double value = 1;
+        int i = 0;
+        for (; i < length; i++) {
+            Object arg = args.getArgument(i);
+            VectorAccess access = VectorAccess.createSlowPath(arg);
+            if (access == null) {
+                break;
+            }
+            RType type = access.getType();
+            if (type != RType.Null && type != RType.Logical && type != RType.Integer && type != RType.Double) {
+                break;
+            }
+            double element = prodDouble(arg, access, naRm);
+            if (!naRm && access.na.check(element)) {
+                return element;
             }
-            product = prod.op(product, value);
+            value *= element;
         }
-        return product;
+        if (i == length) {
+            return value;
+        }
+        RComplex complexValue = RComplex.valueOf(1, 0);
+        for (; i < length; i++) {
+            Object arg = args.getArgument(i);
+            VectorAccess access = VectorAccess.createSlowPath(arg);
+            if (access == null) {
+                break;
+            }
+            RType type = access.getType();
+            if (!type.isNumeric() && type != RType.Null) {
+                break;
+            }
+            RComplex element = prodComplex(arg, access, naRm);
+            if (!naRm && access.na.check(element)) {
+                return element;
+            }
+            complexValue = prod.op(complexValue.getRealPart(), complexValue.getImaginaryPart(), element.getRealPart(), element.getImaginaryPart());
+        }
+        if (i == length) {
+            return complexValue;
+        }
+        throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(args.getArgument(i)));
     }
 
-    @Specialization
-    protected RComplex prod(RAbstractComplexVector x) {
-        RAbstractComplexVector profiledVec = intVecProfile.profile(x);
-        RComplex product = RDataFactory.createComplexRealOne();
-        naCheck.enable(x);
-        for (int k = 0; k < profiledVec.getLength(); k++) {
-            RComplex a = profiledVec.getDataAt(k);
-            if (naCheck.check(a)) {
-                return a;
+    protected static double prodDouble(Object v, VectorAccess access, boolean naRm) {
+        try (SequentialIterator iter = access.access(v)) {
+            double value = 1;
+            while (access.next(iter)) {
+                double element = access.getDouble(iter);
+                if (access.na.check(element)) {
+                    if (!naRm) {
+                        return RRuntime.DOUBLE_NA;
+                    }
+                } else {
+                    value *= element;
+                }
             }
-            product = prod.op(product.getRealPart(), product.getImaginaryPart(), a.getRealPart(), a.getImaginaryPart());
+            return value;
         }
-        return product;
     }
 
-    @Specialization
-    protected double prod(@SuppressWarnings("unused") RNull n) {
-        return 1d;
+    protected RComplex prodComplex(Object v, VectorAccess access, boolean naRm) {
+        try (SequentialIterator iter = access.access(v)) {
+            RComplex value = RComplex.valueOf(1, 0);
+            while (access.next(iter)) {
+                RComplex element = access.getComplex(iter);
+                if (access.na.check(element)) {
+                    if (!naRm) {
+                        return element;
+                    }
+                } else {
+                    value = prod.op(value.getRealPart(), value.getImaginaryPart(), element.getRealPart(), element.getImaginaryPart());
+                }
+            }
+            return value;
+        }
     }
 
     @Fallback
-    protected Object prod(Object o) {
-        throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(o));
+    protected Object prod(Object v, @SuppressWarnings("unused") Object naRm) {
+        throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(v));
     }
 }
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 c015d5ee754805752a2d98c3a36440bb74ef9c7a..c58c83079b2017abcc5d19c3c53d4119d648507c 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
@@ -48245,105 +48245,237 @@ sex                       -1.65487 0.483    0.38527 11.74  1.0 0.00061
 frailty(id, dist = 't', c                           20.33 13.9 0.12000
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#prod()
+#prod(1)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#prod(complex())
-[1] 1+0i
+#prod(1,2,3,4)
+[1] 24
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#prod(numeric())
+#prod(1,2,3,4,na.rm=FALSE)
+[1] 24
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,2,3,4,na.rm=TRUE)
+[1] 24
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,FALSE,na.rm=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,FALSE,na.rm=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1,na.rm=FALSE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{ foo <- function(...) prod(...); foo(); }
+#prod(1,na.rm=TRUE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod('a')}
-Error in prod("a") : invalid 'type' (character) of argument
+#prod(1L,NA,5+3i)
+[1] NA
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod()}
-[1] 1
+#prod(1L,NA,5+3i,na.rm=FALSE)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(1L,NA,5+3i,na.rm=TRUE)
+[1] 5+3i
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(2+3i,42)}
-[1] 84+126i
+#prod(2,TRUE)
+[1] 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(2+3i,42+5i)}
-[1] 69+136i
+#prod(2,TRUE,na.rm=FALSE)
+[1] 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(2+3i,c())}
-[1] 2+3i
+#prod(2,TRUE,na.rm=TRUE)
+[1] 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(42,2+3i)}
-[1] 84+126i
+#prod(4+0i,6,NA)
+[1] NA
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(NULL)}
+#prod(4+0i,6,NA,na.rm=FALSE)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(4+0i,6,NA,na.rm=TRUE)
+[1] 24+0i
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(4L)
+[1] 4
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(4L,na.rm=FALSE)
+[1] 4
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(4L,na.rm=TRUE)
+[1] 4
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(FALSE,na.rm=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(FALSE,na.rm=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA,c(1,2,3))
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA,c(1,2,3),na.rm=FALSE)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA,c(1,2,3),na.rm=TRUE)
+[1] 6
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA_integer_)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA_integer_,na.rm=FALSE)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(NA_integer_,na.rm=TRUE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c())}
+#prod(TRUE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(),c())}
+#prod(TRUE,na.rm=FALSE)
 [1] 1
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(1+2i))}
-[1] 1+2i
+#prod(TRUE,na.rm=TRUE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(1,2,NA),NA)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(1,2,NA),NA,na.rm=FALSE)
+[1] NA
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(1+2i, 2+3i))}
-[1] -4+7i
+#prod(c(1,2,NA),NA,na.rm=TRUE)
+[1] 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(1+2i,1+3i,1+45i))}
-[1] -230-220i
+#prod(c(2,4))
+[1] 8
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(1,2,3,4,5))}
-[1] 120
+#prod(c(2,4),na.rm=FALSE)
+[1] 8
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(2,4))}
+#prod(c(2,4),na.rm=TRUE)
 [1] 8
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(2,4,3))}
+#prod(c(2,4,3))
 [1] 24
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(TRUE, FALSE))}
-[1] 0
+#prod(c(2,4,3),na.rm=FALSE)
+[1] 24
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(c(TRUE, TRUE))}
-[1] 1
+#prod(c(2,4,3),na.rm=TRUE)
+[1] 24
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
-#{prod(list())}
-Error in prod(list()) : invalid 'type' (list) of argument
+#prod(c(2,4,NA))
+[1] NA
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa#
-#{prod(c(1,2,3,4,5,NA),FALSE)}
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(2,4,NA),na.rm=FALSE)
 [1] NA
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa#
-#{prod(c(2,4,3,NA),TRUE)}
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(2,4,NA),na.rm=TRUE)
+[1] 8
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(NA,2L,4L))
 [1] NA
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa#
-#{prod(c(2,4,NA))}
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(NA,2L,4L),na.rm=FALSE)
 [1] NA
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(c(NA,2L,4L),na.rm=TRUE)
+[1] 8
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(complex(),numeric())
+[1] 1+0i
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(complex(),numeric(),na.rm=FALSE)
+[1] 1+0i
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(complex(),numeric(),na.rm=TRUE)
+[1] 1+0i
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric())
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),na.rm=FALSE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),na.rm=TRUE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),numeric())
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),numeric(),na.rm=FALSE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#prod(numeric(),numeric(),na.rm=TRUE)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd#
+#{ foo <- function(...) prod(...); foo(); }
+[1] 1
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testprod1#
 #argv <- list(9L);prod(argv[[1]]);
 [1] 9
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java
index 42a9f0ef49eb81f41d325bbc09fcefceac17ba45..387c17b835001191ea2a0c0ac737ea68aecb02c2 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java
@@ -72,36 +72,13 @@ public class TestBuiltin_prod extends TestBase {
         assertEval("argv <- list(numeric(0));prod(argv[[1]]);");
     }
 
+    private static final String[] VALUES = {"FALSE", "TRUE", "1,FALSE", "2,TRUE", "c(2,4)", "c(2,4,3)", "c(2,4,NA)", "c(NA,2L,4L)", "1", "4L", "NA_integer_", "NA,c(1,2,3)", "c(1,2,NA),NA", "1,2,3,4",
+                    "1L,NA,5+3i", "4+0i,6,NA", "numeric(),numeric()", "numeric()", "complex(),numeric()"};
+    private static final String[] OPTIONS = {"", ",na.rm=TRUE", ",na.rm=FALSE"};
+
     @Test
     public void testProd() {
-        assertEval("{prod(c(2,4))}");
-        assertEval("{prod(c(2,4,3))}");
-        assertEval("{prod(c(1,2,3,4,5))}");
-        assertEval("{prod(c(1+2i))}");
-        assertEval("{prod(c(1+2i, 2+3i))}");
-        assertEval("{prod(c(1+2i,1+3i,1+45i))}");
-        assertEval("{prod(c(TRUE, TRUE))}");
-        assertEval("{prod(c(TRUE, FALSE))}");
-        assertEval("{prod()}");
-        assertEval("{prod(NULL)}");
-        assertEval("{prod(c())}");
-        assertEval("{prod(c(),c())}");
-        assertEval("{prod(2+3i,c())}");
-        assertEval("{prod(2+3i,42+5i)}");
-        assertEval("{prod(2+3i,42)}");
-        assertEval("{prod(42,2+3i)}");
-        assertEval("{prod('a')}");
-        assertEval("{prod(list())}");
-        assertEval("prod()");
-        assertEval("prod(numeric())");
-        assertEval("prod(complex())");
+        assertEval(template("prod(%0%1)", VALUES, OPTIONS));
         assertEval("{ foo <- function(...) prod(...); foo(); }");
     }
-
-    @Test
-    public void testProdNa() {
-        assertEval("{prod(c(2,4,NA))}");
-        assertEval("{prod(c(2,4,3,NA),TRUE)}");
-        assertEval("{prod(c(1,2,3,4,5,NA),FALSE)}");
-    }
 }