From ff307d5d27ff622b52c1f948b725b89554480b7a Mon Sep 17 00:00:00 2001
From: Mick Jordan <mick.jordan@oracle.com>
Date: Mon, 20 Jun 2016 09:02:42 -0700
Subject: [PATCH] In embedded mode delay JLine console creation until
 necessary; remove ConsoleHandler.getWidth

---
 .../engine/shell/EmbeddedConsoleHandler.java  | 62 ++++++++++++-------
 .../r/engine/shell/JLineConsoleHandler.java   | 20 +++---
 .../truffle/r/engine/shell/RCommand.java      | 35 ++++-------
 .../truffle/r/nodes/builtin/base/Format.java  |  2 +-
 .../oracle/truffle/r/runtime/ROptions.java    |  2 +-
 .../r/runtime/context/ConsoleHandler.java     |  6 --
 .../context/DefaultConsoleHandler.java        |  5 --
 7 files changed, 66 insertions(+), 66 deletions(-)

diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
index ac19422484..0e5040ee58 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
@@ -23,7 +23,9 @@
 package com.oracle.truffle.r.engine.shell;
 
 import com.oracle.truffle.r.runtime.RInterfaceCallbacks;
+import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
+import com.oracle.truffle.r.runtime.context.DefaultConsoleHandler;
 import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
@@ -31,26 +33,42 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
  * In embedded mode the console functions as defined in {@code Rinterface.h} can be overridden. This
  * class supports that, delegating to a standard console handler if not redirected.
  *
