diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MathFunctionsNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MathFunctionsNodes.java
new file mode 100644
index 0000000000000000000000000000000000000000..0836be9d21778e18584bab3865abf6192d50f04e
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MathFunctionsNodes.java
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2018, 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 3 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 3 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
+ * 3 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.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.InteropException;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnknownIdentifierException;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.nodes.GetReadonlyData;
+import com.oracle.truffle.r.runtime.ffi.interop.UnsafeAdapter;
+import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
+import com.oracle.truffle.r.runtime.nmath.BesselFunctions;
+import com.oracle.truffle.r.runtime.nmath.Beta;
+import com.oracle.truffle.r.runtime.nmath.Choose;
+import com.oracle.truffle.r.runtime.nmath.GammaFunctions;
+import com.oracle.truffle.r.runtime.nmath.LBeta;
+import com.oracle.truffle.r.runtime.nmath.MathConstants;
+import com.oracle.truffle.r.runtime.nmath.RMath;
+import com.oracle.truffle.r.runtime.nmath.distr.Logis.PLogis;
+import com.oracle.truffle.r.runtime.nmath.distr.Pnorm.PnormBoth;
+
+public final class MathFunctionsNodes {
+
+    public abstract static class RfPnormBothNode extends FFIUpCallNode.Arg5 {
+
+        @Child private Node cumIsPointerNode = Message.IS_POINTER.createNode();
+        @Child private Node cumAsPointerNode;
+        @Child private Node cumRead;
+        @Child private Node cumWrite;
+        @Child private Node ccumIsPointerNode = Message.IS_POINTER.createNode();
+        @Child private Node ccumAsPointerNode;
+        @Child private Node ccumWrite;
+
+        @Specialization
+        protected Object evaluate(double x, Object cum, Object ccum, int lowerTail, int logP) {
+            // cum is R/W double* with size==1 and ccum is Writeonly double* with size==1
+            double[] cumArr = new double[1];
+            double[] ccumArr = new double[1];
+            long cumPtr;
+            long ccumPtr;
+            TruffleObject cumTO = (TruffleObject) cum;
+            if (ForeignAccess.sendIsPointer(cumIsPointerNode, cumTO)) {
+                if (cumAsPointerNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    cumAsPointerNode = insert(Message.AS_POINTER.createNode());
+                }
+                try {
+                    cumPtr = ForeignAccess.sendAsPointer(cumAsPointerNode, cumTO);
+                    cumArr[0] = UnsafeAdapter.UNSAFE.getDouble(cumPtr);
+                } catch (UnsupportedMessageException e) {
+                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
+                }
+            } else {
+                cumPtr = 0L;
+                if (cumRead == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    cumRead = Message.READ.createNode();
+                    cumWrite = Message.WRITE.createNode();
+                }
+                try {
+                    cumArr[0] = ((Number) ForeignAccess.sendRead(cumRead, cumTO, 0)).doubleValue();
+                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                    throw RInternalError.shouldNotReachHere(e);
+                }
+            }
+
+            TruffleObject ccumTO = (TruffleObject) ccum;
+            if (ForeignAccess.sendIsPointer(ccumIsPointerNode, ccumTO)) {
+                if (ccumAsPointerNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    ccumAsPointerNode = insert(Message.AS_POINTER.createNode());
+                }
+                try {
+                    ccumPtr = ForeignAccess.sendAsPointer(ccumAsPointerNode, ccumTO);
+                } catch (UnsupportedMessageException e) {
+                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
+                }
+            } else {
+                ccumPtr = 0L;
+                if (ccumWrite == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    ccumWrite = Message.WRITE.createNode();
+                }
+            }
+
+            PnormBoth.evaluate(x, cumArr, ccumArr, lowerTail != 0, logP != 0);
+            if (cumPtr != 0L) {
+                UnsafeAdapter.UNSAFE.putDouble(cumPtr, cumArr[0]);
+            } else {
+                try {
+                    ForeignAccess.sendWrite(cumWrite, cumTO, 0, cumArr[0]);
+                } catch (InteropException e) {
+                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
+                }
+            }
+            if (ccumPtr != 0L) {
+                UnsafeAdapter.UNSAFE.putDouble(ccumPtr, ccumArr[0]);
+            } else {
+                try {
+                    ForeignAccess.sendWrite(ccumWrite, ccumTO, 0, ccumArr[0]);
+                } catch (InteropException e) {
+                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
+                }
+            }
+            return RNull.instance;
+        }
+
+        public static RfPnormBothNode create() {
+            return MathFunctionsNodesFactory.RfPnormBothNodeGen.create();
+        }
+    }
+
+    public abstract static class Log1pmxNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double a) {
+            return GammaFunctions.log1pmx(a);
+        }
+
+        public static Log1pmxNode create() {
+            return MathFunctionsNodesFactory.Log1pmxNodeGen.create();
+        }
+    }
+
+    public abstract static class Log1pexpNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double a) {
+            return PLogis.log1pexp(a);
+        }
+
+        public static Log1pexpNode create() {
+            return MathFunctionsNodesFactory.Log1pexpNodeGen.create();
+        }
+    }
+
+    public abstract static class Lgamma1pNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double a) {
+            return GammaFunctions.lgamma1p(a);
+        }
+
+        public static Lgamma1pNode create() {
+            return MathFunctionsNodesFactory.Lgamma1pNodeGen.create();
+        }
+    }
+
+    public abstract static class LogspaceAddNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double a, double b) {
+            return MathConstants.logspaceAdd(a, b);
+        }
+
+        public static LogspaceAddNode create() {
+            return MathFunctionsNodesFactory.LogspaceAddNodeGen.create();
+        }
+    }
+
+    public abstract static class LogspaceSubNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double a, double b) {
+            return MathConstants.logspaceSub(a, b);
+        }
+
+        public static LogspaceSubNode create() {
+            return MathFunctionsNodesFactory.LogspaceSubNodeGen.create();
+        }
+    }
+
+    public abstract static class GammafnNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double a) {
+            return GammaFunctions.gammafn(a);
+        }
+
+        public static GammafnNode create() {
+            return MathFunctionsNodesFactory.GammafnNodeGen.create();
+        }
+    }
+
+    public abstract static class LGammafnNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double a) {
+            return GammaFunctions.lgammafn(a);
+        }
+
+        public static LGammafnNode create() {
+            return MathFunctionsNodesFactory.LGammafnNodeGen.create();
+        }
+    }
+
+    public abstract static class LGammafnSignNode extends FFIUpCallNode.Arg2 {
+
+        @Child private Node sgnIsPointerNode = Message.IS_POINTER.createNode();
+        @Child private Node sgnAsPointerNode;
+        @Child private Node sgnRead;
+        @Child private Node sgnWrite;
+
+        @Specialization
+        protected Object evaluate(double a, Object sgn) {
+            int[] sgnArr = new int[1];
+            long sgnPtr;
+            TruffleObject sgnTO = (TruffleObject) sgn;
+            if (ForeignAccess.sendIsPointer(sgnIsPointerNode, sgnTO)) {
+                if (sgnAsPointerNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    sgnAsPointerNode = insert(Message.AS_POINTER.createNode());
+                }
+                try {
+                    sgnPtr = ForeignAccess.sendAsPointer(sgnAsPointerNode, sgnTO);
+                    sgnArr[0] = UnsafeAdapter.UNSAFE.getInt(sgnPtr);
+                } catch (UnsupportedMessageException e) {
+                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
+                }
+            } else {
+                sgnPtr = 0L;
+                if (sgnRead == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    sgnRead = Message.READ.createNode();
+                    sgnWrite = Message.WRITE.createNode();
+                }
+                try {
+                    sgnArr[0] = ((Number) ForeignAccess.sendRead(sgnRead, sgnTO, 0)).intValue();
+                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                    throw RInternalError.shouldNotReachHere(e);
+                }
+            }
+
+            double result = GammaFunctions.lgammafnSign(a, sgnArr);
+            if (sgnPtr != 0L) {
+                UnsafeAdapter.UNSAFE.putInt(sgnPtr, sgnArr[0]);
+            } else {
+                try {
+                    ForeignAccess.sendWrite(sgnWrite, sgnTO, 0, sgnArr[0]);
+                } catch (InteropException e) {
+                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
+                }
+            }
+            return result;
+        }
+
+        public static LGammafnSignNode create() {
+            return MathFunctionsNodesFactory.LGammafnSignNodeGen.create();
+        }
+    }
+
+    public abstract static class DpsiFnNode extends FFIUpCallNode.Arg7 {
+
+        @Child private Node ansIsPointerNode = Message.IS_POINTER.createNode();
+        @Child private Node ansAsPointerNode;
+        @Child private Node ansRead;
+        @Child private Node ansWrite;
+        @Child private Node nzIsPointerNode = Message.IS_POINTER.createNode();
+        @Child private Node nzAsPointerNode;
+        @Child private Node nzRead;
+        @Child private Node nzWrite;
+        @Child private Node ierrIsPointerNode = Message.IS_POINTER.createNode();
+        @Child private Node ierrAsPointerNode;
+        @Child private Node ierrRead;
+        @Child private Node ierrWrite;
+
+        @Specialization
+        protected Object evaluate(double x, int n, int kode, int m, Object ans, Object nz, Object ierr) {
+            // ans is R/W double* size==1 and nz is R/W int* size==1
+            // ierr is R/W int* size==1
+            double ansIn;
+            int nzIn;
+            int ierrIn;
+            TruffleObject ansTO = (TruffleObject) ans;
+            long ansPtr;
+            if (ForeignAccess.sendIsPointer(ansIsPointerNode, ansTO)) {
+                if (ansAsPointerNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    ansAsPointerNode = insert(Message.AS_POINTER.createNode());
+                }
+                try {
+                    ansPtr = ForeignAccess.sendAsPointer(ansAsPointerNode, ansTO);
+                    ansIn = UnsafeAdapter.UNSAFE.getDouble(ansPtr);
+                } catch (UnsupportedMessageException e) {
+                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
+                }
+            } else {
+                ansPtr = 0L;
+                if (ansRead == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    ansRead = Message.READ.createNode();
+                    ansWrite = Message.WRITE.createNode();
+                }
+                try {
+                    ansIn = ((Number) ForeignAccess.sendRead(ansRead, ansTO, 0)).doubleValue();
+                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                    throw RInternalError.shouldNotReachHere(e);
+                }
+            }
+
+            TruffleObject nzTO = (TruffleObject) nz;
+            long nzPtr;
+            if (ForeignAccess.sendIsPointer(nzIsPointerNode, nzTO)) {
+                if (nzAsPointerNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    nzAsPointerNode = insert(Message.AS_POINTER.createNode());
+                }
+                try {
+                    nzPtr = ForeignAccess.sendAsPointer(nzAsPointerNode, nzTO);
+                    nzIn = UnsafeAdapter.UNSAFE.getInt(nzPtr);
+                } catch (UnsupportedMessageException e) {
+                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
+                }
+            } else {
+                nzPtr = 0L;
+                if (nzRead == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    nzRead = Message.READ.createNode();
+                    nzWrite = Message.WRITE.createNode();
+                }
+                try {
+                    nzIn = ((Number) ForeignAccess.sendRead(nzRead, nzTO, 0)).intValue();
+                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                    throw RInternalError.shouldNotReachHere(e);
+                }
+            }
+
+            TruffleObject ierrTO = (TruffleObject) ierr;
+            long ierrPtr;
+            if (ForeignAccess.sendIsPointer(ierrIsPointerNode, ierrTO)) {
+                if (ierrAsPointerNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    ierrAsPointerNode = insert(Message.AS_POINTER.createNode());
+                }
+                try {
+                    ierrPtr = ForeignAccess.sendAsPointer(ierrAsPointerNode, ierrTO);
+                    ierrIn = UnsafeAdapter.UNSAFE.getInt(ierrPtr);
+                } catch (UnsupportedMessageException e) {
+                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
+                }
+            } else {
+                ierrPtr = 0L;
+                if (ierrRead == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    ierrRead = Message.READ.createNode();
+                    ierrWrite = Message.WRITE.createNode();
+                }
+                try {
+                    ierrIn = ((Number) ForeignAccess.sendRead(ierrRead, ierrTO, 0)).intValue();
+                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                    throw RInternalError.shouldNotReachHere(e);
+                }
+            }
+
+            GammaFunctions.DpsiFnResult result = GammaFunctions.dpsifn(x, n, kode, ansIn, nzIn, ierrIn);
+            if (ansPtr != 0L) {
+                UnsafeAdapter.UNSAFE.putDouble(ansPtr, result.ans);
+            } else {
+                try {
+                    ForeignAccess.sendWrite(ansWrite, ansTO, 0, result.ans);
+                } catch (InteropException e) {
+                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
+                }
+            }
+            if (nzPtr != 0L) {
+                UnsafeAdapter.UNSAFE.putInt(nzPtr, result.nz);
+            } else {
+                try {
+                    ForeignAccess.sendWrite(nzWrite, nzTO, 0, result.nz);
+                } catch (InteropException e) {
+                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
+                }
+            }
+            if (ierrPtr != 0L) {
+                UnsafeAdapter.UNSAFE.putInt(ierrPtr, result.ierr);
+            } else {
+                try {
+                    ForeignAccess.sendWrite(ierrWrite, ierrTO, 0, result.ierr);
+                } catch (InteropException e) {
+                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
+                }
+            }
+            return RNull.instance;
+        }
+
+        public static DpsiFnNode create() {
+            return MathFunctionsNodesFactory.DpsiFnNodeGen.create();
+        }
+    }
+
+    public abstract static class PsiGammaNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double x, double deriv) {
+            return GammaFunctions.psigamma(x, deriv);
+        }
+
+        public static PsiGammaNode create() {
+            return MathFunctionsNodesFactory.PsiGammaNodeGen.create();
+        }
+    }
+
+    public abstract static class DiGammaNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double x) {
+            return GammaFunctions.digamma(x);
+        }
+
+        public static DiGammaNode create() {
+            return MathFunctionsNodesFactory.DiGammaNodeGen.create();
+        }
+    }
+
+    public abstract static class TriGammaNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double x) {
+            return GammaFunctions.trigamma(x);
+        }
+
+        public static TriGammaNode create() {
+            return MathFunctionsNodesFactory.TriGammaNodeGen.create();
+        }
+    }
+
+    public abstract static class TetraGammaNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double x) {
+            return GammaFunctions.tetragamma(x);
+        }
+
+        public static TetraGammaNode create() {
+            return MathFunctionsNodesFactory.TetraGammaNodeGen.create();
+        }
+    }
+
+    public abstract static class PentaGammaNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double x) {
+            return GammaFunctions.pentagamma(x);
+        }
+
+        public static PentaGammaNode create() {
+            return MathFunctionsNodesFactory.PentaGammaNodeGen.create();
+        }
+    }
+
+    public abstract static class BetaNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double a, double b) {
+            return Beta.beta(a, b);
+        }
+
+        public static BetaNode create() {
+            return MathFunctionsNodesFactory.BetaNodeGen.create();
+        }
+    }
+
+    public abstract static class LBetaNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double a, double b) {
+            return LBeta.lbeta(a, b);
+        }
+
+        public static LBetaNode create() {
+            return MathFunctionsNodesFactory.LBetaNodeGen.create();
+        }
+    }
+
+    public abstract static class ChooseNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double n, double k) {
+            return Choose.choose(n, k);
+        }
+
+        public static ChooseNode create() {
+            return MathFunctionsNodesFactory.ChooseNodeGen.create();
+        }
+    }
+
+    public abstract static class LChooseNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double n, double k) {
+            return Choose.lchoose(n, k);
+        }
+
+        public static LChooseNode create() {
+            return MathFunctionsNodesFactory.LChooseNodeGen.create();
+        }
+    }
+
+    public abstract static class BesselINode extends FFIUpCallNode.Arg3 {
+
+        @Specialization
+        protected Object evaluate(double a, double b, double c) {
+            return BesselFunctions.bessel_i(a, b, c);
+        }
+
+        public static BesselINode create() {
+            return MathFunctionsNodesFactory.BesselINodeGen.create();
+        }
+    }
+
+    public abstract static class BesselJNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double a, double b) {
+            return BesselFunctions.bessel_j(a, b);
+        }
+
+        public static BesselJNode create() {
+            return MathFunctionsNodesFactory.BesselJNodeGen.create();
+        }
+    }
+
+    public abstract static class BesselKNode extends FFIUpCallNode.Arg3 {
+
+        @Specialization
+        protected Object evaluate(double a, double b, double c) {
+            return BesselFunctions.bessel_k(a, b, c);
+        }
+
+        public static BesselKNode create() {
+            return MathFunctionsNodesFactory.BesselKNodeGen.create();
+        }
+    }
+
+    public abstract static class BesselYNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double a, double b) {
+            return BesselFunctions.bessel_y(a, b);
+        }
+
+        public static BesselYNode create() {
+            return MathFunctionsNodesFactory.BesselYNodeGen.create();
+        }
+    }
+
+    public abstract static class BesselIExNode extends FFIUpCallNode.Arg4 {
+
+        @Specialization
+        protected Object evaluate(final double a, final double b, final double c, Object d,
+                        @Cached("create()") BesselExNode besselEx) {
+            return besselEx.execute(new BesselExCaller() {
+                @Override
+                public double call(double[] arr) {
+                    return BesselFunctions.bessel_i_ex(a, b, c, arr);
+                }
+
+                @Override
+                public int arrLen() {
+                    return (int) Math.floor(b) + 1;
+                }
+            }, d);
+        }
+
+        public static BesselIExNode create() {
+            return MathFunctionsNodesFactory.BesselIExNodeGen.create();
+        }
+    }
+
+    public abstract static class BesselJExNode extends FFIUpCallNode.Arg3 {
+
+        @Specialization
+        protected Object evaluate(final double a, final double b, Object c,
+                        @Cached("create()") BesselExNode besselEx) {
+            return besselEx.execute(new BesselExCaller() {
+                @Override
+                public double call(double[] arr) {
+                    return BesselFunctions.bessel_j_ex(a, b, arr);
+                }
+
+                @Override
+                public int arrLen() {
+                    return (int) Math.floor(b) + 1;
+                }
+            }, c);
+        }
+
+        public static BesselJExNode create() {
+            return MathFunctionsNodesFactory.BesselJExNodeGen.create();
+        }
+    }
+
+    public abstract static class BesselKExNode extends FFIUpCallNode.Arg4 {
+
+        @Specialization
+        protected Object evaluate(double a, double b, double c, Object d,
+                        @Cached("create()") BesselExNode besselEx) {
+            return besselEx.execute(new BesselExCaller() {
+                @Override
+                public double call(double[] arr) {
+                    return BesselFunctions.bessel_k_ex(a, b, c, arr);
+                }
+
+                @Override
+                public int arrLen() {
+                    return (int) Math.floor(b) + 1;
+                }
+            }, d);
+        }
+
+        public static BesselKExNode create() {
+            return MathFunctionsNodesFactory.BesselKExNodeGen.create();
+        }
+    }
+
+    public abstract static class BesselYExNode extends FFIUpCallNode.Arg3 {
+
+        @Specialization
+        protected Object evaluate(double a, double b, Object c,
+                        @Cached("create()") BesselExNode besselEx) {
+            return besselEx.execute(new BesselExCaller() {
+                @Override
+                public double call(double[] arr) {
+                    return BesselFunctions.bessel_y_ex(a, b, arr);
+                }
+
+                @Override
+                public int arrLen() {
+                    return (int) Math.floor(b) + 1;
+                }
+            }, c);
+        }
+
+        public static BesselYExNode create() {
+            return MathFunctionsNodesFactory.BesselYExNodeGen.create();
+        }
+    }
+
+    interface BesselExCaller {
+
+        double call(double[] arr);
+
+        int arrLen();
+
+    }
+
+    abstract static class BesselExNode extends Node {
+
+        @Child private Node bIsPointerNode = Message.IS_POINTER.createNode();
+        @Child private Node bAsPointerNode;
+        @Child private ForeignArray2R bForeignArray2R;
+
+        public abstract double execute(BesselExCaller caller, Object b);
+
+        @Specialization
+        protected double besselEx(BesselExCaller caller, Object b,
+                        @Cached("create()") GetReadonlyData.Double bReadonlyData) {
+            RAbstractDoubleVector bVec;
+            TruffleObject bTO = (TruffleObject) b;
+            if (ForeignAccess.sendIsPointer(bIsPointerNode, bTO)) {
+                if (bAsPointerNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    bAsPointerNode = insert(Message.AS_POINTER.createNode());
+                }
+                long addr;
+                try {
+                    addr = ForeignAccess.sendAsPointer(bAsPointerNode, bTO);
+                    bVec = RDataFactory.createDoubleVectorFromNative(addr, caller.arrLen());
+                } catch (UnsupportedMessageException e) {
+                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
+                }
+            } else {
+                if (bForeignArray2R == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    bForeignArray2R = ForeignArray2R.create();
+                }
+                bVec = (RAbstractDoubleVector) bForeignArray2R.convert(bTO);
+            }
+
+            return caller.call(bReadonlyData.execute(bVec.materialize()));
+        }
+
+        public static BesselExNode create() {
+            return MathFunctionsNodesFactory.BesselExNodeGen.create();
+        }
+
+    }
+
+    public abstract static class SignNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double x) {
+            return RMath.sign(x);
+        }
+
+        public static SignNode create() {
+            return MathFunctionsNodesFactory.SignNodeGen.create();
+        }
+    }
+
+    public abstract static class FPrecNode extends FFIUpCallNode.Arg2 {
+
+        @Specialization
+        protected Object evaluate(double x, double digits) {
+            return RMath.fprec(x, digits);
+        }
+
+        public static FPrecNode create() {
+            return MathFunctionsNodesFactory.FPrecNodeGen.create();
+        }
+    }
+
+    public abstract static class SinpiNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double x) {
+            return RMath.sinpi(x);
+        }
+
+        public static SinpiNode create() {
+            return MathFunctionsNodesFactory.SinpiNodeGen.create();
+        }
+    }
+
+    public abstract static class CospiNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double x) {
+            return RMath.cospi(x);
+        }
+
+        public static CospiNode create() {
+            return MathFunctionsNodesFactory.CospiNodeGen.create();
+        }
+    }
+
+    public abstract static class TanpiNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected Object evaluate(double x) {
+            return RMath.tanpi(x);
+        }
+
+        public static TanpiNode create() {
+            return MathFunctionsNodesFactory.TanpiNodeGen.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 db0abf411ac03679eae6383d7cfe54b164c7bdc6..50a546ea966e9f3f6ae744965046ba2b87fd96ff 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
@@ -26,10 +26,8 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.interop.ForeignAccess;
-import com.oracle.truffle.api.interop.InteropException;
 import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.interop.UnknownIdentifierException;
 import com.oracle.truffle.api.interop.UnsupportedMessageException;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -37,17 +35,9 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RNull;
 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.nodes.GetReadonlyData;
 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.ffi.interop.UnsafeAdapter;
 import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
-import com.oracle.truffle.r.runtime.nmath.BesselFunctions;
-import com.oracle.truffle.r.runtime.nmath.Beta;
-import com.oracle.truffle.r.runtime.nmath.Choose;
-import com.oracle.truffle.r.runtime.nmath.GammaFunctions;
-import com.oracle.truffle.r.runtime.nmath.LBeta;
-import com.oracle.truffle.r.runtime.nmath.MathConstants;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function2_1;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function2_2;
@@ -55,15 +45,12 @@ 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.MathFunctions.Function4_1;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function4_2;
-import com.oracle.truffle.r.runtime.nmath.RMath;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandFunction1_Double;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandFunction2_Double;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandFunction3_Double;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandomNumberProvider;
 import com.oracle.truffle.r.runtime.nmath.RMultinom;
-import com.oracle.truffle.r.runtime.nmath.distr.Logis.PLogis;
 import com.oracle.truffle.r.runtime.nmath.distr.Rbinom;
-import com.oracle.truffle.r.runtime.nmath.distr.Pnorm.PnormBoth;
 
 public final class RandFunctionsNodes {
 
@@ -313,729 +300,4 @@ public final class RandFunctionsNodes {
 
     }
 
-    public abstract static class RfPnormBothNode extends FFIUpCallNode.Arg5 {
-
-        @Child private Node cumIsPointerNode = Message.IS_POINTER.createNode();
-        @Child private Node cumAsPointerNode;
-        @Child private Node cumRead;
-        @Child private Node cumWrite;
-        @Child private Node ccumIsPointerNode = Message.IS_POINTER.createNode();
-        @Child private Node ccumAsPointerNode;
-        @Child private Node ccumWrite;
-
-        @Specialization
-        protected Object evaluate(double x, Object cum, Object ccum, int lowerTail, int logP) {
-            // cum is R/W double* with size==1 and ccum is Writeonly double* with size==1
-            double[] cumArr = new double[1];
-            double[] ccumArr = new double[1];
-            long cumPtr;
-            long ccumPtr;
-            TruffleObject cumTO = (TruffleObject) cum;
-            if (ForeignAccess.sendIsPointer(cumIsPointerNode, cumTO)) {
-                if (cumAsPointerNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    cumAsPointerNode = insert(Message.AS_POINTER.createNode());
-                }
-                try {
-                    cumPtr = ForeignAccess.sendAsPointer(cumAsPointerNode, cumTO);
-                    cumArr[0] = UnsafeAdapter.UNSAFE.getDouble(cumPtr);
-                } catch (UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
-                }
-            } else {
-                cumPtr = 0L;
-                if (cumRead == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    cumRead = Message.READ.createNode();
-                    cumWrite = Message.WRITE.createNode();
-                }
-                try {
-                    cumArr[0] = ((Number) ForeignAccess.sendRead(cumRead, cumTO, 0)).doubleValue();
-                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
-                    throw RInternalError.shouldNotReachHere(e);
-                }
-            }
-
-            TruffleObject ccumTO = (TruffleObject) ccum;
-            if (ForeignAccess.sendIsPointer(ccumIsPointerNode, ccumTO)) {
-                if (ccumAsPointerNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    ccumAsPointerNode = insert(Message.AS_POINTER.createNode());
-                }
-                try {
-                    ccumPtr = ForeignAccess.sendAsPointer(ccumAsPointerNode, ccumTO);
-                } catch (UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
-                }
-            } else {
-                ccumPtr = 0L;
-                if (ccumWrite == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    ccumWrite = Message.WRITE.createNode();
-                }
-            }
-
-            PnormBoth.evaluate(x, cumArr, ccumArr, lowerTail != 0, logP != 0);
-            if (cumPtr != 0L) {
-                UnsafeAdapter.UNSAFE.putDouble(cumPtr, cumArr[0]);
-            } else {
-                try {
-                    ForeignAccess.sendWrite(cumWrite, cumTO, 0, cumArr[0]);
-                } catch (InteropException e) {
-                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
-                }
-            }
-            if (ccumPtr != 0L) {
-                UnsafeAdapter.UNSAFE.putDouble(ccumPtr, ccumArr[0]);
-            } else {
-                try {
-                    ForeignAccess.sendWrite(ccumWrite, ccumTO, 0, ccumArr[0]);
-                } catch (InteropException e) {
-                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
-                }
-            }
-            return RNull.instance;
-        }
-
-        public static RfPnormBothNode create() {
-            return RandFunctionsNodesFactory.RfPnormBothNodeGen.create();
-        }
-    }
-
-    public abstract static class Log1pmxNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double a) {
-            return GammaFunctions.log1pmx(a);
-        }
-
-        public static Log1pmxNode create() {
-            return RandFunctionsNodesFactory.Log1pmxNodeGen.create();
-        }
-    }
-
-    public abstract static class Log1pexpNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double a) {
-            return PLogis.log1pexp(a);
-        }
-
-        public static Log1pexpNode create() {
-            return RandFunctionsNodesFactory.Log1pexpNodeGen.create();
-        }
-    }
-
-    public abstract static class Lgamma1pNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double a) {
-            return GammaFunctions.lgamma1p(a);
-        }
-
-        public static Lgamma1pNode create() {
-            return RandFunctionsNodesFactory.Lgamma1pNodeGen.create();
-        }
-    }
-
-    public abstract static class LogspaceAddNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double a, double b) {
-            return MathConstants.logspaceAdd(a, b);
-        }
-
-        public static LogspaceAddNode create() {
-            return RandFunctionsNodesFactory.LogspaceAddNodeGen.create();
-        }
-    }
-
-    public abstract static class LogspaceSubNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double a, double b) {
-            return MathConstants.logspaceSub(a, b);
-        }
-
-        public static LogspaceSubNode create() {
-            return RandFunctionsNodesFactory.LogspaceSubNodeGen.create();
-        }
-    }
-
-    public abstract static class GammafnNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double a) {
-            return GammaFunctions.gammafn(a);
-        }
-
-        public static GammafnNode create() {
-            return RandFunctionsNodesFactory.GammafnNodeGen.create();
-        }
-    }
-
-    public abstract static class LGammafnNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double a) {
-            return GammaFunctions.lgammafn(a);
-        }
-
-        public static LGammafnNode create() {
-            return RandFunctionsNodesFactory.LGammafnNodeGen.create();
-        }
-    }
-
-    public abstract static class LGammafnSignNode extends FFIUpCallNode.Arg2 {
-
-        @Child private Node sgnIsPointerNode = Message.IS_POINTER.createNode();
-        @Child private Node sgnAsPointerNode;
-        @Child private Node sgnRead;
-        @Child private Node sgnWrite;
-
-        @Specialization
-        protected Object evaluate(double a, Object sgn) {
-            int[] sgnArr = new int[1];
-            long sgnPtr;
-            TruffleObject sgnTO = (TruffleObject) sgn;
-            if (ForeignAccess.sendIsPointer(sgnIsPointerNode, sgnTO)) {
-                if (sgnAsPointerNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    sgnAsPointerNode = insert(Message.AS_POINTER.createNode());
-                }
-                try {
-                    sgnPtr = ForeignAccess.sendAsPointer(sgnAsPointerNode, sgnTO);
-                    sgnArr[0] = UnsafeAdapter.UNSAFE.getInt(sgnPtr);
-                } catch (UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
-                }
-            } else {
-                sgnPtr = 0L;
-                if (sgnRead == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    sgnRead = Message.READ.createNode();
-                    sgnWrite = Message.WRITE.createNode();
-                }
-                try {
-                    sgnArr[0] = ((Number) ForeignAccess.sendRead(sgnRead, sgnTO, 0)).intValue();
-                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
-                    throw RInternalError.shouldNotReachHere(e);
-                }
-            }
-
-            double result = GammaFunctions.lgammafnSign(a, sgnArr);
-            if (sgnPtr != 0L) {
-                UnsafeAdapter.UNSAFE.putInt(sgnPtr, sgnArr[0]);
-            } else {
-                try {
-                    ForeignAccess.sendWrite(sgnWrite, sgnTO, 0, sgnArr[0]);
-                } catch (InteropException e) {
-                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
-                }
-            }
-            return result;
-        }
-
-        public static LGammafnSignNode create() {
-            return RandFunctionsNodesFactory.LGammafnSignNodeGen.create();
-        }
-    }
-
-    public abstract static class DpsiFnNode extends FFIUpCallNode.Arg7 {
-
-        @Child private Node ansIsPointerNode = Message.IS_POINTER.createNode();
-        @Child private Node ansAsPointerNode;
-        @Child private Node ansRead;
-        @Child private Node ansWrite;
-        @Child private Node nzIsPointerNode = Message.IS_POINTER.createNode();
-        @Child private Node nzAsPointerNode;
-        @Child private Node nzRead;
-        @Child private Node nzWrite;
-        @Child private Node ierrIsPointerNode = Message.IS_POINTER.createNode();
-        @Child private Node ierrAsPointerNode;
-        @Child private Node ierrRead;
-        @Child private Node ierrWrite;
-
-        @Specialization
-        protected Object evaluate(double x, int n, int kode, int m, Object ans, Object nz, Object ierr) {
-            // ans is R/W double* size==1 and nz is R/W int* size==1
-            // ierr is R/W int* size==1
-            double ansIn;
-            int nzIn;
-            int ierrIn;
-            TruffleObject ansTO = (TruffleObject) ans;
-            long ansPtr;
-            if (ForeignAccess.sendIsPointer(ansIsPointerNode, ansTO)) {
-                if (ansAsPointerNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    ansAsPointerNode = insert(Message.AS_POINTER.createNode());
-                }
-                try {
-                    ansPtr = ForeignAccess.sendAsPointer(ansAsPointerNode, ansTO);
-                    ansIn = UnsafeAdapter.UNSAFE.getDouble(ansPtr);
-                } catch (UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
-                }
-            } else {
-                ansPtr = 0L;
-                if (ansRead == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    ansRead = Message.READ.createNode();
-                    ansWrite = Message.WRITE.createNode();
-                }
-                try {
-                    ansIn = ((Number) ForeignAccess.sendRead(ansRead, ansTO, 0)).doubleValue();
-                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
-                    throw RInternalError.shouldNotReachHere(e);
-                }
-            }
-
-            TruffleObject nzTO = (TruffleObject) nz;
-            long nzPtr;
-            if (ForeignAccess.sendIsPointer(nzIsPointerNode, nzTO)) {
-                if (nzAsPointerNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    nzAsPointerNode = insert(Message.AS_POINTER.createNode());
-                }
-                try {
-                    nzPtr = ForeignAccess.sendAsPointer(nzAsPointerNode, nzTO);
-                    nzIn = UnsafeAdapter.UNSAFE.getInt(nzPtr);
-                } catch (UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
-                }
-            } else {
-                nzPtr = 0L;
-                if (nzRead == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    nzRead = Message.READ.createNode();
-                    nzWrite = Message.WRITE.createNode();
-                }
-                try {
-                    nzIn = ((Number) ForeignAccess.sendRead(nzRead, nzTO, 0)).intValue();
-                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
-                    throw RInternalError.shouldNotReachHere(e);
-                }
-            }
-
-            TruffleObject ierrTO = (TruffleObject) ierr;
-            long ierrPtr;
-            if (ForeignAccess.sendIsPointer(ierrIsPointerNode, ierrTO)) {
-                if (ierrAsPointerNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    ierrAsPointerNode = insert(Message.AS_POINTER.createNode());
-                }
-                try {
-                    ierrPtr = ForeignAccess.sendAsPointer(ierrAsPointerNode, ierrTO);
-                    ierrIn = UnsafeAdapter.UNSAFE.getInt(ierrPtr);
-                } catch (UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
-                }
-            } else {
-                ierrPtr = 0L;
-                if (ierrRead == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    ierrRead = Message.READ.createNode();
-                    ierrWrite = Message.WRITE.createNode();
-                }
-                try {
-                    ierrIn = ((Number) ForeignAccess.sendRead(ierrRead, ierrTO, 0)).intValue();
-                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
-                    throw RInternalError.shouldNotReachHere(e);
-                }
-            }
-
-            GammaFunctions.DpsiFnResult result = GammaFunctions.dpsifn(x, n, kode, ansIn, nzIn, ierrIn);
-            if (ansPtr != 0L) {
-                UnsafeAdapter.UNSAFE.putDouble(ansPtr, result.ans);
-            } else {
-                try {
-                    ForeignAccess.sendWrite(ansWrite, ansTO, 0, result.ans);
-                } catch (InteropException e) {
-                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
-                }
-            }
-            if (nzPtr != 0L) {
-                UnsafeAdapter.UNSAFE.putInt(nzPtr, result.nz);
-            } else {
-                try {
-                    ForeignAccess.sendWrite(nzWrite, nzTO, 0, result.nz);
-                } catch (InteropException e) {
-                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
-                }
-            }
-            if (ierrPtr != 0L) {
-                UnsafeAdapter.UNSAFE.putInt(ierrPtr, result.ierr);
-            } else {
-                try {
-                    ForeignAccess.sendWrite(ierrWrite, ierrTO, 0, result.ierr);
-                } catch (InteropException e) {
-                    throw RInternalError.shouldNotReachHere("WRITE message support expected");
-                }
-            }
-            return RNull.instance;
-        }
-
-        public static DpsiFnNode create() {
-            return RandFunctionsNodesFactory.DpsiFnNodeGen.create();
-        }
-    }
-
-    public abstract static class PsiGammaNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double x, double deriv) {
-            return GammaFunctions.psigamma(x, deriv);
-        }
-
-        public static PsiGammaNode create() {
-            return RandFunctionsNodesFactory.PsiGammaNodeGen.create();
-        }
-    }
-
-    public abstract static class DiGammaNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double x) {
-            return GammaFunctions.digamma(x);
-        }
-
-        public static DiGammaNode create() {
-            return RandFunctionsNodesFactory.DiGammaNodeGen.create();
-        }
-    }
-
-    public abstract static class TriGammaNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double x) {
-            return GammaFunctions.trigamma(x);
-        }
-
-        public static TriGammaNode create() {
-            return RandFunctionsNodesFactory.TriGammaNodeGen.create();
-        }
-    }
-
-    public abstract static class TetraGammaNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double x) {
-            return GammaFunctions.tetragamma(x);
-        }
-
-        public static TetraGammaNode create() {
-            return RandFunctionsNodesFactory.TetraGammaNodeGen.create();
-        }
-    }
-
-    public abstract static class PentaGammaNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double x) {
-            return GammaFunctions.pentagamma(x);
-        }
-
-        public static PentaGammaNode create() {
-            return RandFunctionsNodesFactory.PentaGammaNodeGen.create();
-        }
-    }
-
-    public abstract static class BetaNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double a, double b) {
-            return Beta.beta(a, b);
-        }
-
-        public static BetaNode create() {
-            return RandFunctionsNodesFactory.BetaNodeGen.create();
-        }
-    }
-
-    public abstract static class LBetaNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double a, double b) {
-            return LBeta.lbeta(a, b);
-        }
-
-        public static LBetaNode create() {
-            return RandFunctionsNodesFactory.LBetaNodeGen.create();
-        }
-    }
-
-    public abstract static class ChooseNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double n, double k) {
-            return Choose.choose(n, k);
-        }
-
-        public static ChooseNode create() {
-            return RandFunctionsNodesFactory.ChooseNodeGen.create();
-        }
-    }
-
-    public abstract static class LChooseNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double n, double k) {
-            return Choose.lchoose(n, k);
-        }
-
-        public static LChooseNode create() {
-            return RandFunctionsNodesFactory.LChooseNodeGen.create();
-        }
-    }
-
-    public abstract static class BesselINode extends FFIUpCallNode.Arg3 {
-
-        @Specialization
-        protected Object evaluate(double a, double b, double c) {
-            return BesselFunctions.bessel_i(a, b, c);
-        }
-
-        public static BesselINode create() {
-            return RandFunctionsNodesFactory.BesselINodeGen.create();
-        }
-    }
-
-    public abstract static class BesselJNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double a, double b) {
-            return BesselFunctions.bessel_j(a, b);
-        }
-
-        public static BesselJNode create() {
-            return RandFunctionsNodesFactory.BesselJNodeGen.create();
-        }
-    }
-
-    public abstract static class BesselKNode extends FFIUpCallNode.Arg3 {
-
-        @Specialization
-        protected Object evaluate(double a, double b, double c) {
-            return BesselFunctions.bessel_k(a, b, c);
-        }
-
-        public static BesselKNode create() {
-            return RandFunctionsNodesFactory.BesselKNodeGen.create();
-        }
-    }
-
-    public abstract static class BesselYNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double a, double b) {
-            return BesselFunctions.bessel_y(a, b);
-        }
-
-        public static BesselYNode create() {
-            return RandFunctionsNodesFactory.BesselYNodeGen.create();
-        }
-    }
-
-    public abstract static class BesselIExNode extends FFIUpCallNode.Arg4 {
-
-        @Specialization
-        protected Object evaluate(final double a, final double b, final double c, Object d,
-                        @Cached("create()") BesselExNode besselEx) {
-            return besselEx.execute(new BesselExCaller() {
-                @Override
-                public double call(double[] arr) {
-                    return BesselFunctions.bessel_i_ex(a, b, c, arr);
-                }
-
-                @Override
-                public int arrLen() {
-                    return (int) Math.floor(b) + 1;
-                }
-            }, d);
-        }
-
-        public static BesselIExNode create() {
-            return RandFunctionsNodesFactory.BesselIExNodeGen.create();
-        }
-    }
-
-    public abstract static class BesselJExNode extends FFIUpCallNode.Arg3 {
-
-        @Specialization
-        protected Object evaluate(final double a, final double b, Object c,
-                        @Cached("create()") BesselExNode besselEx) {
-            return besselEx.execute(new BesselExCaller() {
-                @Override
-                public double call(double[] arr) {
-                    return BesselFunctions.bessel_j_ex(a, b, arr);
-                }
-
-                @Override
-                public int arrLen() {
-                    return (int) Math.floor(b) + 1;
-                }
-            }, c);
-        }
-
-        public static BesselJExNode create() {
-            return RandFunctionsNodesFactory.BesselJExNodeGen.create();
-        }
-    }
-
-    public abstract static class BesselKExNode extends FFIUpCallNode.Arg4 {
-
-        @Specialization
-        protected Object evaluate(double a, double b, double c, Object d,
-                        @Cached("create()") BesselExNode besselEx) {
-            return besselEx.execute(new BesselExCaller() {
-                @Override
-                public double call(double[] arr) {
-                    return BesselFunctions.bessel_k_ex(a, b, c, arr);
-                }
-
-                @Override
-                public int arrLen() {
-                    return (int) Math.floor(b) + 1;
-                }
-            }, d);
-        }
-
-        public static BesselKExNode create() {
-            return RandFunctionsNodesFactory.BesselKExNodeGen.create();
-        }
-    }
-
-    public abstract static class BesselYExNode extends FFIUpCallNode.Arg3 {
-
-        @Specialization
-        protected Object evaluate(double a, double b, Object c,
-                        @Cached("create()") BesselExNode besselEx) {
-            return besselEx.execute(new BesselExCaller() {
-                @Override
-                public double call(double[] arr) {
-                    return BesselFunctions.bessel_y_ex(a, b, arr);
-                }
-
-                @Override
-                public int arrLen() {
-                    return (int) Math.floor(b) + 1;
-                }
-            }, c);
-        }
-
-        public static BesselYExNode create() {
-            return RandFunctionsNodesFactory.BesselYExNodeGen.create();
-        }
-    }
-
-    interface BesselExCaller {
-
-        double call(double[] arr);
-
-        int arrLen();
-
-    }
-
-    abstract static class BesselExNode extends Node {
-
-        @Child private Node bIsPointerNode = Message.IS_POINTER.createNode();
-        @Child private Node bAsPointerNode;
-        @Child private ForeignArray2R bForeignArray2R;
-
-        public abstract double execute(BesselExCaller caller, Object b);
-
-        @Specialization
-        protected double besselEx(BesselExCaller caller, Object b,
-                        @Cached("create()") GetReadonlyData.Double bReadonlyData) {
-            RAbstractDoubleVector bVec;
-            TruffleObject bTO = (TruffleObject) b;
-            if (ForeignAccess.sendIsPointer(bIsPointerNode, bTO)) {
-                if (bAsPointerNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    bAsPointerNode = insert(Message.AS_POINTER.createNode());
-                }
-                long addr;
-                try {
-                    addr = ForeignAccess.sendAsPointer(bAsPointerNode, bTO);
-                    bVec = RDataFactory.createDoubleVectorFromNative(addr, caller.arrLen());
-                } catch (UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere("IS_POINTER message returned true, AS_POINTER should not fail");
-                }
-            } else {
-                if (bForeignArray2R == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    bForeignArray2R = ForeignArray2R.create();
-                }
-                bVec = (RAbstractDoubleVector) bForeignArray2R.convert(bTO);
-            }
-
-            return caller.call(bReadonlyData.execute(bVec.materialize()));
-        }
-
-        public static BesselExNode create() {
-            return RandFunctionsNodesFactory.BesselExNodeGen.create();
-        }
-
-    }
-
-    public abstract static class SignNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double x) {
-            return RMath.sign(x);
-        }
-
-        public static SignNode create() {
-            return RandFunctionsNodesFactory.SignNodeGen.create();
-        }
-    }
-
-    public abstract static class FPrecNode extends FFIUpCallNode.Arg2 {
-
-        @Specialization
-        protected Object evaluate(double x, double digits) {
-            return RMath.fprec(x, digits);
-        }
-
-        public static FPrecNode create() {
-            return RandFunctionsNodesFactory.FPrecNodeGen.create();
-        }
-    }
-
-    public abstract static class SinpiNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double x) {
-            return RMath.sinpi(x);
-        }
-
-        public static SinpiNode create() {
-            return RandFunctionsNodesFactory.SinpiNodeGen.create();
-        }
-    }
-
-    public abstract static class CospiNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double x) {
-            return RMath.cospi(x);
-        }
-
-        public static CospiNode create() {
-            return RandFunctionsNodesFactory.CospiNodeGen.create();
-        }
-    }
-
-    public abstract static class TanpiNode extends FFIUpCallNode.Arg1 {
-
-        @Specialization
-        protected Object evaluate(double x) {
-            return RMath.tanpi(x);
-        }
-
-        public static TanpiNode create() {
-            return RandFunctionsNodesFactory.TanpiNodeGen.create();
-        }
-    }
-
 }
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 dc0f358098d4ebcdf5e0d2182d8787403cd99001..b8c02b22c30795dd8bfa136605491f5570ba7457 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
@@ -56,6 +56,7 @@ import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.SETCADDRNode;
 import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.SETCADRNode;
 import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.SETCARNode;
 import com.oracle.truffle.r.ffi.impl.nodes.MatchNodes;
