src/jdk.jshell/share/classes/jdk/jshell/JShell.java

Print this page

        

@@ -42,17 +42,19 @@
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 
 import java.util.function.Supplier;
 import jdk.internal.jshell.debug.InternalDebugControl;
-import jdk.internal.jshell.jdi.FailOverExecutionControl;
+import jdk.jshell.Snippet.Status;
+import jdk.jshell.execution.JDIDefaultExecutionControl;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.ExecutionControlException;
+import jdk.jshell.spi.ExecutionEnv;
+import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
 import static java.util.stream.Collectors.collectingAndThen;
 import static java.util.stream.Collectors.toList;
 import static jdk.jshell.Util.expunge;
-import jdk.jshell.Snippet.Status;
-import jdk.internal.jshell.jdi.JDIExecutionControl;
-import jdk.jshell.spi.ExecutionEnv;
 
 /**
  * The JShell evaluation state engine.  This is the central class in the JShell
  * API.  A {@code JShell} instance holds the evolving compilation and
  * execution state.  The state is changed with the instance methods

@@ -88,21 +90,21 @@
     final PrintStream err;
     final Supplier<String> tempVariableNameGenerator;
     final BiFunction<Snippet, Integer, String> idGenerator;
     final List<String> extraRemoteVMOptions;
     final List<String> extraCompilerOptions;
-    final ExecutionControl executionControl;
+    final ExecutionControl.Generator executionControlGenerator;
 
     private int nextKeyIndex = 1;
 
     final Eval eval;
-    private final Map<String, byte[]> classnameToBytes = new HashMap<>();
+    final ClassTracker classTracker;
     private final Map<Subscription, Consumer<JShell>> shutdownListeners = new HashMap<>();
     private final Map<Subscription, Consumer<SnippetEvent>> keyStatusListeners = new HashMap<>();
     private boolean closed = false;
 
-    private boolean executionControlLaunched = false;
+    private ExecutionControl executionControl = null;
     private SourceCodeAnalysisImpl sourceCodeAnalysis = null;
 
     private static final String L10N_RB_NAME    = "jdk.jshell.resources.l10n";
     private static ResourceBundle outputRB  = null;
 

@@ -112,21 +114,22 @@
         this.err = b.err;
         this.tempVariableNameGenerator = b.tempVariableNameGenerator;
         this.idGenerator = b.idGenerator;
         this.extraRemoteVMOptions = b.extraRemoteVMOptions;
         this.extraCompilerOptions = b.extraCompilerOptions;
-        this.executionControl = b.executionControl==null
-                ? new FailOverExecutionControl(
-                        new JDIExecutionControl(),
-                        new JDIExecutionControl(false))
-                : b.executionControl;
+        this.executionControlGenerator = b.executionControlGenerator==null
+                ? failOverExecutionControlGenerator(
+                        JDIDefaultExecutionControl.launch(),
+                        JDIDefaultExecutionControl.listen())
+                : b.executionControlGenerator;
 
         this.maps = new SnippetMaps(this);
         this.keyMap = new KeyMap(this);
         this.outerMap = new OuterWrapMap(this);
         this.taskFactory = new TaskFactory(this);
         this.eval = new Eval(this);
+        this.classTracker = new ClassTracker();
     }
 
     /**
      * Builder for {@code JShell} instances.
      * Create custom instances of {@code JShell} by using the setter

@@ -152,11 +155,11 @@
         PrintStream err = System.err;
         Supplier<String> tempVariableNameGenerator = null;
         BiFunction<Snippet, Integer, String> idGenerator = null;
         List<String> extraRemoteVMOptions = new ArrayList<>();
         List<String> extraCompilerOptions = new ArrayList<>();
-        ExecutionControl executionControl;
+        ExecutionControl.Generator executionControlGenerator;
 
         Builder() { }
 
         /**
          * Sets the input for the running evaluation (it's {@code System.in}). Note:

@@ -308,16 +311,16 @@
 
         /**
          * Sets the custom engine for execution. Snippet execution will be
          * provided by the specified {@link ExecutionControl} instance.
          *
-         * @param execEngine the execution engine
+         * @param executionControlGenerator the execution engine generator
          * @return the {@code Builder} instance (for use in chained
          * initialization)
          */