+ * N.B. At the time the constructor is created, we do not know if the console is overridden so we
+ * have be lazy about that.
+ *
  */
 public class EmbeddedConsoleHandler implements ConsoleHandler {
 
+    private final RStartParams startParams;
+    /**
+     * Only not {@code null} when console is not overridden.
+     */
     private ConsoleHandler delegate;
     private REmbedRFFI rEmbedRFFI;
+    private String prompt;
 
-    EmbeddedConsoleHandler(ConsoleHandler delegate) {
-        this.delegate = delegate;
+    EmbeddedConsoleHandler(RStartParams startParams) {
+        this.startParams = startParams;
     }
 
     private REmbedRFFI getREmbedRFFI() {
         if (rEmbedRFFI == null) {
             rEmbedRFFI = RFFIFactory.getRFFI().getREmbedRFFI();
+            if (!(RInterfaceCallbacks.R_WriteConsole.isOverridden() || RInterfaceCallbacks.R_ReadConsole.isOverridden())) {
+                if (startParams.getNoReadline()) {
+                    delegate = new DefaultConsoleHandler(System.in, System.out);
+                } else {
+                    delegate = new JLineConsoleHandler(startParams);
+                }
+            }
         }
         return rEmbedRFFI;
     }
 
     @Override
     public void println(String s) {
-        if (RInterfaceCallbacks.R_WriteConsole.isOverridden()) {
+        getREmbedRFFI();
+        if (delegate == null) {
             getREmbedRFFI().writeConsole(s);
             getREmbedRFFI().writeConsole("\n");
         } else {
@@ -61,8 +79,9 @@ public class EmbeddedConsoleHandler implements ConsoleHandler {
 
     @Override
     public void print(String s) {
-        if (RInterfaceCallbacks.R_WriteConsole.isOverridden()) {
-            getREmbedRFFI().writeConsole(s);
+        getREmbedRFFI();
+        if (delegate == null) {
+            rEmbedRFFI.writeConsole(s);
         } else {
             delegate.print(s);
         }
@@ -71,9 +90,10 @@ public class EmbeddedConsoleHandler implements ConsoleHandler {
 
     @Override
     public void printErrorln(String s) {
-        if (RInterfaceCallbacks.R_WriteConsole.isOverridden()) {
-            getREmbedRFFI().writeErrConsole(s);
-            getREmbedRFFI().writeErrConsole("\n");
+        getREmbedRFFI();
+        if (delegate == null) {
+            rEmbedRFFI.writeErrConsole(s);
+            rEmbedRFFI.writeErrConsole("\n");
         } else {
             delegate.printErrorln(s);
         }
@@ -82,8 +102,9 @@ public class EmbeddedConsoleHandler implements ConsoleHandler {
 
     @Override
     public void printError(String s) {
-        if (RInterfaceCallbacks.R_WriteConsole.isOverridden()) {
-            getREmbedRFFI().writeErrConsole(s);
+        getREmbedRFFI();
+        if (delegate == null) {
+            rEmbedRFFI.writeErrConsole(s);
         } else {
             delegate.printError(s);
         }
@@ -92,8 +113,9 @@ public class EmbeddedConsoleHandler implements ConsoleHandler {
 
     @Override
     public String readLine() {
-        if (RInterfaceCallbacks.R_ReadConsole.isOverridden()) {
-            return getREmbedRFFI().readConsole(delegate.getPrompt());
+        getREmbedRFFI();
+        if (delegate == null) {
+            return rEmbedRFFI.readConsole(prompt);
         } else {
             return delegate.readLine();
         }
@@ -101,28 +123,26 @@ public class EmbeddedConsoleHandler implements ConsoleHandler {
 
     @Override
     public boolean isInteractive() {
-        return delegate.isInteractive();
+        return startParams.getInteractive();
     }
 
     @Override
     public String getPrompt() {
-        return delegate.getPrompt();
+        return prompt;
     }
 
     @Override
     public void setPrompt(String prompt) {
-        delegate.setPrompt(prompt);
-
-    }
+        this.prompt = prompt;
+        if (delegate != null) {
+            delegate.setPrompt(prompt);
+        }
 
-    @Override
-    public int getWidth() {
-        return delegate.getWidth();
     }
 
     @Override
     public String getInputDescription() {
-        return delegate.getInputDescription();
+        return "<embedded input>";
     }
 
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java
index 3dca9591b0..1f78b479c4 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java
@@ -28,9 +28,9 @@ import java.io.PrintWriter;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RInternalSourceDescriptions;
+import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
-import com.oracle.truffle.r.runtime.context.RContext;
 
 import jline.console.ConsoleReader;
 import jline.console.UserInterruptException;
@@ -42,10 +42,17 @@ class JLineConsoleHandler implements ConsoleHandler {
     private final boolean isInteractive;
     private final PrintWriter printWriter;
 
-    JLineConsoleHandler(boolean isInteractive, ConsoleReader console) {
-        this.console = console;
+    JLineConsoleHandler(RStartParams startParams) {
+        try {
+            console = new ConsoleReader(System.in, System.out);
+            console.setHandleUserInterrupt(true);
+            console.setExpandEvents(false);
+        } catch (IOException ex) {
+            throw Utils.fail("unexpected error opening console reader");
+        }
+        // long start = System.currentTimeMillis();
         printWriter = new PrintWriter(console.getOutput());
-        this.isInteractive = isInteractive;
+        this.isInteractive = startParams.getInteractive();
     }
 
     @Override
@@ -108,11 +115,6 @@ class JLineConsoleHandler implements ConsoleHandler {
         console.setPrompt(prompt);
     }
 
-    @Override
-    public int getWidth() {
-        return RContext.CONSOLE_WIDTH;
-    }
-
     @Override
     public String getInputDescription() {
         return RInternalSourceDescriptions.SHELL_INPUT;
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java
index c0e4ab7be4..ee7e0b1aed 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java
@@ -29,8 +29,6 @@ import java.io.Console;
 import java.io.EOFException;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.nio.file.Files;
 import java.util.List;
 
@@ -58,7 +56,6 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
-import jline.console.ConsoleReader;
 import jline.console.UserInterruptException;
 
 /**
@@ -119,8 +116,6 @@ public class RCommand {
          * checked.
          */
         ConsoleHandler consoleHandler;
-        InputStream consoleInput = System.in;
-        OutputStream consoleOutput = System.out;
         if (fileArg != null) {
             List<String> lines;
             String filePath;
@@ -148,31 +143,25 @@ public class RCommand {
              * GnuR behavior differs from the manual entry for {@code interactive} in that {@code
              * --interactive} never applies to {@code -e/-f}, only to console input that has been
              * redirected from a pipe/file etc.
+             *
+             * If we are in embedded mode, the creation of ConsoleReader and the ConsoleHandler
+             * should be lazy, as these may not be necessary and can cause hangs if stdin has been
+             * redirected.
              */
             Console sysConsole = System.console();
-            boolean useReadLine = !rsp.getNoReadline();
-            ConsoleReader consoleReader = null;
-            if (useReadLine) {
-                try {
-                    consoleReader = new ConsoleReader(consoleInput, consoleOutput);
-                    consoleReader.setHandleUserInterrupt(true);
-                    consoleReader.setExpandEvents(false);
-                } catch (IOException ex) {
-                    throw Utils.fail("unexpected error opening console reader");
-                }
-            }
             boolean isInteractive = options.getBoolean(INTERACTIVE) || sysConsole != null;
             if (!isInteractive && rsp.getSaveAction() != SA_TYPE.SAVE && rsp.getSaveAction() != SA_TYPE.NOSAVE) {
                 throw Utils.rSuicide("you must specify '--save', '--no-save' or '--vanilla'");
             }
-            // long start = System.currentTimeMillis();
-            if (useReadLine) {
-                consoleHandler = new JLineConsoleHandler(isInteractive, consoleReader);
-            } else {
-                consoleHandler = new DefaultConsoleHandler(consoleInput, consoleOutput);
-            }
             if (embedded) {
-                consoleHandler = new EmbeddedConsoleHandler(consoleHandler);
+                consoleHandler = new EmbeddedConsoleHandler(rsp);
+            } else {
+                boolean useReadLine = !rsp.getNoReadline();
+                if (useReadLine) {
+                    consoleHandler = new JLineConsoleHandler(rsp);
+                } else {
+                    consoleHandler = new DefaultConsoleHandler(System.in, System.out);
+                }
             }
         }
         return ContextInfo.create(rsp, ContextKind.SHARE_NOTHING, null, consoleHandler).apply(PolyglotEngine.newBuilder()).build();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
index 341d931b55..b109af35f2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
@@ -57,7 +57,7 @@ public abstract class Format extends RBuiltinNode {
         if (printConfig == null) {
             printConfig = new Config();
         }
-        printConfig.width = RContext.getInstance().getConsoleHandler().getWidth();
+        printConfig.width = (int) RContext.getInstance().stateROptions.getValue("width");
         printConfig.naWidth = RRuntime.STRING_NA.length();
         printConfig.naWidthNoQuote = RRuntime.NA_HEADER.length();
         printConfig.digits = 7 /* default */;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
index 7d2ed0909a..a2a7f8b73f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
@@ -130,7 +130,7 @@ public class ROptions {
         map.put("verbose", RDataFactory.createLogicalVectorFromScalar(startParams.getVerbose()));
         map.put("nwarnings", RDataFactory.createIntVectorFromScalar(50));
         map.put("warning.length", RDataFactory.createIntVectorFromScalar(1000));
-        map.put("width", RDataFactory.createIntVectorFromScalar(80));
+        map.put("width", RDataFactory.createIntVectorFromScalar(RContext.CONSOLE_WIDTH));
         map.put("browserNLdisabled", RDataFactory.createLogicalVectorFromScalar(false));
         boolean cBoundsCheck = optionFromEnvVar("R_C_BOUNDS_CHECK", envVars);
         map.put("CBoundsCheck", RDataFactory.createLogicalVectorFromScalar(cBoundsCheck));
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java
index ab347547db..f238108b70 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java
@@ -95,12 +95,6 @@ public interface ConsoleHandler {
     @TruffleBoundary
     void setPrompt(String prompt);
 
-    /**
-     * Get the console width.
-     */
-    @TruffleBoundary
-    int getWidth();
-
     String getInputDescription();
 
     default void setHistoryFrom(@SuppressWarnings("unused") File file) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java
index e7cd144b26..18f2a36cce 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java
@@ -87,11 +87,6 @@ public class DefaultConsoleHandler implements ConsoleHandler {
         this.prompt = prompt;
     }
 
-    @Override
-    public int getWidth() {
-        return 80;
-    }
-
     @Override
     public String getInputDescription() {
         return "<PolyglotEngine env input>";
-- 
GitLab