8165405: jshell tool: /classpath is inconsistent
authorrfield
Fri, 06 Jan 2017 10:31:25 -0800
changeset 43038 7b8b8750a78e
parent 43037 3e1520a857fa
child 43039 d2a8a38e3070
8165405: jshell tool: /classpath is inconsistent 8172103: JShell: crash in TaskFactory$WrapSourceHandler.diag Reviewed-by: jlahoda
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties
langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java
langtools/test/jdk/jshell/CommandCompletionTest.java
langtools/test/jdk/jshell/ToolBasicTest.java
langtools/test/jdk/jshell/ToolReloadTest.java
langtools/test/jdk/jshell/ToolSimpleTest.java
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Fri Jan 06 14:16:45 2017 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Fri Jan 06 10:31:25 2017 -0800
@@ -47,7 +47,9 @@
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
@@ -185,10 +187,7 @@
     private IOContext input = null;
     private boolean regenerateOnDeath = true;
     private boolean live = false;
-    private boolean feedbackInitialized = false;
-    private String commandLineFeedbackMode = null;
-    private List<String> remoteVMOptions = new ArrayList<>();
-    private List<String> compilerOptions = new ArrayList<>();
+    private Options options;
 
     SourceCodeAnalysis analysis;
     JShell state = null;
@@ -198,7 +197,6 @@
 
     private boolean debug = false;
     public boolean testPrompt = false;
-    private String cmdlineClasspath = null;
     private String defaultStartup = null;
     private String startup = null;
     private String executionControlSpec = null;
@@ -221,6 +219,16 @@
     static final Pattern BUILTIN_FILE_PATTERN = Pattern.compile("\\w+");
     static final String BUILTIN_FILE_PATH_FORMAT = "jrt:/jdk.jshell/jdk/jshell/tool/resources/%s.jsh";
 
+    // match anything followed by whitespace
+    private static final Pattern OPTION_PRE_PATTERN =
+            Pattern.compile("\\s*(\\S+\\s+)*?");
+    // match a (possibly incomplete) option flag with optional double-dash and/or internal dashes
+    private static final Pattern OPTION_PATTERN =
+            Pattern.compile(OPTION_PRE_PATTERN.pattern() + "(?<dd>-??)(?<flag>-([a-z][a-z\\-]*)?)");
+    // match an option flag and a (possibly missing or incomplete) value
+    private static final Pattern OPTION_VALUE_PATTERN =
+            Pattern.compile(OPTION_PATTERN.pattern() + "\\s+(?<val>\\S*)");
+
     // Tool id (tid) mapping: the three name spaces
     NameSpace mainNamespace;
     NameSpace startNamespace;
@@ -229,7 +237,278 @@
     // Tool id (tid) mapping: the current name spaces
     NameSpace currentNameSpace;
 
