From 8cebc13ac5fce5b1235092e812a7658e00fca73e Mon Sep 17 00:00:00 2001
From: Lukas Stadler <lukas.stadler@oracle.com>
Date: Tue, 19 Sep 2017 17:26:54 +0200
Subject: [PATCH] various fixes and extensions on NFI rffi

---
 .../ffi/impl/common/JavaUpCallsRFFIImpl.java  |  7 ++-
 .../impl/nfi/TruffleNFI_UpCallsRFFIImpl.java  |  3 +-
 .../truffle/r/library/tools/DirChmod.java     |  6 +--
 .../r/nodes/builtin/base/FileFunctions.java   | 18 ++++----
 .../r/nodes/builtin/base/LaFunctions.java     | 46 ++++++++++---------
 .../truffle/r/nodes/builtin/base/Sum.java     | 11 ++++-
 .../r/nodes/builtin/base/SysFunctions.java    | 16 ++++---
 .../r/nodes/builtin/base/foreign/Fft.java     |  7 +--
 .../com/oracle/truffle/r/runtime/RError.java  |  2 +-
 .../truffle/r/runtime/data/RListBase.java     |  1 +
 10 files changed, 68 insertions(+), 49 deletions(-)

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 22a22bf9a9..49f7079617 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
@@ -1521,12 +1521,15 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     public int R_ProtectWithIndex(Object x) {
-        throw RInternalError.unimplemented();
+        ArrayList<RObject> stack = getContext().protectStack;
+        stack.add(guaranteeInstanceOf(x, RObject.class));
+        return stack.size() - 1;
     }
 
     @Override
     public void R_Reprotect(Object x, int y) {
-        throw RInternalError.unimplemented();
+        ArrayList<RObject> stack = getContext().protectStack;
+        stack.set(y, guaranteeInstanceOf(x, RObject.class));
     }
 
     @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java
index b9f38b7afb..383bd0f96c 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java
@@ -74,6 +74,7 @@ public class TruffleNFI_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
     private static Node asPointer = Message.AS_POINTER.createNode();
 
     @Override
+    @TruffleBoundary
     public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
         // "bytes" is actually a Long unboxed from a NativePointer
         // TODO: handle encoding properly
@@ -216,7 +217,7 @@ public class TruffleNFI_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
         if (result == null) {
             throw RError.error(RError.NO_CALLER, RError.Message.UNKNOWN_OBJECT, functionName);
         }
-        return result.address.asAddress();
+        return result.address.value;
     }
 
     @Override
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
index 27121e5966..38bc4c0ad2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
@@ -24,7 +24,6 @@ import java.util.Iterator;
 import java.util.stream.Stream;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-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.r.nodes.builtin.RExternalBuiltinNode;
