diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java index e20a312a0f8ed428c7c2e839b3265911f2a8088d..3b7eb5535210ed6c49e3009df37ab3e7cebd05c8 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java @@ -133,7 +133,7 @@ public class REmbedded { RContext ctx = RContext.getInstance(); ctx.completeEmbeddedInitialization(); ctx.getRFFI().initializeEmbedded(ctx); - int status = RCommand.readEvalPrint(context, consoleHandler); + int status = RCommand.readEvalPrint(context, consoleHandler, false); context.leave(); context.close(); Utils.systemExit(status); diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java index b0a17bf8ea6697e396ec98042a2d84c87dbb781a..70ef3a473b7d7372a5385dd56041054e3a2ac8d6 100644 --- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java +++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java @@ -31,6 +31,8 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.function.Supplier; import org.graalvm.polyglot.Context; @@ -101,7 +103,7 @@ public class RCommand extends RAbstractLauncher { srcFile = new File(fileOption); } - return readEvalPrint(context, consoleHandler, srcFile); + return readEvalPrint(context, consoleHandler, srcFile, true); } else { return 0; } @@ -209,8 +211,8 @@ public class RCommand extends RAbstractLauncher { private static final Source GET_PROMPT = Source.newBuilder("R", ".Internal(getOption('prompt'))", "<prompt>").internal(true).buildLiteral(); private static final Source GET_CONTINUE_PROMPT = Source.newBuilder("R", ".Internal(getOption('continue'))", "<continue-prompt>").internal(true).buildLiteral(); - public static int readEvalPrint(Context context, ConsoleHandler consoleHandler) { - return readEvalPrint(context, consoleHandler, null); + public static int readEvalPrint(Context context, ConsoleHandler consoleHandler, boolean useExecutor) { + return readEvalPrint(context, consoleHandler, null, useExecutor); } /** @@ -223,7 +225,11 @@ public class RCommand extends RAbstractLauncher { * In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before * exiting. So,in either case, we never return. */ - public static int readEvalPrint(Context context, ConsoleHandler consoleHandler, File srcFile) { + public static int readEvalPrint(Context context, ConsoleHandler consoleHandler, File srcFile, boolean useExecutor) { + ExecutorService executor = null; + if (useExecutor) { + executor = context.eval(Source.newBuilder("R", ".fastr.getExecutor()", "<get-executor>").internal(true).buildLiteral()).asHostObject(); + } int lastStatus = 0; try { while (true) { // processing inputs @@ -253,7 +259,17 @@ public class RCommand extends RAbstractLauncher { } else { src = Source.newBuilder("R", sb.toString(), "<REPL>").interactive(true).buildLiteral(); } - context.eval(src); + if (useExecutor) { + try { + executor.submit(() -> context.eval(src)).get(); + } catch (ExecutionException ex) { + throw ex.getCause(); + } + } else { + context.eval(src); + } + } catch (InterruptedException ex) { + throw fatal("Unexpected interrup error"); } catch (PolyglotException e) { if (continuePrompt == null) { continuePrompt = doEcho ? getContinuePrompt(context) : null; @@ -300,6 +316,9 @@ public class RCommand extends RAbstractLauncher { } } catch (ExitException e) { return e.code; + } catch (Throwable ex) { + System.err.println("Unexpected error in REPL"); + return 1; } } diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java index 642d2b6c0cc701e04af0875b445d3c4e81204cdc..4a9513301d247ad93295a970b0309d897f6b29fd 100644 --- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java +++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java @@ -73,7 +73,7 @@ public final class RscriptCommand extends RAbstractLauncher { if (fileOption != null) { return executeFile(fileOption); } else { - return RCommand.readEvalPrint(context, consoleHandler, null); + return RCommand.readEvalPrint(context, consoleHandler, null, true); } } else { return 0; diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java index 370705c4d0e639a292b92cf8d18b2924ef2e063b..d8c1643b12052a8db1c4015becf7283405dd7ade 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java @@ -62,14 +62,17 @@ public final class GridContext { devices.add(new DeviceAndState(null, null)); } - public static GridContext getContext() { - RContext rCtx = RContext.getInstance(); + public static GridContext getContext(RContext rCtx) { if (rCtx.gridContext == null) { rCtx.gridContext = new GridContext(); } return (GridContext) rCtx.gridContext; } + public static GridContext getContext() { + return getContext(RContext.getInstance()); + } + @TruffleBoundary public GridState getGridState() { gridState.setDeviceState(devices.get(currentDeviceIdx).state); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/WindowDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/WindowDevice.java index 89e503375ae303eddf7d426985b78bfb7a3ce599..99140fc5bd74d5e31ae6076df1b53a58ada73878 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/WindowDevice.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/WindowDevice.java @@ -42,8 +42,9 @@ public final class WindowDevice { public static GridDevice createWindowDevice(int width, int height) { JFrameDevice frameDevice = new JFrameDevice(width, height); - if (RContext.getInstance().hasExecutor()) { - frameDevice.setResizeListener(WindowDevice::redrawAll); + RContext ctx = RContext.getInstance(); + if (ctx.hasExecutor()) { + frameDevice.setResizeListener(() -> redrawAll(ctx)); } else { noSchedulingSupportWarning(); } @@ -54,12 +55,13 @@ public final class WindowDevice { throw RError.error(RError.NO_CALLER, Message.GENERIC, "AWT based grid devices are not supported."); } - private static void redrawAll() { - RContext ctx = RContext.getInstance(); + private static void redrawAll(RContext ctx) { if (ctx.hasExecutor()) { // to be robust we re-check the executor availability ctx.schedule(() -> { - GridContext.getContext().evalInternalRFunction("redrawAll"); + Object prev = ctx.getEnv().getContext().enter(); + GridContext.getContext(ctx).evalInternalRFunction("redrawAll"); + ctx.getEnv().getContext().leave(prev); }); } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/JFrameDevice.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/JFrameDevice.java index ff4d2ddbbb3c55deaf78608f63ae238971e26c22..bef04f3c3bb2f7629ffbe9e884034adaf078065e 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/JFrameDevice.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/device/awt/JFrameDevice.java @@ -55,7 +55,7 @@ public final class JFrameDevice implements GridDevice, ImageSaver { // This will be drawn on the component private BufferedImage componentImage; - // Grid draings will be made into this image, may be == componentImage if isOnHold is false + // Grid drawings will be made into this image, may be == componentImage if isOnHold is false private BufferedImage image; // If have we created a new image for buffering while on hold, we keep it to reuse it private BufferedImage cachedImage; @@ -198,6 +198,11 @@ public final class JFrameDevice implements GridDevice, ImageSaver { defaultInitGraphics(graphics); graphics.clearRect(0, 0, width, height); inner = new Graphics2DDevice(graphics, width, height, true); + componentImage = image; + cachedImage = null; + if (isOnHold) { + hold(); + } } private void disposeImageDevice() { @@ -217,7 +222,10 @@ public final class JFrameDevice implements GridDevice, ImageSaver { disposeImageDevice(); openGraphics2DDevice(newWidth, newHeight); if (onResize != null) { + // note: onResize action should take care of initiating the repaint onResize.run(); + } else { + repaint(); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 00c73793904ea592fdf7e7fa41ccdf50e49dc8db..4065174aa36442b2f54e462130143beb42ec970d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -127,6 +127,7 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRRefCountInfo; import com.oracle.truffle.r.nodes.builtin.fastr.FastRRefCountInfoNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRRegisterFunctions; import com.oracle.truffle.r.nodes.builtin.fastr.FastRRegisterFunctionsNodeGen; +import com.oracle.truffle.r.nodes.builtin.fastr.FastRGetExecutor; import com.oracle.truffle.r.nodes.builtin.fastr.FastRSlotAssign; import com.oracle.truffle.r.nodes.builtin.fastr.FastRSlotAssignNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRSourceInfo; @@ -436,6 +437,7 @@ public class BasePackage extends RBuiltinPackage { add(WithVisible.class, WithVisibleNodeGen::create, WithVisible::createSpecial); add(Exists.class, ExistsNodeGen::create); add(Expression.class, ExpressionNodeGen::create); + add(FastRGetExecutor.class, FastRGetExecutor::new); add(FastRContext.R.class, FastRContextFactory.RNodeGen::create); add(FastRContext.Rscript.class, FastRContextFactory.RscriptNodeGen::create); add(FastRContext.CloseChannel.class, FastRContextFactory.CloseChannelNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java index 5cee144e27517e118dbfadbaca305c550240a80f..bd8d2c4312705d43ab68c229050dd42a5d6c802c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java @@ -58,6 +58,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RAttributesLayout; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RMissing; +import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RTypes; import com.oracle.truffle.r.runtime.data.RVector; @@ -99,7 +100,7 @@ public abstract class Repeat extends RBuiltinNode.Arg2 { static { Casts casts = new Casts(Repeat.class); - casts.arg("x").mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, typeName()); + casts.arg("x").allowNull().mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, typeName()); // prepare cast pipeline nodes for vararg matching PB_TIMES = new PipelineBuilder("times"); @@ -137,6 +138,11 @@ public abstract class Repeat extends RBuiltinNode.Arg2 { return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY}; } + @Specialization + protected RNull repeatNull(@SuppressWarnings("unused") RNull x, @SuppressWarnings("unused") RArgsValuesAndNames args) { + return RNull.instance; + } + @Specialization protected Object repeat(VirtualFrame frame, RAbstractVector x, RArgsValuesAndNames args) { RArgsValuesAndNames margs = prepareArgs.execute(args, null); @@ -238,7 +244,7 @@ public abstract class Repeat extends RBuiltinNode.Arg2 { * Extend or truncate the vector to a specified length. */ private static RVector<?> handleLengthOut(RAbstractVector x, int lengthOut) { - return x.copyResized(lengthOut, false); + return x.copyResized(lengthOut, x.getLength() == 0); } /** diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRGetExecutor.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRGetExecutor.java new file mode 100644 index 0000000000000000000000000000000000000000..3c01867839a2c1aed5ef7b411208741d1a71807b --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRGetExecutor.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018, 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.nodes.builtin.fastr; + +import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.context.RContext; + +@RBuiltin(name = ".fastr.getExecutor", kind = PRIMITIVE, behavior = COMPLEX, parameterNames = {}) +public class FastRGetExecutor extends RBuiltinNode.Arg0 { + + static { + Casts.noCasts(FastRGetExecutor.class); + } + + @Override + public Object execute(VirtualFrame frame) { + RContext context = RContext.getInstance(); + if (!context.hasExecutor()) { + context.initExecutor(); + } + return context.getExecutor(); + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index 9762df621c5343f76c61707e1d479458f11752de..7bd99534069cdf92a6d3d3e443d34ee942c5f935 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -44,6 +44,7 @@ import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.function.Supplier; import com.oracle.truffle.api.Assumption; @@ -246,7 +247,7 @@ public final class RContext { private final int multiSlotIndex; private TruffleContext truffleContext; - public Executor executor; + private Executor executor; private final InputStream stdin; private final OutputStreamWriter stdout; @@ -752,10 +753,18 @@ public final class RContext { return startParameters; } + public void initExecutor() { + this.executor = Executors.newSingleThreadExecutor(); + } + public boolean hasExecutor() { return executor != null; } + public Executor getExecutor() { + return this.executor; + } + /** * Allows another thread to schedule some code to be run in this context's thread. The action * can be scheduled only if this context was created with an Executor. diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java index a5498304f6410c181058c235544dca84fafee8d0..7e9bbe7ebd088a626acd839c00879af200cde77d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java @@ -153,16 +153,18 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract private double[] copyResizedData(int size, boolean fillNA) { int csize = size << 1; - double[] newData = Arrays.copyOf(getReadonlyData(), csize); - if (csize > this.getLength()) { + double[] localData = getReadonlyData(); + double[] newData = Arrays.copyOf(localData, csize); + if (csize > localData.length) { if (fillNA) { - for (int i = data.length; i < size; i++) { + for (int i = localData.length; i < csize; i++) { newData[i] = RRuntime.DOUBLE_NA; } } else { - for (int i = data.length, j = 0; i <= csize - 2; i += 2, j = Utils.incMod(j + 1, data.length)) { - newData[i] = data[j]; - newData[i + 1] = data[j + 1]; + assert localData.length > 0 : "cannot call resize on empty vector if fillNA == false"; + for (int i = localData.length, j = 0; i <= csize - 2; i += 2, j = Utils.incMod(j + 1, localData.length)) { + newData[i] = localData[j]; + newData[i + 1] = localData[j + 1]; } } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java index c591f5f6b4ba0e831678fed17bf33a6cee4346f2..893b7512a9b1a8da5b8c78ca579394226ee1b02c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java @@ -178,6 +178,7 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD newData[i] = RRuntime.DOUBLE_NA; } } else { + assert oldData.length > 0 : "cannot call resize on empty vector if fillNA == false"; for (int i = oldDataLength, j = 0; i < newData.length; ++i, j = Utils.incMod(j, oldDataLength)) { newData[i] = oldData[j]; } @@ -187,8 +188,9 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD } private double[] copyResizedData(int size, boolean fillNA) { - double[] newData = Arrays.copyOf(getReadonlyData(), size); - return resizeData(newData, this.data, this.getLength(), fillNA); + double[] localData = getReadonlyData(); + double[] newData = Arrays.copyOf(localData, size); + return resizeData(newData, localData, localData.length, fillNA); } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java index d3552c1fdb6010c9d0d6ce8ac49ed02c7e3a0519..20438aaa0d152fada24d795ebac07e4a93fd8c68 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java @@ -181,6 +181,7 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect newData[i] = RRuntime.INT_NA; } } else { + assert oldDataLength > 0 : "cannot call resize on empty vector if fillNA == false"; for (int i = oldDataLength, j = 0; i < newData.length; ++i, j = Utils.incMod(j, oldDataLength)) { newData[i] = oldData[j]; } @@ -190,8 +191,9 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect } private int[] copyResizedData(int size, boolean fillNA) { - int[] newData = Arrays.copyOf(getReadonlyData(), size); - return resizeData(newData, this.data, this.getLength(), fillNA); + int[] localData = getReadonlyData(); + int[] newData = Arrays.copyOf(localData, size); + return resizeData(newData, localData, localData.length, fillNA); } @Override 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 3c59ac2adc4ee7ee83e87823fa66990af0df81bf..ad9adb0365c9ea5c5b8b960e847e6dbfd19a6a7d 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 @@ -169,6 +169,7 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi newData[i] = RNull.instance; } } else { + assert oldDataLength > 0 : "cannot call resize on empty vector if fillNA == false"; for (int i = oldData.length, j = 0; i < newData.length; ++i, j = Utils.incMod(j, oldData.length)) { newData[i] = oldData[j]; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java index c5f4390abf7e3177f4427b1544574e0ab1a01ae6..483fdec59880d2e59044b1fb00586b952a26655a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java @@ -154,15 +154,17 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo } private byte[] copyResizedData(int size, boolean fillNA) { - byte[] newData = Arrays.copyOf(getReadonlyData(), size); - if (size > this.getLength()) { + byte[] localData = getReadonlyData(); + byte[] newData = Arrays.copyOf(localData, size); + if (size > localData.length) { if (fillNA) { - for (int i = data.length; i < size; i++) { + for (int i = localData.length; i < size; i++) { newData[i] = RRuntime.LOGICAL_NA; } } else { - for (int i = data.length, j = 0; i < size; ++i, j = Utils.incMod(j, data.length)) { - newData[i] = data[j]; + assert localData.length > 0 : "cannot call resize on empty vector if fillNA == false"; + for (int i = localData.length, j = 0; i < size; ++i, j = Utils.incMod(j, localData.length)) { + newData[i] = localData[j]; } } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java index 49ef57251f49cf163402d23c2620d96f8debb611..2edd0d69e979dff5c37a4e4e69a2fa6626a1e8b0 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java @@ -155,10 +155,12 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec } private byte[] copyResizedData(int size, boolean fillNA) { - byte[] newData = Arrays.copyOf(getReadonlyData(), size); + byte[] localData = getReadonlyData(); + byte[] newData = Arrays.copyOf(localData, size); if (!fillNA) { + assert localData.length > 0 : "cannot call resize on empty vector if fillNA == false"; // NA is 00 for raw - for (int i = data.length, j = 0; i < size; ++i, j = Utils.incMod(j, data.length)) { + for (int i = localData.length, j = 0; i < size; ++i, j = Utils.incMod(j, localData.length)) { newData[i] = data[j]; } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java index eeb21176719f2f2b16fb82d76dbc054b9eee9f80..c73b9f689e45aed7df603ced95c7284384794cfa 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java @@ -146,15 +146,17 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS } private String[] copyResizedData(int size, String fill) { - String[] newData = Arrays.copyOf(data, size); - if (size > this.getLength()) { + String[] localData = getReadonlyData(); + String[] newData = Arrays.copyOf(localData, size); + if (size > localData.length) { if (fill != null) { - for (int i = data.length; i < size; i++) { + for (int i = localData.length; i < size; i++) { newData[i] = fill; } } else { - for (int i = data.length, j = 0; i < size; ++i, j = Utils.incMod(j, data.length)) { - newData[i] = data[j]; + assert localData.length > 0 : "cannot call resize on empty vector if fillNA == false"; + for (int i = localData.length, j = 0; i < size; ++i, j = Utils.incMod(j, localData.length)) { + newData[i] = localData[j]; } } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java index 1369f5fffc2e5229bb01468d07f87d42e6918ec5..fcc1b4d1f335b6eb732d247f74aeb69a6f8b3cbe 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java @@ -481,9 +481,10 @@ public class DLL { handle = DLLRFFI.DLOpenRootNode.create(context).call(path, false, false); } catch (UnsatisfiedLinkError ex) { throw RSuicide.rSuicide(context, "error loading libR from: " + path + ".\n" + - "If running on NFI backend, did you provide location of libtrufflenfi.so as value of system " + - "property 'truffle.nfi.library'?\nThe current value is '" + - System.getProperty("truffle.nfi.library") + "'. \nDetails: " + ex.getMessage()); + "If running on the NFI backend, did you provide the location of libtrufflenfi.so as the value of the system " + + "property 'truffle.nfi.library'?\nThe current value is '" + System.getProperty("truffle.nfi.library") + "'.\n" + + "Is the OpenMP runtime library (libgomp.so) present on your system? This library is, e.g., typically part of the GCC package.\n" + + "Details: " + ex.getMessage()); } catch (Throwable ex) { throw RSuicide.rSuicide(context, "error loading libR from: " + path + ". Details: " + ex.getMessage()); } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 8027948599d7c1970107e0814a172e353b2d0023..3b787d3e951f582f2b95faf4ad856f155322c935 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -53121,6 +53121,39 @@ attr(,"useBytes") #rep(3, 4,) [1] 3 3 3 3 +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(NULL) +NULL + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(character(), length.out=2) +[1] NA NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(complex(), length.out=2) +[1] NA NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(list(), length.out=2) +[[1]] +NULL + +[[2]] +NULL + + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(numeric(), length.out=2) +[1] NA NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(numeric(), times=3) +numeric(0) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# +#rep(raw(), length.out=2) +[1] 00 00 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# #rep(x<-42) [1] 42 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java index a6aaf4e37581c2dbc96e97f65b52c3146241e47f..028788e9f3a0467d954afc7e6ec69a9637f4ac68 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java @@ -244,5 +244,15 @@ public class TestBuiltin_rep extends TestBase { // FIXME: should not print the warnings if empty args occur in '...' assertEval(Output.IgnoreWarningMessage, "rep(3, 4,)"); + + assertEval("rep(numeric(), length.out=2)"); + assertEval("rep(character(), length.out=2)"); + assertEval("rep(raw(), length.out=2)"); + assertEval("rep(complex(), length.out=2)"); + assertEval("rep(list(), length.out=2)"); + + assertEval("rep(numeric(), times=3)"); + + assertEval("rep(NULL)"); } }