-    Map<Snippet,SnippetInfo> mapSnippet;
+    Map<Snippet, SnippetInfo> mapSnippet;
+
+    // Kinds of compiler/runtime init options
+    private enum OptionKind {
+        CLASS_PATH("--class-path", true),
+        MODULE_PATH("--module-path", true),
+        ADD_MODULES("--add-modules", false),
+        ADD_EXPORTS("--add-exports", false),
+        TO_COMPILER("-C", false, false, true, false),
+        TO_REMOTE_VM("-R", false, false, false, true),;
+        final String optionFlag;
+        final boolean onlyOne;
+        final boolean passFlag;
+        final boolean toCompiler;
+        final boolean toRemoteVm;
+
+        private OptionKind(String optionFlag, boolean onlyOne) {
+            this(optionFlag, onlyOne, true, true, true);
+        }
+
+        private OptionKind(String optionFlag, boolean onlyOne, boolean passFlag,
+                boolean toCompiler, boolean toRemoteVm) {
+            this.optionFlag = optionFlag;
+            this.onlyOne = onlyOne;
+            this.passFlag = passFlag;
+            this.toCompiler = toCompiler;
+            this.toRemoteVm = toRemoteVm;
+        }
+
+    }
+
+    // compiler/runtime init option values
+    private static class Options {
+
+        private Map<OptionKind, List<String>> optMap = new HashMap<>();
+
+        private String[] selectOptions(Predicate<Entry<OptionKind, List<String>>> pred) {
+            return optMap.entrySet().stream()
+                    .filter(pred)
+                    .flatMap(e -> e.getValue().stream())
+                    .toArray(String[]::new);
+        }
+
+        String[] remoteVmOptions() {
+            return selectOptions(e -> e.getKey().toRemoteVm);
+        }
+
+        String[] compilerOptions() {
+            return selectOptions(e -> e.getKey().toCompiler);
+        }
+
+        String[] commonOptions() {
+            return selectOptions(e -> e.getKey().passFlag);
+        }
+
+        void addAll(OptionKind kind, Collection<String> vals) {
+            optMap.computeIfAbsent(kind, k -> new ArrayList<>())
+                    .addAll(vals);
+        }
+
+        void override(Options newer) {
+            newer.optMap.entrySet().stream()
+                    .forEach(e -> {
+                        if (e.getKey().onlyOne) {
+                            // Only one allowed, override last
+                            optMap.put(e.getKey(), e.getValue());
+                        } else {
+                            // Additive
+                            addAll(e.getKey(), e.getValue());
+                        }
+                    });
+        }
+    }
+
+    // base option parsing of /env, /reload, and /reset and command-line options
+    private class OptionParserBase {
+
+        final OptionParser parser = new OptionParser();
+        private final OptionSpec<String> argClassPath = parser.accepts("class-path").withRequiredArg();
+        private final OptionSpec<String> argModulePath = parser.accepts("module-path").withRequiredArg();
+        private final OptionSpec<String> argAddModules = parser.accepts("add-modules").withRequiredArg();
+        private final OptionSpec<String> argAddExports = parser.accepts("add-exports").withRequiredArg();
+        private final NonOptionArgumentSpec<String> argNonOptions = parser.nonOptions();
+
+        private Options opts = new Options();
+        private List<String> nonOptions;
+        private boolean failed = false;
+
+        List<String> nonOptions() {
+            return nonOptions;
+        }
+
+        void msg(String key, Object... args) {
+            errormsg(key, args);
+        }
+
+        Options parse(String[] args) throws OptionException {
+            try {
+                OptionSet oset = parser.parse(args);
+                nonOptions = oset.valuesOf(argNonOptions);
+                return parse(oset);
+            } catch (OptionException ex) {
+                if (ex.options().isEmpty()) {
+                    msg("jshell.err.opt.invalid", stream(args).collect(joining(", ")));
+                } else {
+                    boolean isKnown = parser.recognizedOptions().containsKey(ex.options().iterator().next());
+                    msg(isKnown
+                            ? "jshell.err.opt.arg"
+                            : "jshell.err.opt.unknown",
+                            ex.options()
+                            .stream()
+                            .collect(joining(", ")));
+                }
+                return null;
+            }
+        }
+
+        Options parse(OptionSet options) {
+            addOptions(OptionKind.CLASS_PATH, options.valuesOf(argClassPath));
+            addOptions(OptionKind.MODULE_PATH, options.valuesOf(argModulePath));
+            addOptions(OptionKind.ADD_MODULES, options.valuesOf(argAddModules));
+            addOptions(OptionKind.ADD_EXPORTS, options.valuesOf(argAddExports).stream()
+                    .map(mp -> mp.contains("=") ? mp : mp + "=ALL-UNNAMED")
+                    .collect(toList())
+            );
+
+            return failed ? null : opts;
+        }
+
+        void addOptions(OptionKind kind, Collection<String> vals) {
+            if (!vals.isEmpty()) {
+                if (kind.onlyOne && vals.size() > 1) {
+                    msg("jshell.err.opt.one", kind.optionFlag);
+                    failed = true;
+                    return;
+                }
+                if (kind.passFlag) {
+                    vals = vals.stream()
+                            .flatMap(mp -> Stream.of(kind.optionFlag, mp))
+                            .collect(toList());
+                }
+                opts.addAll(kind, vals);
+            }
+        }
+    }
+
+    // option parsing for /reload (adds -restore -quiet)
+    private class OptionParserReload extends OptionParserBase {
+
+        private final OptionSpecBuilder argRestore = parser.accepts("restore");
+        private final OptionSpecBuilder argQuiet   = parser.accepts("quiet");
+
+        private boolean restore = false;
+        private boolean quiet = false;
+
+        boolean restore() {
+            return restore;
+        }
+
+        boolean quiet() {
+            return quiet;
+        }
+
+        @Override
+        Options parse(OptionSet options) {
+            if (options.has(argRestore)) {
+                restore = true;
+            }
+            if (options.has(argQuiet)) {
+                quiet = true;
+            }
+            return super.parse(options);
+        }
+    }
+
+    // option parsing for command-line
+    private class OptionParserCommandLine extends OptionParserBase {
+
+        private final OptionSpec<String> argStart = parser.accepts("startup").withRequiredArg();
+        private final OptionSpecBuilder argNoStart = parser.acceptsAll(asList("n", "no-startup"));
+        private final OptionSpec<String> argFeedback = parser.accepts("feedback").withRequiredArg();
+        private final OptionSpec<String> argExecution = parser.accepts("execution").withRequiredArg();
+        private final OptionSpecBuilder argQ = parser.accepts("q");
+        private final OptionSpecBuilder argS = parser.accepts("s");
+        private final OptionSpecBuilder argV = parser.accepts("v");
+        private final OptionSpec<String> argR = parser.accepts("R").withRequiredArg();
+        private final OptionSpec<String> argC = parser.accepts("C").withRequiredArg();
+        private final OptionSpecBuilder argHelp = parser.acceptsAll(asList("h", "help"));
+        private final OptionSpecBuilder argVersion = parser.accepts("version");
+        private final OptionSpecBuilder argFullVersion = parser.accepts("full-version");
+        private final OptionSpecBuilder argX = parser.accepts("X");
+
+        private String feedbackMode = null;
+        private String initialStartup = null;
+
+        String feedbackMode() {
+            return feedbackMode;
+        }
+
+        String startup() {
+            return initialStartup;
+        }
+
+        @Override
+        void msg(String key, Object... args) {
+            startmsg(key, args);
+        }
+
+        @Override
+        Options parse(OptionSet options) {
+            if (options.has(argHelp)) {
+                printUsage();
+                return null;
+            }
+            if (options.has(argX)) {
+                printUsageX();
+                return null;
+            }
+            if (options.has(argVersion)) {
+                cmdout.printf("jshell %s\n", version());
+                return null;
+            }
+            if (options.has(argFullVersion)) {
+                cmdout.printf("jshell %s\n", fullVersion());
+                return null;
+            }
+            if ((options.valuesOf(argFeedback).size() +
+                    (options.has(argQ) ? 1 : 0) +
+                    (options.has(argS) ? 1 : 0) +
+                    (options.has(argV) ? 1 : 0)) > 1) {
+                msg("jshell.err.opt.feedback.one");
+                return null;
+            } else if (options.has(argFeedback)) {
+                feedbackMode = options.valueOf(argFeedback);
+            } else if (options.has("q")) {
+                feedbackMode = "concise";
+            } else if (options.has("s")) {
+                feedbackMode = "silent";
+            } else if (options.has("v")) {
+                feedbackMode = "verbose";
+            }
+            if (options.has(argStart)) {
+                List<String> sts = options.valuesOf(argStart);
+                if (options.has("no-startup")) {
+                    startmsg("jshell.err.opt.startup.conflict");
+                    return null;
+                }
+                StringBuilder sb = new StringBuilder();
+                for (String fn : sts) {
+                    String s = readFile(fn, "--startup");
+                    if (s == null) {
+                        return null;
+                    }
+                    sb.append(s);
+                }
+                initialStartup = sb.toString();
+            } else if (options.has(argNoStart)) {
+                initialStartup = "";
+            } else {
+                initialStartup = prefs.get(STARTUP_KEY);
+                if (initialStartup == null) {
+                    initialStartup = defaultStartup();
+                }
+            }
+            if (options.has(argExecution)) {
+                executionControlSpec = options.valueOf(argExecution);
+            }
+            addOptions(OptionKind.TO_REMOTE_VM, options.valuesOf(argR));
+            addOptions(OptionKind.TO_COMPILER, options.valuesOf(argC));
+            return super.parse(options);
+        }
+    }
 
     /**
      * Is the input/output currently interactive
@@ -464,43 +743,45 @@
     }
 
     public void start(String[] args) throws Exception {
-        List<String> loadList = processCommandArgs(args);
-        if (loadList == null) {
+        OptionParserCommandLine commandLineArgs = new OptionParserCommandLine();
+        options = commandLineArgs.parse(args);
+        if (options == null) {
             // Abort
             return;
         }
-        try (IOContext in = new ConsoleIOContext(this, cmdin, console)) {
-            start(in, loadList);
-        }
-    }
-
-    private void start(IOContext in, List<String> loadList) {
-        // If startup hasn't been set by command line, set from retained/default
-        if (startup == null) {
-            startup = prefs.get(STARTUP_KEY);
-            if (startup == null) {
-                startup = defaultStartup();
-            }
-        }
-
+        startup = commandLineArgs.startup();
+        // initialize editor settings
         configEditor();
-
-        resetState(); // Initialize
-
+        // initialize JShell instance
+        resetState();
         // Read replay history from last jshell session into previous history
         String prevReplay = prefs.get(REPLAY_RESTORE_KEY);
         if (prevReplay != null) {
             replayableHistoryPrevious = Arrays.asList(prevReplay.split(RECORD_SEPARATOR));
         }
-
-        for (String loadFile : loadList) {
+        // load snippet/command files given on command-line
+        for (String loadFile : commandLineArgs.nonOptions()) {
             runFile(loadFile, "jshell");
         }
+        // if we survived that...
+        if (regenerateOnDeath) {
+            // initialize the predefined feedback modes
+            initFeedback(commandLineArgs.feedbackMode());
+        }
+        // check again, as feedback setting could have failed
+        if (regenerateOnDeath) {
+            // if we haven't died, and the feedback mode wants fluff, print welcome
+            if (feedback.shouldDisplayCommandFluff()) {
+                hardmsg("jshell.msg.welcome", version());
+            }
+            // execute from user input
+            try (IOContext in = new ConsoleIOContext(this, cmdin, console)) {
+                start(in);
+            }
+        }
+    }
 
-        if (regenerateOnDeath && feedback.shouldDisplayCommandFluff()) {
-            hardmsg("jshell.msg.welcome", version());
-        }
-
+    private void start(IOContext in) {
         try {
             while (regenerateOnDeath) {
                 if (!live) {
@@ -530,144 +811,6 @@
         return editor = BUILT_IN_EDITOR;
     }
 
-    /**
-     * Process the command line arguments.
-     * Set options.
-     * @param args the command line arguments
-     * @return the list of files to be loaded
-     */
-    private List<String> processCommandArgs(String[] args) {
-        OptionParser parser = new OptionParser();
-        OptionSpec<String> cp = parser.accepts("class-path").withRequiredArg();
-        OptionSpec<String> mpath = parser.accepts("module-path").withRequiredArg();
-        OptionSpec<String> amods = parser.accepts("add-modules").withRequiredArg();
-        OptionSpec<String> st = parser.accepts("startup").withRequiredArg();
-        parser.acceptsAll(asList("n", "no-startup"));
-        OptionSpec<String> fb = parser.accepts("feedback").withRequiredArg();
-        OptionSpec<String> ec = parser.accepts("execution").withRequiredArg();
-        parser.accepts("q");
-        parser.accepts("s");
-        parser.accepts("v");
-        OptionSpec<String> r = parser.accepts("R").withRequiredArg();
-        OptionSpec<String> c = parser.accepts("C").withRequiredArg();
-        parser.acceptsAll(asList("h", "help"));
-        parser.accepts("version");
-        parser.accepts("full-version");
-
-        parser.accepts("X");
-        OptionSpec<String> addExports = parser.accepts("add-exports").withRequiredArg();
-
-        NonOptionArgumentSpec<String> loadFileSpec = parser.nonOptions();
-
-        OptionSet options;
-        try {
-            options = parser.parse(args);
-        } catch (OptionException ex) {
-            if (ex.options().isEmpty()) {
-                startmsg("jshell.err.opt.invalid", stream(args).collect(joining(", ")));
-            } else {
-                boolean isKnown = parser.recognizedOptions().containsKey(ex.options().iterator().next());
-                startmsg(isKnown
-                        ? "jshell.err.opt.arg"
-                        : "jshell.err.opt.unknown",
-                        ex.options()
-                        .stream()
-                        .collect(joining(", ")));
-            }
-            return null;
-        }
-
-        if (options.has("help")) {
-            printUsage();
-            return null;
-        }
-        if (options.has("X")) {
-            printUsageX();
-            return null;
-        }
-        if (options.has("version")) {
-            cmdout.printf("jshell %s\n", version());
-            return null;
-        }
-        if (options.has("full-version")) {
-            cmdout.printf("jshell %s\n", fullVersion());
-            return null;
-        }
-        if (options.has(cp)) {
-            List<String> cps = options.valuesOf(cp);
-            if (cps.size() > 1) {
-                startmsg("jshell.err.opt.one", "--class-path");
-                return null;
-            }
-            cmdlineClasspath = cps.get(0);
-        }
-        if (options.has(st)) {
-            List<String> sts = options.valuesOf(st);
-            if (options.has("no-startup")) {
-                startmsg("jshell.err.opt.startup.conflict");
-                return null;
-            }
-            StringBuilder sb = new StringBuilder();
-            for (String fn : sts) {
-                String s = readFile(fn, "--startup");
-                if (s == null) {
-                    return null;
-                }
-                sb.append(s);
-            }
-            startup = sb.toString();
-        } else if (options.has("no-startup")) {
-            startup = "";
-        }
-        if ((options.valuesOf(fb).size() +
-                 (options.has("q") ? 1 : 0) +
-                 (options.has("s") ? 1 : 0) +
-                 (options.has("v") ? 1 : 0)) > 1) {
-            startmsg("jshell.err.opt.feedback.one");
-            return null;
-        } else if (options.has(fb)) {
-            commandLineFeedbackMode = options.valueOf(fb);
-        } else if (options.has("q")) {
-            commandLineFeedbackMode = "concise";
-        } else if (options.has("s")) {
-            commandLineFeedbackMode = "silent";
-        } else if (options.has("v")) {
-            commandLineFeedbackMode = "verbose";
-        }
-        if (options.has(r)) {
-            remoteVMOptions.addAll(options.valuesOf(r));
-        }
-        if (options.has(c)) {
-            compilerOptions.addAll(options.valuesOf(c));
-        }
-        if (options.has(mpath)) {
-            compilerOptions.add("--module-path");
-            compilerOptions.addAll(options.valuesOf(mpath));
-            remoteVMOptions.add("--module-path");
-            remoteVMOptions.addAll(options.valuesOf(mpath));
-        }
-        if (options.has(amods)) {
-            compilerOptions.add("--add-modules");
-            compilerOptions.addAll(options.valuesOf(amods));
-            remoteVMOptions.add("--add-modules");
-            remoteVMOptions.addAll(options.valuesOf(amods));
-        }
-        if (options.has(ec)) {
-            executionControlSpec = options.valueOf(ec);
-        }
-
-        if (options.has(addExports)) {
-            List<String> exports = options.valuesOf(addExports).stream()
-                    .map(mp -> mp + "=ALL-UNNAMED")
-                    .flatMap(mp -> Stream.of("--add-exports", mp))
-                    .collect(toList());
-            remoteVMOptions.addAll(exports);
-            compilerOptions.addAll(exports);
-        }
-
-        return options.valuesOf(loadFileSpec);
-    }
-
     private void printUsage() {
         cmdout.print(getResourceString("help.usage"));
     }
