changeset 1396:61b401b23fc2 jdk9-b80

Merge
author lana
date Thu, 27 Aug 2015 13:22:30 -0700
parents 0a68f2d8e06f 6263188b48de
children cffb8ad5ad94 c16cb85c1aec
files
diffstat 27 files changed, 1316 insertions(+), 77 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/classes.js	Thu Aug 27 13:22:30 2015 -0700
@@ -0,0 +1,47 @@
+// Usage: jjs classes.js [ -- <java_package_name > ]
+
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// print all Java classes of the given package and its subpackages.
+var pkg = arguments.length > 0? arguments[0] : "java.lang";
+
+with (new JavaImporter(javax.tools, java.util)) {
+    var compiler = ToolProvider.systemJavaCompiler;
+    var fm = compiler.getStandardFileManager(null, null, null);
+    var kinds = EnumSet.of(JavaFileObject.Kind.CLASS);
+    var loc = StandardLocation.PLATFORM_CLASS_PATH;
+    var itr = fm.list(loc, pkg, kinds, true).iterator();
+    while(itr.hasNext()) {
+        print(fm.inferBinaryName(loc, itr.next()));
+    }
+    fm.close();
+}
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Console.java	Thu Aug 27 13:22:30 2015 -0700
@@ -34,6 +34,11 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import jdk.internal.jline.NoInterruptUnixTerminal;
+import jdk.internal.jline.Terminal;
+import jdk.internal.jline.TerminalFactory;
+import jdk.internal.jline.TerminalFactory.Flavor;
+import jdk.internal.jline.WindowsTerminal;
 import jdk.internal.jline.console.ConsoleReader;
 import jdk.internal.jline.console.completer.Completer;
 import jdk.internal.jline.console.history.FileHistory;
