src/jdk.jshell/share/classes/jdk/jshell/JShell.java
Print this page
*** 42,58 ****
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 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
--- 42,60 ----
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import jdk.internal.jshell.debug.InternalDebugControl;
! 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;
/**
* 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,108 ****
final PrintStream err;
final Supplier<String> tempVariableNameGenerator;
final BiFunction<Snippet, Integer, String> idGenerator;
final List<String> extraRemoteVMOptions;
final List<String> extraCompilerOptions;
! final ExecutionControl executionControl;
private int nextKeyIndex = 1;
final Eval eval;
! private final Map<String, byte[]> classnameToBytes = new HashMap<>();
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 SourceCodeAnalysisImpl sourceCodeAnalysis = null;
private static final String L10N_RB_NAME = "jdk.jshell.resources.l10n";
private static ResourceBundle outputRB = null;
--- 90,110 ----
final PrintStream err;
final Supplier<String> tempVariableNameGenerator;
final BiFunction<Snippet, Integer, String> idGenerator;
final List<String> extraRemoteVMOptions;
final List<String> extraCompilerOptions;
! final ExecutionControl.Generator executionControlGenerator;
private int nextKeyIndex = 1;
final Eval eval;
! 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 ExecutionControl executionControl = null;
private SourceCodeAnalysisImpl sourceCodeAnalysis = null;
private static final String L10N_RB_NAME = "jdk.jshell.resources.l10n";
private static ResourceBundle outputRB = null;
*** 112,132 ****
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.maps = new SnippetMaps(this);
this.keyMap = new KeyMap(this);
this.outerMap = new OuterWrapMap(this);
this.taskFactory = new TaskFactory(this);
this.eval = new Eval(this);
}
/**
* Builder for {@code JShell} instances.
* Create custom instances of {@code JShell} by using the setter
--- 114,135 ----
this.err = b.err;
this.tempVariableNameGenerator = b.tempVariableNameGenerator;
this.idGenerator = b.idGenerator;
this.extraRemoteVMOptions = b.extraRemoteVMOptions;
this.extraCompilerOptions = b.extraCompilerOptions;
! 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,162 ****
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;
Builder() { }
/**
* Sets the input for the running evaluation (it's {@code System.in}). Note:
--- 155,165 ----
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.Generator executionControlGenerator;
Builder() { }
/**
* Sets the input for the running evaluation (it's {@code System.in}). Note:
*** 308,323 ****
/**
* Sets the custom engine for execution. Snippet execution will be
* provided by the specified {@link ExecutionControl} instance.
*
! * @param execEngine the execution engine
* @return the {@code Builder} instance (for use in chained
* initialization)
*/
! public Builder executionEngine(ExecutionControl execEngine) {
! this.executionControl = execEngine;
return this;
}
/**
* Builds a JShell state engine. This is the entry-point to all JShell
--- 311,326 ----
/**
* Sets the custom engine for execution. Snippet execution will be
* provided by the specified {@link ExecutionControl} instance.
*
! * @param executionControlGenerator the execution engine generator
* @return the {@code Builder} instance (for use in chained
* initialization)
*/
! 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,405 ****
* 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
* 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.
--- 398,409 ----
* 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>
! * 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,456 ****
* 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
if (sourceCodeAnalysis != null) {
sourceCodeAnalysis.classpathChanged();
}
}
--- 449,466 ----
* 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) {
! // Compiler
! taskFactory.addToClasspath(path);
! // Runtime
! try {
! executionControl().addToClasspath(path);
! } catch (ExecutionControlException ex) {
! debug(ex, "on addToClasspath(" + path + ")");
! }
if (sourceCodeAnalysis != null) {
sourceCodeAnalysis.classpathChanged();
}
}
*** 466,477 ****
* 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)
executionControl.stop();
}
/**
* Close this state engine. Frees resources. Should be called when this
* state engine is no longer needed.
--- 476,492 ----
* 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) {
! 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,630 ****
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());
return expunge(value);
}
/**
* Register a callback to be called when the Status of a snippet changes.
--- 635,653 ----
checkValidSnippet(snippet);
if (snippet.status() != Status.VALID) {
throw new IllegalArgumentException(
messageFormat("jshell.exc.var.not.valid", snippet, snippet.status()));
}
! 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.
*** 704,751 ****
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) {
try {
! executionControlLaunched = true;
! executionControl.start(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) {
--- 727,754 ----
public List<String> extraRemoteVMOptions() {
return extraRemoteVMOptions;
}
@Override
public void closeDown() {
JShell.this.closeDown();
}
+
}
// --- private / package-private implementation support ---
ExecutionControl executionControl() {
! if (executionControl == null) {
try {
! executionControl = executionControlGenerator.generate(new ExecutionEnvImpl());
} catch (Throwable ex) {
throw new InternalError("Launching execution engine threw: " + ex.getMessage(), ex);
}
}
return executionControl;
}
void debug(int flags, String format, Object... args) {
InternalDebugControl.debug(this, err, flags, format, args);
}
void debug(Exception ex, String where) {