@@ -734,8 +877,8 @@
                 .idGenerator((sn, i) -> (currentNameSpace == startNamespace || state.status(sn).isActive())
                         ? currentNameSpace.tid(sn)
                         : errorNamespace.tid(sn))
-                .remoteVMOptions(remoteVMOptions.stream().toArray(String[]::new))
-                .compilerOptions(compilerOptions.stream().toArray(String[]::new));
+                .remoteVMOptions(options.remoteVmOptions())
+                .compilerOptions(options.compilerOptions());
         if (executionControlSpec != null) {
             builder.executionEngine(executionControlSpec);
         }
@@ -748,15 +891,6 @@
         });
         analysis = state.sourceCodeAnalysis();
         live = true;
-        if (!feedbackInitialized) {
-            // One time per run feedback initialization
-            feedbackInitialized = true;
-            initFeedback();
-        }
-
-        if (cmdlineClasspath != null) {
-            state.addToClasspath(cmdlineClasspath);
-        }
 
         startUpRun(startup);
         currentNameSpace = mainNamespace;
@@ -767,7 +901,7 @@
     }
 
     //where -- one-time per run initialization of feedback modes
-    private void initFeedback() {
+    private void initFeedback(String initMode) {
         // No fluff, no prefix, for init failures
         MessageHandler initmh = new InitMessageHandler();
         // Execute the feedback initialization code in the resource file
@@ -782,12 +916,11 @@
                 prefs.remove(MODE_KEY);
             }
         }