@@ -45,6 +50,8 @@
     Console(final InputStream cmdin, final PrintStream cmdout, final File historyFile,
             final Completer completer) throws IOException {
         in = new ConsoleReader(cmdin, cmdout);
+        TerminalFactory.registerFlavor(Flavor.WINDOWS, JJSWindowsTerminal :: new);
+        TerminalFactory.registerFlavor(Flavor.UNIX, JJSUnixTerminal :: new);
         in.setExpandEvents(false);
         in.setHandleUserInterrupt(true);
         in.setBellEnabled(true);
@@ -71,4 +78,60 @@
     FileHistory getHistory() {
         return (FileHistory) in.getHistory();
     }
+
+    boolean terminalEditorRunning() {
+        Terminal terminal = in.getTerminal();
+        if (terminal instanceof JJSUnixTerminal) {
+            return ((JJSUnixTerminal) terminal).isRaw();
+        }
+        return false;
+    }
+
+    void suspend() {
+        try {
+            in.getTerminal().restore();
+        } catch (Exception ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    void resume() {
+        try {
+            in.getTerminal().init();
+        } catch (Exception ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    static final class JJSUnixTerminal extends NoInterruptUnixTerminal {
+        JJSUnixTerminal() throws Exception {
+        }
+
+        boolean isRaw() {
+            try {
+                return getSettings().get("-a").contains("-icanon");
+            } catch (IOException | InterruptedException ex) {
+                return false;
+            }
+        }
+
+        @Override
+        public void disableInterruptCharacter() {
+        }
+
+        @Override
+        public void enableInterruptCharacter() {
+        }
+    }
+
+    static final class JJSWindowsTerminal extends WindowsTerminal {
+        public JJSWindowsTerminal() throws Exception {
+        }
+
+        @Override
+        public void init() throws Exception {
+            super.init();
+            setAnsiSupported(false);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/EditObject.java	Thu Aug 27 13:22:30 2015 -0700
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.tools.jjs;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Consumer;
+import jdk.nashorn.api.scripting.AbstractJSObject;
+import jdk.nashorn.internal.runtime.JSType;
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
+/*
+ * "edit" top level script function which shows an external Window
+ * for editing and evaluating scripts from it.
+ */
+final class EditObject extends AbstractJSObject {
+    private static final Set<String> props;
+    static {
+        final HashSet<String> s = new HashSet<>();
+        s.add("editor");
+        props = Collections.unmodifiableSet(s);
+    }
+
+    private final Console console;
+    private final Consumer<String> errorHandler;
+    private final Consumer<String> evaluator;
+    private String editor;
+
+    EditObject(final Console console, final Consumer<String> errorHandler,
+            final Consumer<String> evaluator) {
+        this.console = console;
+        this.errorHandler = errorHandler;
+        this.evaluator = evaluator;
+    }
+
+    @Override
+    public Object getDefaultValue(final Class<?> hint) {
+        if (hint == String.class) {
+            return toString();
+        }
+        return UNDEFINED;
+    }
+
+    @Override
+    public String toString() {
+        return "function edit() { [native code] }";
+    }
+
+    @Override
+    public Set<String> keySet() {
+        return props;
+    }
+
+    @Override
+    public Object getMember(final String name) {
+        if (name.equals("editor")) {
+            return editor;
+        }
+        return UNDEFINED;
+    }
+
+    @Override
+    public void setMember(final String name, final Object value) {
+        if (name.equals("editor")) {
+            this.editor = value != null && value != UNDEFINED? JSType.toString(value) : "";
+        }
+    }
+
+    // called whenever user 'saves' script in editor
+    class SaveHandler implements Consumer<String> {
+         private String lastStr; // last seen code
+
+         SaveHandler(final String str) {
+             this.lastStr = str;
+         }
+
+         @Override
+         public void accept(final String str) {
+             // ignore repeated save of the same code!
+             if (! str.equals(lastStr)) {
+                 this.lastStr = str;
+                 // evaluate the new code
+                 evaluator.accept(str);
+             }
+         }
+    }
+
+    @Override
+    public Object call(final Object thiz, final Object... args) {
+        final String initText = args.length > 0? JSType.toString(args[0]) : "";
+        final SaveHandler saveHandler = new SaveHandler(initText);
+        if (editor != null && !editor.isEmpty()) {
+            ExternalEditor.edit(editor, errorHandler, initText, saveHandler, console);
+        } else if (! Main.HEADLESS) {
+            EditPad.edit(errorHandler, initText, saveHandler);
+        } else {
+            errorHandler.accept(Main.getMessage("no.editor"));
+        }
+        return UNDEFINED;
+    }
+
+    @Override
+    public boolean isFunction() {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/EditPad.java	Thu Aug 27 13:22:30 2015 -0700
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.tools.jjs;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.function.Consumer;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+/**
+ * A minimal Swing editor as a fallback when the user does not specify an
+ * external editor.
+ */
+final class EditPad extends JFrame implements Runnable {
+    private static final long serialVersionUID = 1;
+    private final Consumer<String> errorHandler;
+    private final String initialText;
+    private final boolean[] closeLock;
+    private final Consumer<String> saveHandler;
+
+    EditPad(Consumer<String> errorHandler, String initialText,
+            boolean[] closeLock, Consumer<String> saveHandler) {
+        super("Edit Pad (Experimental)");
+        this.errorHandler = errorHandler;
+        this.initialText = initialText;
+        this.closeLock = closeLock;
+        this.saveHandler = saveHandler;
+    }
+
+    @Override
+    public void run() {
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(WindowEvent e) {
+                EditPad.this.dispose();
+                notifyClose();
+            }
+        });
+        setLocationRelativeTo(null);
+        setLayout(new BorderLayout());
+        JTextArea textArea = new JTextArea(initialText);
+        add(new JScrollPane(textArea), BorderLayout.CENTER);
+        add(buttons(textArea), BorderLayout.SOUTH);
+
+        setSize(800, 600);
+        setVisible(true);
+    }
+
+    private JPanel buttons(JTextArea textArea) {
+        FlowLayout flow = new FlowLayout();
+        flow.setHgap(35);
+        JPanel buttons = new JPanel(flow);
+        JButton cancel = new JButton("Cancel");
+        cancel.setMnemonic(KeyEvent.VK_C);
+        JButton accept = new JButton("Accept");
+        accept.setMnemonic(KeyEvent.VK_A);
+        JButton exit = new JButton("Exit");
+        exit.setMnemonic(KeyEvent.VK_X);
+        buttons.add(cancel);
+        buttons.add(accept);
+        buttons.add(exit);
+
+        cancel.addActionListener(e -> {
+            close();
+        });
+        accept.addActionListener(e -> {
+            saveHandler.accept(textArea.getText());
+        });
+        exit.addActionListener(e -> {
+            saveHandler.accept(textArea.getText());
+            close();
+        });
+
+        return buttons;
+    }
+
+    private void close() {
+        setVisible(false);
+        dispose();
+        notifyClose();
+    }
+
+    private void notifyClose() {
+        synchronized (closeLock) {
+            closeLock[0] = true;
+            closeLock.notify();
+        }
+    }
+
+    static void edit(Consumer<String> errorHandler, String initialText,
+            Consumer<String> saveHandler) {
+        boolean[] closeLock = new boolean[1];
+        SwingUtilities.invokeLater(
+                new EditPad(errorHandler, initialText, closeLock, saveHandler));
+        synchronized (closeLock) {
+            while (!closeLock[0]) {
+                try {
+                    closeLock.wait();
+                } catch (InterruptedException ex) {
+                    // ignore and loop
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/ExternalEditor.java	Thu Aug 27 13:22:30 2015 -0700
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.tools.jjs;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.ClosedWatchServiceException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.List;
+import java.util.function.Consumer;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+
+final class ExternalEditor {
+    private final Consumer<String> errorHandler;
+    private final Consumer<String> saveHandler;
+    private final Console input;
+
+    private WatchService watcher;
+    private Thread watchedThread;
+    private Path dir;
+    private Path tmpfile;
+
+    ExternalEditor(Consumer<String> errorHandler, Consumer<String> saveHandler, Console input) {
+        this.errorHandler = errorHandler;
+        this.saveHandler = saveHandler;
+        this.input = input;
+    }
+
+    private void edit(String cmd, String initialText) {
+        try {
+            setupWatch(initialText);
+            launch(cmd);
+        } catch (IOException ex) {
+            errorHandler.accept(ex.getMessage());
+        }
+    }
+
+    /**
+     * Creates a WatchService and registers the given directory
+     */
+    private void setupWatch(String initialText) throws IOException {
+        this.watcher = FileSystems.getDefault().newWatchService();
+        this.dir = Files.createTempDirectory("REPL");
+        this.tmpfile = Files.createTempFile(dir, null, ".js");
+        Files.write(tmpfile, initialText.getBytes(Charset.forName("UTF-8")));
+        dir.register(watcher,
+                ENTRY_CREATE,
+                ENTRY_DELETE,
+                ENTRY_MODIFY);
+        watchedThread = new Thread(() -> {
+            for (;;) {
+                WatchKey key;
+                try {
+                    key = watcher.take();
+                } catch (ClosedWatchServiceException ex) {
+                    break;
+                } catch (InterruptedException ex) {
+                    continue; // tolerate an intrupt
+                }
+
+                if (!key.pollEvents().isEmpty()) {
+                    if (!input.terminalEditorRunning()) {
+                        saveFile();
+                    }
+                }
+
+                boolean valid = key.reset();
+                if (!valid) {
+                    errorHandler.accept("Invalid key");
+                    break;
+                }
+            }
+        });
+        watchedThread.start();
+    }
+
+    private void launch(String cmd) throws IOException {
+        ProcessBuilder pb = new ProcessBuilder(cmd, tmpfile.toString());
+        pb = pb.inheritIO();
+
+        try {
+            input.suspend();
+            Process process = pb.start();
+            process.waitFor();
+        } catch (IOException ex) {
+            errorHandler.accept("process IO failure: " + ex.getMessage());
+        } catch (InterruptedException ex) {
+            errorHandler.accept("process interrupt: " + ex.getMessage());
+        } finally {
+            try {
+                watcher.close();
+                watchedThread.join(); //so that saveFile() is finished.
+                saveFile();
+            } catch (InterruptedException ex) {
+                errorHandler.accept("process interrupt: " + ex.getMessage());
+            } finally {
+                input.resume();
+            }
+        }
+    }
+
+    private void saveFile() {
+        List<String> lines;
+        try {
+            lines = Files.readAllLines(tmpfile);
+        } catch (IOException ex) {
+            errorHandler.accept("Failure read edit file: " + ex.getMessage());
+            return ;
+        }
+        StringBuilder sb = new StringBuilder();
+        for (String ln : lines) {
+            sb.append(ln);
+            sb.append('\n');
+        }
+        saveHandler.accept(sb.toString());
+    }
+
+    static void edit(String cmd, Consumer<String> errorHandler, String initialText,
+            Consumer<String> saveHandler, Console input) {
+        ExternalEditor ed = new ExternalEditor(errorHandler,  saveHandler, input);
+        ed.edit(cmd, initialText);
+    }
+}
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/HistoryObject.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/HistoryObject.java	Thu Aug 27 13:22:30 2015 -0700
@@ -25,16 +25,23 @@
 
 package jdk.nashorn.tools.jjs;
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.Supplier;
 import jdk.internal.jline.console.history.FileHistory;
 import jdk.internal.jline.console.history.History;
 import jdk.nashorn.api.scripting.AbstractJSObject;
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.internal.runtime.JSType;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 
 /*
@@ -46,15 +53,51 @@
         final HashSet<String> s = new HashSet<>();
         s.add("clear");
         s.add("forEach");
+        s.add("load");
         s.add("print");
+        s.add("save");
         s.add("size");
+        s.add("toString");
         props = Collections.unmodifiableSet(s);
     }
 
     private final FileHistory hist;
+    private final PrintWriter err;
+    private final Consumer<String> evaluator;
 
-    HistoryObject(final FileHistory hist) {
+    HistoryObject(final FileHistory hist, final PrintWriter err,
+            final Consumer<String> evaluator) {
         this.hist = hist;
+        this.err = err;
+        this.evaluator = evaluator;
+    }
+
+    @Override
+    public boolean isFunction() {
+        return true;
+    }
+
+    @Override
+    public Object call(final Object thiz, final Object... args) {
+        if (args.length > 0) {
+            int index = JSType.toInteger(args[0]);
+            if (index < 0) {
+                index += (hist.size() - 1);
+            } else {
+                index--;
+            }
+
+            if (index >= 0 && index < (hist.size() - 1)) {
+                final CharSequence src = hist.get(index);
+                hist.replace(src);
+                err.println(src);
+                evaluator.accept(src.toString());
+            } else {
+                hist.removeLast();
+                err.println("no history entry @ " + (index + 1));
+            }
+        }
+        return UNDEFINED;
     }
 
     @Override
@@ -64,10 +107,16 @@
                 return (Runnable)hist::clear;
             case "forEach":
                 return (Function<JSObject, Object>)this::iterate;
+            case "load":
+                return (Consumer<Object>)this::load;
             case "print":
                 return (Runnable)this::print;
+            case "save":
+                return (Consumer<Object>)this::save;
             case "size":
                 return hist.size();
+            case "toString":
+                return (Supplier<String>)this::toString;
         }
         return UNDEFINED;
     }
@@ -82,7 +131,11 @@
 
     @Override
     public String toString() {
-        return "[object history]";
+        final StringBuilder buf = new StringBuilder();
+        for (History.Entry e : hist) {
+            buf.append(e.value()).append('\n');
+        }
+        return buf.toString();
     }
 
     @Override
@@ -90,9 +143,32 @@
         return props;
     }
 
+    private void save(final Object obj) {
+        final File file = getFile(obj);
+        try (final PrintWriter pw = new PrintWriter(file)) {
+            for (History.Entry e : hist) {
+                pw.println(e.value());
+            }
+        } catch (final IOException exp) {
+            throw new RuntimeException(exp);
+        }
+    }
+
+    private void load(final Object obj) {
+        final File file = getFile(obj);
+        String item = null;
+        try (final BufferedReader r = new BufferedReader(new FileReader(file))) {
+            while ((item = r.readLine()) != null) {
+                hist.add(item);
+            }
+        } catch (final IOException exp) {
+            throw new RuntimeException(exp);
+        }
+    }
+
     private void print() {
         for (History.Entry e : hist) {
-            System.out.println(e.value());
+            System.out.printf("%3d %s\n", e.index() + 1, e.value());
         }
     }
 
@@ -104,4 +180,17 @@
         }
         return UNDEFINED;
     }
+
+    private static File getFile(final Object obj) {
+        File file = null;
+        if (obj instanceof String) {
+            file = new File((String)obj);
+        } else if (obj instanceof File) {
+            file = (File)obj;
+        } else {
+            throw typeError("not.a.file", JSType.toString(obj));
+        }
+
+        return file;
+    }
 }
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/Main.java	Thu Aug 27 13:22:30 2015 -0700
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.tools.jjs;
 
+import java.awt.GraphicsEnvironment;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStream;
@@ -32,12 +33,14 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.util.function.Consumer;
 import jdk.internal.jline.console.completer.Completer;
 import jdk.internal.jline.console.UserInterruptException;
 import jdk.nashorn.api.scripting.NashornException;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.tools.Shell;
@@ -48,6 +51,9 @@
 public final class Main extends Shell {
     private Main() {}
 
+    static final boolean DEBUG = Boolean.getBoolean("nashorn.jjs.debug");
+    static final boolean HEADLESS = GraphicsEnvironment.isHeadless();
+
     // file where history is persisted.
     private static final File HIST_FILE = new File(new File(System.getProperty("user.home")), ".jjs.history");
 
@@ -96,10 +102,12 @@
     protected int readEvalPrint(final Context context, final Global global) {
         final ScriptEnvironment env = context.getEnv();
         final String prompt = bundle.getString("shell.prompt");
+        final String prompt2 = bundle.getString("shell.prompt2");
         final PrintWriter err = context.getErr();
         final Global oldGlobal = Context.getGlobal();
         final boolean globalChanged = (oldGlobal != global);
-        final Completer completer = new NashornCompleter(context, global, this);
+        final PropertiesHelper propsHelper = new PropertiesHelper(env._classpath);
+        final NashornCompleter completer = new NashornCompleter(context, global, this, propsHelper);
 
         try (final Console in = new Console(System.in, System.out, HIST_FILE, completer)) {
             if (globalChanged) {
@@ -107,8 +115,30 @@
             }
 
             global.addShellBuiltins();
-            // expose history object for reflecting on command line history
-            global.put("history", new HistoryObject(in.getHistory()), false);
+
+            if (System.getSecurityManager() == null) {
+                final Consumer<String> evaluator = str -> {
+                    // could be called from different thread (GUI), we need to handle Context set/reset
+                    final Global _oldGlobal = Context.getGlobal();
+                    final boolean _globalChanged = (oldGlobal != global);
+                    if (_globalChanged) {
+                        Context.setGlobal(global);
+                    }
+                    try {
+                        evalImpl(context, global, str, err, env._dump_on_error);
+                    } finally {
+                        if (_globalChanged) {
+                            Context.setGlobal(_oldGlobal);
+                        }
+                    }
+                };
+
+                // expose history object for reflecting on command line history
+                global.addOwnProperty("history", Property.NOT_ENUMERABLE, new HistoryObject(in.getHistory(), err, evaluator));
+
+                // 'edit' command
+                global.addOwnProperty("edit", Property.NOT_ENUMERABLE, new EditObject(in, err::println, evaluator));
+            }
 
             while (true) {
                 String source = "";
@@ -133,10 +163,25 @@
                     if (res != ScriptRuntime.UNDEFINED) {
                         err.println(JSType.toString(res));
                     }
-                } catch (final Exception e) {
-                    err.println(e);
-                    if (env._dump_on_error) {
-                        e.printStackTrace(err);
+                } catch (final Exception exp) {
+                    // Is this a ECMAScript SyntaxError at last column (of the single line)?
+                    // If so, it is because parser expected more input but got EOF. Try to
+                    // to more lines from the user (multiline edit support).
+
+                    if (completer.isSyntaxErrorAt(exp, 1, source.length())) {
+                        final String fullSrc = completer.readMoreLines(source, exp, in, prompt2, err);
+
+                        // check if we succeeded in getting complete code.
+                        if (fullSrc != null && !fullSrc.isEmpty()) {
+                            evalImpl(context, global, fullSrc, err, env._dump_on_error);
+                        } // else ignore, error reported already by 'completer.readMoreLines'
+                    } else {
+
+                        // can't read more lines to have parseable/complete code.
+                        err.println(exp);
+                        if (env._dump_on_error) {
+                            exp.printStackTrace(err);
+                        }
                     }
                 }
             }
@@ -149,8 +194,34 @@
             if (globalChanged) {
                 Context.setGlobal(oldGlobal);
             }
+            try {
+                propsHelper.close();
+            } catch (final Exception exp) {
+                if (DEBUG) {
+                    exp.printStackTrace();
+                }
+            }
         }
 
         return SUCCESS;
     }
+
+    static String getMessage(final String id) {
+        return bundle.getString(id);
+    }
+
+    private void evalImpl(final Context context, final Global global, final String source,
+            final PrintWriter err, final boolean doe) {
+        try {
+            final Object res = context.eval(global, source, global, "<shell>");
+            if (res != ScriptRuntime.UNDEFINED) {
+                err.println(JSType.toString(res));
+            }
+        } catch (final Exception e) {
+            err.println(e);
+            if (doe) {
+                e.printStackTrace(err);
+            }
+        }
+    }
 }
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/NashornCompleter.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/NashornCompleter.java	Thu Aug 27 13:22:30 2015 -0700
@@ -25,9 +25,18 @@
 
 package jdk.nashorn.tools.jjs;
 
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
 import java.util.regex.Pattern;
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.SwingUtilities;
 import jdk.internal.jline.console.completer.Completer;
+import jdk.internal.jline.console.UserInterruptException;
 import jdk.nashorn.api.tree.AssignmentTree;
 import jdk.nashorn.api.tree.BinaryTree;
 import jdk.nashorn.api.tree.CompilationUnitTree;
@@ -46,28 +55,143 @@
 import jdk.nashorn.api.tree.Parser;
 import jdk.nashorn.api.scripting.NashornException;
 import jdk.nashorn.tools.PartialParser;
+import jdk.nashorn.internal.objects.NativeSyntaxError;
 import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.runtime.ECMAException;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
-// A simple source completer for nashorn
+/**
+ * A simple source completer for nashorn. Handles code completion for
+ * expressions as well as handles incomplete single line code.
+ */
 final class NashornCompleter implements Completer {
     private final Context context;
     private final Global global;
+    private final ScriptEnvironment env;
     private final PartialParser partialParser;
+    private final PropertiesHelper propsHelper;
     private final Parser parser;
+    private static final boolean BACKSLASH_FILE_SEPARATOR = File.separatorChar == '\\';
 
-    NashornCompleter(final Context context, final Global global, final PartialParser partialParser) {
+    NashornCompleter(final Context context, final Global global,
+            final PartialParser partialParser, final PropertiesHelper propsHelper) {
         this.context = context;
         this.global = global;
+        this.env = context.getEnv();
         this.partialParser = partialParser;
-        this.parser = Parser.create();
+        this.propsHelper = propsHelper;
+        this.parser = createParser(env);
+    }
+
+
+    /**
+     * Is this a ECMAScript SyntaxError thrown for parse issue at the given line and column?
+     *
+     * @param exp Throwable to check
+     * @param line line number to check
+     * @param column column number to check
+     *
+     * @return true if the given Throwable is a ECMAScript SyntaxError at given line, column
+     */
+    boolean isSyntaxErrorAt(final Throwable exp, final int line, final int column) {
+        if (exp instanceof ECMAException) {
+            final ECMAException eexp = (ECMAException)exp;
+            if (eexp.getThrown() instanceof NativeSyntaxError) {
+                return isParseErrorAt(eexp.getCause(), line, column);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Is this a parse error at the given line and column?
+     *
+     * @param exp Throwable to check
+     * @param line line number to check
+     * @param column column number to check
+     *
+     * @return true if the given Throwable is a parser error at given line, column
+     */
+    boolean isParseErrorAt(final Throwable exp, final int line, final int column) {
+        if (exp instanceof NashornException) {
+            final NashornException nexp = (NashornException)exp;
+            return nexp.getLineNumber() == line && nexp.getColumnNumber() == column;
+        }
+        return false;
+    }
+
+
+    /**
+     * Read more lines of code if we got SyntaxError at EOF and we can it fine by
+     * by reading more lines of code from the user. This is used for multiline editing.
+     *
+     * @param firstLine First line of code from the user
+     * @param exp       Exception thrown by evaluting first line code
+     * @param in        Console to get read more lines from the user
+     * @param prompt    Prompt to be printed to read more lines from the user
+     * @param err       PrintWriter to print any errors in the proecess of reading
+     *
+     * @return Complete code read from the user including the first line. This is null
+     *         if any error or the user discarded multiline editing by Ctrl-C.
+     */
+    String readMoreLines(final String firstLine, final Exception exp, final Console in,
+            final String prompt, final PrintWriter err) {
+        int line = 1;
+        final StringBuilder buf = new StringBuilder(firstLine);
+        while (true) {
+            buf.append('\n');
+            String curLine = null;
+            try {
+                curLine = in.readLine(prompt);
+                buf.append(curLine);
+                line++;
+            } catch (final Throwable th) {
+                if (th instanceof UserInterruptException) {
+                    // Ctrl-C from user - discard the whole thing silently!
+                    return null;
+                } else {
+                    // print anything else -- but still discard the code
+                    err.println(th);
+                    if (env._dump_on_error) {
+                        th.printStackTrace(err);
+                    }
+                    return null;
+                }
+            }
+
+            final String allLines = buf.toString();
+            try {
+                parser.parse("<shell>", allLines, null);
+            } catch (final Exception pexp) {
+                // Do we have a parse error at the end of current line?
+                // If so, read more lines from the console.
+                if (isParseErrorAt(pexp, line, curLine.length())) {
+                    continue;
+                } else {
+                    // print anything else and bail out!
+                    err.println(pexp);
+                    if (env._dump_on_error) {
+                        pexp.printStackTrace(err);
+                    }
+                    return null;
+                }
+            }
+
+            // We have complete parseable code!
+            return buf.toString();
+        }
     }
 
     // Pattern to match a unfinished member selection expression. object part and "."
     // but property name missing pattern.
     private static final Pattern SELECT_PROP_MISSING = Pattern.compile(".*\\.\\s*");
 
+    // Pattern to match load call
+    private static final Pattern LOAD_CALL = Pattern.compile("\\s*load\\s*\\(\\s*");
+
     @Override
     public int complete(final String test, final int cursor, final List<CharSequence> result) {
         // check that cursor is at the end of test string. Do not complete in the middle!
@@ -96,6 +220,19 @@
 
         final ExpressionTree topExpr = getTopLevelExpression(parser, completeExpr);
         if (topExpr == null) {
+            // special case for load call that looks like "load(" with optional whitespaces
+            if (LOAD_CALL.matcher(test).matches()) {
+                String name = readFileName(context.getErr());
+                if (name != null) {
+                    // handle '\' file separator
+                    if (BACKSLASH_FILE_SEPARATOR) {
+                        name = name.replace("\\", "\\\\");
+                    }
+                    result.add("\"" + name + "\")");
+                    return cursor + name.length() + 3;
+                }
+            }
+
             // did not parse to be a top level expression, no suggestions!
             return cursor;
         }
@@ -113,6 +250,38 @@
         }
     }
 
+    // Internals only below this point
+
+    // read file name from the user using by showing a swing file chooser diablog
+    private static String readFileName(final PrintWriter err) {
+        // if running on AWT Headless mode, don't attempt swing dialog box!
+        if (Main.HEADLESS) {
+            return null;
+        }
+
+        final FutureTask<String> fileChooserTask = new FutureTask<String>(() -> {
+            // show a file chooser dialog box
+            final JFileChooser chooser = new JFileChooser();
+            chooser.setFileFilter(new FileNameExtensionFilter("JavaScript Files", "js"));
+            final int retVal = chooser.showOpenDialog(null);
+            return retVal == JFileChooser.APPROVE_OPTION ?
+                chooser.getSelectedFile().getAbsolutePath() : null;
+        });
+
+        SwingUtilities.invokeLater(fileChooserTask);
+
+        try {
+            return fileChooserTask.get();
+        } catch (final ExecutionException | InterruptedException e) {
+            err.println(e);
+            if (Main.DEBUG) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    // fill properties of the incomplete member expression
     private int completeMemberSelect(final String exprStr, final int cursor, final List<CharSequence> result,
                 final MemberSelectTree select, final boolean endsWithDot) {
         final ExpressionTree objExpr = select.getExpression();
@@ -122,19 +291,22 @@
         Object obj = null;
         try {
             obj = context.eval(global, objExprCode, global, "<suggestions>");
-        } catch (Exception ignored) {
-            // throw the exception - this is during tab-completion
+        } catch (Exception exp) {
+            // throw away the exception - this is during tab-completion
+            if (Main.DEBUG) {
+                exp.printStackTrace();
+            }
         }
 
         if (obj != null && obj != ScriptRuntime.UNDEFINED) {
             if (endsWithDot) {
                 // no user specified "prefix". List all properties of the object
-                result.addAll(PropertiesHelper.getProperties(obj));
+                result.addAll(propsHelper.getProperties(obj));
                 return cursor;
             } else {
                 // list of properties matching the user specified prefix
                 final String prefix = select.getIdentifier();
-                result.addAll(PropertiesHelper.getProperties(obj, prefix));
+                result.addAll(propsHelper.getProperties(obj, prefix));
                 return cursor - prefix.length();
             }
         }
@@ -142,10 +314,11 @@
         return cursor;
     }
 
+    // fill properties for the given (partial) identifer
     private int completeIdentifier(final String test, final int cursor, final List<CharSequence> result,
                 final IdentifierTree ident) {
         final String name = ident.getName();
-        result.addAll(PropertiesHelper.getProperties(global, name));
+        result.addAll(propsHelper.getProperties(global, name));
         return cursor - name.length();
     }
 
@@ -169,6 +342,7 @@
         return null;
     }
 
+    // get the right most expreesion of the given expression
     private Tree getRightMostExpression(final ExpressionTree expr) {
         return expr.accept(new SimpleTreeVisitorES5_1<Tree, Void>() {
             @Override
@@ -228,4 +402,27 @@
             }
         }, null);
     }
+
+    // create a Parser instance that uses compatible command line options of the
+    // current ScriptEnvironment being used for REPL.
+    private static Parser createParser(final ScriptEnvironment env) {
+        final List<String> args = new ArrayList<>();
+        if (env._const_as_var) {
+            args.add("--const-as-var");
+        }
+
+        if (env._no_syntax_extensions) {
+            args.add("-nse");
+        }
+
+        if (env._scripting) {
+            args.add("-scripting");
+        }
+
+        if (env._strict) {
+            args.add("-strict");
+        }
+
+        return Parser.create(args.toArray(new String[0]));
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/PackagesHelper.java	Thu Aug 27 13:22:30 2015 -0700
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.tools.jjs;
+
+import java.io.IOException;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+/**
+ * A helper class to compute properties of a Java package object. Properties of
+ * package object are (simple) top level class names in that java package and
+ * immediate subpackages of that package.
+ */
+final class PackagesHelper {
+    // JavaCompiler may be null on certain platforms (eg. JRE)
+    private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+
+    /**
+     * Is Java package properties helper available?
+     *
+     * @return true if package properties support is available
+     */
+    static boolean isAvailable() {
+        return compiler != null;
+    }
+
+    private final StandardJavaFileManager fm;
+    private final Set<JavaFileObject.Kind> fileKinds;
+
+    /**
+     * Construct a new PackagesHelper.
+     *
+     * @param classPath Class path to compute properties of java package objects
+     */
+    PackagesHelper(final String classPath) throws IOException {
+        assert isAvailable() : "no java compiler found!";
+
+        fm = compiler.getStandardFileManager(null, null, null);
+        fileKinds = EnumSet.of(JavaFileObject.Kind.CLASS);
+
+        if (classPath != null && !classPath.isEmpty()) {
+            fm.setLocation(StandardLocation.CLASS_PATH, getFiles(classPath));
+        } else {
+            // no classpath set. Make sure that it is empty and not any default like "."
+            fm.setLocation(StandardLocation.CLASS_PATH, Collections.<File>emptyList());
+        }
+    }
+
+    // LRU cache for java package properties lists
+    private final LinkedHashMap<String, List<String>> propsCache =
+        new LinkedHashMap<String, List<String>>(32, 0.75f, true) {
+            private static final int CACHE_SIZE = 100;
+            private static final long serialVersionUID = 1;
+
+            @Override
+            protected boolean removeEldestEntry(final Map.Entry<String, List<String>> eldest) {
+                return size() > CACHE_SIZE;
+            }
+        };
+
+    /**
+     * Return the list of properties of the given Java package or package prefix
+     *
+     * @param pkg Java package name or package prefix name
+     * @return the list of properties of the given Java package or package prefix
+     */
+    List<String> getPackageProperties(final String pkg) {
+        // check the cache first
+        if (propsCache.containsKey(pkg)) {
+            return propsCache.get(pkg);
+        }
+
+        try {
+            // make sorted list of properties
+            final List<String> props = new ArrayList<>(listPackage(pkg));
+            Collections.sort(props);
+            propsCache.put(pkg, props);
+            return props;
+        } catch (final IOException exp) {
+            if (Main.DEBUG) {
+                exp.printStackTrace();
+            }
+            return Collections.<String>emptyList();
+        }
+    }
+
+    public void close() throws IOException {
+        fm.close();
+    }
+
+    private Set<String> listPackage(final String pkg) throws IOException {
+        final Set<String> props = new HashSet<>();
+        listPackage(StandardLocation.PLATFORM_CLASS_PATH, pkg, props);
+        listPackage(StandardLocation.CLASS_PATH, pkg, props);
+        return props;
+    }
+
+    private void listPackage(final Location loc, final String pkg, final Set<String> props)
+            throws IOException {
+        for (JavaFileObject file : fm.list(loc, pkg, fileKinds, true)) {
+            final String binaryName = fm.inferBinaryName(loc, file);
+            // does not start with the given package prefix
+            if (!binaryName.startsWith(pkg + ".")) {
+                continue;
+            }
+
+            final int nextDot = binaryName.indexOf('.', pkg.length() + 1);
+            final int start = pkg.length() + 1;
+
+            if (nextDot != -1) {
+                // subpackage - eg. "regex" for "java.util"
+                props.add(binaryName.substring(start, nextDot));
+            } else {
+                // class - filter out nested, inner, anonymous, local classes.
+                // Dynalink supported public nested classes as properties of
+                // StaticClass object anyway. We don't want to expose those
+                // "$" internal names as properties of package object.
+
+                final String clsName = binaryName.substring(start);
+                if (clsName.indexOf('$') == -1) {
+                    props.add(clsName);
+                }
+            }
+        }
+    }
+
+    // return list of File objects for the given class path
+    private static List<File> getFiles(final String classPath) {
+        return Stream.of(classPath.split(File.pathSeparator))
+                    .map(File::new)
+                    .collect(Collectors.toList());
+    }
+}
--- a/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/PropertiesHelper.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn.shell/share/classes/jdk/nashorn/tools/jjs/PropertiesHelper.java	Thu Aug 27 13:22:30 2015 -0700
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.tools.jjs;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -32,6 +33,7 @@
 import java.util.WeakHashMap;
 import java.util.stream.Collectors;
 import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.NativeJavaPackage;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
@@ -41,19 +43,59 @@
  * A helper class to get properties of a given object for source code completion.
  */
 final class PropertiesHelper {
-    private PropertiesHelper() {}
+    // Java package properties helper, may be null
+    private PackagesHelper pkgsHelper;
+    // cached properties list
+    private final WeakHashMap<Object, List<String>> propsCache = new WeakHashMap<>();
 
-    // cached properties list
-    private static final WeakHashMap<Object, List<String>> propsCache = new WeakHashMap<>();
+    /**
+     * Construct a new PropertiesHelper.
+     *
+     * @param classPath Class path to compute properties of java package objects
+     */
+    PropertiesHelper(final String classPath) {
+        if (PackagesHelper.isAvailable()) {
+            try {
+                this.pkgsHelper = new PackagesHelper(classPath);
+            } catch (final IOException exp) {
+                if (Main.DEBUG) {
+                    exp.printStackTrace();
+                }
+                this.pkgsHelper = null;
+            }
+        }
+    }
 
-    // returns the list of properties of the given object
-    static List<String> getProperties(final Object obj) {
+    void close() throws Exception {
+        propsCache.clear();
+        pkgsHelper.close();
+    }
+
+    /**
+     * returns the list of properties of the given object.
+     *
+     * @param obj object whose property list is returned
+     * @return the list of properties of the given object
+     */
+    List<String> getProperties(final Object obj) {
         assert obj != null && obj != ScriptRuntime.UNDEFINED;
 
+        // wrap JS primitives as objects before gettting properties
         if (JSType.isPrimitive(obj)) {
             return getProperties(JSType.toScriptObject(obj));
         }
 
+        // Handle Java package prefix case first. Should do it before checking
+        // for its super class ScriptObject!
+        if (obj instanceof NativeJavaPackage) {
+            if (pkgsHelper != null) {
+                return pkgsHelper.getPackageProperties(((NativeJavaPackage)obj).getName());
+            } else {
+                return Collections.<String>emptyList();
+            }
+        }
+
+        // script object - all inherited and non-enumerable, non-index properties
         if (obj instanceof ScriptObject) {
             final ScriptObject sobj = (ScriptObject)obj;
             final PropertyMap pmap = sobj.getMap();
@@ -71,6 +113,7 @@
             return props;
         }
 
+        // java class case - don't refer to StaticClass directly
         if (NativeJava.isType(ScriptRuntime.UNDEFINED, obj)) {
             if (propsCache.containsKey(obj)) {
                 return propsCache.get(obj);
@@ -82,6 +125,7 @@
             return props;
         }
 
+        // any other Java object
         final Class<?> clazz = obj.getClass();
         if (propsCache.containsKey(clazz)) {
             return propsCache.get(clazz);
@@ -94,8 +138,14 @@
         return props;
     }
 
-    // returns the list of properties of the given object that start with the given prefix
-    static List<String> getProperties(final Object obj, final String prefix) {
+    /**
+     * Returns the list of properties of the given object that start with the given prefix.
+     *
+     * @param obj object whose property list is returned
+     * @param prefix property prefix to be matched
+     * @return the list of properties of the given object
+     */
+    List<String> getProperties(final Object obj, final String prefix) {
         assert prefix != null && !prefix.isEmpty();
         return getProperties(obj).stream()
                    .filter(s -> s.startsWith(prefix))
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Aug 27 13:22:30 2015 -0700
@@ -249,7 +249,7 @@
     private final Set<String> emittedMethods = new HashSet<>();
 
     // Function Id -> ContinuationInfo. Used by compilation of rest-of function only.
-    private final Map<Integer, ContinuationInfo> fnIdToContinuationInfo = new HashMap<>();
+    private ContinuationInfo continuationInfo;
 
     private final Deque<Label> scopeEntryLabels = new ArrayDeque<>();
 
@@ -349,11 +349,20 @@
         final int flags = getScopeCallSiteFlags(symbol);
         if (isFastScope(symbol)) {
             // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope.
-            if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD && !isOptimisticOrRestOf()) {
-                method.loadCompilerConstant(SCOPE);
-                // As shared scope vars are only used in non-optimistic compilation, we switch from using TypeBounds to
+            if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD && !identNode.isOptimistic()) {
+                // As shared scope vars are only used with non-optimistic identifiers, we switch from using TypeBounds to
                 // just a single definitive type, resultBounds.widest.
-                loadSharedScopeVar(resultBounds.widest, symbol, flags);
+                new OptimisticOperation(identNode, TypeBounds.OBJECT) {
+                    @Override
+                    void loadStack() {
+                        method.loadCompilerConstant(SCOPE);
+                    }
+
+                    @Override
+                    void consumeStack() {
+                        loadSharedScopeVar(resultBounds.widest, symbol, flags);
+                    }
+                }.emit();
             } else {
                 new LoadFastScopeVar(identNode, resultBounds, flags).emit();
             }
@@ -384,10 +393,6 @@
         return continuationEntryPoints != null;
     }
 
-    private boolean isOptimisticOrRestOf() {
-        return useOptimisticTypes() || isRestOf();
-    }
-
     private boolean isCurrentContinuationEntryPoint(final int programPoint) {
         return isRestOf() && getCurrentContinuationEntryPoint() == programPoint;
     }
@@ -464,12 +469,8 @@
     }
 
     private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) {
-        assert !isOptimisticOrRestOf();
-        if (isFastScope(symbol)) {
-            method.load(getScopeProtoDepth(lc.getCurrentBlock(), symbol));
-        } else {
-            method.load(-1);
-        }
+        assert isFastScope(symbol);
+        method.load(getScopeProtoDepth(lc.getCurrentBlock(), symbol));
         return lc.getScopeGet(unit, symbol, valueType, flags).generateInvoke(method);
     }
 
@@ -1573,7 +1574,7 @@
                     } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
                             || !isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD
                             || CodeGenerator.this.lc.inDynamicScope()
-                            || isOptimisticOrRestOf()) {
+                            || callNode.isOptimistic()) {
                         scopeCall(node, flags);
                     } else {
                         sharedScopeCall(node, flags);
@@ -2070,8 +2071,6 @@
 
     @Override
     public boolean enterFunctionNode(final FunctionNode functionNode) {
-        final int fnId = functionNode.getId();
-
         if (skipFunction(functionNode)) {
             // In case we are not generating code for the function, we must create or retrieve the function object and
             // load it on the stack here.
@@ -2109,9 +2108,9 @@
             method.begin();
 
             if (isRestOf()) {
-                final ContinuationInfo ci = new ContinuationInfo();
-                fnIdToContinuationInfo.put(fnId, ci);
-                method.gotoLoopStart(ci.getHandlerLabel());
+                assert continuationInfo == null;
+                continuationInfo = new ContinuationInfo();
+                method.gotoLoopStart(continuationInfo.getHandlerLabel());
             }
         }
 
@@ -5308,7 +5307,7 @@
     }
 
     private ContinuationInfo getContinuationInfo() {
-        return fnIdToContinuationInfo.get(lc.getCurrentFunction().getId());
+        return continuationInfo;
     }
 
     private void generateContinuationHandler() {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Thu Aug 27 13:22:30 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1451,9 +1451,22 @@
                 skip(3);
             }
 
-            // Scan identifier.
+            // Scan identifier. It might be quoted, indicating that no string editing should take place.
+            final char quoteChar = ch0;
+            final boolean noStringEditing = quoteChar == '"' || quoteChar == '\'';
+            if (noStringEditing) {
+                skip(1);
+            }
             final int identStart = position;
             final int identLength = scanIdentifier();
+            if (noStringEditing) {
+                if (ch0 != quoteChar) {
+                    error(Lexer.message("here.non.matching.delimiter"), last, position, position);
+                    restoreState(saved);
+                    return false;
+                }
+                skip(1);
+            }
 
             // Check for identifier.
             if (identLength == 0) {
@@ -1523,7 +1536,7 @@
             }
 
             // Edit string if appropriate.
-            if (scripting && !stringState.isEmpty()) {
+            if (!noStringEditing && !stringState.isEmpty()) {
                 editString(STRING, stringState);
             } else {
                 // Add here string.
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Thu Aug 27 13:22:30 2015 -0700
@@ -46,6 +46,11 @@
  * and output and error writers, top level Namespace etc.
  */
 public final class ScriptEnvironment {
+    // Primarily intended to be used in test environments so that eager compilation tests work without an
+    // error when tested with optimistic compilation.
+    private static final boolean ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE = Options.getBooleanProperty(
+            "nashorn.options.allowEagerCompilationSilentOverride", false);
+
     /** Output writer for this environment */
     private final PrintWriter out;
 
@@ -61,6 +66,9 @@
     /** Size of the per-global Class cache size */
     public final int     _class_cache_size;
 
+    /** -classpath value. */
+    public final String  _classpath;
+
     /** Only compile script, do not run it or generate other ScriptObjects */
     public final boolean _compile_only;
 
@@ -220,6 +228,7 @@
         this.options = options;
 
         _class_cache_size     = options.getInteger("class.cache.size");
+        _classpath            = options.getString("classpath");
         _compile_only         = options.getBoolean("compile.only");
         _const_as_var         = options.getBoolean("const.as.var");
         _debug_lines          = options.getBoolean("debug.lines");
@@ -237,8 +246,20 @@
         }
         _fx                   = options.getBoolean("fx");
         _global_per_engine    = options.getBoolean("global.per.engine");
-        _lazy_compilation     = options.getBoolean("lazy.compilation");
         _optimistic_types     = options.getBoolean("optimistic.types");
+        final boolean lazy_compilation = options.getBoolean("lazy.compilation");
+        if (!lazy_compilation && _optimistic_types) {
+            if (!ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE) {
+                throw new IllegalStateException(
+                        ECMAErrors.getMessage(
+                                "config.error.eagerCompilationConflictsWithOptimisticTypes",
+                                options.getOptionTemplateByKey("lazy.compilation").getName(),
+                                options.getOptionTemplateByKey("optimistic.types").getName()));
+            }
+            _lazy_compilation = true;
+        } else {
+            _lazy_compilation = lazy_compilation;
+        }
         _loader_per_compile   = options.getBoolean("loader.per.compile");
         _no_java              = options.getBoolean("no.java");
         _no_syntax_extensions = options.getBoolean("no.syntax.extensions");
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java	Thu Aug 27 13:22:30 2015 -0700
@@ -28,12 +28,14 @@
 import java.io.IOException;
 import java.io.StringReader;
 import java.util.ArrayList;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.LongAdder;
+import java.util.function.Function;
 import java.util.function.Supplier;
-
 import jdk.nashorn.internal.codegen.CompileUnit;
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
 import jdk.nashorn.internal.runtime.logging.Loggable;
@@ -156,11 +158,12 @@
     }
 
     final class TimeSupplier implements Supplier<String> {
-        private final Map<String, Long> timings;
-
-        TimeSupplier() {
-            timings   = new LinkedHashMap<>();
-        }
+        private final Map<String, LongAdder> timings = new ConcurrentHashMap<>();
+        private final LinkedBlockingQueue<String> orderedTimingNames = new LinkedBlockingQueue<>();
+        private final Function<String, LongAdder> newTimingCreator = s -> {
+            orderedTimingNames.add(s);
+            return new LongAdder();
+        };
 
         String[] getStrings() {
             final List<String> strs = new ArrayList<>();
@@ -184,26 +187,26 @@
             int  maxKeyLength = 0;
             int  maxValueLength = 0;
 
-            for (final Map.Entry<String, Long> entry : timings.entrySet()) {
+            for (final Map.Entry<String, LongAdder> entry : timings.entrySet()) {
                 maxKeyLength   = Math.max(maxKeyLength, entry.getKey().length());
-                maxValueLength = Math.max(maxValueLength, toMillisPrint(entry.getValue()).length());
+                maxValueLength = Math.max(maxValueLength, toMillisPrint(entry.getValue().longValue()).length());
             }
             maxKeyLength++;
 
             final StringBuilder sb = new StringBuilder();
             sb.append("Accumulated compilation phase timings:\n\n");
-            for (final Map.Entry<String, Long> entry : timings.entrySet()) {
+            for (final String timingName: orderedTimingNames) {
                 int len;
 
                 len = sb.length();
-                sb.append(entry.getKey());
+                sb.append(timingName);
                 len = sb.length() - len;
 
                 while (len++ < maxKeyLength) {
                     sb.append(' ');
                 }
 
-                final Long duration = entry.getValue();
+                final long duration = timings.get(timingName).longValue();
                 final String strDuration = toMillisPrint(duration);
                 len = strDuration.length();
                 for (int i = 0; i < maxValueLength - len; i++) {
@@ -233,11 +236,7 @@
         }
 
         private void accumulateTime(final String module, final long duration) {
-            Long accumulatedTime = timings.get(module);
-            if (accumulatedTime == null) {
-                accumulatedTime = 0L;
-            }
-            timings.put(module, accumulatedTime + duration);
+            timings.computeIfAbsent(module, newTimingCreator).add(duration);
         }
     }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java	Thu Aug 27 13:22:30 2015 -0700
@@ -24,7 +24,6 @@
  */
 
 package jdk.nashorn.internal.runtime;
-
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
@@ -34,6 +33,7 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.util.concurrent.Callable;
 import jdk.nashorn.internal.lookup.Lookup;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@@ -80,6 +80,15 @@
     private final static MethodHandle INVOKE_LONG_SETTER = findOwnMH_S("invokeLongSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, long.class);
     private final static MethodHandle INVOKE_NUMBER_SETTER = findOwnMH_S("invokeNumberSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, double.class);
 
+    private static final Object OBJECT_GETTER_INVOKER_KEY = new Object();
+    private static MethodHandle getObjectGetterInvoker() {
+        return Context.getGlobal().getDynamicInvoker(OBJECT_GETTER_INVOKER_KEY, new Callable<MethodHandle>() {
+            @Override
+            public MethodHandle call() throws Exception {
+                return getINVOKE_UA_GETTER(Object.class, INVALID_PROGRAM_POINT);
+            }
+        });
+    }
 
     static MethodHandle getINVOKE_UA_GETTER(final Class<?> returnType, final int programPoint) {
         if (UnwarrantedOptimismException.isValid(programPoint)) {
@@ -90,6 +99,16 @@
         }
     }
 
+    private static final Object OBJECT_SETTER_INVOKER_KEY = new Object();
+    private static MethodHandle getObjectSetterInvoker() {
+        return Context.getGlobal().getDynamicInvoker(OBJECT_SETTER_INVOKER_KEY, new Callable<MethodHandle>() {
+            @Override
+            public MethodHandle call() throws Exception {
+                return getINVOKE_UA_SETTER(Object.class);
+            }
+        });
+    }
+
     static MethodHandle getINVOKE_UA_SETTER(final Class<?> valueType) {
         return Bootstrap.createDynamicInvoker("dyn:call", void.class, Object.class, Object.class, valueType);
     }
@@ -181,7 +200,7 @@
     @Override
     public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
         try {
-            return invokeObjectGetter(getAccessors((owner != null) ? owner : self), getINVOKE_UA_GETTER(Object.class, INVALID_PROGRAM_POINT), self);
+            return invokeObjectGetter(getAccessors((owner != null) ? owner : self), getObjectGetterInvoker(), self);
         } catch (final Error | RuntimeException t) {
             throw t;
         } catch (final Throwable t) {
@@ -207,7 +226,7 @@
     @Override
     public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
         try {
-            invokeObjectSetter(getAccessors((owner != null) ? owner : self), getINVOKE_UA_SETTER(Object.class), strict ? getKey() : null, self, value);
+            invokeObjectSetter(getAccessors((owner != null) ? owner : self), getObjectSetterInvoker(), strict ? getKey() : null, self, value);
         } catch (final Error | RuntimeException t) {
             throw t;
         } catch (final Throwable t) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/options/OptionTemplate.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/options/OptionTemplate.java	Thu Aug 27 13:22:30 2015 -0700
@@ -304,8 +304,8 @@
         }
     }
 
-    boolean matches(final String key0) {
-        return key0.equals(this.shortName) || key0.equals(this.name);
+    boolean nameMatches(final String aName) {
+        return aName.equals(this.shortName) || aName.equals(this.name);
     }
 
     private static final int LINE_BREAK = 64;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/options/Options.java	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/options/Options.java	Thu Aug 27 13:22:30 2015 -0700
@@ -520,9 +520,25 @@
         }
     }
 
-    private static OptionTemplate getOptionTemplate(final String key) {
+    /**
+     * Retrieves an option template identified by key.
+     * @param shortKey the short (that is without the e.g. "nashorn.option." part) key
+     * @return the option template identified by the key
+     * @throws IllegalArgumentException if the key doesn't specify an existing template
+     */
+    public OptionTemplate getOptionTemplateByKey(final String shortKey) {
+        final String fullKey = key(shortKey);
+        for(final OptionTemplate t: validOptions) {
+            if(t.getKey().equals(fullKey)) {
+                return t;
+            }
+        }
+        throw new IllegalArgumentException(shortKey);
+    }
+
+    private static OptionTemplate getOptionTemplateByName(final String name) {
         for (final OptionTemplate t : Options.validOptions) {
-            if (t.matches(key)) {
+            if (t.nameMatches(name)) {
                 return t;
             }
         }
@@ -682,7 +698,7 @@
             }
 
             final String token = st.nextToken();
-            this.template = Options.getOptionTemplate(token);
+            this.template = getOptionTemplateByName(token);
             if (this.template == null) {
                 throw new IllegalArgumentException(argument);
             }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Thu Aug 27 13:22:30 2015 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
 lexer.error.json.invalid.number=Invalid JSON number format
 lexer.error.invalid.escape.char=Invalid escape character
 lexer.error.illegal.identifier.character=Illegal character in identifier
+lexer.error.here.non.matching.delimiter=Quoted here string end marker must have matching delimiters
 
 parser.error.illegal.continue.stmt=Illegal continue statement
 parser.error.illegal.break.stmt=Illegal break statement
@@ -172,7 +173,9 @@
 syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement
 
 io.error.cant.write=cannot write "{0}"
+
 config.error.no.dest=no destination directory supplied
+config.error.eagerCompilationConflictsWithOptimisticTypes={0}=false (eager compilation) is not compatible with {1}=true.
 
 uri.error.bad.uri=Bad URI "{0}" near offset {1}
 list.adapter.null.global=Attempted to create the adapter from outside a JavaScript execution context.
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/resources/Shell.properties	Thu Aug 27 12:59:56 2015 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/resources/Shell.properties	Thu Aug 27 13:22:30 2015 -0700
@@ -29,4 +29,6 @@
 
 shell.prompt=jjs> 
 
+shell.prompt2=...> 
 
+no.editor=AWT Headless mode set and no external editor is configured!
--- a/test/script/basic/JDK-8053905.js	Thu Aug 27 12:59:56 2015 -0700
+++ b/test/script/basic/JDK-8053905.js	Thu Aug 27 13:22:30 2015 -0700
@@ -28,6 +28,7 @@
  * @runif external.octane
  * @fork
  * @option -Dnashorn.compiler.splitter.threshold=1000
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
  * @option -scripting
  * @option --lazy-compilation=false
  */
--- a/test/script/basic/JDK-8058561.js	Thu Aug 27 12:59:56 2015 -0700
+++ b/test/script/basic/JDK-8058561.js	Thu Aug 27 13:22:30 2015 -0700
@@ -26,7 +26,9 @@
  *
  * @test
  * @run
+ * @fork
  * @option --lazy-compilation=false
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
  */
 
 // Just attempting to compile this caused the NPE
--- a/test/script/basic/JDK-8078612_eager_1a.js	Thu Aug 27 12:59:56 2015 -0700
+++ b/test/script/basic/JDK-8078612_eager_1a.js	Thu Aug 27 13:22:30 2015 -0700
@@ -29,6 +29,7 @@
  * @option -pcc
  * @option --lazy-compilation=false
  * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
  * @fork
  */
 
--- a/test/script/basic/JDK-8078612_eager_1b.js	Thu Aug 27 12:59:56 2015 -0700
+++ b/test/script/basic/JDK-8078612_eager_1b.js	Thu Aug 27 13:22:30 2015 -0700
@@ -29,6 +29,7 @@
  * @option -pcc
  * @option --lazy-compilation=false
  * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
  * @fork
  */
 
--- a/test/script/basic/JDK-8078612_eager_2a.js	Thu Aug 27 12:59:56 2015 -0700
+++ b/test/script/basic/JDK-8078612_eager_2a.js	Thu Aug 27 13:22:30 2015 -0700
@@ -29,6 +29,7 @@
  * @option -pcc
  * @option --lazy-compilation=false
  * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
  * @fork
  */
 
--- a/test/script/basic/JDK-8078612_eager_2b.js	Thu Aug 27 12:59:56 2015 -0700
+++ b/test/script/basic/JDK-8078612_eager_2b.js	Thu Aug 27 13:22:30 2015 -0700
@@ -29,6 +29,7 @@
  * @option -pcc
  * @option --lazy-compilation=false
  * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
  * @fork
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/nosecurity/JDK-8073613.js	Thu Aug 27 13:22:30 2015 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8073613: Here documents: how to avoid string interpolation?
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+var a = 2,
+    b = 3
+
+print(<<EOD)
+${a}${b}
+EOD
+
+print(<<"EOD")
+${a}${b}
+EOD
+
+print(<<'EOM')
+${a}${b}
+EOM
+
+print(<<"EOM")
+$\{a}
+EOM
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/nosecurity/JDK-8073613.js.EXPECTED	Thu Aug 27 13:22:30 2015 -0700
@@ -0,0 +1,4 @@
+23
+${a}${b}
+${a}${b}
+$\{a}