@@ -47,10 +46,11 @@ public abstract class DirChmod extends RExternalBuiltinNode.Arg2 {
         casts.arg(1).asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
+    @Child private BaseRFFI.ChmodNode chmodNode = BaseRFFI.ChmodNode.create();
+
     @Specialization
     @TruffleBoundary
-    protected RNull dirChmod(String pathName, boolean setGroupWrite,
-                    @Cached("create()") BaseRFFI.ChmodNode chmodNode) {
+    protected RNull dirChmod(String pathName, boolean setGroupWrite) {
         Path path = FileSystems.getDefault().getPath(pathName);
         int fileMask = setGroupWrite ? GRPWRITE_FILE_MASK : FILE_MASK;
         int dirMask = setGroupWrite ? GRPWRITE_DIR_MASK : DIR_MASK;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
index a5b17287ed..4cd95cf8fc 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
@@ -57,7 +57,6 @@ import java.util.stream.Stream;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -1224,10 +1223,11 @@ public class FileFunctions {
             casts.arg("mode").asIntegerVector().findFirst().mapIf(intNA(), constant(0777));
         }
 
+        @Child private BaseRFFI.MkdirNode mkdirNode = BaseRFFI.MkdirNode.create();
+
         @Specialization
         @TruffleBoundary
-        protected byte dirCreate(String pathIn, boolean showWarnings, boolean recursive, int octMode,
-                        @Cached("create()") BaseRFFI.MkdirNode mkdirNode) {
+        protected byte dirCreate(String pathIn, boolean showWarnings, boolean recursive, int octMode) {
             boolean ok;
             if (RRuntime.isNA(pathIn)) {
                 ok = false;
@@ -1235,30 +1235,30 @@ public class FileFunctions {
                 ok = true;
                 String path = Utils.tildeExpand(pathIn);
                 if (recursive) {
-                    ok = mkparentdirs(mkdirNode, new File(path).getAbsoluteFile().getParentFile(), showWarnings, octMode);
+                    ok = mkparentdirs(new File(path).getAbsoluteFile().getParentFile(), showWarnings, octMode);
                 }
                 if (ok) {
-                    ok = mkdir(mkdirNode, path, showWarnings, octMode);
+                    ok = mkdir(path, showWarnings, octMode);
                 }
             }
             return RRuntime.asLogical(ok);
         }
 
-        private boolean mkparentdirs(BaseRFFI.MkdirNode mkdirNode, File file, boolean showWarnings, int mode) {
+        private boolean mkparentdirs(File file, boolean showWarnings, int mode) {
             if (file.isDirectory()) {
                 return true;
             }
             if (file.exists()) {
                 return false;
             }
-            if (mkparentdirs(mkdirNode, file.getParentFile(), showWarnings, mode)) {
-                return mkdir(mkdirNode, file.getAbsolutePath(), showWarnings, mode);
+            if (mkparentdirs(file.getParentFile(), showWarnings, mode)) {
+                return mkdir(file.getAbsolutePath(), showWarnings, mode);
             } else {
                 return false;
             }
         }
 
-        private boolean mkdir(BaseRFFI.MkdirNode mkdirNode, String path, boolean showWarnings, int mode) {
+        private boolean mkdir(String path, boolean showWarnings, int mode) {
             try {
                 mkdirNode.execute(path, mode);
                 return true;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
index ec52c0c753..cca501bce3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
@@ -106,11 +106,11 @@ public class LaFunctions {
         static {
             createCasts(Rg.class);
         }
+        @Child private LapackRFFI.DgeevNode dgeevNode = LapackRFFI.DgeevNode.create();
 
         @Specialization
         protected Object doRg(RAbstractDoubleVector matrix, boolean onlyValues,
-                        @Cached("create()") GetDimAttributeNode getDimsNode,
-                        @Cached("create()") LapackRFFI.DgeevNode dgeevNode) {
+                        @Cached("create()") GetDimAttributeNode getDimsNode) {
             int[] dims = getDimsNode.getDimensions(matrix);
             // copy array component of matrix as Lapack destroys it
             int n = dims[0];
@@ -204,11 +204,11 @@ public class LaFunctions {
         static {
             createCasts(Rs.class);
         }
+        @Child private LapackRFFI.DsyevrNode dsyevrNode = LapackRFFI.DsyevrNode.create();
 
         @Specialization
         protected Object doRs(RAbstractDoubleVector matrix, boolean onlyValues,
-                        @Cached("create()") GetDimAttributeNode getDimsNode,
-                        @Cached("create()") LapackRFFI.DsyevrNode dsyevrNode) {
+                        @Cached("create()") GetDimAttributeNode getDimsNode) {
             int[] dims = getDimsNode.getDimensions(matrix);
             int n = dims[0];
             char jobv = onlyValues ? 'N' : 'V';
@@ -268,12 +268,12 @@ public class LaFunctions {
             Casts casts = new Casts(Qr.class);
             casts.arg("in").asDoubleVector(false, true, false).mustBe(matrix(), Message.MUST_BE_NUMERIC_MATRIX, "a");
         }
+        @Child private LapackRFFI.Dgeqp3Node dgeqp3Node = LapackRFFI.Dgeqp3Node.create();
 
         @Specialization
         protected RList doQr(RAbstractDoubleVector aIn,
                         @Cached("create()") GetDimAttributeNode getDimsNode,
-                        @Cached("create()") SetDimAttributeNode setDimsNode,
-                        @Cached("create()") LapackRFFI.Dgeqp3Node dgeqp3Node) {
+                        @Cached("create()") SetDimAttributeNode setDimsNode) {
             // This implementation is sufficient for B25 matcal-5.
             int[] dims = getDimsNode.getDimensions(aIn);
             // copy array component of matrix as Lapack destroys it
@@ -319,14 +319,15 @@ public class LaFunctions {
             casts.arg("b").asDoubleVector(false, true, false).mustBe(matrix(), Message.MUST_BE_NUMERIC_MATRIX, "b");
         }
 
+        @Child private LapackRFFI.DormqrNode dormqrNode = LapackRFFI.DormqrNode.create();
+        @Child private LapackRFFI.DtrtrsNode dtrtrsNode = LapackRFFI.DtrtrsNode.create();
+
         @Specialization
         protected RDoubleVector doQrCoefReal(RList qIn, RAbstractDoubleVector b,
                         @Cached("create()") GetReadonlyData.Double qrToArrayNode,
                         @Cached("create()") GetReadonlyData.Double tauToArrayNode,
                         @Cached("create()") GetDimAttributeNode getBDimsNode,
-                        @Cached("create()") GetDimAttributeNode getQDimsNode,
-                        @Cached("create()") LapackRFFI.DormqrNode dormqrNode,
-                        @Cached("create()") LapackRFFI.DtrtrsNode dtrtrsNode) {
+                        @Cached("create()") GetDimAttributeNode getQDimsNode) {
             RDoubleVector qr = (RDoubleVector) qIn.getDataAt(0);
 
             RDoubleVector tau = (RDoubleVector) qIn.getDataAt(2);
@@ -384,12 +385,12 @@ public class LaFunctions {
             casts.arg("uselog").defaultError(Message.MUST_BE_LOGICAL, "logarithm").asLogicalVector().findFirst().mustNotBeNA().map(toBoolean());
         }
 
-        @Specialization
+        @Child private LapackRFFI.DgetrfNode dgetrfNode = LapackRFFI.DgetrfNode.create();
 
+        @Specialization
         protected RList doDetGeReal(RAbstractDoubleVector aIn, boolean useLog,
                         @Cached("create()") GetReadonlyData.Double vectorToArrayNode,
-                        @Cached("create()") GetDimAttributeNode getDimsNode,
-                        @Cached("create()") LapackRFFI.DgetrfNode dgetrfNode) {
+                        @Cached("create()") GetDimAttributeNode getDimsNode) {
             RDoubleVector a = (RDoubleVector) aIn.copy();
             int[] aDims = getDimsNode.getDimensions(aIn);
             int n = aDims[0];
@@ -466,14 +467,15 @@ public class LaFunctions {
             casts.arg("tol").asDoubleVector().findFirst(RRuntime.DOUBLE_NA);
         }
 
+        @Child private LapackRFFI.DpotrfNode dpotrfNode = LapackRFFI.DpotrfNode.create();
+        @Child private LapackRFFI.DpstrfNode dpstrfNode = LapackRFFI.DpstrfNode.create();
+
         @Specialization
         protected RDoubleVector doDetGeReal(RAbstractDoubleVector aIn, boolean piv, double tol,
                         @Cached("create()") UnaryCopyAttributesNode copyAttributesNode,
                         @Cached("create()") GetDimAttributeNode getDimsNode,
                         @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
-                        @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
-                        @Cached("create()") LapackRFFI.DpotrfNode dpotrfNode,
-                        @Cached("create()") LapackRFFI.DpstrfNode dpstrfNode) {
+                        @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
             double[] aData = aIn.materialize().getDataCopy();
             int[] aDims = getDimsNode.getDimensions(aIn);
             int n = aDims[0];
@@ -540,10 +542,11 @@ public class LaFunctions {
             casts.arg("size").asIntegerVector().mustBe(notEmpty()).findFirst().mustBe(gt(0), Message.MUST_BE_POSITIVE_INT);
         }
 
+        @Child private LapackRFFI.DpotriNode dpotriNode = LapackRFFI.DpotriNode.create();
+
         @Specialization
         protected RDoubleVector chol2inv(RAbstractDoubleVector a, int size,
-                        @Cached("create()") GetDimAttributeNode getDimsNode,
-                        @Cached("create()") LapackRFFI.DpotriNode dpotriNode) {
+                        @Cached("create()") GetDimAttributeNode getDimsNode) {
 
             int[] aDims = getDimsNode.getDimensions(a);
             int m = aDims[0];
@@ -617,6 +620,10 @@ public class LaFunctions {
             casts.arg("tolin").asDoubleVector().findFirst(RRuntime.DOUBLE_NA);
         }
 
+        @Child private LapackRFFI.DgesvNode dgesvNode = LapackRFFI.DgesvNode.create();
+        @Child private LapackRFFI.DgeconNode dgeconNode = LapackRFFI.DgeconNode.create();
+        @Child private LapackRFFI.DlangeNode dlangeNode = LapackRFFI.DlangeNode.create();
+
         @Specialization
         protected RDoubleVector laSolve(RAbstractVector a, RAbstractDoubleVector bin, double tol,
                         @Cached("create()") GetDimAttributeNode getADimsNode,
@@ -625,10 +632,7 @@ public class LaFunctions {
                         @Cached("create()") SetDimNamesAttributeNode setBDimNamesNode,
                         @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
                         @Cached("create()") GetDimNamesAttributeNode getBinDimNamesNode,
-                        @Cached("create()") SetNamesAttributeNode setNamesNode,
-                        @Cached("create()") LapackRFFI.DgesvNode dgesvNode,
-                        @Cached("create()") LapackRFFI.DgeconNode dgeconNode,
-                        @Cached("create()") LapackRFFI.DlangeNode dlangeNode) {
+                        @Cached("create()") SetNamesAttributeNode setNamesNode) {
             int[] aDims = getADimsNode.getDimensions(a);
             int n = aDims[0];
             if (n == 0) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
index 24a3fbadbb..377550336e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
@@ -27,8 +27,10 @@ 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.Specialization;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -73,6 +75,8 @@ public abstract class Sum extends RBuiltinNode.Arg2 {
         return value instanceof RDoubleVector;
     }
 
+    @Child private MiscRFFI.ExactSumNode exactSumNode;
+
     @Specialization(guards = {"FULL_PRECISION", "args.getLength() == 1", "isRDoubleVector(args.getArgument(0))", "naRm == cachedNaRm"})
     protected double sumLengthOneRDoubleVector(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean naRm,
                     @Cached("create()") GetReadonlyData.Double vectorToArrayNode,
@@ -80,12 +84,15 @@ public abstract class Sum extends RBuiltinNode.Arg2 {
                     @Cached("create()") VectorLengthProfile lengthProfile,
                     @Cached("createCountingProfile()") LoopConditionProfile loopProfile,
                     @Cached("create()") NACheck na,
-                    @Cached("createBinaryProfile()") ConditionProfile needsExactSumProfile,
-                    @Cached("create()") MiscRFFI.ExactSumNode exactSumNode) {
+                    @Cached("createBinaryProfile()") ConditionProfile needsExactSumProfile) {
         RDoubleVector vector = (RDoubleVector) args.getArgument(0);
         int length = lengthProfile.profile(vector.getLength());
 
         if (needsExactSumProfile.profile(length >= 3)) {
+            if (exactSumNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                exactSumNode = (MiscRFFI.ExactSumNode) insert((Node) MiscRFFI.ExactSumNode.create());
+            }
             return exactSumNode.execute(vectorToArrayNode.execute(vector), !vector.isComplete(), cachedNaRm);
         } else {
             na.enable(vector);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
index 3a89f202b0..27f194f7e9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
@@ -45,7 +45,6 @@ import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
@@ -255,10 +254,11 @@ public class SysFunctions {
             casts.arg("paths").mustBe(stringValue());
         }
 
+        @Child private BaseRFFI.ReadlinkNode readlinkNode = BaseRFFI.ReadlinkNode.create();
+
         @Specialization
         @TruffleBoundary
-        protected Object sysReadlink(RAbstractStringVector vector,
-                        @Cached("create()") BaseRFFI.ReadlinkNode readlinkNode) {
+        protected Object sysReadlink(RAbstractStringVector vector) {
             String[] paths = new String[vector.getLength()];
             boolean complete = RDataFactory.COMPLETE_VECTOR;
             for (int i = 0; i < paths.length; i++) {
@@ -300,10 +300,11 @@ public class SysFunctions {
             casts.arg("use_umask").asLogicalVector().findFirst().mustNotBeNA().map(toBoolean());
         }
 
+        @Child private BaseRFFI.ChmodNode chmodNode = BaseRFFI.ChmodNode.create();
+
         @Specialization
         @TruffleBoundary
-        protected RLogicalVector sysChmod(RAbstractStringVector pathVec, RAbstractIntVector octmode, @SuppressWarnings("unused") boolean useUmask,
-                        @Cached("create()") BaseRFFI.ChmodNode chmodNode) {
+        protected RLogicalVector sysChmod(RAbstractStringVector pathVec, RAbstractIntVector octmode, @SuppressWarnings("unused") boolean useUmask) {
             byte[] data = new byte[pathVec.getLength()];
             for (int i = 0; i < data.length; i++) {
                 String path = Utils.tildeExpand(pathVec.getDataAt(i));
@@ -378,10 +379,11 @@ public class SysFunctions {
             casts.arg("dirmask").asLogicalVector().findFirst().mustNotBeNA().map(toBoolean());
         }
 
+        @Child private BaseRFFI.GlobNode globNode = BaseRFFI.GlobNode.create();
+
         @Specialization
         @TruffleBoundary
-        protected Object sysGlob(RAbstractStringVector pathVec, @SuppressWarnings("unused") boolean dirMask,
-                        @Cached("create()") BaseRFFI.GlobNode globNode) {
+        protected Object sysGlob(RAbstractStringVector pathVec, @SuppressWarnings("unused") boolean dirMask) {
             ArrayList<String> matches = new ArrayList<>();
             // Sys.glob closure already called path.expand
             for (int i = 0; i < pathVec.getLength(); i++) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java
index 401b82d01e..b12640db88 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java
@@ -35,12 +35,13 @@ public abstract class Fft extends RExternalBuiltinNode.Arg2 {
         casts.arg(1).mustNotBeNull().asLogicalVector().findFirst().map(Predef.toBoolean());
     }
 
+    @Child private StatsRFFI.FactorNode factorNode = StatsRFFI.FactorNode.create();
+    @Child private StatsRFFI.WorkNode workNode = StatsRFFI.WorkNode.create();
+
     // TODO: handle more argument types (this is sufficient to run the b25 benchmarks)
     @Specialization
     public Object execute(RAbstractComplexVector zVec, boolean inverse,
-                    @Cached("create()") GetDimAttributeNode getDimNode,
-                    @Cached("create()") StatsRFFI.FactorNode factorNode,
-                    @Cached("create()") StatsRFFI.WorkNode workNode) {
+                    @Cached("create()") GetDimAttributeNode getDimNode) {
         double[] z = zVec.materialize().getDataTemp();
         int inv = inverse ? 2 : -2;
         int[] d = getDimNode.getDimensions(zVec);
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 c1436c2187..b992cca27d 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
@@ -761,7 +761,7 @@ public final class RError extends RuntimeException implements TruffleException {
         DEPARSE_INVALID_CUTOFF("invalid 'cutoff' value for 'deparse', using default"),
         FILE_CANNOT_CREATE("cannot create file '%s'"),
         FILE_CANNOT_LINK("  cannot link '%s' to '%s', reason %s"),
-        FILE_CANNOT_COPY("  cannot link '%s' to '%s', reason %s"),
+        FILE_CANNOT_COPY("  cannot copy '%s' to '%s', reason %s"),
         FILE_CANNOT_REMOVE("  cannot remove file '%s'"),
         FILE_CANNOT_RENAME("  cannot rename file '%s' to '%s'"),
         FILE_COPY_RECURSIVE_IGNORED("'recursive' will be ignored as 'to' is not a single existing directory"),
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
index 73cb3411ce..7e0cc18e71 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
@@ -118,6 +118,7 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi
      * Unlike atomic vectors, {@code RList} cannot have a native memory mirror, therefore this is a
      * fast operation.
      */
+    @Override
     public final Object[] getReadonlyData() {
         return data;
     }
-- 
GitLab