-        if (commandLineFeedbackMode != null) {
+        if (initMode != null) {
             // The feedback mode to use was specified on the command line, use it
-            if (!setFeedback(initmh, new ArgTokenizer("--feedback", commandLineFeedbackMode))) {
+            if (!setFeedback(initmh, new ArgTokenizer("--feedback", initMode))) {
                 regenerateOnDeath = false;
             }
-            commandLineFeedbackMode = null;
         } else {
             String fb = prefs.get(FEEDBACK_KEY);
             if (fb != null) {
@@ -1016,6 +1149,13 @@
             this.alternatives = alternatives;
         }
 
+        // Add more options to an existing provider
+        public FixedCompletionProvider(FixedCompletionProvider base, String... alternatives) {
+            List<String> l = new ArrayList<>(Arrays.asList(base.alternatives));
+            l.addAll(Arrays.asList(alternatives));
+            this.alternatives = l.toArray(new String[l.size()]);
+        }
+
         @Override
         public List<Suggestion> completionSuggestions(String input, int cursor, int[] anchor) {
             List<Suggestion> result = new ArrayList<>();
@@ -1037,11 +1177,20 @@
     private static final CompletionProvider SNIPPET_HISTORY_OPTION_COMPLETION_PROVIDER = new FixedCompletionProvider("-all", "-start ", "-history");
     private static final CompletionProvider SAVE_OPTION_COMPLETION_PROVIDER = new FixedCompletionProvider("-all ", "-start ", "-history ");
     private static final CompletionProvider SNIPPET_OPTION_COMPLETION_PROVIDER = new FixedCompletionProvider("-all", "-start " );
-    private static final CompletionProvider RELOAD_OPTIONS_COMPLETION_PROVIDER = new FixedCompletionProvider("-restore ", "-quiet ");
-    private static final CompletionProvider RESTORE_COMPLETION_PROVIDER = new FixedCompletionProvider("-restore");
-    private static final CompletionProvider QUIET_COMPLETION_PROVIDER = new FixedCompletionProvider("-quiet");
+    private static final FixedCompletionProvider COMMAND_LINE_LIKE_OPTIONS_COMPLETION_PROVIDER = new FixedCompletionProvider(
+            "-class-path ", "-module-path ", "-add-modules ", "-add-exports ");
+    private static final CompletionProvider RELOAD_OPTIONS_COMPLETION_PROVIDER = new FixedCompletionProvider(
+            COMMAND_LINE_LIKE_OPTIONS_COMPLETION_PROVIDER,
+            "-restore ", "-quiet ");
     private static final CompletionProvider SET_MODE_OPTIONS_COMPLETION_PROVIDER = new FixedCompletionProvider("-command", "-quiet", "-delete");
     private static final CompletionProvider FILE_COMPLETION_PROVIDER = fileCompletions(p -> true);
+    private static final Map<String, CompletionProvider> ARG_OPTIONS = new HashMap<>();
+    static {
+        ARG_OPTIONS.put("-class-path", classPathCompletion());
+        ARG_OPTIONS.put("-module-path", fileCompletions(Files::isDirectory));
+        ARG_OPTIONS.put("-add-modules", EMPTY_COMPLETION_PROVIDER);
+        ARG_OPTIONS.put("-add-exports", EMPTY_COMPLETION_PROVIDER);
+    }
     private final Map<String, Command> commands = new LinkedHashMap<>();
     private void registerCommand(Command cmd) {
         commands.put(cmd.command, cmd);
@@ -1167,32 +1316,70 @@
         };
     }
 
-    private static CompletionProvider reloadCompletion() {
+    // command-line-like option completion -- options with values
+    private static CompletionProvider optionCompletion(CompletionProvider provider) {
         return (code, cursor, anchor) -> {
-            CompletionProvider provider;
-            int pastSpace = code.indexOf(' ') + 1; // zero if no space
-            if (pastSpace == 0) {
-                provider = RELOAD_OPTIONS_COMPLETION_PROVIDER;
-            } else {
-                switch (code.substring(0, pastSpace - 1)) {
-                    case "-quiet":
-                        provider = RESTORE_COMPLETION_PROVIDER;
-                        break;
-                    case "-restore":
-                        provider = QUIET_COMPLETION_PROVIDER;
-                        break;
-                    default:
-                        provider = EMPTY_COMPLETION_PROVIDER;
-                        break;
+            Matcher ovm = OPTION_VALUE_PATTERN.matcher(code);
+            if (ovm.matches()) {
+                String flag = ovm.group("flag");
+                List<CompletionProvider> ps = ARG_OPTIONS.entrySet().stream()
+                        .filter(es -> es.getKey().startsWith(flag))
+                        .map(es -> es.getValue())
+                        .collect(toList());
+                if (ps.size() == 1) {
+                    int pastSpace = ovm.start("val");
+                    List<Suggestion> result = ps.get(0).completionSuggestions(
+                            ovm.group("val"), cursor - pastSpace, anchor);
+                    anchor[0] += pastSpace;
+                    return result;
                 }
             }
-            List<Suggestion> result = provider.completionSuggestions(
-                    code.substring(pastSpace), cursor - pastSpace, anchor);
-            anchor[0] += pastSpace;
-            return result;
+            Matcher om = OPTION_PATTERN.matcher(code);
+            if (om.matches()) {
+                int pastSpace = om.start("flag");
+                List<Suggestion> result = provider.completionSuggestions(
+                        om.group("flag"), cursor - pastSpace, anchor);
+                if (!om.group("dd").isEmpty()) {
+                    result = result.stream()
+                            .map(sug -> new Suggestion() {
+                                @Override
+                                public String continuation() {
+                                    return "-" + sug.continuation();
+                                }
+
+                                @Override
+                                public boolean matchesType() {
+                                    return false;
+                                }
+                            })
+                            .collect(toList());
+                    --pastSpace;
+                }
+                anchor[0] += pastSpace;
+                return result;
+            }
+            Matcher opp = OPTION_PRE_PATTERN.matcher(code);
+            if (opp.matches()) {
+                int pastSpace = opp.end();
+                List<Suggestion> result = provider.completionSuggestions(
+                        "", cursor - pastSpace, anchor);
+                anchor[0] += pastSpace;
+                return result;
+            }
+            return Collections.emptyList();
         };
     }
 
+    // /reload command completion
+    private static CompletionProvider reloadCompletion() {
+        return optionCompletion(RELOAD_OPTIONS_COMPLETION_PROVIDER);
+    }
+
+    // /env command completion
+    private static CompletionProvider envCompletion() {
+        return optionCompletion(COMMAND_LINE_LIKE_OPTIONS_COMPLETION_PROVIDER);
+    }
+
     private static CompletionProvider orMostSpecificCompletion(
             CompletionProvider left, CompletionProvider right) {
         return (code, cursor, anchor) -> {
@@ -1286,16 +1473,15 @@
         registerCommand(new Command("/exit",
                 arg -> cmdExit(),
                 EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/env",
+                arg -> cmdEnv(arg),
+                envCompletion()));
         registerCommand(new Command("/reset",
-                arg -> cmdReset(),
-                EMPTY_COMPLETION_PROVIDER));
+                arg -> cmdReset(arg),
+                envCompletion()));
         registerCommand(new Command("/reload",
                 this::cmdReload,
                 reloadCompletion()));
-        registerCommand(new Command("/classpath",
-                this::cmdClasspath,
-                classPathCompletion(),
-                CommandKind.REPLAY));
         registerCommand(new Command("/history",
                 arg -> cmdHistory(),
                 EMPTY_COMPLETION_PROVIDER));
@@ -1344,6 +1530,9 @@
         registerCommand(new Command("shortcuts",
                 "help.shortcuts",
                 CommandKind.HELP_SUBJECT));
+        registerCommand(new Command("context",
+                "help.context",
+                CommandKind.HELP_SUBJECT));
 
         commandCompletions = new ContinuousCompletionProvider(
                 commands.values().stream()
@@ -1692,17 +1881,6 @@
         hard(stset);
     }
 
-    boolean cmdClasspath(String arg) {
-        if (arg.isEmpty()) {
-            errormsg("jshell.err.classpath.arg");
-            return false;
-        } else {
-            state.addToClasspath(toPathResolvingUserHome(arg).toString());
-            fluffmsg("jshell.msg.classpath", arg);
-            return true;
-        }
-    }
-
     boolean cmdDebug(String arg) {
         if (arg.isEmpty()) {
             debug = !debug;
@@ -2228,7 +2406,6 @@
 
     }
 
-    // Read a built-in file from resources or null
     String getResource(String name) {
         if (BUILTIN_FILE_PATTERN.matcher(name).matches()) {
             try {
@@ -2266,20 +2443,22 @@
         return defaultStartup;
     }
 
-    private boolean cmdReset() {
+    private boolean cmdReset(String rawargs) {
+        if (!parseCommandLineLikeFlags(rawargs, new OptionParserBase())) {
+            return false;
+        }
         live = false;
         fluffmsg("jshell.msg.resetting.state");
         return true;
     }
 
     private boolean cmdReload(String rawargs) {
-        ArgTokenizer at = new ArgTokenizer("/reload", rawargs.trim());
-        at.allowedOptions("-restore", "-quiet");
-        if (!checkOptionsAndRemainingInput(at)) {
+        OptionParserReload ap = new OptionParserReload();
+        if (!parseCommandLineLikeFlags(rawargs, ap)) {
             return false;
         }
         Iterable<String> history;
-        if (at.hasOption("-restore")) {
+        if (ap.restore()) {
             if (replayableHistoryPrevious == null) {
                 errormsg("jshell.err.reload.no.previous");
                 return false;
@@ -2290,13 +2469,57 @@
             history = replayableHistory;
             fluffmsg("jshell.err.reload.restarting.state");
         }
-        boolean echo = !at.hasOption("-quiet");
+        return doReload(history, !ap.quiet());
+    }
+
+    private boolean cmdEnv(String rawargs) {
+        if (rawargs.trim().isEmpty()) {
+            // No arguments, display current settings (as option flags)
+            StringBuilder sb = new StringBuilder();
+            for (String a : options.commonOptions()) {
+                sb.append(
+                        a.startsWith("-")
+                            ? sb.length() > 0
+                                    ? "\n   "
+                                    :   "   "
+                            : " ");
+                sb.append(a);
+            }
+            if (sb.length() > 0) {
+                rawout(prefix(sb.toString()));
+            }
+            return false;
+        }
+        if (!parseCommandLineLikeFlags(rawargs, new OptionParserBase())) {
+            return false;
+        }
+        fluffmsg("jshell.msg.set.restore");
+        return doReload(replayableHistory, false);
+    }
+
+    private boolean doReload(Iterable<String> history, boolean echo) {
         resetState();
         run(new ReloadIOContext(history,
                 echo ? cmdout : null));
         return true;
     }
 
+    private boolean parseCommandLineLikeFlags(String rawargs, OptionParserBase ap) {
+        String[] args = Arrays.stream(rawargs.split("\\s+"))
+                .filter(s -> !s.isEmpty())
+                .toArray(String[]::new);
+        Options opts = ap.parse(args);
+        if (opts == null) {
+            return false;
+        }
+        if (!ap.nonOptions().isEmpty()) {
+            errormsg("jshell.err.unexpected.at.end", ap.nonOptions(), rawargs);
+            return false;
+        }
+        options.override(opts);
+        return true;
+    }
+
     private boolean cmdSave(String rawargs) {
         ArgTokenizer at = new ArgTokenizer("/save", rawargs.trim());
         at.allowedOptions("-all", "-start", "-history");
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Fri Jan 06 14:16:45 2017 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Fri Jan 06 10:31:25 2017 -0800
@@ -52,6 +52,7 @@
 
 jshell.err.no.such.command.or.snippet.id = No such command or snippet id: {0}
 jshell.err.command.ambiguous = Command: ''{0}'' is ambiguous: {1}
+jshell.msg.set.restore = Setting new options and restoring state.
 jshell.msg.set.editor.set = Editor set to: {0}
 jshell.msg.set.editor.retain = Editor setting retained: {0}
 jshell.err.no.builtin.editor = Built-in editor not available.
@@ -319,21 +320,25 @@
 Save any work before using this command
 
 help.reset.summary = reset jshell
-help.reset.args =
+help.reset.args = \
+[-class-path <path>] [-module-path <path>] [-add-modules <modules>]...
 help.reset =\
 Reset the jshell tool code and execution state:\n\t\
    * All entered code is lost.\n\t\
    * Start-up code is re-executed.\n\t\
    * The execution state is restarted.\n\t\
-   * The classpath is cleared.\n\
 Tool settings are maintained, as set with: /set ...\n\
-Save any work before using this command
+Save any work before using this command.\n\
+The /reset command accepts context options, see:\n\n\t\
+     /help context\n\
+
 
 help.reload.summary = reset and replay relevant history -- current or previous (-restore)
-help.reload.args = [-restore] [-quiet]
+help.reload.args = \
+[-restore] [-quiet] [-class-path <path>] [-module-path <path>]...
 help.reload =\
 Reset the jshell tool code and execution state then replay each valid snippet\n\
-and any /drop or /classpath commands in the order they were entered.\n\
+and any /drop commands in the order they were entered.\n\
 \n\
 /reload\n\t\
      Reset and replay the valid history since jshell was entered, or\n\t\
@@ -345,12 +350,31 @@
      command was executed. This can thus be used to restore a previous\n\t\
      jshell tool session.\n\n\
 /reload [-restore] -quiet\n\t\
-     With the '-quiet' argument the replay is not shown.  Errors will display.
+     With the '-quiet' argument the replay is not shown.  Errors will display.\n\
+\n\
+Each of the above accepts context options, see:\n\n\t\
+     /help context\n\
+\n\
+For example:\n\n\t\
+     /reload -add-modules com.greetings -restore
 
-help.classpath.summary = add a path to the classpath
-help.classpath.args = <path>
-help.classpath =\
-Append a additional path to the classpath.
+help.env.summary = view or change the evaluation context
+help.env.args = \
+[-class-path <path>] [-module-path <path>] [-add-modules <modules>] ...
+help.env =\
+View or change the evaluation context.  The evaluation context is the class path,\n\
+module path, etc.\n\
+/env\n\t\
+     Show the evaluation context displayed as context options.\n\n\
+/env [-class-path <path>] [-module-path <path>] [-add-modules <modules>] ...\n\t\
+     With at least one option set, sets the evaluation context.  If snippets\n\t\
+     have been defined, the execution state is reset with the new\n\t\
+     evaluation context and the snippets will be replayed -- the replay is not\n\t\
+     shown, however, errors will display.  This is equivalent to: /reload -quiet\n\t\
+     For details of context options, see:\n\n\t\t\
+           /help context\n\n\t\
+     For example:\n\n\t\t\
+           /env -add-modules com.greetings
 
 help.history.summary = history of what you have typed
 help.history.args =
@@ -473,6 +497,37 @@
         possible fully qualified names based on the content of the specified classpath.\n\t\t\
         The "<fix-shortcut>" is either Alt-F1 or Alt-Enter, depending on the platform.
 
+help.context.summary = the evaluation context options for /env /reload and /reset
+help.context =\
+These options configure the evaluation context, they can be specified when\n\
+jshell is started: on the command-line, or restarted with the commands /env,\n\
+/reload, or /reset.\n\
+\n\
+They are:\n\t\
+    --class-path <class search path of directories and zip/jar files>\n\t\t\
+                  A list of directories, JAR archives,\n\t\t\
+                  and ZIP archives to search for class files.\n\t\t\
+                  The list is separated with the path separator\n\t\t\
+                  (a : on unix/linux/mac, and ; on windows).\n\t\
+    --module-path <module path>...\n\t\t\
+                  A list of directories, each directory\n\t\t\
+                  is a directory of modules.\n\t\t\
+                  The list is separated with the path separator\n\t\t\
+                  (a : on unix/linux/mac, and ; on windows).\n\t\
+    --add-modules <modulename>[,<modulename>...]\n\t\t\
+                  root modules to resolve in addition to the initial module.\n\t\t\
+                  <modulename> can also be ALL-DEFAULT, ALL-SYSTEM,\n\t\t\
+                  ALL-MODULE-PATH.\n\t\
+    --add-exports <module>/<package>=<target-module>(,<target-module>)*\n\t\t\
+                  updates <module> to export <package> to <target-module>,\n\t\t\
+                  regardless of module declaration.\n\t\t\
+                  <target-module> can be ALL-UNNAMED to export to all\n\t\t\
+                  unnamed modules. In jshell, if the <target-module> is not\n\t\t\
+                  specified (no =) then ALL-UNNAMED is used.\n\
+\n\
+On the command-line these options must have two dashes, e.g.: --module-path\n\
+On jshell commands they can have one or two dashes, e.g.: -module-path\n\
+
 help.set._retain = \
 The '-retain' option saves a setting so that it is used in future sessions.\n\
 The -retain option can be used on the following forms of /set:\n\n\t\
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Fri Jan 06 14:16:45 2017 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Fri Jan 06 10:31:25 2017 -0800
@@ -161,6 +161,10 @@
         @Override
         public Diag diag(Diagnostic<? extends JavaFileObject> d) {
             SourceMemoryJavaFileObject smjfo = (SourceMemoryJavaFileObject) d.getSource();
+            if (smjfo == null) {
+                // Handle failure that doesn't preserve mapping
+                return new StringSourceHandler().diag(d);
+            }
             OuterWrap w = (OuterWrap) smjfo.getOrigin();
             return w.wrapDiag(d);
         }
--- a/langtools/test/jdk/jshell/CommandCompletionTest.java	Fri Jan 06 14:16:45 2017 +0100
+++ b/langtools/test/jdk/jshell/CommandCompletionTest.java	Fri Jan 06 10:31:25 2017 -0800
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8144095 8164825 8169818 8153402
+ * @bug 8144095 8164825 8169818 8153402 8165405
  * @summary Test Command Completion
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -138,7 +138,7 @@
     @Test
     public void testEdit() {
         test(false, new String[]{"--no-startup"},
-                a -> assertCompletion(a, "/e|", false, "/edit ", "/exit "),
+                a -> assertCompletion(a, "/e|", false, "/edit ", "/env ", "/exit "),
                 a -> assertCompletion(a, "/ed|", false, "/edit "),
                 a -> assertClass(a, "class cTest {}", "class", "cTest"),
                 a -> assertMethod(a, "int mTest() { return 0; }", "()I", "mTest"),
@@ -158,15 +158,17 @@
     public void testHelp() {
         testNoStartUp(
                 a -> assertCompletion(a, "/help |", false,
-                "/! ", "/-<n> ", "/<id> ", "/? ", "/classpath ", "/drop ",
-                "/edit ", "/exit ", "/help ", "/history ", "/imports ",
+                "/! ", "/-<n> ", "/<id> ", "/? ", "/drop ",
+                "/edit ", "/env ", "/exit ",
+                "/help ", "/history ", "/imports ",
                 "/list ", "/methods ", "/open ", "/reload ", "/reset ",
-                "/save ", "/set ", "/types ", "/vars ", "intro ", "shortcuts "),
+                "/save ", "/set ", "/types ", "/vars ", "context ", "intro ", "shortcuts "),
                 a -> assertCompletion(a, "/? |", false,
-                "/! ", "/-<n> ", "/<id> ", "/? ", "/classpath ", "/drop ",
-                "/edit ", "/exit ", "/help ", "/history ", "/imports ",
+                "/! ", "/-<n> ", "/<id> ", "/? ", "/drop ",
+                "/edit ", "/env ", "/exit ",
+                "/help ", "/history ", "/imports ",
                 "/list ", "/methods ", "/open ", "/reload ", "/reset ",
-                "/save ", "/set ", "/types ", "/vars ", "intro ", "shortcuts "),
+                "/save ", "/set ", "/types ", "/vars ", "context ", "intro ", "shortcuts "),
                 a -> assertCompletion(a, "/help /s|", false,
                 "/save ", "/set "),
                 a -> assertCompletion(a, "/help /set |", false,
@@ -177,17 +179,63 @@
 
     @Test
     public void testReload() {
+        String[] ropts = new String[] { "-add-exports ", "-add-modules ",
+            "-class-path ", "-module-path ", "-quiet ", "-restore " };
+        String[] dropts = new String[] { "--add-exports ", "--add-modules ",
+            "--class-path ", "--module-path ", "--quiet ", "--restore " };
         testNoStartUp(
-                a -> assertCompletion(a, "/reload |", false, "-quiet ", "-restore "),
-                a -> assertCompletion(a, "/reload -restore |", false, "-quiet"),
-                a -> assertCompletion(a, "/reload -quiet |", false, "-restore"),
-                a -> assertCompletion(a, "/reload -restore -quiet |", false)
+                a -> assertCompletion(a, "/reloa |", false, ropts),
+                a -> assertCompletion(a, "/relo               |", false, ropts),
+                a -> assertCompletion(a, "/reload -|", false, ropts),
+                a -> assertCompletion(a, "/reload --|", false, dropts),
+                a -> assertCompletion(a, "/reload -restore |", false, ropts),
+                a -> assertCompletion(a, "/reload -restore --|", false, dropts),
+                a -> assertCompletion(a, "/reload -rest|", false, "-restore "),
+                a -> assertCompletion(a, "/reload --r|", false, "--restore "),
+                a -> assertCompletion(a, "/reload -q|", false, "-quiet "),
+                a -> assertCompletion(a, "/reload -add|", false, "-add-exports ", "-add-modules "),
+                a -> assertCompletion(a, "/reload -class-path . -quiet |", false, ropts)
+        );
+    }
+
+    @Test
+    public void testEnv() {
+        String[] ropts = new String[] { "-add-exports ", "-add-modules ",
+            "-class-path ", "-module-path " };
+        String[] dropts = new String[] { "--add-exports ", "--add-modules ",
+            "--class-path ", "--module-path " };
+        testNoStartUp(
+                a -> assertCompletion(a, "/env |", false, ropts),
+                a -> assertCompletion(a, "/env -|", false, ropts),
+                a -> assertCompletion(a, "/env --|", false, dropts),
+                a -> assertCompletion(a, "/env --a|", false, "--add-exports ", "--add-modules "),
+                a -> assertCompletion(a, "/env -add-|", false, "-add-exports ", "-add-modules "),
+                a -> assertCompletion(a, "/env -class-path . |", false, ropts),
+                a -> assertCompletion(a, "/env -class-path . --|", false, dropts)
+        );
+    }
+
+    @Test
+    public void testReset() {
+        String[] ropts = new String[] { "-add-exports ", "-add-modules ",
+            "-class-path ", "-module-path " };
+        String[] dropts = new String[] { "--add-exports ", "--add-modules ",
+            "--class-path ", "--module-path " };
+        testNoStartUp(
+                a -> assertCompletion(a, "/reset    |", false, ropts),
+                a -> assertCompletion(a, "/res -m|", false, "-module-path "),
+                a -> assertCompletion(a, "/res -module-|", false, "-module-path "),
+                a -> assertCompletion(a, "/res --m|", false, "--module-path "),
+                a -> assertCompletion(a, "/res --module-|", false, "--module-path "),
+                a -> assertCompletion(a, "/reset -add|", false, "-add-exports ", "-add-modules "),
+                a -> assertCompletion(a, "/rese -class-path . |", false, ropts),
+                a -> assertCompletion(a, "/rese -class-path . --|", false, dropts)
         );
     }
 
     @Test
     public void testVarsMethodsTypes() {
-        test(false, new String[]{"--no-startup"},
+        testNoStartUp(
                 a -> assertCompletion(a, "/v|", false, "/vars "),
                 a -> assertCompletion(a, "/m|", false, "/methods "),
                 a -> assertCompletion(a, "/t|", false, "/types "),
@@ -245,9 +293,6 @@
 
     @Test
     public void testClassPath() throws IOException {
-        testNoStartUp(
-                a -> assertCompletion(a, "/classp|", false, "/classpath ")
-        );
         Compiler compiler = new Compiler();
         Path outDir = compiler.getPath("testClasspathCompletion");
         Files.createDirectories(outDir);
@@ -259,8 +304,13 @@
         compiler.jar(outDir, jarName, "pkg/A.class");
         compiler.getPath(outDir).resolve(jarName);
         List<String> paths = listFiles(outDir, CLASSPATH_FILTER);
+        String[] pathArray = paths.toArray(new String[paths.size()]);
         testNoStartUp(
-                a -> assertCompletion(a, "/classpath " + outDir + "/|", false, paths.toArray(new String[paths.size()]))
+                a -> assertCompletion(a, "/env -class-path " + outDir + "/|", false, pathArray),
+                a -> assertCompletion(a, "/env --class-path " + outDir + "/|", false, pathArray),
+                a -> assertCompletion(a, "/env -clas    " + outDir + "/|", false, pathArray),
+                a -> assertCompletion(a, "/env --class-p    " + outDir + "/|", false, pathArray),
+                a -> assertCompletion(a, "/env --module-path . --class-p    " + outDir + "/|", false, pathArray)
         );
     }
 
@@ -275,7 +325,7 @@
                                  .collect(Collectors.toList());
         }
         testNoStartUp(
-                a -> assertCompletion(a, "/classpath ~/|", false, completions.toArray(new String[completions.size()]))
+                a -> assertCompletion(a, "/env --class-path ~/|", false, completions.toArray(new String[completions.size()]))
         );
     }
 
--- a/langtools/test/jdk/jshell/ToolBasicTest.java	Fri Jan 06 14:16:45 2017 +0100
+++ b/langtools/test/jdk/jshell/ToolBasicTest.java	Fri Jan 06 10:31:25 2017 -0800
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 8154714 8166649 8167643 8170162 8172102
+ * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 8143955 8157953 8080347 8154714 8166649 8167643 8170162 8172102 8165405
  * @summary Tests for Basic tests for REPL tool
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -263,7 +263,8 @@
         compiler.compile(outDir, "package pkg; public class A { public String toString() { return \"A\"; } }");
         Path classpath = compiler.getPath(outDir);
         test(
-                (a) -> assertCommand(a, "/classpath " + classpath, String.format("|  Path '%s' added to classpath", classpath)),
+                (a) -> assertCommand(a, "/env --class-path " + classpath,
+                        "|  Setting new options and restoring state."),
                 (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A")
         );
         test(new String[] { "--class-path", classpath.toString() },
@@ -279,7 +280,8 @@
         compiler.jar(outDir, jarName, "pkg/A.class");
         Path jarPath = compiler.getPath(outDir).resolve(jarName);
         test(
-                (a) -> assertCommand(a, "/classpath " + jarPath, String.format("|  Path '%s' added to classpath", jarPath)),
+                (a) -> assertCommand(a, "/env --class-path " + jarPath,
+                        "|  Setting new options and restoring state."),
                 (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "A")
         );
         test(new String[] { "--class-path", jarPath.toString() },
--- a/langtools/test/jdk/jshell/ToolReloadTest.java	Fri Jan 06 14:16:45 2017 +0100
+++ b/langtools/test/jdk/jshell/ToolReloadTest.java	Fri Jan 06 10:31:25 2017 -0800
@@ -24,7 +24,7 @@
 /*
  * @test
  * @key intermittent
- * @bug 8081845 8147898 8143955
+ * @bug 8081845 8147898 8143955  8165405
  * @summary Tests for /reload in JShell tool
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -70,8 +70,8 @@
         compiler.compile(outDir, prog.apply("A"));
         Path classpath = compiler.getPath(outDir);
         test(
-                (a) -> assertCommand(a, "/classpath " + classpath,
-                        String.format("|  Path '%s' added to classpath", classpath)),
+                (a) -> assertCommand(a, "/env --class-path " + classpath,
+                        "|  Setting new options and restoring state."),
                 (a) -> assertMethod(a, "String foo() { return (new pkg.A()).toString(); }",
                         "()String", "foo"),
                 (a) -> assertVariable(a, "String", "v", "foo()", "\"A\""),
@@ -79,7 +79,6 @@
                        if (!a) compiler.compile(outDir, prog.apply("Aprime"));
                        assertCommand(a, "/reload",
                         "|  Restarting and restoring state.\n" +
-                        "-: /classpath " + classpath + "\n" +
                         "-: String foo() { return (new pkg.A()).toString(); }\n" +
                         "-: String v = foo();\n");
                        },
--- a/langtools/test/jdk/jshell/ToolSimpleTest.java	Fri Jan 06 14:16:45 2017 +0100
+++ b/langtools/test/jdk/jshell/ToolSimpleTest.java	Fri Jan 06 10:31:25 2017 -0800
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102
+ * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103  8165405
  * @summary Simple jshell tool tests
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -196,7 +196,7 @@
 
     @Test
     public void testEmptyClassPath() {
-        test(after -> assertCommand(after, "/classpath", "|  The /classpath command requires a path argument."));
+        test(after -> assertCommand(after, "/env --class-path", "|  Argument to class-path missing."));
     }
 
     @Test
@@ -606,6 +606,13 @@
     }
 
     @Test
+    public void testWrapSourceHandlerDiagCrash() {
+        test(new String[]{"--add-exports", "jdk.javadoc/ALL-UNNAMED"},
+                (a) -> assertCommand(a, "1+1", "$1 ==> 2")
+         );
+    }
+
+    @Test
     public void test8156910() {
         test(
                 (a) -> assertCommandOutputContains(a, "System.out.println(\"%5d\", 10);", "%5d"),