--- old/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java 2016-07-12 22:46:52.129867717 -0700 +++ new/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java 2016-07-12 22:46:52.043865505 -0700 @@ -22,133 +22,247 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jshell.spi; -import java.util.Collection; -import jdk.jshell.JShellException; +import java.io.Serializable; /** - * This interface specifies the functionality that must provided to implement - * a pluggable JShell execution engine. + * This interface specifies the functionality that must provided to implement a + * pluggable JShell execution engine. *
- * The audience for this Service Provider Interface is engineers - * wishing to implement their own version of the execution engine in support - * of the JShell API. This is NOT a part of the JShell API. + * The audience for this Service Provider Interface is engineers wishing to + * implement their own version of the execution engine in support of the JShell + * API. *
- * A Snippet is compiled into code wrapped in a 'wrapper class'. The execution - * engine is used by the core JShell implementation to load and, for - * executable Snippets, execute the Snippet. + * A Snippet is compiled into code wrapped in a 'wrapper class'. The execution + * engine is used by the core JShell implementation to load and, for executable + * Snippets, execute the Snippet. *
* Methods defined in this interface should only be called by the core JShell * implementation. *
- * To install an instance of ExecutionControl, it is passed to - * {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl) }. + * To install an {@code ExecutionControl}, it's {@code Generator} is passed to + * {@link jdk.jshell.JShell.Builder#executionEngine(ExecutionControl.Generator) }. */ public interface ExecutionControl { + + public interface Generator { + ExecutionControl generate(ExecutionEnv env) throws Throwable; + } /** - * Represents the current status of a class in the execution engine. - */ - public enum ClassStatus { - /** - * Class is not known to the execution engine (not loaded). - */ - UNKNOWN, - - /** - * Class is loaded, but the loaded/redefined bytes do not match those - * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }. - */ - NOT_CURRENT, - - /** - * Class is loaded and loaded/redefined bytes match those - * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }. - */ - CURRENT - }; - - /** - * Initializes the instance. No methods in this interface can be called - * before this. + * Attempts to load new classes. * - * @param env the execution environment information provided by JShell - * @throws Exception if the instance is unable to initialize + * @param cbcs the class name and bytecodes to load + * @throws ClassInstallException exception occurred loading the classes, + * some or all were not loaded + * @throws EngineTerminationException the execution engine has terminated */ - void start(ExecutionEnv env) throws Exception; + void load(ClassBytecodes[] cbcs) + throws ClassInstallException, EngineTerminationException; /** - * Shuts down this execution engine. Implementation should free all - * resources held by this execution engine. - *
- * No calls to methods on this interface should be made after close.
- */
- void close();
-
- /**
- * Adds the path to the execution class path.
+ * Attempts to redefine previously loaded classes.
*
- * @param path the path to add
- * @return true if successful
+ * @param cbcs the class name and bytecodes to redefine
+ * @throws ClassInstallException exception occurred redefining the classes,
+ * some or all were not redefined
+ * @throws EngineTerminationException the execution engine has terminated
*/
- boolean addToClasspath(String path);
+ void redefine(ClassBytecodes[] cbcs)
+ throws ClassInstallException, EngineTerminationException;
/**
* Invokes an executable Snippet by calling a method on the specified
* wrapper class. The method must have no arguments and return String.
*
- * @param classname the class whose method should be invoked
- * @param methodname the name of method to invoke
+ * @param className the class whose method should be invoked
+ * @param methodName the name of method to invoke
* @return the result of the execution or null if no result
- * @throws JShellException if a user exception if thrown,
- * {@link jdk.jshell.EvalException EvalException} will be thrown; if an
- * unresolved reference is encountered,
- * {@link jdk.jshell.UnresolvedReferenceException UnresolvedReferenceException}
- * will be thrown
- */
- String invoke(String classname, String methodname) throws JShellException;
+ * @throws UserException the invoke raised a user exception
+ * @throws ResolutionException the invoke attempted to directly or
+ * indirectly invoke an unresolved snippet
+ * @throws StoppedException if the {@code invoke()} was canceled by
+ * {@link ExecutionControl#stop}
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ String invoke(String className, String methodName)
+ throws RunException,
+ EngineTerminationException, InternalException;
+
+ /**
+ * Returns the value of a variable.
+ *
+ * @param className the name of the wrapper class of the variable
+ * @param varName the name of the variable
+ * @return the value of the variable
+ * @throws UserException formatting the value raised a user exception
+ * @throws ResolutionException formatting the value attempted to directly or
+ * indirectly invoke an unresolved snippet
+ * @throws StoppedException if the formatting the value was canceled by
+ * {@link ExecutionControl#stop}
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ String varValue(String className, String varName)
+ throws RunException,
+ EngineTerminationException, InternalException;
/**
- * Attempts to load new classes. Class bytes are retrieved from
- * {@link ExecutionEnv#getClassBytes(java.lang.String) }
+ * Adds the path to the execution class path.
*
- * @param classes list of class names to load
- * @return true if load succeeded
+ * @param path the path to add
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
*/
- boolean load(Collection
+ * No calls to methods on this interface should be made after close.
*/
- void stop();
+ void close();
+
+ public static final class ClassBytecodes implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ public ClassBytecodes(String name, byte[] bytecodes) {
+ this.name = name;
+ this.bytecodes = bytecodes;
+ }
+ public final String name;
+ public final byte[] bytecodes;
+ }
+
+ @SuppressWarnings("serial")
+ public static abstract class ExecutionControlException extends Exception {
+
+ public ExecutionControlException(String message) {
+ super(message);
+ }
+ }
/**
- * Returns the value of a variable.
- *
- * @param classname the name of the wrapper class of the variable
- * @param varname the name of the variable
- * @return the value of the variable
+ * Unbidden execution engine termination has occurred.
*/
- String varValue(String classname, String varname);
+ @SuppressWarnings("serial")
+ public static class EngineTerminationException extends ExecutionControlException {
+
+ public EngineTerminationException(String message) {
+ super(message);
+ System.err.printf("EngineTerminationException: %s\n", message);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class InternalException extends ExecutionControlException {
+
+ public InternalException(String message) {
+ super(message);
+ }
+ }
+
+ @SuppressWarnings("serial")
+ public static class ClassInstallException extends ExecutionControlException {
+
+ private final boolean[] installed;
+
+ public ClassInstallException(String message, boolean[] installed) {
+ super(message);
+ this.installed = installed;
+ }
+
+ public boolean[] installed() {
+ return installed;
+ }
+ }
+
+ @SuppressWarnings("serial") // serialVersionUID intentionally omitted
+ public static abstract class RunException extends ExecutionControlException {
+
+ private RunException(String message) {
+ super(message);
+ }
+ }
+
+ @SuppressWarnings("serial") // serialVersionUID intentionally omitted
+ public static class UserException extends RunException {
+
+ private final String causeExceptionClass;
+
+ public UserException(String message, String causeExceptionClass, StackTraceElement[] stackElements) {
+ super(message);
+ this.causeExceptionClass = causeExceptionClass;
+ this.setStackTrace(stackElements);
+ }
+
+ public String causeExceptionClass() {
+ return causeExceptionClass;
+ }
+ }
+
+ @SuppressWarnings("serial") // serialVersionUID intentionally omitted
+ public static class ResolutionException extends RunException {
+
+ private final int id;
+
+ /**
+ * Constructs an exception indicating that a
+ * {@code DeclarationSnippet} with unresolved references has been
+ * encountered. The throw of this exception is generated into the body
+ * of a
+ * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED}
+ * method.
+ *
+ * @param id An internal identifier of the specific method
+ * @param stackElements the stack trace
+ */
+ public ResolutionException(int id, StackTraceElement[] stackElements) {
+ super("resolution exception: " + id);
+ this.id = id;
+ this.setStackTrace(stackElements);
+ }
+
+ /**
+ * Retrieves the internal identifier of the unresolved identifier.
+ *
+ * @return the internal identifier
+ */
+ public int id() {
+ return id;
+ }
+ }
+
+ @SuppressWarnings("serial") // serialVersionUID intentionally omitted
+ public static class StoppedException extends RunException {
+
+ public StoppedException() {
+ super("stopped by stop()");
+ }
+ }
+
}