Skip to content
Snippets Groups Projects
Commit e7f37ef1 authored by stepan's avatar stepan
Browse files

Implement graphics resizing using custom Executor in RContext

parent 7e83711f
No related branches found
No related tags found
No related merge requests found
Showing
with 107 additions and 16 deletions
......@@ -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);
......
......@@ -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;
}
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
});
}
}
......
......@@ -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();
}
}
......
......@@ -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);
......
/*
* 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();
}
}
......@@ -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.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment