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) {