+import com.oracle.truffle.r.ffi.impl.nodes.MathFunctionsNodes;
 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.MiscNodes.SetObjectNode;
@@ -528,7 +529,7 @@ public interface StdUpCallsRFFI {
     @RFFIUpCallNode(value = RandFunctionsNodes.RandFunction2Node.class, functionClass = Rnorm.class)
     double Rf_rnorm(double a, double b);
 
-    @RFFIUpCallNode(value = RandFunctionsNodes.RfPnormBothNode.class)
+    @RFFIUpCallNode(value = MathFunctionsNodes.RfPnormBothNode.class)
     void Rf_pnorm_both(double a, @RFFICpointer Object b, @RFFICpointer Object c, int d, int e);
 
     @RFFIUpCallNode(value = RandFunctionsNodes.RandFunction3_1Node.class, functionClass = LogNormal.DLNorm.class)
@@ -555,19 +556,19 @@ public interface StdUpCallsRFFI {
     @RFFIUpCallNode(value = RandFunctionsNodes.RandFunction2Node.class, functionClass = RGamma.class)
     double Rf_rgamma(double a, double b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.Log1pmxNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.Log1pmxNode.class)
     double Rf_log1pmx(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.Log1pexpNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.Log1pexpNode.class)
     double Rf_log1pexp(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.Lgamma1pNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.Lgamma1pNode.class)
     double Rf_lgamma1p(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.LogspaceAddNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.LogspaceAddNode.class)
     double Rf_logspace_add(double a, double b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.LogspaceSubNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.LogspaceSubNode.class)
     double Rf_logspace_sub(double a, double b);
 
     @RFFIUpCallNode(value = RandFunctionsNodes.RandFunction3_1Node.class, functionClass = DBeta.class)
@@ -789,84 +790,84 @@ public interface StdUpCallsRFFI {
     @RFFIUpCallNode(value = RandFunctionsNodes.RandFunction1Node.class, functionClass = Signrank.RSignrank.class)
     double Rf_rsignrank(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.GammafnNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.GammafnNode.class)
     double Rf_gammafn(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.LGammafnNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.LGammafnNode.class)
     double Rf_lgammafn(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.LGammafnSignNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.LGammafnSignNode.class)
     double Rf_lgammafn_sign(double a, @RFFICpointer Object b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.DpsiFnNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.DpsiFnNode.class)
     void Rf_dpsifn(double a, int b, int c, int d, @RFFICpointer Object e, @RFFICpointer Object f, @RFFICpointer Object g);
 
-    @RFFIUpCallNode(RandFunctionsNodes.PsiGammaNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.PsiGammaNode.class)
     double Rf_psigamma(double a, double b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.DiGammaNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.DiGammaNode.class)
     double Rf_digamma(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.TriGammaNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.TriGammaNode.class)
     double Rf_trigamma(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.TetraGammaNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.TetraGammaNode.class)
     double Rf_tetragamma(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.PentaGammaNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.PentaGammaNode.class)
     double Rf_pentagamma(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.BetaNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.BetaNode.class)
     double Rf_beta(double a, double b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.LBetaNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.LBetaNode.class)
     double Rf_lbeta(double a, double b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.ChooseNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.ChooseNode.class)
     double Rf_choose(double a, double b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.LChooseNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.LChooseNode.class)
     double Rf_lchoose(double a, double b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.BesselINode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.BesselINode.class)
     double Rf_bessel_i(double a, double b, double c);
 
-    @RFFIUpCallNode(RandFunctionsNodes.BesselJNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.BesselJNode.class)
     double Rf_bessel_j(double a, double b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.BesselKNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.BesselKNode.class)
     double Rf_bessel_k(double a, double b, double c);
 
-    @RFFIUpCallNode(RandFunctionsNodes.BesselYNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.BesselYNode.class)
     double Rf_bessel_y(double a, double b);
 
-    @RFFIUpCallNode(RandFunctionsNodes.BesselIExNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.BesselIExNode.class)
     double Rf_bessel_i_ex(double a, double b, double c, @RFFICpointer Object d);
 
-    @RFFIUpCallNode(RandFunctionsNodes.BesselJExNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.BesselJExNode.class)
     double Rf_bessel_j_ex(double a, double b, @RFFICpointer Object c);
 
-    @RFFIUpCallNode(RandFunctionsNodes.BesselKExNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.BesselKExNode.class)
     double Rf_bessel_k_ex(double a, double b, double c, @RFFICpointer Object d);
 
-    @RFFIUpCallNode(RandFunctionsNodes.BesselYExNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.BesselYExNode.class)
     double Rf_bessel_y_ex(double a, double b, @RFFICpointer Object c);
 
-    @RFFIUpCallNode(RandFunctionsNodes.SignNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.SignNode.class)
     double Rf_sign(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.FPrecNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.FPrecNode.class)
     double Rf_fprec(double a, double b);
 
     double Rf_ftrunc(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.CospiNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.CospiNode.class)
     double Rf_cospi(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.SinpiNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.SinpiNode.class)
     double Rf_sinpi(double a);
 
-    @RFFIUpCallNode(RandFunctionsNodes.TanpiNode.class)
+    @RFFIUpCallNode(MathFunctionsNodes.TanpiNode.class)
     double Rf_tanpi(double a);
 
     @RFFIUpCallNode(MiscNodes.NamesGetsNode.class)