-        public Builder executionEngine(ExecutionControl execEngine) {
-            this.executionControl = execEngine;
+        public Builder executionEngine(ExecutionControl.Generator executionControlGenerator) {
+            this.executionControlGenerator = executionControlGenerator;
             return this;
         }
 
         /**
          * Builds a JShell state engine. This is the entry-point to all JShell

@@ -395,11 +398,12 @@
      * allowed and are errors.
      * If a previous definition of a declaration is overwritten then there will
      * be an event showing its status changed to OVERWRITTEN, this will not
      * occur for dropped, rejected, or already overwritten declarations.
      * <p>
-     * The execution environment is out of process.  If the evaluated code
+     * If execution environment is out of process, as is the default case, then
+     * if the evaluated code
      * causes the execution environment to terminate, this {@code JShell}
      * instance will be closed but the calling process and VM remain valid.
      * @param input The input String to evaluate
      * @return the list of events directly or indirectly caused by this evaluation.
      * @throws IllegalStateException if this {@code JShell} instance is closed.

@@ -445,12 +449,18 @@
      * Note that the unnamed package is not accessible from the package in which
      * {@link JShell#eval(String)} code is placed.
      * @param path the path to add to the classpath.
      */
     public void addToClasspath(String path) {
-        taskFactory.addToClasspath(path);  // Compiler
-        executionControl().addToClasspath(path);       // Runtime
+        // Compiler
+        taskFactory.addToClasspath(path);
+        // Runtime
+        try {
+            executionControl().addToClasspath(path);
+        } catch (ExecutionControlException ex) {
+            debug(ex, "on addToClasspath(" + path + ")");
+        }
         if (sourceCodeAnalysis != null) {
             sourceCodeAnalysis.classpathChanged();
         }
     }
 

@@ -466,12 +476,17 @@
      * The attempt to stop the user's code may fail in some case, which may include
      * when the execution is blocked on an I/O operation, or when the user's code is
      * catching the {@link ThreadDeath} exception.
      */
     public void stop() {
-        if (executionControl != null)
+        if (executionControl != null) {
+            try {
             executionControl.stop();
+            } catch (ExecutionControlException ex) {
+                debug(ex, "on stop()");
+            }
+        }
     }
 
     /**
      * Close this state engine. Frees resources. Should be called when this
      * state engine is no longer needed.

@@ -620,11 +635,19 @@
         checkValidSnippet(snippet);
         if (snippet.status() != Status.VALID) {
             throw new IllegalArgumentException(
                     messageFormat("jshell.exc.var.not.valid",  snippet, snippet.status()));
         }
-        String value = executionControl().varValue(snippet.classFullName(), snippet.name());
+        String value;
+        try {
+            value = executionControl().varValue(snippet.classFullName(), snippet.name());
+        } catch (EngineTerminationException ex) {
+            throw new IllegalStateException(ex.getMessage());
+        } catch (ExecutionControlException ex) {
+            debug(ex, "In varValue()");
+            return "[" + ex.getMessage() + "]";
+        }
         return expunge(value);
     }
 
     /**
      * Register a callback to be called when the Status of a snippet changes.

@@ -694,58 +717,33 @@
         public PrintStream userErr() {
             return err;
         }
 
         @Override
-        public JShell state() {
-            return JShell.this;
-        }
-
-        @Override
         public List<String> extraRemoteVMOptions() {
             return extraRemoteVMOptions;
         }
 
         @Override
-        public byte[] getClassBytes(String classname) {
-            return classnameToBytes.get(classname);
-        }
-
-        @Override
-        public EvalException createEvalException(String message, String exceptionClass, StackTraceElement[] stackElements) {
-            return new EvalException(message, exceptionClass, stackElements);
-        }
-
-        @Override
-        public UnresolvedReferenceException createUnresolvedReferenceException(int id, StackTraceElement[] stackElements) {
-            DeclarationSnippet sn = (DeclarationSnippet) maps.getSnippetDeadOrAlive(id);
-            return new UnresolvedReferenceException(sn, stackElements);
-        }
-
-        @Override
         public void closeDown() {
             JShell.this.closeDown();
         }
+
     }
 
     // --- private / package-private implementation support ---
     ExecutionControl executionControl() {
-        if (!executionControlLaunched) {
+        if (executionControl == null) {
             try {
-                executionControlLaunched = true;
-                executionControl.start(new ExecutionEnvImpl());
+                executionControl =  executionControlGenerator.generate(new ExecutionEnvImpl());
             } catch (Throwable ex) {
                 throw new InternalError("Launching execution engine threw: " + ex.getMessage(), ex);
             }
         }
         return executionControl;
     }
 
-    void setClassnameToBytes(String classname, byte[] bytes) {
-        classnameToBytes.put(classname, bytes);
-    }
-
     void debug(int flags, String format, Object... args) {
         InternalDebugControl.debug(this, err, flags, format, args);
     }
 
     void debug(Exception ex, String where) {