changeset 3258:844a36d83020

merge with b93
author mcimadamore
date Tue, 24 Nov 2015 00:42:53 +0000
parents e89e4eee7e7e 58525132b5b0
children 08f35559a66d
files make/build.properties src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java test/tools/javac/lambda/T8129740/Universe.java.out
diffstat 220 files changed, 29065 insertions(+), 730 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Nov 23 11:39:55 2015 +0000
+++ b/.hgtags	Tue Nov 24 00:42:53 2015 +0000
@@ -330,3 +330,9 @@
 7ef2c66892a3af15540c2800104c660c4f7f45e9 jdk9-b85
 130a7c2a85900dde04e119bc36853b73146e3414 jdk9-b86
 45f796d8cdcd8dbde5d4d660c3e749a14c923e6d jdk9-b87
+ac57d80b205db48d726084ade228e0199735831b jdk9-b88
+16873e56156e9917ad97ba5da0d0abe44fc94003 jdk9-b89
+00a25f93cee8a82096a0736716da392cafdb0cb0 jdk9-b90
+79501a97ca5720af846509f4bf3c6c04d7bdf82a jdk9-b91
+a3415b57507c928af8f2ad1c771eebafcd00c6c7 jdk9-b92
+7f880f98506c9046f8fb69597a41762ea1b7d042 jdk9-b93
--- a/make/build.properties	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/build.properties	Tue Nov 24 00:42:53 2015 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2007, 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
@@ -47,11 +47,21 @@
 boot.javac.target = 8
 
 #configuration of submodules (share by both the bootstrap and normal compilation):
-langtools.modules=java.compiler:jdk.compiler:jdk.jdeps:jdk.javadoc
+langtools.modules=java.compiler:jdk.compiler:jdk.jdeps:jdk.javadoc:jdk.jshell:jdk.internal.le:jdk.jdi
 java.compiler.dependencies=
 jdk.compiler.dependencies=java.compiler
 jdk.javadoc.dependencies=java.compiler:jdk.compiler
 jdk.jdeps.dependencies=java.compiler:jdk.compiler
+jdk.internal.le.dependencies=
+jdk.jdi.dependencies=
+jdk.jshell.dependencies=java.compiler:jdk.internal.le:jdk.compiler:jdk.jdi
+
+tool.javac.main.class=com.sun.tools.javac.Main
+tool.javadoc.main.class=com.sun.tools.javadoc.Main
+tool.javap.main.class=com.sun.tools.javap.Main
+tool.javah.main.class=com.sun.tools.javah.Main
+tool.sjavac.main.class=com.sun.tools.sjavac.Main
+tool.jshell.main.class=jdk.internal.jshell.tool.JShellTool
 
 javac.resource.includes = \
         com/sun/tools/javac/resources/compiler.properties
--- a/make/build.xml	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/build.xml	Tue Nov 24 00:42:53 2015 +0000
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2007, 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
@@ -172,6 +172,7 @@
         <build-tool name="javap"/>
         <build-tool name="javah"/>
         <build-tool name="sjavac"/>
+        <build-tool name="jshell"/>
     </target>
 
     <target name="build-all-classes" depends="-def-build-all-module-classes,build-bootstrap-javac-classes">
@@ -417,10 +418,14 @@
         <copy todir=".idea" >
             <fileset dir="make/intellij" excludes="**/src/**"/>
         </copy>
-        <condition property="jtreg.idea.home" value="${jtreg.home}" else = "[jtreg.home]">
+        <condition property="idea.jtreg.home" value="${jtreg.home}" else = "[jtreg.home]">
             <isset property="jtreg.home"/>
         </condition>
-        <replace file=".idea/ant.xml" token="@@@" value="${jtreg.idea.home}"/>
+        <condition property="idea.target.jdk" value="${target.java.home}" else = "$JDKPath$">
+            <isset property="target.java.home"/>
+        </condition>
+        <replace file=".idea/ant.xml" token="@IDEA_JTREG_HOME@" value="${idea.jtreg.home}"/>
+        <replace file=".idea/ant.xml" token="@IDEA_TARGET_JDK@" value="${idea.target.jdk}"/>
         <replace file=".idea/workspace.xml" token="@FILE_SEP@" value="${file.separator}"/>
         <replace file=".idea/workspace.xml" token="@PATH_SEP@" value="${path.separator}"/>
         <mkdir dir=".idea/classes"/>
@@ -464,6 +469,9 @@
                 <build-module-jar module.name="jdk.compiler" compilation.kind="@{compilation.kind}" />
                 <build-module-jar module.name="jdk.javadoc" compilation.kind="@{compilation.kind}" />
                 <build-module-jar module.name="jdk.jdeps" compilation.kind="@{compilation.kind}" />
+                <build-module-jar module.name="jdk.internal.le" compilation.kind="@{compilation.kind}" />
+                <build-module-jar module.name="jdk.jdi" compilation.kind="@{compilation.kind}" />
+                <build-module-jar module.name="jdk.jshell" compilation.kind="@{compilation.kind}" />
             </sequential>
         </macrodef>
     </target>
@@ -502,11 +510,12 @@
             <attribute name="compilation.kind" default=""/>
             <attribute name="bin.dir" default="${@{compilation.kind}dist.bin.dir}"/>
             <attribute name="java" default="${launcher.java}"/>
+            <attribute name="main.class" default="${tool.@{name}.main.class}"/>
             <sequential>
                 <mkdir dir="@{bin.dir}"/>
                 <copy file="${make.dir}/launcher.sh-template" tofile="@{bin.dir}/@{name}">
                     <filterset begintoken="#" endtoken="#">
-                        <filter token="PROGRAM" value="@{name}"/>
+                        <filter token="PROGRAM" value="@{main.class}"/>
                         <filter token="TARGET_JAVA" value="@{java}"/>
                         <filter token="PS" value="${path.separator}"/>
                     </filterset>
@@ -529,11 +538,17 @@
                                       compilation.kind="@{compilation.kind}" />
                 <build-module-classes module.name="jdk.jdeps"
                                       compilation.kind="@{compilation.kind}" />
+                <copy-module-classes  module.name="jdk.internal.le"
+                                      compilation.kind="@{compilation.kind}" />
+                <copy-module-classes  module.name="jdk.jdi"
+                                      compilation.kind="@{compilation.kind}" />
+                <build-module-classes module.name="jdk.jshell"
+                                      compilation.kind="@{compilation.kind}" />
             </sequential>
         </macrodef>
     </target>
 
-    <target name="-def-build-module-classes" depends="-def-pcompile,-def-pparse">
+    <target name="-def-build-module-classes" depends="-def-pcompile,-def-pparse,-def-cdumper">
         <macrodef name="build-module-classes">
             <attribute name="module.name"/>
             <attribute name="compilation.kind" default=""/>
@@ -646,6 +661,18 @@
                 </copy>
             </sequential>
         </macrodef>
+        <macrodef name="copy-module-classes">
+            <attribute name="module.name"/>
+            <attribute name="compilation.kind" default=""/>
+            <attribute name="build.dir" default="${@{compilation.kind}build.dir}"/>
+            <attribute name="classes.dir" default="@{build.dir}/@{module.name}/classes"/>
+            <attribute name="java.home" default="${boot.java.home}"/>
+            <sequential>
+                <property name="classes.origin.dir" location="${target.java.home}/../../jdk/modules/@{module.name}"/>
+                <mkdir dir="@{classes.dir}"/>
+                <dumpclasses moduleName="@{module.name}" destDir="@{classes.dir}" />
+            </sequential>
+        </macrodef>
     </target>
 
     <target name="-def-pparse">
@@ -670,6 +697,25 @@
                  classpath="${build.toolclasses.dir}/"/>
     </target>
 
+    <target name="-def-cdumper">
+        <mkdir dir="${build.toolclasses.dir}"/>
+        <javac fork="true"
+               source="${boot.javac.source}"
+               target="${boot.javac.target}"
+               executable="${boot.java.home}/bin/javac"
+               srcdir="${make.tools.dir}"
+               includes="anttasks/DumpClass*"
+               destdir="${build.toolclasses.dir}/"
+               classpath="${ant.core.lib}"
+               bootclasspath="${boot.java.home}/jre/lib/rt.jar"
+               includeantruntime="false">
+            <compilerarg line="${javac.lint.opts}"/>
+        </javac>
+        <taskdef name="dumpclasses"
+                 classname="anttasks.DumpClassesTask"
+                 classpath="${build.toolclasses.dir}/:${target.java.home}/jrt-fs.jar"/>
+    </target>
+
     <target name="-do-depend" if="do.depend">
         <depend srcdir="${src.dir}:${gensrc.dir}" destdir="${classes.dir}" classpath="${classpath}"
                 cache="${depcache.dir}"/>
--- a/make/gendata/Gendata-jdk.compiler.gmk	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/gendata/Gendata-jdk.compiler.gmk	Tue Nov 24 00:42:53 2015 +0000
@@ -23,6 +23,7 @@
 # questions.
 #
 
+include JarArchive.gmk
 include JavaCompilation.gmk
 include SetupJavaCompilers.gmk
 
@@ -52,9 +53,9 @@
 	    $(@D)
 	$(TOUCH) $@
 
-# Can't generate ct.sym directly into modules libs as the SetupArchive macro
+# Can't generate ct.sym directly into modules libs as the SetupJarArchive macro
 # creates meta data files in the output dir.
-$(eval $(call SetupArchive, CREATE_CTSYM, \
+$(eval $(call SetupJarArchive, CREATE_CTSYM, \
     DEPENDENCIES := $(SUPPORT_OUTPUTDIR)/symbols/ct.sym-files/_the.symbols, \
     SRCS := $(SUPPORT_OUTPUTDIR)/symbols/ct.sym-files, \
     SUFFIXES := .sig, \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/gensrc/Gensrc-jdk.jshell.gmk	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+include GensrcCommon.gmk
+
+$(eval $(call SetupVersionProperties,JSHELL_VERSION, \
+    jdk/internal/jshell/tool/resources/version.properties))
+
+$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
+    $(JSHELL_VERSION) $(JAVAH_VERSION)))
+
+all: $(COMPILE_PROPERTIES)
--- a/make/intellij/ant.xml	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/intellij/ant.xml	Tue Nov 24 00:42:53 2015 +0000
@@ -5,8 +5,8 @@
       <properties>
         <property name="boot.java.home" value="$JDKPath$" />
         <property name="jtreg.tests" value="$FilePath$" />
-        <property name="target.java.home" value="$JDKPath$" />
-        <property name="jtreg.home" value="@@@" />
+        <property name="target.java.home" value="@IDEA_TARGET_JDK@" />
+        <property name="jtreg.home" value="@IDEA_JTREG_HOME@" />
         <property name="javac.debuglevel" value="source,lines,vars" />
         <property name="jtreg.jpda.jvmargs" value="-agentlib:jdwp=transport=dt_socket,server=n,address=localhost:5900,suspend=y" />
       </properties>
--- a/make/intellij/langtools.iml	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/intellij/langtools.iml	Tue Nov 24 00:42:53 2015 +0000
@@ -13,6 +13,7 @@
       <sourceFolder url="file://$MODULE_DIR$/build/bootstrap/jdk.compiler/gensrc" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/build/bootstrap/jdk.javadoc/gensrc" isTestSource="false" />
       <sourceFolder url="file://$MODULE_DIR$/build/bootstrap/jdk.jdeps/gensrc" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/jdk.jshell/share/classes" isTestSource="false" />
     </content>
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="inheritedJdk" />
--- a/make/intellij/workspace.xml	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/intellij/workspace.xml	Tue Nov 24 00:42:53 2015 +0000
@@ -103,6 +103,23 @@
         <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
       </method>
     </configuration>
+    <configuration default="false" name="jshell" type="Application" factoryName="Application">
+      <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+      <option name="MAIN_CLASS_NAME" value="jdk.internal.jshell.tool.JShellTool" />
+      <option name="VM_PARAMETERS" value="-Xbootclasspath/p:build/jdk.internal.le/classes:build/jdk.jdi/classes:build/jdk.jshell/classes:build/java.compiler/classes:build/jdk.compiler/classes:build/jdk.javadoc/classes:build/jdk.jdeps/classes" />
+      <option name="PROGRAM_PARAMETERS" value="" />
+      <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+      <option name="ENABLE_SWING_INSPECTOR" value="false" />
+      <option name="ENV_VARIABLES" />
+      <option name="PASS_PARENT_ENVS" value="true" />
+      <module name="langtools" />
+      <envs />
+      <method>
+        <option name="Make" enabled="false" />
+        <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
+      </method>
+    </configuration>
     <!-- bootstrap javac -->
     <configuration default="false" name="javac (bootstrap)" type="Application" factoryName="Application">
       <option name="MAIN_CLASS_NAME" value="com.sun.tools.javac.Main" />
--- a/make/launcher.sh-template	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/launcher.sh-template	Tue Nov 24 00:42:53 2015 +0000
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 #
-# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 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
@@ -71,4 +71,4 @@
 unset DUALCASE
 
 IFS=$nl
-"#TARGET_JAVA#" "${bcp:+-Xbootclasspath/p:"$bcp"}" ${ea} ${javaOpts} com.sun.tools.#PROGRAM#.Main ${toolOpts}
+"#TARGET_JAVA#" "${bcp:+-Xbootclasspath/p:"$bcp"}" ${ea} ${javaOpts} #PROGRAM# ${toolOpts}
--- a/make/netbeans/langtools/build.xml	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/netbeans/langtools/build.xml	Tue Nov 24 00:42:53 2015 +0000
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2007, 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
@@ -81,11 +81,21 @@
         the user.
     -->
 
-    <target name="run" depends="-check-target.java.home,-build-classes,-def-run,-get-tool-and-args,-setup-bootclasspath"
+    <target name="run" depends="-check-target.java.home,-build-classes,-def-run,-get-tool-and-args,-setup-bootclasspath,-def-resolve-main-class"
             description="run tool">
         <echo level="info" message="${with_bootclasspath}"/>
         <echo level="info" message="Run ${use_bootstrap}${langtools.tool.name} with args ${langtools.tool.args}"/>
-        <run bcp="${with_bootclasspath}" mainclass="com.sun.tools.${langtools.tool.name}.Main" args="${langtools.tool.args}"/>
+        <resolve-main-class tool.name="${langtools.tool.name}" />
+        <run bcp="${with_bootclasspath}" mainclass="${langtools.main.class}" args="${langtools.tool.args}"/>
+    </target>
+
+    <target name="-def-resolve-main-class">
+        <macrodef name="resolve-main-class">
+          <attribute name="tool.name"/>
+          <sequential>
+            <property name="langtools.main.class" value="${tool.@{tool.name}.main.class}"/>
+          </sequential>
+        </macrodef>
     </target>
 
     <target name="-build-classes" depends="-get-tool-if-set,-build-classes-bootstrap-javac,-build-classes-all" />
@@ -159,10 +169,11 @@
 
     <!-- Debug tool in NetBeans. -->
 
-    <target name="debug" depends="-check-target.java.home,-def-run,-def-start-debugger,-get-tool-and-args,-setup-bootclasspath,-build-classes" if="netbeans.home">
+    <target name="debug" depends="-check-target.java.home,-def-run,-def-start-debugger,-get-tool-and-args,-setup-bootclasspath,-build-classes,-def-resolve-main-class" if="netbeans.home">
         <echo level="info" message="Debug ${use_bootstrap}${langtools.tool.name} with args ${langtools.tool.args}"/>
         <start-debugger/>
-        <run bcp="${with_bootclasspath}" mainclass="com.sun.tools.${langtools.tool.name}.Main" args="${langtools.tool.args}" jpda.jvmargs="${jpda.jvmargs}"/>
+        <resolve-main-class tool.name="${langtools.tool.name}" />
+        <run bcp="${with_bootclasspath}" mainclass="${langtools.main.class}" args="${langtools.tool.args}" jpda.jvmargs="${jpda.jvmargs}"/>
     </target>
 
     <!-- Debug a selected class . -->
--- a/make/netbeans/langtools/nbproject/project.xml	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/netbeans/langtools/nbproject/project.xml	Tue Nov 24 00:42:53 2015 +0000
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2007, 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
@@ -76,6 +76,11 @@
                     <type>java</type>
                     <location>${root}/src/jdk.javadoc/share/classes</location>
                 </source-folder>
+                <source-folder>
+                    <label>Source files - jdk.jshell</label>
+                    <type>java</type>
+                    <location>${root}/src/jdk.jshell/share/classes</location>
+                </source-folder>
                 <build-file>
                     <location>${root}/build/classes</location>
                 </build-file>
@@ -152,6 +157,19 @@
                         </arity>
                     </context>
                 </action>
+                <action name="compile.single">
+                    <target>compile-single</target>
+                    <property name="module.name">jdk.jshell</property>
+                    <context>
+                        <property>includes</property>
+                        <folder>${root}/src/jdk.jshell/share/classes</folder>
+                        <pattern>\.java$</pattern>
+                        <format>relative-path</format>
+                        <arity>
+                            <separated-files>,</separated-files>
+                        </arity>
+                    </context>
+                </action>
                 <action name="run">
                     <target>run</target>
                 </action>
@@ -215,6 +233,18 @@
                         </arity>
                     </context>
                 </action>
+                <action name="run.single">
+                    <target>run-single</target>
+                    <context>
+                        <property>run.classname</property>
+                        <folder>${root}/src/jdk.jshell/share/classes</folder>
+                        <pattern>\.java$</pattern>
+                        <format>java-name</format>
+                        <arity>
+                            <one-file-only/>
+                        </arity>
+                    </context>
+                </action>
                 <!--
  Note: NetBeans does not appear to support context menu items
  on shell scripts :-(
@@ -285,6 +315,18 @@
                         </arity>
                     </context>
                 </action>
+                <action name="debug.single">
+                    <target>debug-single</target>
+                    <context>
+                        <property>debug.classname</property>
+                        <folder>${root}/src/jdk.jshell/share/classes</folder>
+                        <pattern>\.java$</pattern>
+                        <format>java-name</format>
+                        <arity>
+                            <one-file-only/>
+                        </arity>
+                    </context>
+                </action>
                 <!--
  Note: NetBeans does not appear to support context menu items
  on shell scripts :-(
@@ -353,6 +395,19 @@
                         </arity>
                     </context>
                 </action>
+                <action name="debug.fix">
+                    <target>debug-fix</target>
+                    <property name="module.name">jdk.jshell</property>
+                    <context>
+                        <property>class</property>
+                        <folder>${root}/src/jdk.jshell/share/classes</folder>
+                        <pattern>\.java$</pattern>
+                        <format>relative-path-noext</format>
+                        <arity>
+                            <one-file-only/>
+                        </arity>
+                    </context>
+                </action>
                 <action name="javadoc">
                     <target>javadoc</target>
                 </action>
@@ -390,6 +445,10 @@
                         <location>${root}/src/jdk.javadoc/share/classes</location>
                     </source-folder>
                     <source-folder style="tree">
+                        <label>Source files - jdk.jshell</label>
+                        <location>${root}/src/jdk.jshell/share/classes</location>
+                    </source-folder>
+                    <source-folder style="tree">
                         <label>Test files</label>
                         <location>${root}/test</location>
                     </source-folder>
@@ -456,6 +515,15 @@
                 <built-to>${root}/build/jdk.javadoc/classes</built-to>
                 <source-level>1.8</source-level>
             </compilation-unit>
+            <compilation-unit>
+                <package-root>${root}/src/jdk.jshell/share/classes</package-root>
+                <package-root>${root}/build/bootstrap/jdk.jshell/gensrc</package-root>
+                <package-root>${root}/../jdk/src/jdk.internal.le/share/classes</package-root>
+                <package-root>${root}/../jdk/src/jdk.jdi/share/classes</package-root>
+                <classpath mode="compile">${root}/build/java.compiler/classes:${root}/build/jdk.compiler/classes:${root}/build/jdk.internal.le/aux:${root}/build/jdk.jdi/aux:${root}/build/jdk.internal.le/classes:${root}/build/jdk.jdi/classes</classpath>
+                <built-to>${root}/build/jdk.jshell/classes</built-to>
+                <source-level>1.8</source-level>
+            </compilation-unit>
         </java-data>
     </configuration>
 </project>
--- a/make/test/sym/CreateSymbolsTest.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/test/sym/CreateSymbolsTest.java	Tue Nov 24 00:42:53 2015 +0000
@@ -56,21 +56,21 @@
         Path compileDir = testClasses.resolve("data");
         deleteRecursively(compileDir);
         Files.createDirectories(compileDir);
-        Path createSymbols = findFile("../../make/src/build/tools/symbolgenerator/CreateSymbols.java");
+        Path createSymbols = findFile("../../make/src/classes/build/tools/symbolgenerator/CreateSymbols.java");
 
         if (createSymbols == null) {
             System.err.println("Warning: cannot find CreateSymbols, skipping.");
             return ;
         }
 
-        Path createTestImpl = findFile("../../make/test/tools/sym/CreateSymbolsTestImpl.java");
+        Path createTestImpl = findFile("../../make/test/sym/CreateSymbolsTestImpl.java");
 
         if (createTestImpl == null) {
-            System.err.println("Warning: cannot find CreateSymbols, skipping.");
+            System.err.println("Warning: cannot find CreateSymbolsTestImpl, skipping.");
             return ;
         }
 
-        Path toolBox = findFile("../../langtools/test/tools/lib/ToolBox.java");
+        Path toolBox = findFile("../../test/tools/lib/ToolBox.java");
 
         if (toolBox == null) {
             System.err.println("Warning: cannot find ToolBox, skipping.");
--- a/make/test/sym/CreateSymbolsTestImpl.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/test/sym/CreateSymbolsTestImpl.java	Tue Nov 24 00:42:53 2015 +0000
@@ -41,12 +41,12 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-import symbolgenerator.CreateSymbols;
-import symbolgenerator.CreateSymbols.ClassDescription;
-import symbolgenerator.CreateSymbols.ClassList;
-import symbolgenerator.CreateSymbols.CtSymKind;
-import symbolgenerator.CreateSymbols.ExcludeIncludeList;
-import symbolgenerator.CreateSymbols.VersionDescription;
+import build.tools.symbolgenerator.CreateSymbols;
+import build.tools.symbolgenerator.CreateSymbols.ClassDescription;
+import build.tools.symbolgenerator.CreateSymbols.ClassList;
+import build.tools.symbolgenerator.CreateSymbols.CtSymKind;
+import build.tools.symbolgenerator.CreateSymbols.ExcludeIncludeList;
+import build.tools.symbolgenerator.CreateSymbols.VersionDescription;
 
 public class CreateSymbolsTestImpl {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/tools/anttasks/DumpClassesTask.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,81 @@
+/*
+ * 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 anttasks;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.Collections;
+import java.util.stream.Stream;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+public class DumpClassesTask extends Task {
+
+    private String moduleName;
+    private File dir;
+
+    public void setModuleName(String moduleName) {
+        this.moduleName = moduleName;
+    }
+
+    public void setDestDir(File dir) {
+        this.dir = dir;
+    }
+
+    @Override
+    public void execute() {
+        try (FileSystem fs = FileSystems.newFileSystem(new URI("jrt:/"), Collections.emptyMap(), DumpClassesTask.class.getClassLoader())) {
+            Path source = fs.getPath("modules", moduleName);
+            Path target = dir.toPath();
+
+            try (Stream<Path> content = Files.walk(source)) {
+                content.filter(Files :: isRegularFile)
+                       .forEach(p -> {
+                    try {
+                        Path targetFile = target.resolve(source.relativize(p).toString());
+                        if (!Files.exists(targetFile) || Files.getLastModifiedTime(targetFile).compareTo(Files.getLastModifiedTime(source)) < 0) {
+                            Files.createDirectories(targetFile.getParent());
+                            Files.copy(p, targetFile, StandardCopyOption.REPLACE_EXISTING);
+                        }
+                    } catch (IOException ex) {
+                        throw new UncheckedIOException(ex);
+                    }
+                });
+            }
+        } catch (URISyntaxException | IOException | UncheckedIOException ex) {
+            throw new BuildException(ex);
+        }
+    }
+}
--- a/make/tools/anttasks/SelectToolTask.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/make/tools/anttasks/SelectToolTask.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -88,7 +88,8 @@
         },
         JAVADOC("javadoc"),
         JAVAH("javah"),
-        JAVAP("javap");
+        JAVAP("javap"),
+        JSHELL("jshell");
 
         String toolName;
         boolean bootstrap;
--- a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocCommentTree.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocCommentTree.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,6 +25,7 @@
 
 package com.sun.source.doctree;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -44,6 +45,20 @@
     List<? extends DocTree> getFirstSentence();
 
     /**
+     * Returns the entire body of a documentation comment, appearing
+     * before any block tags, including the first sentence.
+     * @return body of a documentation comment first sentence inclusive
+     *
+     * @since 1.9
+     */
+    default List<? extends DocTree> getFullBody() {
+        ArrayList<DocTree> bodyList = new ArrayList<>();
+        bodyList.addAll(getFirstSentence());
+        bodyList.addAll(getBody());
+        return bodyList;
+    }
+
+    /**
      * Returns the body of a documentation comment,
      * appearing after the first sentence, and before any block tags.
      * @return the body of a documentation comment
--- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,12 +25,18 @@
 
 package com.sun.source.util;
 
+import java.io.IOException;
+import java.text.BreakIterator;
+import java.util.List;
+
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.Element;
+import javax.tools.Diagnostic;
+import javax.tools.FileObject;
 import javax.tools.JavaCompiler.CompilationTask;
 
 import com.sun.source.doctree.DocCommentTree;
-import javax.tools.Diagnostic;
+import com.sun.source.doctree.DocTree;
 
 /**
  * Provides access to syntax trees for doc comments.
@@ -62,6 +68,16 @@
     }
 
     /**
+     * Returns the break iterator used to compute the first sentence of
+     * documentation comments.
+     * Returns {@code null} if none has been specified.
+     * @return the break iterator
+     *
+     * @since 1.9
+     */
+    public abstract BreakIterator getBreakIterator();
+
+    /**
      * Returns the doc comment tree, if any, for the Tree node identified by a given TreePath.
      * Returns {@code null} if no doc comment was found.
      * @param path the path for the tree node
@@ -70,6 +86,47 @@
     public abstract DocCommentTree getDocCommentTree(TreePath path);
 
     /**
+     * Returns the doc comment tree of the given element.
+     * Returns {@code null} if no doc comment was found.
+     * @param e an element whose documentation is required
+     * @return the doc comment tree
+     *
+     * @since 1.9
+     */
+    public abstract DocCommentTree getDocCommentTree(Element e);
+
+    /**
+     * Returns the doc comment tree of the given file. The file must be
+     * an HTML file, in which case the doc comment tree represents the
+     * contents of the &lt;body&gt; tag, and any enclosing tags are ignored.
+     * Returns {@code null} if no doc comment was found.
+     * Future releases may support additional file types.
+     *
+     * @param fileObject the content container
+     * @return the doc comment tree
+     *
+     * @since 1.9
+     */
+    public abstract DocCommentTree getDocCommentTree(FileObject fileObject);
+
+    /**
+     * Returns the doc comment tree of the given file whose path is
+     * specified relative to the given element. The file must be an HTML
+     * file, in which case the doc comment tree represents the contents
+     * of the &lt;body&gt; tag, and any enclosing tags are ignored.
+     * Returns {@code null} if no doc comment was found.
+     * Future releases may support additional file types.
+     *
+     * @param e an element whose path is used as a reference
+     * @param relativePath the relative path from the Element
+     * @return the doc comment tree
+     * @throws java.io.IOException if an exception occurs
+     *
+     * @since 1.9
+     */
+    public abstract DocCommentTree getDocCommentTree(Element e, String relativePath) throws IOException;
+
+    /**
      * Returns the language model element referred to by the leaf node of the given
      * {@link DocTreePath}, or {@code null} if unknown.
      * @param path the path for the tree node
@@ -78,6 +135,17 @@
     public abstract Element getElement(DocTreePath path);
 
     /**
+     * Returns the list of {@link DocTree} representing the first sentence of
+     * a comment.
+     *
+     * @param list the DocTree list to interrogate
+     * @return the first sentence
+     *
+     * @since 1.9
+     */
+    public abstract List<DocTree> getFirstSentence(List<? extends DocTree> list);
+
+    /**
      * Returns a utility object for accessing the source positions
      * of documentation tree nodes.
      * @return the utility object
@@ -98,4 +166,14 @@
             com.sun.source.doctree.DocTree t,
             com.sun.source.doctree.DocCommentTree c,
             com.sun.source.tree.CompilationUnitTree root);
+
+    /**
+     * Sets the break iterator to compute the first sentence of
+     * documentation comments.
+     * @param breakiterator a break iterator or {@code null} to specify the default
+     *                      sentence breaker
+     *
+     * @since 1.9
+     */
+    public abstract void setBreakIterator(BreakIterator breakiterator);
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/doclint/HtmlTag.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/doclint/HtmlTag.java	Tue Nov 24 00:42:53 2015 +0000
@@ -25,19 +25,18 @@
 
 package com.sun.tools.doclint;
 
-import java.util.Set;
 import java.util.Collections;
 import java.util.EnumMap;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Map;
-
+import java.util.Set;
 import javax.lang.model.element.Name;
 
+import com.sun.tools.javac.util.StringUtils;
+
 import static com.sun.tools.doclint.HtmlTag.Attr.*;
 
-import com.sun.tools.javac.util.StringUtils;
-
 /**
  * Enum representing HTML tags.
  *
@@ -646,15 +645,14 @@
         return map;
     }
 
-    private static final Map<String,HtmlTag> index = new HashMap<>();
+    private static final Map<String, HtmlTag> index = new HashMap<>();
     static {
         for (HtmlTag t: values()) {
             index.put(t.getText(), t);
         }
     }
 
-    static HtmlTag get(Name tagName) {
+    public static HtmlTag get(Name tagName) {
         return index.get(StringUtils.toLowerCase(tagName.toString()));
     }
-
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Tue Nov 24 00:42:53 2015 +0000
@@ -25,9 +25,13 @@
 
 package com.sun.tools.javac.api;
 
+import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.text.BreakIterator;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.AnnotationMirror;
@@ -35,13 +39,22 @@
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import javax.tools.Diagnostic;
+import javax.tools.FileObject;
+import javax.tools.ForwardingFileObject;
+import javax.tools.ForwardingJavaFileObject;
 import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.StandardLocation;
 
 import com.sun.source.doctree.DocCommentTree;
 import com.sun.source.doctree.DocTree;
@@ -75,7 +88,12 @@
 import com.sun.tools.javac.comp.Env;
 import com.sun.tools.javac.comp.MemberEnter;
 import com.sun.tools.javac.comp.Resolve;
+import com.sun.tools.javac.file.BaseFileManager;
 import com.sun.tools.javac.model.JavacElements;
+import com.sun.tools.javac.parser.DocCommentParser;
+import com.sun.tools.javac.parser.ParserFactory;
+import com.sun.tools.javac.parser.Tokens.Comment;
+import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 import com.sun.tools.javac.tree.DCTree;
 import com.sun.tools.javac.tree.DCTree.DCBlockTag;
@@ -86,9 +104,17 @@
 import com.sun.tools.javac.tree.DCTree.DCParam;
 import com.sun.tools.javac.tree.DCTree.DCReference;
 import com.sun.tools.javac.tree.DCTree.DCText;
+import com.sun.tools.javac.tree.DocTreeMaker;
 import com.sun.tools.javac.tree.EndPosTable;
 import com.sun.tools.javac.tree.JCTree;
-import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCCatch;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
 import com.sun.tools.javac.tree.TreeCopier;
 import com.sun.tools.javac.tree.TreeInfo;
 import com.sun.tools.javac.tree.TreeMaker;
@@ -97,6 +123,7 @@
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.DiagnosticSource;
 import com.sun.tools.javac.util.JCDiagnostic;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
 import com.sun.tools.javac.util.List;
@@ -133,6 +160,10 @@
     private JavacTaskImpl javacTaskImpl;
     private Names names;
     private Types types;
+    private DocTreeMaker doctreeMaker;
+    private BreakIterator breakIterator;
+    private JavaFileManager fileManager;
+    private ParserFactory parser;
 
     // called reflectively from Trees.instance(CompilationTask task)
     public static JavacTrees instance(JavaCompiler.CompilationTask task) {
@@ -156,6 +187,7 @@
     }
 
     protected JavacTrees(Context context) {
+        this.breakIterator = null;
         context.put(JavacTrees.class, this);
         init(context);
     }
@@ -174,31 +206,38 @@
         memberEnter = MemberEnter.instance(context);
         names = Names.instance(context);
         types = Types.instance(context);
-
+        doctreeMaker = DocTreeMaker.instance(context);
+        parser = ParserFactory.instance(context);
+        fileManager = context.get(JavaFileManager.class);
         JavacTask t = context.get(JavacTask.class);
         if (t instanceof JavacTaskImpl)
             javacTaskImpl = (JavacTaskImpl) t;
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
+    public BreakIterator getBreakIterator() {
+        return breakIterator;
+    }
+
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public DocSourcePositions getSourcePositions() {
         return new DocSourcePositions() {
-                @DefinedBy(Api.COMPILER_TREE)
+                @Override @DefinedBy(Api.COMPILER_TREE)
                 public long getStartPosition(CompilationUnitTree file, Tree tree) {
                     return TreeInfo.getStartPos((JCTree) tree);
                 }
 
-                @DefinedBy(Api.COMPILER_TREE)
+                @Override @DefinedBy(Api.COMPILER_TREE)
                 public long getEndPosition(CompilationUnitTree file, Tree tree) {
                     EndPosTable endPosTable = ((JCCompilationUnit) file).endPositions;
                     return TreeInfo.getEndPos((JCTree) tree, endPosTable);
                 }
 
-                @DefinedBy(Api.COMPILER_TREE)
+                @Override @DefinedBy(Api.COMPILER_TREE)
                 public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
                     return ((DCTree) tree).getSourcePosition((DCDocComment) comment);
                 }
-                @SuppressWarnings("fallthrough") @DefinedBy(Api.COMPILER_TREE)
+                @Override  @DefinedBy(Api.COMPILER_TREE) @SuppressWarnings("fallthrough")
                 public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
                     DCDocComment dcComment = (DCDocComment) comment;
                     if (tree instanceof DCEndPosTree) {
@@ -260,7 +299,7 @@
 
         tree.accept(new DocTreeScanner<Void, Void>() {
             @Override @DefinedBy(Api.COMPILER_TREE)
- public Void scan(DocTree node, Void p) {
+            public Void scan(DocTree node, Void p) {
                 if (node != null) last[0] = node;
                 return null;
             }
@@ -269,27 +308,27 @@
         return last[0];
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public JCClassDecl getTree(TypeElement element) {
         return (JCClassDecl) getTree((Element) element);
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public JCMethodDecl getTree(ExecutableElement method) {
         return (JCMethodDecl) getTree((Element) method);
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public JCTree getTree(Element element) {
         return getTree(element, null);
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public JCTree getTree(Element e, AnnotationMirror a) {
         return getTree(e, a, null);
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public JCTree getTree(Element e, AnnotationMirror a, AnnotationValue v) {
         Tuple2<JCTree, JCCompilationUnit> treeTopLevel = elements.getTreeAndTopLevel(e, a, v);
         if (treeTopLevel == null)
@@ -297,22 +336,22 @@
         return treeTopLevel.elem0;
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public TreePath getPath(CompilationUnitTree unit, Tree node) {
         return TreePath.getPath(unit, node);
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public TreePath getPath(Element e) {
         return getPath(e, null, null);
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public TreePath getPath(Element e, AnnotationMirror a) {
         return getPath(e, a, null);
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public TreePath getPath(Element e, AnnotationMirror a, AnnotationValue v) {
         final Tuple2<JCTree, JCCompilationUnit> treeTopLevel = elements.getTreeAndTopLevel(e, a, v);
         if (treeTopLevel == null)
@@ -320,7 +359,7 @@
         return TreePath.getPath(treeTopLevel.elem1, treeTopLevel.elem0);
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public Symbol getElement(TreePath path) {
         JCTree tree = (JCTree) path.getLeaf();
         Symbol sym = TreeInfo.symbolFor(tree);
@@ -357,6 +396,11 @@
         return null;
     }
 
+    @Override @DefinedBy(Api.COMPILER_TREE)
+    public java.util.List<DocTree> getFirstSentence(java.util.List<? extends DocTree> list) {
+        return doctreeMaker.getFirstSentence(list);
+    }
+
     private Symbol attributeDocReference(TreePath path, DCReference ref) {
         Env<AttrContext> env = getAttrContext(path);
 
@@ -465,7 +509,7 @@
 
     /** @see com.sun.tools.javadoc.ClassDocImpl#findField */
     private VarSymbol findField(ClassSymbol tsym, Name fieldName) {
-        return searchField(tsym, fieldName, new HashSet<ClassSymbol>());
+        return searchField(tsym, fieldName, new HashSet<>());
     }
 
     /** @see com.sun.tools.javadoc.ClassDocImpl#searchField */
@@ -529,7 +573,7 @@
 
     /** @see com.sun.tools.javadoc.ClassDocImpl#findMethod */
     private MethodSymbol findMethod(ClassSymbol tsym, Name methodName, List<Type> paramTypes) {
-        return searchMethod(tsym, methodName, paramTypes, new HashSet<ClassSymbol>());
+        return searchMethod(tsym, methodName, paramTypes, new HashSet<>());
     }
 
     /** @see com.sun.tools.javadoc.ClassDocImpl#searchMethod */
@@ -694,19 +738,19 @@
         }
     };
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public TypeMirror getTypeMirror(TreePath path) {
         Tree t = path.getLeaf();
         Type ty = ((JCTree)t).type;
         return ty == null ? null : ty.stripMetadataIfNeeded();
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public JavacScope getScope(TreePath path) {
         return JavacScope.create(getAttrContext(path));
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public String getDocComment(TreePath path) {
         CompilationUnitTree t = path.getCompilationUnit();
         Tree leaf = path.getLeaf();
@@ -719,7 +763,7 @@
         return null;
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public DocCommentTree getDocCommentTree(TreePath path) {
         CompilationUnitTree t = path.getCompilationUnit();
         Tree leaf = path.getLeaf();
@@ -732,7 +776,28 @@
         return null;
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
+    public DocCommentTree getDocCommentTree(Element e) {
+        TreePath path = getPath(e);
+        if (path == null) {
+            return null;
+        }
+        return getDocCommentTree(path);
+    }
+
+    @Override @DefinedBy(Api.COMPILER_TREE)
+    public DocCommentTree getDocCommentTree(Element e, String relativeFileName) throws IOException {
+        PackageElement pkg = elements.getPackageOf(e);
+        FileObject fileForInput = fileManager.getFileForInput(StandardLocation.SOURCE_PATH,
+                pkg.getQualifiedName().toString(), relativeFileName);
+
+        if (fileForInput == null) {
+            throw new FileNotFoundException(relativeFileName);
+        }
+        return getDocCommentTree(fileForInput);
+    }
+
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public boolean isAccessible(Scope scope, TypeElement type) {
         if (scope instanceof JavacScope && type instanceof ClassSymbol) {
             Env<AttrContext> env = ((JavacScope) scope).env;
@@ -741,7 +806,7 @@
             return false;
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public boolean isAccessible(Scope scope, Element member, DeclaredType type) {
         if (scope instanceof JavacScope
                 && member instanceof Symbol
@@ -764,7 +829,6 @@
             javacTaskImpl.enter(null);
         }
 
-
         JCCompilationUnit unit = (JCCompilationUnit) path.getCompilationUnit();
         Copier copier = createCopier(treeMaker.forToplevel(unit));
 
@@ -849,6 +913,109 @@
         }
     }
 
+    private JavaFileObject asJavaFileObject(FileObject fileObject) {
+        JavaFileObject jfo = null;
+
+        if (fileObject instanceof JavaFileObject) {
+            jfo = (JavaFileObject) fileObject;
+            checkHtmlKind(fileObject, Kind.HTML);
+            return jfo;
+        }
+
+        checkHtmlKind(fileObject);
+        jfo = new HtmlFileObject(fileObject);
+        return jfo;
+    }
+
+    private void checkHtmlKind(FileObject fileObject) {
+        checkHtmlKind(fileObject, BaseFileManager.getKind(fileObject.getName()));
+    }
+
+    private void checkHtmlKind(FileObject fileObject, JavaFileObject.Kind kind) {
+        if (kind != JavaFileObject.Kind.HTML) {
+            throw new IllegalArgumentException("HTML file expected:" + fileObject.getName());
+        }
+    }
+
+    private static class HtmlFileObject extends ForwardingFileObject<FileObject>
+            implements JavaFileObject {
+
+        public HtmlFileObject(FileObject fileObject) {
+            super(fileObject);
+        }
+
+        @Override @DefinedBy(Api.COMPILER)
+        public Kind getKind() {
+            return BaseFileManager.getKind(fileObject.getName());
+        }
+
+        @Override @DefinedBy(Api.COMPILER)
+        public boolean isNameCompatible(String simpleName, Kind kind) {
+            return false;
+        }
+
+        @Override @DefinedBy(Api.COMPILER)
+        public NestingKind getNestingKind() {
+            return null;
+        }
+
+        @Override @DefinedBy(Api.COMPILER)
+        public Modifier getAccessLevel() {
+            return null;
+        }
+    }
+
+    @Override @DefinedBy(Api.COMPILER_TREE)
+    public DocCommentTree getDocCommentTree(FileObject fileObject) {
+        JavaFileObject jfo = asJavaFileObject(fileObject);
+        DiagnosticSource diagSource = new DiagnosticSource(jfo, log);
+
+        final Comment comment = new Comment() {
+            int offset = 0;
+            @Override
+            public String getText() {
+                try {
+                    CharSequence rawDoc = fileObject.getCharContent(true);
+                    Pattern bodyPat =
+                            Pattern.compile("(?is).*?<body\\b[^>]*>(.*)</body\\b.*");
+                    Matcher m = bodyPat.matcher(rawDoc);
+                    if (m.matches()) {
+                        offset = m.end(1);
+                        return m.group(1);
+                    } else {
+                        // Assume doclint will do the right thing.
+                        return "";
+                    }
+                } catch (IOException ignore) {
+                    // do nothing
+                }
+                return "";
+            }
+
+            @Override
+            public int getSourcePos(int index) {
+                return offset + index;
+            }
+
+            @Override
+            public CommentStyle getStyle() {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public boolean isDeprecated() {
+                throw new UnsupportedOperationException();
+            }
+        };
+
+        return new DocCommentParser(parser, diagSource, comment).parse();
+    }
+
+    @Override @DefinedBy(Api.COMPILER_TREE)
+    public void setBreakIterator(BreakIterator breakiterator) {
+        this.breakIterator = breakiterator;
+    }
+
     /**
      * Makes a copy of a tree, noting the value resulting from copying a particular leaf.
      **/
@@ -878,7 +1045,7 @@
      * @return TypeMirror corresponding to the original type, replaced by the ErrorType.
      *         noType (type.tag == NONE) is returned if there is no original type.
      */
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public TypeMirror getOriginalType(javax.lang.model.type.ErrorType errorType) {
         if (errorType instanceof com.sun.tools.javac.code.Type.ErrorType) {
             return ((com.sun.tools.javac.code.Type.ErrorType)errorType).getOriginalType();
@@ -896,14 +1063,14 @@
      * @param t    the tree to use as a position hint
      * @param root the compilation unit that contains tree
      */
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public void printMessage(Diagnostic.Kind kind, CharSequence msg,
             com.sun.source.tree.Tree t,
             com.sun.source.tree.CompilationUnitTree root) {
         printMessage(kind, msg, ((JCTree) t).pos(), root);
     }
 
-    @DefinedBy(Api.COMPILER_TREE)
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public void printMessage(Diagnostic.Kind kind, CharSequence msg,
             com.sun.source.doctree.DocTree t,
             com.sun.source.doctree.DocCommentTree c,
@@ -958,4 +1125,30 @@
             return v.type;
         }
     }
+
+    public TreePath makeTreePath(final FileObject fileObject, final int offset) {
+        JavaFileObject jfo = asJavaFileObject(fileObject);
+        JCCompilationUnit jcCompilationUnit = new JCCompilationUnit(List.nil()) {
+            public int getPos() {
+                return offset;
+            }
+
+            public JavaFileObject getSourcefile() {
+                return jfo;
+            }
+
+            @Override @DefinedBy(Api.COMPILER_TREE)
+            public Position.LineMap getLineMap() {
+                try {
+                    CharSequence content = fileObject.getCharContent(true);
+                    String s = content.toString();
+                    return Position.makeLineMap(s.toCharArray(), s.length(), true);
+                } catch (IOException ignore) {}
+                return null;
+            }
+        };
+        jcCompilationUnit.sourcefile = jfo;
+        enter.main(List.of(jcCompilationUnit));
+        return new TreePath(jcCompilationUnit);
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Tue Nov 24 00:42:53 2015 +0000
@@ -133,10 +133,9 @@
      */
     public static final int BLOCK            = 1<<20;
 
-    /** Flag is set for compiler-generated abstract methods that implement
-     *  an interface method (Miranda methods).
+    /** Flag bit 21 is available. (used earlier to tag compiler-generated abstract methods that implement
+     *  an interface method (Miranda methods)).
      */
-    public static final int IPROXY           = 1<<21;
 
     /** Flag is set for nested classes that do not access instance members
      *  or `this' of an outer class and therefore don't need to be passed
@@ -227,11 +226,7 @@
      */
     public static final long UNION = 1L<<39;
 
-    /**
-     * Flag that marks a special kind of bridge method (the ones that
-     * come from restricted supertype bounds).
-     */
-    public static final long OVERRIDE_BRIDGE = 1L<<40;
+    // Flag bit (1L << 40) is available.
 
     /**
      * Flag that marks an 'effectively final' local variable.
@@ -406,7 +401,6 @@
         ENUM(Flags.ENUM),
         MANDATED(Flags.MANDATED),
         VALUE(Flags.VALUE),
-        IPROXY(Flags.IPROXY),
         NOOUTERTHIS(Flags.NOOUTERTHIS),
         EXISTS(Flags.EXISTS),
         COMPOUND(Flags.COMPOUND),
@@ -423,7 +417,6 @@
         HYPOTHETICAL(Flags.HYPOTHETICAL),
         PROPRIETARY(Flags.PROPRIETARY),
         UNION(Flags.UNION),
-        OVERRIDE_BRIDGE(Flags.OVERRIDE_BRIDGE),
         EFFECTIVELY_FINAL(Flags.EFFECTIVELY_FINAL),
         CLASH(Flags.CLASH),
         AUXILIARY(Flags.AUXILIARY),
@@ -448,4 +441,5 @@
         final long value;
         final String lowercaseName;
     }
+
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Nov 24 00:42:53 2015 +0000
@@ -37,6 +37,10 @@
 import javax.tools.JavaFileObject;
 
 import com.sun.tools.javac.code.Types.AsSuperKind;
+import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.TypeAnnotations.AnnotationType;
+import com.sun.tools.javac.code.TypeMetadata.Entry;
+import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Type.*;
@@ -183,6 +187,14 @@
                 : metadata.getInitTypeAttributes();
     }
 
+    public void setInitTypeAttributes(List<Attribute.TypeCompound> l) {
+        initedMetadata().setInitTypeAttributes(l);
+    }
+
+    public void setClassInitTypeAttributes(List<Attribute.TypeCompound> l) {
+        initedMetadata().setClassInitTypeAttributes(l);
+    }
+
     public List<Attribute.Compound> getDeclarationAttributes() {
         return (metadata == null)
                 ? List.<Attribute.Compound>nil()
@@ -1547,9 +1559,33 @@
          *  It is assumed that both symbols have the same name.  The static
          *  modifier is ignored for this test.
          *
+         *  A quirk in the works is that if the receiver is a method symbol for
+         *  an inherited abstract method we answer false summarily all else being
+         *  immaterial. Abstract "own" methods (i.e `this' is a direct member of
+         *  origin) don't get rejected as summarily and are put to test against the
+         *  suitable criteria.
+         *
          *  See JLS 8.4.6.1 (without transitivity) and 8.4.6.4
          */
         public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean checkResult) {
+            return overrides(_other, origin, types, checkResult, true);
+        }
+
+        /** Does this symbol override `other' symbol, when both are seen as
+         *  members of class `origin'?  It is assumed that _other is a member
+         *  of origin.
+         *
+         *  Caveat: If `this' is an abstract inherited member of origin, it is
+         *  deemed to override `other' only when `requireConcreteIfInherited'
+         *  is false.
+         *
+         *  It is assumed that both symbols have the same name.  The static
+         *  modifier is ignored for this test.
+         *
+         *  See JLS 8.4.6.1 (without transitivity) and 8.4.6.4
+         */
+        public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean checkResult,
+                                            boolean requireConcreteIfInherited) {
             if (isConstructor() || _other.kind != MTH) return false;
 
             if (this == _other) return true;
@@ -1569,7 +1605,7 @@
             }
 
             // check for an inherited implementation
-            if ((flags() & ABSTRACT) != 0 ||
+            if (((flags() & ABSTRACT) != 0 && requireConcreteIfInherited) ||
                     ((other.flags() & ABSTRACT) == 0 && (other.flags() & DEFAULT) == 0) ||
                     !other.isOverridableIn(origin) ||
                     !this.isMemberOf(origin, types))
@@ -1616,7 +1652,11 @@
             }
         }
 
-        /**
+		public boolean isLambdaMethod() {
+            return (flags() & LAMBDA_METHOD) == LAMBDA_METHOD;
+        }
+
+		/**
          * Return the simple name of a 'template' method. Template method names are prefixed
          * with padding sequences in order to avoid clashes with existing methods (as they are only meant
          * to be used as templates for the runtime specializer).
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Tue Nov 24 00:42:53 2015 +0000
@@ -144,6 +144,10 @@
         return false;
     }
 
+    public boolean isIntegral() {
+        return false;
+    }
+
     public boolean isPrimitive() {
         return false;
     }
@@ -585,11 +589,13 @@
         return false;
     }
 
+    /**
+     * A compound type is a special class type whose supertypes are used to store a list
+     * of component types. There are two kinds of compound types: (i) intersection types
+     * {@see IntersectionClassType} and (ii) union types {@see UnionClassType}.
+     */
     public boolean isCompound() {
-        // Compound types can't have a (non-terminal) completer.  Calling
-        // flags() will complete the symbol causing the compiler to load
-        // classes unnecessarily.  This led to regression 6180021.
-        return tsym.isCompleted() && (tsym.flags() & COMPOUND) != 0;
+        return false;
     }
 
     public boolean isIntersection() {
@@ -707,6 +713,20 @@
         }
 
         @Override
+        public boolean isIntegral() {
+            switch (tag) {
+                case CHAR:
+                case BYTE:
+                case SHORT:
+                case INT:
+                case LONG:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        @Override
         public boolean isPrimitive() {
             return true;
         }
@@ -1196,6 +1216,11 @@
             return true;
         }
 
+        @Override
+        public boolean isCompound() {
+            return getLub().isCompound();
+        }
+
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
         public TypeKind getKind() {
             return TypeKind.UNION;
@@ -1238,6 +1263,11 @@
             return Collections.unmodifiableList(getExplicitComponents());
         }
 
+        @Override
+        public boolean isCompound() {
+            return true;
+        }
+
         public List<Type> getComponents() {
             return interfaces_field.prepend(supertype_field);
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Tue Nov 24 00:42:53 2015 +0000
@@ -32,6 +32,7 @@
 
 import com.sun.tools.javac.code.Attribute.Array;
 import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.TypeSymbol;
 import com.sun.tools.javac.code.Type.ArrayType;
 import com.sun.tools.javac.code.Type.CapturedType;
@@ -356,7 +357,7 @@
 
             if (sym.getKind() == ElementKind.METHOD) {
                 sym.type.asMethodType().restype = type;
-            } else if (sym.getKind() == ElementKind.PARAMETER) {
+            } else if (sym.getKind() == ElementKind.PARAMETER && currentLambda == null) {
                 sym.type = type;
                 if (sym.getQualifiedName().equals(names._this)) {
                     sym.owner.type.asMethodType().recvtype = type;
@@ -388,8 +389,21 @@
                 sym.getKind() == ElementKind.RESOURCE_VARIABLE ||
                 sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
                 // Make sure all type annotations from the symbol are also
-                // on the owner.
-                sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes());
+                // on the owner. If the owner is an initializer block, propagate
+                // to the type.
+                final long ownerFlags = sym.owner.flags();
+                if ((ownerFlags & Flags.BLOCK) != 0) {
+                    // Store init and clinit type annotations with the ClassSymbol
+                    // to allow output in Gen.normalizeDefs.
+                    ClassSymbol cs = (ClassSymbol) sym.owner.owner;
+                    if ((ownerFlags & Flags.STATIC) != 0) {
+                        cs.appendClassInitTypeAttributes(typeAnnotations);
+                    } else {
+                        cs.appendInitTypeAttributes(typeAnnotations);
+                    }
+                } else {
+                    sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes());
+                }
             }
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1793,10 +1793,10 @@
                     }
                 }
 
-                if (t.isIntersection() || s.isIntersection()) {
-                    return !t.isIntersection() ?
-                            visitIntersectionType((IntersectionClassType)s, t, true) :
-                            visitIntersectionType((IntersectionClassType)t, s, false);
+                if (t.isCompound() || s.isCompound()) {
+                    return !t.isCompound() ?
+                            visitCompoundType((ClassType)s, t, true) :
+                            visitCompoundType(t, s, false);
                 }
 
                 if (s.hasTag(CLASS) || s.hasTag(ARRAY)) {
@@ -1874,9 +1874,9 @@
                 return false;
             }
 
-            boolean visitIntersectionType(IntersectionClassType ict, Type s, boolean reverse) {
+            boolean visitCompoundType(ClassType ct, Type s, boolean reverse) {
                 Warner warn = noWarnings;
-                for (Type c : ict.getComponents()) {
+                for (Type c : directSupertypes(ct)) {
                     warn.clear();
                     if (reverse ? !isCastable(s, c, warn) : !isCastable(c, s, warn))
                         return false;
@@ -3320,14 +3320,9 @@
                         ? interfaces(type)
                         : interfaces(type).prepend(sup);
                 } else {
-                    return visitIntersectionType((IntersectionClassType) type);
+                    return ((IntersectionClassType)type).getExplicitComponents();
                 }
             }
-
-            private List<Type> visitIntersectionType(final IntersectionClassType it) {
-                return it.getExplicitComponents();
-            }
-
         };
 
     public boolean isDirectSuperInterface(TypeSymbol isym, TypeSymbol origin) {
@@ -3727,7 +3722,7 @@
                 Scope s = c.members();
                 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
                     if (sym.kind == MTH &&
-                            (sym.flags() & (SYNTHETIC|ABSTRACT|IPROXY|DEFAULT|PRIVATE)) == ABSTRACT) {
+                            (sym.flags() & (SYNTHETIC|ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) {
                         //skip ref-only method as needed
                         if (c != impl &&
                                 ((MethodSymbol)sym).isApplicabilityRestrictedIn(impl.type, this)) {
@@ -3764,6 +3759,7 @@
             return undef;
         }
 
+
     //where
     public List<MethodSymbol> interfaceCandidates(Type site, MethodSymbol ms) {
         Filter<Symbol> filter = new MethodFilter(ms, site);
@@ -5216,7 +5212,7 @@
 
     private boolean giveWarning(Type from, Type to) {
         List<Type> bounds = to.isCompound() ?
-                ((IntersectionClassType)to).getComponents() : List.of(to);
+                directSupertypes(to) : List.of(to);
         for (Type b : bounds) {
             Type subFrom = asSub(from, b.tsym);
             if (b.isParameterized() &&
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1118,11 +1118,11 @@
 
         @Override
         public void visitNewClass(JCNewClass tree) {
-            if (tree.def == null) {
-                // For an anonymous class instantiation the class
-                // will be visited separately.
-                super.visitNewClass(tree);
-            }
+            scan(tree.encl);
+            scan(tree.typeargs);
+            scan(tree.clazz);
+            scan(tree.args);
+            // the anonymous class instantiation if any will be visited separately.
         }
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java	Tue Nov 24 00:42:53 2015 +0000
@@ -263,6 +263,8 @@
                 attr.memberReferenceQualifierResult(tree));
         JCMemberReference mref2 = new TreeCopier<Void>(attr.make).copy(tree);
         mref2.expr = exprTree;
+        Symbol lhsSym = TreeInfo.symbol(exprTree);
+        localEnv.info.selectSuper = lhsSym != null && lhsSym.name == lhsSym.name.table.names._super;
         Symbol res =
                 attr.rs.getMemberReference(tree, localEnv, mref2,
                         exprTree.type, tree.name);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Nov 24 00:42:53 2015 +0000
@@ -57,7 +57,6 @@
 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
-import com.sun.tools.javac.util.Dependencies.AttributionKind;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
 import com.sun.tools.javac.util.List;
@@ -763,7 +762,6 @@
      */
     void attribTypeVariables(List<JCTypeParameter> typarams, Env<AttrContext> env) {
         for (JCTypeParameter tvar : typarams) {
-            dependencies.push(AttributionKind.TVAR, tvar);
             TypeVar a = (TypeVar)tvar.type;
             a.tsym.flags_field |= tvar.flags | UNATTRIBUTED;
             a.bound = Type.noType;
@@ -780,7 +778,6 @@
                     types.setBounds(a, List.of(implicitBound));
             }
             a.tsym.flags_field &= ~UNATTRIBUTED;
-            dependencies.pop();
         }
         for (JCTypeParameter tvar : typarams) {
             chk.checkNonCyclic(tvar.pos(), (TypeVar)tvar.type);
@@ -1933,7 +1930,8 @@
 
             // Check that value of resulting type is admissible in the
             // current context.  Also, capture the return type
-            result = check(tree, capture(restype), KindSelector.VAL, resultInfo);
+            Type capturedRes = resultInfo.checkContext.inferenceContext().cachedCapture(tree, restype, true);
+            result = check(tree, capturedRes, KindSelector.VAL, resultInfo);
         }
         chk.validate(tree.typeargs, localEnv);
     }
@@ -2865,8 +2863,10 @@
                 //omitted as we don't know at this stage as to whether this is a
                 //raw selector (because of inference)
                 chk.validate(that.expr, env, false);
+            } else {
+                Symbol lhsSym = TreeInfo.symbol(that.expr);
+                localEnv.info.selectSuper = lhsSym != null && lhsSym.name == names._super;
             }
-
             //attrib type-arguments
             List<Type> typeargtypes = List.nil();
             if (that.typeargs != null) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Nov 24 00:42:53 2015 +0000
@@ -417,6 +417,8 @@
  * Class name generation
  **************************************************************************/
 
+    private Map<Tuple2<Name, Name>, Integer> localClassNameIndexes = new HashMap<>();
+
     /** Return name of local class.
      *  This is of the form   {@code <enclClass> $ n <classname> }
      *  where
@@ -424,17 +426,28 @@
      *    classname is the simple name of the local class
      */
     public Name localClassName(ClassSymbol c) {
-        for (int i=1; ; i++) {
-            Name flatname = names.
-                fromString("" + c.owner.enclClass().flatname +
-                           syntheticNameChar + i +
-                           c.name);
-            if (compiled.get(flatname) == null) return flatname;
+        Name enclFlatname = c.owner.enclClass().flatname;
+        String enclFlatnameStr = enclFlatname.toString();
+        Tuple2<Name, Name> key = new Tuple2<>(enclFlatname, c.name);
+        Integer index = localClassNameIndexes.get(key);
+        for (int i = (index == null) ? 1 : index; ; i++) {
+            Name flatname = names.fromString(enclFlatnameStr
+                    + syntheticNameChar + i + c.name);
+            if (compiled.get(flatname) == null) {
+                localClassNameIndexes.put(key, i + 1);
+                return flatname;
+            }
         }
     }
 
+    void clearLocalClassNameIndexes(ClassSymbol c) {
+        localClassNameIndexes.remove(new Tuple2<>(
+                c.owner.enclClass().flatname, c.name));
+    }
+
     public void newRound() {
         compiled.clear();
+        localClassNameIndexes.clear();
     }
 
 /* *************************************************************************
@@ -1828,11 +1841,18 @@
         boolean resultTypesOK =
             types.returnTypeSubstitutable(mt, ot, otres, overrideWarner);
         if (!resultTypesOK) {
-            log.error(TreeInfo.diagnosticPositionFor(m, tree),
-                      "override.incompatible.ret",
-                      cannotOverride(m, other),
-                      mtres, otres);
-            m.flags_field |= BAD_OVERRIDE;
+            if ((m.flags() & STATIC) != 0 && (other.flags() & STATIC) != 0) {
+                log.error(TreeInfo.diagnosticPositionFor(m, tree),
+                        Errors.OverrideIncompatibleRet(Fragments.CantHide(m, m.location(), other,
+                                        other.location()), mtres, otres));
+                m.flags_field |= BAD_OVERRIDE;
+            } else {
+                log.error(TreeInfo.diagnosticPositionFor(m, tree),
+                        "override.incompatible.ret",
+                        cannotOverride(m, other),
+                        mtres, otres);
+                m.flags_field |= BAD_OVERRIDE;
+            }
             return;
         } else if (overrideWarner.hasNonSilentLint(LintCategory.UNCHECKED)) {
             warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree),
@@ -2523,7 +2543,6 @@
                     types.isSameType(types.erasure(sym.type), types.erasure(sym2.type)) &&
                     sym != sym2 &&
                     (sym.flags() & Flags.SYNTHETIC) != (sym2.flags() & Flags.SYNTHETIC) &&
-                    (sym.flags() & IPROXY) == 0 && (sym2.flags() & IPROXY) == 0 &&
                     (sym.flags() & BRIDGE) == 0 && (sym2.flags() & BRIDGE) == 0) {
                     syntheticError(pos, (sym2.flags() & SYNTHETIC) == 0 ? sym2 : sym);
                     return;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Nov 24 00:42:53 2015 +0000
@@ -475,6 +475,7 @@
                 if (csym == null) return;
                 typeEnvs.remove(csym);
                 chk.compiled.remove(csym.flatname);
+                chk.clearLocalClassNameIndexes(csym);
                 syms.classes.remove(csym.flatname);
                 super.visitClassDef(tree);
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Tue Nov 24 00:42:53 2015 +0000
@@ -392,6 +392,9 @@
                 to = generateReturnConstraintsUndetVarToReference(
                         tree, uv, to, resultInfo, inferenceContext);
             }
+        } else if (rsInfoInfContext.free(resultInfo.pt)) {
+            //propagation - cache captured vars
+            qtype = inferenceContext.asUndetVar(rsInfoInfContext.cachedCapture(tree, from, false));
         }
         Assert.check(allowGraphInference || !rsInfoInfContext.free(to),
                 "legacy inference engine cannot handle constraints on both sides of a subtyping assertion");
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Nov 24 00:42:53 2015 +0000
@@ -46,9 +46,11 @@
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
 import com.sun.tools.javac.code.Symbol.TypeSymbol;
 import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.code.Type.TypeVar;
@@ -66,12 +68,16 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
 
 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
+
+import javax.lang.model.element.ElementKind;
 import javax.lang.model.type.TypeKind;
 
 /**
@@ -88,8 +94,11 @@
     private JCDiagnostic.Factory diags;
     private Log log;
     private Lower lower;
+    private Names names;
+    private Symtab syms;
+    private Resolve rs;
     private Operators operators;
-
+    private TreeMaker make;
     private Types types;
     private TransTypes transTypes;
     private SpecializeTypes specializeTypes;
@@ -140,7 +149,11 @@
         diags = JCDiagnostic.Factory.instance(context);
         log = Log.instance(context);
         lower = Lower.instance(context);
+        names = Names.instance(context);
+        syms = Symtab.instance(context);
+        rs = Resolve.instance(context);
         operators = Operators.instance(context);
+        make = TreeMaker.instance(context);
         types = Types.instance(context);
         transTypes = TransTypes.instance(context);
         specializeTypes = SpecializeTypes.instance(context);
@@ -275,21 +288,34 @@
         MethodSymbol sym = localContext.translatedSym;
         MethodType lambdaType = sym.type.asMethodType();
 
-        {
+        {   /* Type annotation management: Based on where the lambda features, type annotations that
+               are interior to it, may at this point be attached to the enclosing method, or the first
+               constructor in the class, or in the enclosing class symbol or in the field whose
+               initializer is the lambda. In any event, gather up the annotations that belong to the
+               lambda and attach it to the implementation method.
+            */
+
             Symbol owner = localContext.owner;
-            ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
-            ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
+            apportionTypeAnnotations(tree,
+                    owner::getRawTypeAttributes,
+                    owner::setTypeAttributes,
+                    sym::setTypeAttributes);
 
-            for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
-                if (tc.position.onLambda == tree) {
-                    lambdaTypeAnnos.append(tc);
-                } else {
-                    ownerTypeAnnos.append(tc);
-                }
+
+            boolean init;
+            if ((init = (owner.name == names.init)) || owner.name == names.clinit) {
+                owner = owner.owner;
+                apportionTypeAnnotations(tree,
+                        init ? owner::getInitTypeAttributes : owner::getClassInitTypeAttributes,
+                        init ? owner::setInitTypeAttributes : owner::setClassInitTypeAttributes,
+                        sym::appendUniqueTypeAttributes);
             }
-            if (lambdaTypeAnnos.nonEmpty()) {
-                owner.setTypeAttributes(ownerTypeAnnos.toList());
-                sym.setTypeAttributes(lambdaTypeAnnos.toList());
+            if (localContext.self != null && localContext.self.getKind() == ElementKind.FIELD) {
+                owner = localContext.self;
+                apportionTypeAnnotations(tree,
+                        owner::getRawTypeAttributes,
+                        owner::setTypeAttributes,
+                        sym::appendUniqueTypeAttributes);
             }
         }
 
@@ -345,6 +371,11 @@
                 syntheticInits.append((JCExpression) captured_local);
             }
         }
+        // add captured outer this instances (used only when `this' capture itself is illegal)
+        for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) {
+            JCTree captured_local = make.QualThis(fv.type);
+            syntheticInits.append((JCExpression) captured_local);
+        }
 
         //then, determine the arguments to the indy call
         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
@@ -356,6 +387,29 @@
         result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
     }
 
+    // where
+        // Reassign type annotations from the source that should really belong to the lambda
+        private void apportionTypeAnnotations(JCLambda tree,
+                                              Supplier<List<Attribute.TypeCompound>> source,
+                                              Consumer<List<Attribute.TypeCompound>> owner,
+                                              Consumer<List<Attribute.TypeCompound>> lambda) {
+
+            ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
+            ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
+
+            for (Attribute.TypeCompound tc : source.get()) {
+                if (tc.position.onLambda == tree) {
+                    lambdaTypeAnnos.append(tc);
+                } else {
+                    ownerTypeAnnos.append(tc);
+                }
+            }
+            if (lambdaTypeAnnos.nonEmpty()) {
+                owner.accept(ownerTypeAnnos.toList());
+                lambda.accept(lambdaTypeAnnos.toList());
+            }
+        }
+
     /**
      * Translate a method reference into an invokedynamic call to the
      * meta-factory.
@@ -433,6 +487,32 @@
         }
     }
 
+    /**
+     * Translate qualified `this' references within a lambda to the mapped identifier
+     * @param tree
+     */
+    @Override
+    public void visitSelect(JCFieldAccess tree) {
+        if (context == null || !analyzer.lambdaFieldAccessFilter(tree)) {
+            super.visitSelect(tree);
+        } else {
+            int prevPos = make.pos;
+            try {
+                make.at(tree);
+
+                LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
+                JCTree ltree = lambdaContext.translate(tree);
+                if (ltree != null) {
+                    result = ltree;
+                } else {
+                    super.visitSelect(tree);
+                }
+            } finally {
+                make.at(prevPos);
+            }
+        }
+    }
+
     @Override
     public void visitVarDef(JCVariableDecl tree) {
         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
@@ -797,13 +877,14 @@
             switch (tree.kind) {
                 case BOUND:
                     // The receiver is explicit in the method reference
-                    rcvr = addParameter("rec$", tree.getQualifierExpression().unerasedType, false);
+                    rcvr = addParameter("rec$", types.decorateDescriptor(tree.getQualifierExpression().unerasedType,
+                            tree.getQualifierExpression().type), false);
                     receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
                     break;
                 case UNBOUND:
                     // The receiver is the first parameter, extract it and
                     // adjust the SAM and unerased type lists accordingly
-                    rcvr = addParameter("rec$", tree.referentSite, false);
+                    rcvr = addParameter("rec$", types.decorateDescriptor(tree.referentSite, samDesc.getParameterTypes().head), false);
                     samPTypes = samPTypes.tail;
                     descPTypes = descPTypes.tail;
                     break;
@@ -1110,10 +1191,15 @@
                 return extractUnerasedType(((JCUnary)expr).arg);
             default:
                 return expr.unerasedType == null ?
-                        expr.type : expr.unerasedType;
+                        expr.type : types.decorateDescriptor(expr.unerasedType, unspecializeErased(expr.type));
         }
     }
 
+    Type unspecializeErased(Type t) {
+        return (t.tsym.flags() & SPECIALIZED_CLASS) != 0 ?
+                types.unspecialize(t.tsym.type) : t;
+    }
+
     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
     /**
      * This visitor collects information about translation of a lambda expression.
@@ -1133,6 +1219,11 @@
         private int lambdaCount = 0;
 
         /**
+         * List of types undergoing construction via explicit constructor chaining.
+         */
+        private List<ClassSymbol> typesUnderConstruction;
+
+        /**
          * keep the count of lambda expression defined in given context (used to
          * generate unambiguous names for serializable lambdas)
          */
@@ -1162,11 +1253,36 @@
 
         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
             frameStack = List.nil();
+            typesUnderConstruction = List.nil();
             localClassDefs = new HashMap<>();
             return translate(tree);
         }
 
         @Override
+        public void visitApply(JCMethodInvocation tree) {
+            List<ClassSymbol> previousNascentTypes = typesUnderConstruction;
+            try {
+                Name methName = TreeInfo.name(tree.meth);
+                if (methName == names._this || methName == names._super) {
+                    typesUnderConstruction = typesUnderConstruction.prepend(currentClass());
+                }
+                super.visitApply(tree);
+            } finally {
+                typesUnderConstruction = previousNascentTypes;
+            }
+        }
+            // where
+            private ClassSymbol currentClass() {
+                for (Frame frame : frameStack) {
+                    if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
+                        JCClassDecl cdef = (JCClassDecl) frame.tree;
+                        return cdef.sym;
+                    }
+                }
+                return null;
+            }
+
+        @Override
         public void visitBlock(JCBlock tree) {
             List<Frame> prevStack = frameStack;
             try {
@@ -1641,6 +1757,22 @@
         }
 
         /**
+         *  This is used to filter out those select nodes that need to be adjusted
+         *  when translating away lambda expressions - at the moment, this is the
+         *  set of nodes that select `this' (qualified this)
+         */
+        private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) {
+            LambdaTranslationContext lambdaContext =
+                    context instanceof LambdaTranslationContext ?
+                            (LambdaTranslationContext) context : null;
+            return lambdaContext != null
+                    && !fAccess.sym.isStatic()
+                    && fAccess.name == names._this
+                    && (fAccess.sym.owner.kind == TYP)
+                    && !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty();
+        }
+
+        /**
          * This is used to filter out those new class expressions that need to
          * be qualified with an enclosing tree
          */
@@ -1814,6 +1946,7 @@
                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
+                translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>());
                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
 
                 freeVarProcessedLocalClasses = new HashSet<>();
@@ -1926,6 +2059,16 @@
                             }
                         };
                         break;
+                    case CAPTURED_OUTER_THIS:
+                        Name name = names.fromString(new String(sym.flatName().toString() + names.dollarThis));
+                        ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
+                            @Override
+                            public Symbol baseSymbol() {
+                                //keep mapping with original captured symbol
+                                return sym;
+                            }
+                        };
+                        break;
                     case LOCAL_VAR:
                         ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
@@ -1946,6 +2089,14 @@
             }
 
             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
+                if (skind == CAPTURED_THIS && sym != null && sym.kind == TYP && !typesUnderConstruction.isEmpty()) {
+                    ClassSymbol currentClass = currentClass();
+                    if (currentClass != null && typesUnderConstruction.contains(currentClass)) {
+                        // reference must be to enclosing outer instance, mutate capture kind.
+                        Assert.check(sym != currentClass); // should have been caught right in Attr
+                        skind = CAPTURED_OUTER_THIS;
+                    }
+                }
                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
                 if (!transMap.containsKey(sym)) {
                     transMap.put(sym, translate(sym, skind));
@@ -1959,18 +2110,51 @@
             }
 
             JCTree translate(JCIdent lambdaIdent) {
-                for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
-                    if (m.containsKey(lambdaIdent.sym)) {
-                        Symbol tSym = m.get(lambdaIdent.sym);
-                        JCExpression t = make.Ident(tSym).setType(lambdaIdent.type);
-                        t.unerasedType = lambdaIdent.unerasedType;
-                        tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
-                        return t;
+                for (LambdaSymbolKind kind : LambdaSymbolKind.values()) {
+                    Map<Symbol, Symbol> m = getSymbolMap(kind);
+                    switch(kind) {
+                        default:
+                            if (m.containsKey(lambdaIdent.sym)) {
+                                Symbol tSym = m.get(lambdaIdent.sym);
+                                JCExpression t = make.Ident(tSym).setType(lambdaIdent.type);
+                                t.unerasedType = lambdaIdent.unerasedType;
+                                tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
+                                return t;
+                            }
+                            break;
+                        case CAPTURED_OUTER_THIS:
+                            if (lambdaIdent.sym.owner.kind == TYP && m.containsKey(lambdaIdent.sym.owner)) {
+                                // Transform outer instance variable references anchoring them to the captured synthetic.
+                                Symbol tSym = m.get(lambdaIdent.sym.owner);
+                                JCExpression t = make.Ident(tSym).setType(lambdaIdent.sym.owner.type);
+                                tSym.setTypeAttributes(lambdaIdent.sym.owner.getRawTypeAttributes());
+                                t = make.Select(t, lambdaIdent.name);
+                                t.unerasedType = lambdaIdent.unerasedType;
+                                t.setType(lambdaIdent.type);
+                                TreeInfo.setSymbol(t, lambdaIdent.sym);
+                                return t;
+                            }
+                            break;
                     }
                 }
                 return null;
             }
 
+            /* Translate away qualified this expressions, anchoring them to synthetic parameters that
+               capture the qualified this handle. `fieldAccess' is guaranteed to one such.
+            */
+            public JCTree translate(JCFieldAccess fieldAccess) {
+                Assert.check(fieldAccess.name == names._this);
+                Map<Symbol, Symbol> m = translatedSymbols.get(LambdaSymbolKind.CAPTURED_OUTER_THIS);
+                if (m.containsKey(fieldAccess.sym.owner)) {
+                    Symbol tSym = m.get(fieldAccess.sym.owner);
+                    JCExpression t = make.Ident(tSym).setType(fieldAccess.sym.owner.type);
+                    tSym.setTypeAttributes(fieldAccess.sym.owner.getRawTypeAttributes());
+                    return t;
+                }
+                return null;
+            }
+
             /**
              * The translatedSym is not complete/accurate until the analysis is
              * finished.  Once the analysis is finished, the translatedSym is
@@ -2008,6 +2192,10 @@
                     params.append(make.VarDef((VarSymbol) thisSym, null));
                     parameterSymbols.append((VarSymbol) thisSym);
                 }
+                for (Symbol thisSym : getSymbolMap(CAPTURED_OUTER_THIS).values()) {
+                    params.append(make.VarDef((VarSymbol) thisSym, null));
+                    parameterSymbols.append((VarSymbol) thisSym);
+                }
                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
                     params.append(make.VarDef((VarSymbol) thisSym, null));
                     parameterSymbols.append((VarSymbol) thisSym);
@@ -2114,9 +2302,6 @@
              */
             boolean interfaceParameterIsIntersectionType() {
                 List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
-                if (tree.kind == ReferenceKind.UNBOUND) {
-                    tl = tl.tail;
-                }
                 for (; tl.nonEmpty(); tl = tl.tail) {
                     Type pt = tl.head;
                     if (pt.getKind() == TypeKind.TYPEVAR) {
@@ -2174,6 +2359,7 @@
         LOCAL_VAR,      // original to translated lambda locals
         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
+        CAPTURED_OUTER_THIS, // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)
         TYPE_VAR       // original to translated lambda type variables
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1864,7 +1864,7 @@
     private JCStatement makeResourceCloseInvocation(JCExpression resource) {
         // convert to AutoCloseable if needed
         if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
-            resource = (JCExpression) convert(resource, syms.autoCloseableType);
+            resource = convert(resource, syms.autoCloseableType);
         }
 
         // create resource.close() method invocation
@@ -2303,7 +2303,7 @@
  *************************************************************************/
 
     interface TreeBuilder {
-        JCTree build(JCTree arg);
+        JCExpression build(JCExpression arg);
     }
 
     /** Construct an expression using the builder, with the given rval
@@ -2321,7 +2321,7 @@
      *  where <code><b>TEMP</b></code> is a newly declared variable
      *  in the let expression.
      */
-    JCTree abstractRval(JCTree rval, Type type, TreeBuilder builder) {
+    JCExpression abstractRval(JCExpression rval, Type type, TreeBuilder builder) {
         rval = TreeInfo.skipParens(rval);
         switch (rval.getTag()) {
         case LITERAL:
@@ -2339,15 +2339,15 @@
                                       type,
                                       currentMethodSym);
         rval = convert(rval,type);
-        JCVariableDecl def = make.VarDef(var, (JCExpression)rval); // XXX cast
-        JCTree built = builder.build(make.Ident(var));
-        JCTree res = make.LetExpr(def, built);
+        JCVariableDecl def = make.VarDef(var, rval); // XXX cast
+        JCExpression built = builder.build(make.Ident(var));
+        JCExpression res = make.LetExpr(def, built);
         res.type = built.type;
         return res;
     }
 
     // same as above, with the type of the temporary variable computed
-    JCTree abstractRval(JCTree rval, TreeBuilder builder) {
+    JCExpression abstractRval(JCExpression rval, TreeBuilder builder) {
         return abstractRval(rval, rval.type, builder);
     }
 
@@ -2356,30 +2356,28 @@
     // Select expressions, where we place the left-hand-side of the
     // select in a temporary, and for Indexed expressions, where we
     // place both the indexed expression and the index value in temps.
-    JCTree abstractLval(JCTree lval, final TreeBuilder builder) {
+    JCExpression abstractLval(JCExpression lval, final TreeBuilder builder) {
         lval = TreeInfo.skipParens(lval);
         switch (lval.getTag()) {
         case IDENT:
             return builder.build(lval);
         case SELECT: {
             final JCFieldAccess s = (JCFieldAccess)lval;
-            JCTree selected = TreeInfo.skipParens(s.selected);
             Symbol lid = TreeInfo.symbol(s.selected);
             if (lid != null && lid.kind == TYP) return builder.build(lval);
             return abstractRval(s.selected, new TreeBuilder() {
-                    public JCTree build(final JCTree selected) {
-                        return builder.build(make.Select((JCExpression)selected, s.sym));
+                    public JCExpression build(final JCExpression selected) {
+                        return builder.build(make.Select(selected, s.sym));
                     }
                 });
         }
         case INDEXED: {
             final JCArrayAccess i = (JCArrayAccess)lval;
             return abstractRval(i.indexed, new TreeBuilder() {
-                    public JCTree build(final JCTree indexed) {
+                    public JCExpression build(final JCExpression indexed) {
                         return abstractRval(i.index, syms.intType, new TreeBuilder() {
-                                public JCTree build(final JCTree index) {
-                                    JCTree newLval = make.Indexed((JCExpression)indexed,
-                                                                (JCExpression)index);
+                                public JCExpression build(final JCExpression index) {
+                                    JCExpression newLval = make.Indexed(indexed, index);
                                     newLval.setType(i.type);
                                     return builder.build(newLval);
                                 }
@@ -2395,9 +2393,9 @@
     }
 
     // evaluate and discard the first expression, then evaluate the second.
-    JCTree makeComma(final JCTree expr1, final JCTree expr2) {
+    JCExpression makeComma(final JCExpression expr1, final JCExpression expr2) {
         return abstractRval(expr1, new TreeBuilder() {
-                public JCTree build(final JCTree discarded) {
+                public JCExpression build(final JCExpression discarded) {
                     return expr2;
                 }
             });
@@ -2430,7 +2428,7 @@
 
     /** Visitor method: Translate a single node, boxing or unboxing if needed.
      */
-    public <T extends JCTree> T translate(T tree, Type type) {
+    public <T extends JCExpression> T translate(T tree, Type type) {
         return (tree == null) ? null : boxIfNeeded(translate(tree), type);
     }
 
@@ -2456,7 +2454,7 @@
 
     /** Visitor method: Translate list of trees.
      */
-    public <T extends JCTree> List<T> translate(List<T> trees, Type type) {
+    public <T extends JCExpression> List<T> translate(List<T> trees, Type type) {
         if (trees == null) return null;
         for (List<T> l = trees; l.nonEmpty(); l = l.tail)
             l.head = translate(l.head, type);
@@ -3044,10 +3042,10 @@
         }
     }
 //where
-    private JCTree convert(JCTree tree, Type pt) {
+    private JCExpression convert(JCExpression tree, Type pt) {
         if (tree.type == pt || tree.type.hasTag(BOT))
             return tree;
-        JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
+        JCExpression result = make_at(tree.pos()).TypeCast(make.Type(pt), tree);
         result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
                                                        : pt;
         return result;
@@ -3212,7 +3210,7 @@
 
     /** Expand a boxing or unboxing conversion if needed. */
     @SuppressWarnings("unchecked") // XXX unchecked
-    <T extends JCTree> T boxIfNeeded(T tree, Type type) {
+    <T extends JCExpression> T boxIfNeeded(T tree, Type type) {
         boolean havePrimitive = tree.type.isPrimitive();
         if (havePrimitive == type.isPrimitive())
             return tree;
@@ -3221,12 +3219,12 @@
             if (!unboxedTarget.hasTag(NONE)) {
                 if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89;
                     tree.type = unboxedTarget.constType(tree.type.constValue());
-                return (T)boxPrimitive((JCExpression)tree, types.erasure(type));
+                return (T)boxPrimitive(tree, types.erasure(type));
             } else {
-                tree = (T)boxPrimitive((JCExpression)tree);
+                tree = (T)boxPrimitive(tree);
             }
         } else {
-            tree = (T)unbox((JCExpression)tree, type);
+            tree = (T)unbox(tree, type);
         }
         return tree;
     }
@@ -3309,7 +3307,7 @@
             // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
             // (but without recomputing x)
             JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() {
-                    public JCTree build(final JCTree lhs) {
+                    public JCExpression build(final JCExpression lhs) {
                         JCTree.Tag newTag = tree.getTag().noAssignOp();
                         // Erasure (TransTypes) can change the type of
                         // tree.lhs.  However, we can still get the
@@ -3319,7 +3317,7 @@
                                                                       newTag,
                                                                       tree.type,
                                                                       tree.rhs.type);
-                        JCExpression expr = (JCExpression)lhs;
+                        JCExpression expr = lhs;
                         if (expr.type != tree.type)
                             expr = make.TypeCast(tree.type, expr);
                         JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
@@ -3328,7 +3326,7 @@
                         JCExpression newRhs = boxingReq ?
                             make.TypeCast(types.unboxedType(tree.type), opResult) :
                             opResult;
-                        return make.Assign((JCExpression)lhs, newRhs).setType(tree.type);
+                        return make.Assign(lhs, newRhs).setType(tree.type);
                     }
                 });
             result = translate(newTree);
@@ -3355,22 +3353,22 @@
     }
 
     /** Lower a tree of the form e++ or e-- where e is an object type */
-    JCTree lowerBoxedPostop(final JCUnary tree) {
+    JCExpression lowerBoxedPostop(final JCUnary tree) {
         // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
         // or
         // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
         // where OP is += or -=
         final boolean cast = TreeInfo.skipParens(tree.arg).hasTag(TYPECAST);
         return abstractLval(tree.arg, new TreeBuilder() {
-                public JCTree build(final JCTree tmp1) {
+                public JCExpression build(final JCExpression tmp1) {
                     return abstractRval(tmp1, tree.arg.type, new TreeBuilder() {
-                            public JCTree build(final JCTree tmp2) {
+                            public JCExpression build(final JCExpression tmp2) {
                                 JCTree.Tag opcode = (tree.hasTag(POSTINC))
                                     ? PLUS_ASG : MINUS_ASG;
                                 JCTree lhs = cast
-                                    ? make.TypeCast(tree.arg.type, (JCExpression)tmp1)
+                                    ? make.TypeCast(tree.arg.type, tmp1)
                                     : tmp1;
-                                JCTree update = makeAssignop(opcode,
+                                JCExpression update = makeAssignop(opcode,
                                                              lhs,
                                                              make.Literal(1));
                                 return makeComma(update, tmp2);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java	Tue Nov 24 00:42:53 2015 +0000
@@ -404,13 +404,20 @@
      */
     class UnaryNumericOperator extends UnaryOperatorHelper {
 
+        Predicate<Type> numericTest;
+
         UnaryNumericOperator(Tag tag) {
+            this(tag, Type::isNumeric);
+        }
+
+        UnaryNumericOperator(Tag tag, Predicate<Type> numericTest) {
             super(tag);
+            this.numericTest = numericTest;
         }
 
         @Override
         public boolean test(Type type) {
-            return unaryPromotion(type).isNumeric();
+            return numericTest.test(unaryPromotion(type));
         }
 
         @Override
@@ -462,8 +469,15 @@
      */
     class BinaryNumericOperator extends BinaryOperatorHelper {
 
+        Predicate<Type> numericTest;
+
         BinaryNumericOperator(Tag tag) {
+            this(tag, Type::isNumeric);
+        }
+
+        BinaryNumericOperator(Tag tag, Predicate<Type> numericTest) {
             super(tag);
+            this.numericTest = numericTest;
         }
 
         @Override
@@ -474,7 +488,8 @@
 
         @Override
         public boolean test(Type arg1, Type arg2) {
-            return unaryPromotion(arg1).isNumeric() && unaryPromotion(arg2).isNumeric();
+            return numericTest.test(unaryPromotion(arg1)) &&
+                    numericTest.test(unaryPromotion(arg2));
         }
     }
 
@@ -518,20 +533,22 @@
 
         @Override
         public boolean test(Type arg1, Type arg2) {
-            return types.isSameType(arg1, syms.stringType) ||
+            boolean hasStringOp = types.isSameType(arg1, syms.stringType) ||
                     types.isSameType(arg2, syms.stringType);
+            boolean hasVoidOp = arg1.hasTag(TypeTag.VOID) || arg2.hasTag(TypeTag.VOID);
+            return hasStringOp && !hasVoidOp;
         }
 
         /**
          * This routine applies following mappings:
          * - if input type is primitive, apply numeric promotion
-         * - if input type is either 'null' or 'String' leave it untouched
+         * - if input type is either 'void', 'null' or 'String' leave it untouched
          * - otherwise return 'Object'
          */
         private Type stringPromotion(Type t) {
             if (t.isPrimitive()) {
                 return unaryPromotion(t);
-            } else if (t.hasTag(TypeTag.BOT) ||
+            } else if (t.hasTag(TypeTag.VOID) || t.hasTag(TypeTag.BOT) ||
                     types.isSameType(t, syms.stringType)) {
                 return t;
             } else if (t.hasTag(TypeTag.TYPEVAR)) {
@@ -644,7 +661,7 @@
                         .addUnaryOperator(FLOAT, FLOAT, fneg)
                         .addUnaryOperator(LONG, LONG, lneg)
                         .addUnaryOperator(INT, INT, ineg),
-                new UnaryNumericOperator(Tag.COMPL)
+                new UnaryNumericOperator(Tag.COMPL, Type::isIntegral)
                         .addUnaryOperator(LONG, LONG, lxor)
                         .addUnaryOperator(INT, INT, ixor),
                 new UnaryPrefixPostfixOperator(Tag.POSTINC)
@@ -717,17 +734,17 @@
                     .addBinaryOperator(INT, INT, INT, imod),
             new BinaryBooleanOperator(Tag.BITAND)
                     .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, iand),
-            new BinaryNumericOperator(Tag.BITAND)
+            new BinaryNumericOperator(Tag.BITAND, Type::isIntegral)
                     .addBinaryOperator(LONG, LONG, LONG, land)
                     .addBinaryOperator(INT, INT, INT, iand),
             new BinaryBooleanOperator(Tag.BITOR)
                     .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ior),
-            new BinaryNumericOperator(Tag.BITOR)
+            new BinaryNumericOperator(Tag.BITOR, Type::isIntegral)
                     .addBinaryOperator(LONG, LONG, LONG, lor)
                     .addBinaryOperator(INT, INT, INT, ior),
             new BinaryBooleanOperator(Tag.BITXOR)
                     .addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ixor),
-            new BinaryNumericOperator(Tag.BITXOR)
+            new BinaryNumericOperator(Tag.BITXOR, Type::isIntegral)
                     .addBinaryOperator(LONG, LONG, LONG, lxor)
                     .addBinaryOperator(INT, INT, INT, ixor),
             new BinaryShiftOperator(Tag.SL)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Nov 24 00:42:53 2015 +0000
@@ -3220,8 +3220,7 @@
                 findDiamond(env, site, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
                 findMethod(env, site, name, argtypes, typeargtypes,
                         phase.isBoxingRequired(), phase.isVarargsRequired());
-            return site.getEnclosingType().hasTag(CLASS) && !hasEnclosingInstance(env, site) ?
-                        new BadConstructorReferenceError(sym) : sym;
+            return enclosingInstanceMissing(env, site) ? new BadConstructorReferenceError(sym) : sym;
         }
 
         @Override
@@ -3354,9 +3353,12 @@
         }
     }
 
-    boolean hasEnclosingInstance(Env<AttrContext> env, Type type) {
-        Symbol encl = resolveSelfContainingInternal(env, type.tsym, false);
-        return encl != null && !encl.kind.isResolutionError();
+    boolean enclosingInstanceMissing(Env<AttrContext> env, Type type) {
+        if (type.hasTag(CLASS) && type.getEnclosingType().hasTag(CLASS)) {
+            Symbol encl = resolveSelfContainingInternal(env, type.tsym, false);
+            return encl == null || encl.kind.isResolutionError();
+        }
+        return false;
     }
 
     private Symbol resolveSelfContainingInternal(Env<AttrContext> env,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Tue Nov 24 00:42:53 2015 +0000
@@ -35,6 +35,7 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
@@ -90,7 +91,7 @@
         log = Log.instance(context);
         syms = Symtab.instance(context);
         enter = Enter.instance(context);
-        overridden = new HashMap<>();
+        bridgeSpans = new HashMap<>();
         types = Types.instance(context);
         make = TreeMaker.instance(context);
         resolve = Resolve.instance(context);
@@ -100,10 +101,12 @@
         annotate = Annotate.instance(context);
     }
 
-    /** A hashtable mapping bridge methods to the methods they override after
-     *  type erasure.
+    /** A hashtable mapping bridge methods to the pair of methods they bridge.
+     *  The bridge overrides the first of the pair after type erasure and deflects
+     *  to the second of the pair (which differs in type erasure from the one
+     *  it overrides thereby necessitating the bridge)
      */
-    Map<MethodSymbol,MethodSymbol> overridden;
+    Map<MethodSymbol, Tuple2<MethodSymbol, MethodSymbol>> bridgeSpans;
 
     /** Construct an attributed tree for a cast of expression to target type,
      *  unless it already has precisely that type.
@@ -319,9 +322,9 @@
             bridges.append(md);
         }
 
-        // Add bridge to scope of enclosing class and `overridden' table.
+        // Add bridge to scope of enclosing class and keep track of the bridge span.
         origin.members().enter(bridge);
-        overridden.put(bridge, meth);
+        bridgeSpans.put(bridge, new Tuple2<>(meth, impl));
     }
 
     private List<VarSymbol> createBridgeParams(MethodSymbol impl, MethodSymbol bridge,
@@ -369,13 +372,13 @@
         if (sym.kind == MTH &&
             sym.name != names.init &&
             (sym.flags() & (PRIVATE | STATIC)) == 0 &&
-            (sym.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC &&
+            (sym.flags() & SYNTHETIC) != SYNTHETIC &&
             sym.isMemberOf(origin, types) &&
             !((MethodSymbol)sym).isApplicabilityRestrictedIn(origin.type, types))
         {
             MethodSymbol meth = (MethodSymbol)sym;
             MethodSymbol bridge = meth.binaryImplementation(origin, types);
-            MethodSymbol impl = meth.implementation(origin, types, true, overrideBridgeFilter);
+            MethodSymbol impl = meth.implementation(origin, types, true);
             if (bridge == null ||
                 bridge == meth ||
                 (impl != null && !bridge.owner.isSubClass(impl.owner, types))) {
@@ -391,14 +394,19 @@
                     // reflection design error.
                     addBridge(pos, meth, impl, origin, false, bridges);
                 }
-            } else if ((bridge.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) == SYNTHETIC) {
-                MethodSymbol other = overridden.get(bridge);
+            } else if ((bridge.flags() & SYNTHETIC) == SYNTHETIC) {
+                final Tuple2<MethodSymbol, MethodSymbol> bridgeSpan = bridgeSpans.get(bridge);
+                MethodSymbol other = bridgeSpan == null ? null : bridgeSpan.elem0;
                 if (other != null && other != meth) {
                     if (impl == null || !impl.overrides(other, origin, types, true)) {
-                        // Bridge for other symbol pair was added
-                        log.error(pos, "name.clash.same.erasure.no.override",
-                                  other, other.location(origin.type, types),
-                                  meth,  meth.location(origin.type, types));
+                        // Is bridge effectively also the bridge for `meth', if so no clash.
+                        MethodSymbol target = bridgeSpan == null ? null : bridgeSpan.elem1;
+                        if (target == null || !target.overrides(meth, origin, types, true, false)) {
+                            // Bridge for other symbol pair was added
+                            log.error(pos, "name.clash.same.erasure.no.override",
+                                    other, other.location(origin.type, types),
+                                    meth, meth.location(origin.type, types));
+                        }
                     }
                 }
             } else if (!bridge.overrides(meth, origin, types, true)) {
@@ -414,11 +422,6 @@
         }
     }
     // where
-        private Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
-            public boolean accepts(Symbol s) {
-                return (s.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC;
-            }
-        };
 
         /**
          * @param method The symbol for which a bridge might have to be added
@@ -859,10 +862,6 @@
     public void visitSelect(JCFieldAccess tree) {
         Type t = types.skipTypeVars(tree.selected.type, false);
         if (t.isCompound()) {
-            if ((tree.sym.flags() & IPROXY) != 0) {
-                tree.sym = ((MethodSymbol)tree.sym).
-                    implemented((TypeSymbol)tree.sym.owner, types);
-            }
             tree.selected = coerce(
                 translate(tree.selected, tree.selected.type),
                 erasure(tree.sym.owner.type));
@@ -884,7 +883,17 @@
     }
 
     public void visitReference(JCMemberReference tree) {
-        tree.expr = translate(tree.expr, tree.expr.type);
+        Type t = types.skipTypeVars(tree.expr.type, false);
+        Type receiverTarget = t.isCompound() ? erasure(tree.sym.owner.type) : erasure(t);
+        Type unerasedRecvrType = tree.expr.type;
+        if (tree.kind == ReferenceKind.UNBOUND) {
+            tree.expr = make.Type(receiverTarget);
+            tree.expr.unerasedType = unerasedRecvrType;
+        } else {
+            tree.expr = translate(tree.expr, receiverTarget);
+            tree.expr.unerasedType = unerasedRecvrType;
+        }
+
         tree.type = erasure(tree.type);
         if (tree.varargsElement != null)
             tree.varargsElement = erasure(tree.varargsElement);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Tue Nov 24 00:42:53 2015 +0000
@@ -54,7 +54,6 @@
 import static com.sun.tools.javac.code.TypeTag.ERROR;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
-import com.sun.tools.javac.util.Dependencies.AttributionKind;
 import com.sun.tools.javac.util.Dependencies.CompletionCause;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -372,7 +371,6 @@
         }
 
         private void doImport(JCImport tree) {
-            dependencies.push(AttributionKind.IMPORT, tree);
             JCFieldAccess imp = (JCFieldAccess)tree.qualid;
             Name name = TreeInfo.name(imp);
 
@@ -399,7 +397,6 @@
                     importNamed(tree.pos(), c, env, tree);
                 }
             }
-            dependencies.pop();
         }
 
         Type attribImportType(JCTree tree, Env<AttrContext> env) {
@@ -647,13 +644,7 @@
 
             if (tree.extending != null) {
                 extending = clearTypeParams(tree.extending);
-                dependencies.push(AttributionKind.EXTENDS, tree.extending);
-                try {
-                    supertype = attr.attribBase(extending, baseEnv,
-                                                true, false, true);
-                } finally {
-                    dependencies.pop();
-                }
+                supertype = attr.attribBase(extending, baseEnv, true, false, true);
             } else {
                 extending = null;
                 supertype = ((tree.mods.flags & Flags.ENUM) != 0)
@@ -671,20 +662,14 @@
             List<JCExpression> interfaceTrees = tree.implementing;
             for (JCExpression iface : interfaceTrees) {
                 iface = clearTypeParams(iface);
-                dependencies.push(AttributionKind.IMPLEMENTS, iface);
-                try {
-                    Type it = attr.attribBase(iface, baseEnv, false, true, true);
-                    if (it.hasTag(CLASS)) {
-                        interfaces.append(it);
-                        if (all_interfaces != null) all_interfaces.append(it);
-                    } else {
-                        if (all_interfaces == null)
-                            all_interfaces = new ListBuffer<Type>().appendList(interfaces);
-                        all_interfaces.append(modelMissingTypes(it, iface, true));
-
-                    }
-                } finally {
-                    dependencies.pop();
+                Type it = attr.attribBase(iface, baseEnv, false, true, true);
+                if (it.hasTag(CLASS)) {
+                    interfaces.append(it);
+                    if (all_interfaces != null) all_interfaces.append(it);
+                } else {
+                    if (all_interfaces == null)
+                        all_interfaces = new ListBuffer<Type>().appendList(interfaces);
+                    all_interfaces.append(modelMissingTypes(it, iface, true));
                 }
             }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1282,8 +1282,10 @@
             endAttr(alenIdx);
             acount++;
         }
-        if (options.isSet(PARAMETERS))
-            acount += writeMethodParametersAttr(m);
+        if (options.isSet(PARAMETERS)) {
+            if (!m.isLambdaMethod()) // Per JDK-8138729, do not emit parameters table for lambda bodies.
+                acount += writeMethodParametersAttr(m);
+        }
         if (m.whereClauses != WhereClause.emptyWhereClause) {
             acount += writeMethodWhereClauses(m);
         }
@@ -1291,7 +1293,8 @@
             acount += writeBridgeAttr(m);
         }
         acount += writeMemberAttrs(m);
-        acount += writeParameterAttrs(m);
+        if (!m.isLambdaMethod())
+            acount += writeParameterAttrs(m);
         acount += writeTypeVariablesMapIfNeeded(m);
         endAttrs(acountIdx, acount);
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1852,8 +1852,13 @@
     public void visitReturn(JCReturn tree) {
         int limit = code.nextreg;
         final Env<GenContext> targetEnv;
-        final Type returnType = env.enclMethod.sym.getReturnType();
+		final Type returnType = env.enclMethod.sym.getReturnType();
         final Type erasedReturnType = types.erasure(returnType);
+
+        /* Save and then restore the location of the return in case a finally
+         * is expanded (with unwind()) in the middle of our bytecodes.
+         */
+        int tmpPos = code.pendingStatPos;
         if (tree.expr != null) {
             Item r = genExpr(tree.expr, erasedReturnType).load();
             if (hasFinally(env.enclMethod, env)) {
@@ -1861,6 +1866,7 @@
                 r.store();
             }
             targetEnv = unwind(env.enclMethod, env);
+            code.pendingStatPos = tmpPos;
             r.load();
             emitAndMarkIfNeeded1(returnType, types::isSpecializableTypeVar,
                     () -> code.emitop0(returnType.isValue() ? vreturn :
@@ -1873,7 +1879,7 @@
              *  we need to store the code.pendingStatPos value before generating
              *  the finalizer.
              */
-            int tmpPos = code.pendingStatPos;
+            tmpPos = code.pendingStatPos;
             targetEnv = unwind(env.enclMethod, env);
             code.pendingStatPos = tmpPos;
             code.emitop0(return_);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Tue Nov 24 00:42:53 2015 +0000
@@ -26,12 +26,8 @@
 package com.sun.tools.javac.parser;
 
 import java.text.BreakIterator;
-import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
 
 import com.sun.source.doctree.AttributeTree.ValueKind;
 import com.sun.tools.javac.parser.DocCommentParser.TagParser.Kind;
@@ -40,12 +36,10 @@
 import com.sun.tools.javac.tree.DCTree;
 import com.sun.tools.javac.tree.DCTree.DCAttribute;
 import com.sun.tools.javac.tree.DCTree.DCDocComment;
-import com.sun.tools.javac.tree.DCTree.DCEndElement;
 import com.sun.tools.javac.tree.DCTree.DCEndPosTree;
 import com.sun.tools.javac.tree.DCTree.DCErroneous;
 import com.sun.tools.javac.tree.DCTree.DCIdentifier;
 import com.sun.tools.javac.tree.DCTree.DCReference;
-import com.sun.tools.javac.tree.DCTree.DCStartElement;
 import com.sun.tools.javac.tree.DCTree.DCText;
 import com.sun.tools.javac.tree.DocTreeMaker;
 import com.sun.tools.javac.tree.JCTree;
@@ -55,9 +49,8 @@
 import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Names;
-import com.sun.tools.javac.util.Options;
 import com.sun.tools.javac.util.Position;
-import com.sun.tools.javac.util.StringUtils;
+
 import static com.sun.tools.javac.util.LayoutCharacters.*;
 
 /**
@@ -100,24 +93,20 @@
 
     Map<Name, TagParser> tagParsers;
 
-    DocCommentParser(ParserFactory fac, DiagnosticSource diagSource, Comment comment) {
+    public DocCommentParser(ParserFactory fac, DiagnosticSource diagSource, Comment comment) {
         this.fac = fac;
         this.diagSource = diagSource;
         this.comment = comment;
         names = fac.names;
         m = fac.docTreeMaker;
-
-        Locale locale = (fac.locale == null) ? Locale.getDefault() : fac.locale;
-
-        Options options = fac.options;
-        boolean useBreakIterator = options.isSet("breakIterator");
-        if (useBreakIterator || !locale.getLanguage().equals(Locale.ENGLISH.getLanguage()))
-            sentenceBreaker = BreakIterator.getSentenceInstance(locale);
-
         initTagParsers();
     }
 
-    DCDocComment parse() {
+    public DocCommentParser(ParserFactory fac) {
+        this(fac, null, null);
+    }
+
+    public DCDocComment parse() {
         String c = comment.getText();
         buf = new char[c.length() + 1];
         c.getChars(0, c.length(), buf, 0);
@@ -128,54 +117,11 @@
 
         List<DCTree> body = blockContent();
         List<DCTree> tags = blockTags();
+        int pos = !body.isEmpty()
+                ? body.head.pos
+                : !tags.isEmpty() ? tags.head.pos : Position.NOPOS;
 
-        // split body into first sentence and body
-        ListBuffer<DCTree> fs = new ListBuffer<>();
-        loop:
-        for (; body.nonEmpty(); body = body.tail) {
-            DCTree t = body.head;
-            switch (t.getKind()) {
-                case TEXT:
-                    String s = ((DCText) t).getBody();
-                    int i = getSentenceBreak(s);
-                    if (i > 0) {
-                        int i0 = i;
-                        while (i0 > 0 && isWhitespace(s.charAt(i0 - 1)))
-                            i0--;
-                        fs.add(m.at(t.pos).Text(s.substring(0, i0)));
-                        int i1 = i;
-                        while (i1 < s.length() && isWhitespace(s.charAt(i1)))
-                            i1++;
-                        body = body.tail;
-                        if (i1 < s.length())
-                            body = body.prepend(m.at(t.pos + i1).Text(s.substring(i1)));
-                        break loop;
-                    } else if (body.tail.nonEmpty()) {
-                        if (isSentenceBreak(body.tail.head)) {
-                            int i0 = s.length() - 1;
-                            while (i0 > 0 && isWhitespace(s.charAt(i0)))
-                                i0--;
-                            fs.add(m.at(t.pos).Text(s.substring(0, i0 + 1)));
-                            body = body.tail;
-                            break loop;
-                        }
-                    }
-                    break;
-
-                case START_ELEMENT:
-                case END_ELEMENT:
-                    if (isSentenceBreak(t))
-                        break loop;
-                    break;
-            }
-            fs.add(t);
-        }
-
-        @SuppressWarnings("unchecked")
-        DCTree first = getFirst(fs.toList(), body, tags);
-        int pos = (first == null) ? Position.NOPOS : first.pos;
-
-        DCDocComment dc = m.at(pos).DocComment(comment, fs.toList(), body, tags);
+        DCDocComment dc = m.at(pos).DocComment(comment, body, tags);
         return dc;
     }
 
@@ -331,23 +277,28 @@
             nextChar();
             if (isIdentifierStart(ch)) {
                 Name name = readTagName();
-                skipWhitespace();
+                TagParser tp = tagParsers.get(name);
 
-                TagParser tp = tagParsers.get(name);
                 if (tp == null) {
-                    DCTree text = inlineText();
+                    skipWhitespace();
+                    DCTree text = inlineText(WhitespaceRetentionPolicy.REMOVE_ALL);
                     if (text != null) {
                         nextChar();
                         return m.at(p).UnknownInlineTag(name, List.of(text)).setEndPos(bp);
                     }
-                } else if (tp.getKind() == TagParser.Kind.INLINE) {
-                    DCEndPosTree<?> tree = (DCEndPosTree<?>) tp.parse(p);
-                    if (tree != null) {
-                        return tree.setEndPos(bp);
+                } else {
+                    if (!tp.retainWhiteSpace) {
+                        skipWhitespace();
                     }
-                } else {
-                    inlineText(); // skip content
-                    nextChar();
+                    if (tp.getKind() == TagParser.Kind.INLINE) {
+                        DCEndPosTree<?> tree = (DCEndPosTree<?>) tp.parse(p);
+                        if (tree != null) {
+                            return tree.setEndPos(bp);
+                        }
+                    } else { // handle block tags (ex: @see) in inline content
+                        inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip content
+                        nextChar();
+                    }
                 }
             }
             return erroneous("dc.no.tag.name", p);
@@ -356,13 +307,32 @@
         }
     }
 
+    private static enum WhitespaceRetentionPolicy {
+        RETAIN_ALL,
+        REMOVE_FIRST_SPACE,
+        REMOVE_ALL
+    }
+
     /**
      * Read plain text content of an inline tag.
      * Matching pairs of { } are skipped; the text is terminated by the first
      * unmatched }. It is an error if the beginning of the next tag is detected.
      */
-    protected DCTree inlineText() throws ParseException {
-        skipWhitespace();
+    private DCTree inlineText(WhitespaceRetentionPolicy whitespacePolicy) throws ParseException {
+        switch (whitespacePolicy) {
+            case REMOVE_ALL:
+                skipWhitespace();
+                break;
+            case REMOVE_FIRST_SPACE:
+                if (ch == ' ')
+                    nextChar();
+                break;
+            case RETAIN_ALL:
+            default:
+                // do nothing
+                break;
+
+        }
         int pos = bp;
         int depth = 1;
 
@@ -742,7 +712,8 @@
                 }
                 if (ch == '>') {
                     nextChar();
-                    return m.at(p).StartElement(name, attrs, selfClosing).setEndPos(bp);
+                    DCTree dctree = m.at(p).StartElement(name, attrs, selfClosing).setEndPos(bp);
+                    return dctree;
                 }
             }
         } else if (ch == '/') {
@@ -884,15 +855,6 @@
         return m.at(pos).Erroneous(newString(pos, i + 1), diagSource, code);
     }
 
-    @SuppressWarnings("unchecked")
-    <T> T getFirst(List<T>... lists) {
-        for (List<T> list: lists) {
-            if (list.nonEmpty())
-                return list.head;
-        }
-        return null;
-    }
-
     protected boolean isIdentifierStart(char ch) {
         return Character.isUnicodeIdentifierStart(ch);
     }
@@ -916,8 +878,11 @@
     protected Name readTagName() {
         int start = bp;
         nextChar();
-        while (bp < buflen && (Character.isUnicodeIdentifierPart(ch) || ch == '.'))
+        while (bp < buflen
+                && (Character.isUnicodeIdentifierPart(ch) || ch == '.'
+                || ch == '-' || ch == ':')) {
             nextChar();
+        }
         return names.fromChars(buf, start, bp - start);
     }
 
@@ -960,59 +925,9 @@
     }
 
     protected void skipWhitespace() {
-        while (isWhitespace(ch))
+        while (isWhitespace(ch)) {
             nextChar();
-    }
-
-    protected int getSentenceBreak(String s) {
-        if (sentenceBreaker != null) {
-            sentenceBreaker.setText(s);
-            int i = sentenceBreaker.next();
-            return (i == s.length()) ? -1 : i;
         }
-
-        // scan for period followed by whitespace
-        boolean period = false;
-        for (int i = 0; i < s.length(); i++) {
-            switch (s.charAt(i)) {
-                case '.':
-                    period = true;
-                    break;
-
-                case ' ':
-                case '\f':
-                case '\n':
-                case '\r':
-                case '\t':
-                    if (period)
-                        return i;
-                    break;
-
-                default:
-                    period = false;
-                    break;
-            }
-        }
-        return -1;
-    }
-
-
-    Set<String> htmlBlockTags = new HashSet<>(Arrays.asList(
-                    "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"));
-
-    protected boolean isSentenceBreak(Name n) {
-        return htmlBlockTags.contains(StringUtils.toLowerCase(n.toString()));
-    }
-
-    protected boolean isSentenceBreak(DCTree t) {
-        switch (t.getKind()) {
-            case START_ELEMENT:
-                return isSentenceBreak(((DCStartElement) t).getName());
-
-            case END_ELEMENT:
-                return isSentenceBreak(((DCEndElement) t).getName());
-        }
-        return false;
     }
 
     /**
@@ -1026,12 +941,21 @@
     static abstract class TagParser {
         enum Kind { INLINE, BLOCK }
 
-        Kind kind;
-        DCTree.Kind treeKind;
+        final Kind kind;
+        final DCTree.Kind treeKind;
+        final boolean retainWhiteSpace;
+
 
         TagParser(Kind k, DCTree.Kind tk) {
             kind = k;
             treeKind = tk;
+            retainWhiteSpace = false;
+        }
+
+        TagParser(Kind k, DCTree.Kind tk, boolean retainWhiteSpace) {
+            kind = k;
+            treeKind = tk;
+            this.retainWhiteSpace = retainWhiteSpace;
         }
 
         Kind getKind() {
@@ -1059,9 +983,9 @@
             },
 
             // {@code text}
-            new TagParser(Kind.INLINE, DCTree.Kind.CODE) {
+            new TagParser(Kind.INLINE, DCTree.Kind.CODE, true) {
                 public DCTree parse(int pos) throws ParseException {
-                    DCTree text = inlineText();
+                    DCTree text = inlineText(WhitespaceRetentionPolicy.REMOVE_FIRST_SPACE);
                     nextChar();
                     return m.at(pos).Code((DCText) text);
                 }
@@ -1082,7 +1006,7 @@
                         nextChar();
                         return m.at(pos).DocRoot();
                     }
-                    inlineText(); // skip unexpected content
+                    inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip unexpected content
                     nextChar();
                     throw new ParseException("dc.unexpected.content");
                 }
@@ -1105,7 +1029,7 @@
                         nextChar();
                         return m.at(pos).InheritDoc();
                     }
-                    inlineText(); // skip unexpected content
+                    inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip unexpected content
                     nextChar();
                     throw new ParseException("dc.unexpected.content");
                 }
@@ -1130,9 +1054,9 @@
             },
 
             // {@literal text}
-            new TagParser(Kind.INLINE, DCTree.Kind.LITERAL) {
+            new TagParser(Kind.INLINE, DCTree.Kind.LITERAL, true) {
                 public DCTree parse(int pos) throws ParseException {
-                    DCTree text = inlineText();
+                    DCTree text = inlineText(WhitespaceRetentionPolicy.REMOVE_FIRST_SPACE);
                     nextChar();
                     return m.at(pos).Literal((DCText) text);
                 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Nov 24 00:42:53 2015 +0000
@@ -981,7 +981,7 @@
          */
         protected JCExpression foldStrings(JCExpression tree) {
             if (!allowStringFolding)
-                return null;
+                return tree;
             ListBuffer<JCExpression> opStack = new ListBuffer<>();
             ListBuffer<JCLiteral> litBuf = new ListBuffer<>();
             boolean needsFolding = false;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Nov 24 00:42:53 2015 +0000
@@ -2347,6 +2347,10 @@
     {0} in {1} cannot override {2} in {3}
 
 # 0: symbol, 1: symbol, 2: symbol, 3: symbol
+compiler.misc.cant.hide=\
+    {0} in {1} cannot hide {2} in {3}
+
+# 0: symbol, 1: symbol, 2: symbol, 3: symbol
 compiler.misc.cant.implement=\
     {0} in {1} cannot implement {2} in {3}
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,7 +25,6 @@
 
 package com.sun.tools.javac.tree;
 
-
 import javax.tools.Diagnostic;
 
 import com.sun.source.doctree.*;
@@ -39,8 +38,10 @@
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Position;
+
 import java.io.IOException;
 import java.io.StringWriter;
+
 import javax.tools.JavaFileObject;
 
 /**
@@ -104,14 +105,19 @@
     public static class DCDocComment extends DCTree implements DocCommentTree {
         public final Comment comment; // required for the implicit source pos table
 
+        public final List<DCTree> fullBody;
         public final List<DCTree> firstSentence;
         public final List<DCTree> body;
         public final List<DCTree> tags;
 
         public DCDocComment(Comment comment,
-                List<DCTree> firstSentence, List<DCTree> body, List<DCTree> tags) {
+                            List<DCTree> fullBody,
+                            List<DCTree> firstSentence,
+                            List<DCTree> body,
+                            List<DCTree> tags) {
             this.comment = comment;
             this.firstSentence = firstSentence;
+            this.fullBody = fullBody;
             this.body = body;
             this.tags = tags;
         }
@@ -132,6 +138,11 @@
         }
 
         @DefinedBy(Api.COMPILER_TREE)
+        public List<? extends DocTree> getFullBody() {
+            return fullBody;
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
         public List<? extends DocTree> getBody() {
             return body;
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -25,15 +25,15 @@
 
 package com.sun.tools.javac.tree;
 
+import java.io.IOException;
 import java.io.Writer;
+import java.util.List;
 
 import com.sun.source.doctree.*;
 import com.sun.source.doctree.AttributeTree.ValueKind;
 import com.sun.tools.javac.util.Convert;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
-import java.io.IOException;
-import java.util.List;
 
 /**
  * Prints out a doc comment tree.
@@ -201,14 +201,10 @@
     @DefinedBy(Api.COMPILER_TREE)
     public Void visitDocComment(DocCommentTree node, Void p) {
         try {
-            List<? extends DocTree> fs = node.getFirstSentence();
-            List<? extends DocTree> b = node.getBody();
+            List<? extends DocTree> b = node.getFullBody();
             List<? extends DocTree> t = node.getBlockTags();
-            print(fs);
-            if (!fs.isEmpty() && !b.isEmpty())
-                print(" ");
             print(b);
-            if ((!fs.isEmpty() || !b.isEmpty()) && !t.isEmpty())
+            if (!b.isEmpty() && !t.isEmpty())
                 print("\n");
             print(t, "\n");
         } catch (IOException e) {
@@ -308,7 +304,10 @@
         try {
             print("{");
             printTagName(node);
-            print(" ");
+            String body = node.getBody().getBody();
+            if (!body.isEmpty() && !Character.isWhitespace(body.charAt(0))) {
+                print(" ");
+            }
             print(node.getBody());
             print("}");
         } catch (IOException e) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java	Tue Nov 24 00:42:53 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,18 +25,60 @@
 
 package com.sun.tools.javac.tree;
 
+import java.text.BreakIterator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.ListIterator;
+
 import com.sun.source.doctree.AttributeTree.ValueKind;
+import com.sun.source.doctree.DocTree;
 import com.sun.source.doctree.DocTree.Kind;
-
+import com.sun.source.doctree.EndElementTree;
+import com.sun.source.doctree.StartElementTree;
+import com.sun.source.doctree.TextTree;
+import com.sun.tools.doclint.HtmlTag;
+import com.sun.tools.javac.api.JavacTrees;
 import com.sun.tools.javac.parser.Tokens.Comment;
-import com.sun.tools.javac.tree.DCTree.*;
+import com.sun.tools.javac.tree.DCTree.DCAttribute;
+import com.sun.tools.javac.tree.DCTree.DCAuthor;
+import com.sun.tools.javac.tree.DCTree.DCComment;
+import com.sun.tools.javac.tree.DCTree.DCDeprecated;
+import com.sun.tools.javac.tree.DCTree.DCDocComment;
+import com.sun.tools.javac.tree.DCTree.DCDocRoot;
+import com.sun.tools.javac.tree.DCTree.DCEndElement;
+import com.sun.tools.javac.tree.DCTree.DCEntity;
+import com.sun.tools.javac.tree.DCTree.DCErroneous;
+import com.sun.tools.javac.tree.DCTree.DCIdentifier;
+import com.sun.tools.javac.tree.DCTree.DCInheritDoc;
+import com.sun.tools.javac.tree.DCTree.DCLink;
+import com.sun.tools.javac.tree.DCTree.DCLiteral;
+import com.sun.tools.javac.tree.DCTree.DCParam;
+import com.sun.tools.javac.tree.DCTree.DCReference;
+import com.sun.tools.javac.tree.DCTree.DCReturn;
+import com.sun.tools.javac.tree.DCTree.DCSee;
+import com.sun.tools.javac.tree.DCTree.DCSerial;
+import com.sun.tools.javac.tree.DCTree.DCSerialData;
+import com.sun.tools.javac.tree.DCTree.DCSerialField;
+import com.sun.tools.javac.tree.DCTree.DCSince;
+import com.sun.tools.javac.tree.DCTree.DCStartElement;
+import com.sun.tools.javac.tree.DCTree.DCText;
+import com.sun.tools.javac.tree.DCTree.DCThrows;
+import com.sun.tools.javac.tree.DCTree.DCUnknownBlockTag;
+import com.sun.tools.javac.tree.DCTree.DCUnknownInlineTag;
+import com.sun.tools.javac.tree.DCTree.DCValue;
+import com.sun.tools.javac.tree.DCTree.DCVersion;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.DiagnosticSource;
 import com.sun.tools.javac.util.JCDiagnostic;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Position;
+import com.sun.tools.javac.util.Tuple.Tuple2;
+
+import static com.sun.tools.doclint.HtmlTag.*;
 
 /**
  *
@@ -50,6 +92,10 @@
     /** The context key for the tree factory. */
     protected static final Context.Key<DocTreeMaker> treeMakerKey = new Context.Key<>();
 
+    // A subset of block tags, which acts as sentence breakers, appearing
+    // anywhere but the zero'th position in the first sentence.
+    final EnumSet<HtmlTag> sentenceBreakTags;
+
     /** Get the TreeMaker instance. */
     public static DocTreeMaker instance(Context context) {
         DocTreeMaker instance = context.get(treeMakerKey);
@@ -65,12 +111,16 @@
     /** Access to diag factory for ErroneousTrees. */
     private final JCDiagnostic.Factory diags;
 
+    private final JavacTrees trees;
+
     /** Create a tree maker with NOPOS as initial position.
      */
     protected DocTreeMaker(Context context) {
         context.put(treeMakerKey, this);
         diags = JCDiagnostic.Factory.instance(context);
         this.pos = Position.NOPOS;
+        trees = JavacTrees.instance(context);
+        sentenceBreakTags = EnumSet.of(H1, H2, H3, H4, H5, H6, PRE, P);
     }
 
     /** Reassign current position.
@@ -117,12 +167,27 @@
         return tree;
     }
 
-    public DCDocComment DocComment(Comment comment, List<DCTree> firstSentence, List<DCTree> body, List<DCTree> tags) {
-        DCDocComment tree = new DCDocComment(comment, firstSentence, body, tags);
+    public DCDocComment DocComment(Comment comment, List<DCTree> fullBody, List<DCTree> tags) {
+        Tuple2<List<DCTree>, List<DCTree>> pair = splitBody(fullBody);
+        DCDocComment tree = new DCDocComment(comment, fullBody, pair.elem0, pair.elem1, tags);
         tree.pos = pos;
         return tree;
     }
 
+    /*
+     * Primarily to produce a DocCommenTree when given a
+     * first sentence and a body, this is useful, in cases
+     * where the trees are being synthesized by a tool.
+     */
+    public DCDocComment DocComment(List<DCTree> firstSentence, List<DCTree> body, List<DCTree> tags) {
+        ListBuffer<DCTree> lb = new ListBuffer<>();
+        lb.addAll(firstSentence);
+        lb.addAll(body);
+        List<DCTree> fullBody = lb.toList();
+        DCDocComment tree = new DCDocComment(null, fullBody, firstSentence, body, tags);
+        return tree;
+    }
+
     public DCDocRoot DocRoot() {
         DCDocRoot tree = new DCDocRoot();
         tree.pos = pos;
@@ -273,4 +338,231 @@
         tree.pos = pos;
         return tree;
     }
+
+    public java.util.List<DocTree> getFirstSentence(java.util.List<? extends DocTree> list) {
+        Tuple2<List<DCTree>, List<DCTree>> pair = splitBody(list);
+        return new ArrayList<>(pair.elem0);
+    }
+
+    /*
+     * Breaks up the body tags into the first sentence and its successors.
+     * The first sentence is determined with the presence of a period,
+     * block tag, or a sentence break, as returned by the BreakIterator.
+     * Trailing whitespaces are trimmed.
+     */
+    private Tuple2<List<DCTree>, List<DCTree>> splitBody(Collection<? extends DocTree> list) {
+        // pos is modified as we create trees, therefore
+        // we save the pos and restore it later.
+        final int savedpos = this.pos;
+        try {
+            ListBuffer<DCTree> body = new ListBuffer<>();
+            // split body into first sentence and body
+            ListBuffer<DCTree> fs = new ListBuffer<>();
+            if (list.isEmpty()) {
+                return new Tuple2<>(fs.toList(), body.toList());
+            }
+            boolean foundFirstSentence = false;
+            ArrayList<DocTree> alist = new ArrayList<>(list);
+            ListIterator<DocTree> itr = alist.listIterator();
+            while (itr.hasNext()) {
+                boolean isFirst = !itr.hasPrevious();
+                DocTree dt = itr.next();
+                int spos = ((DCTree) dt).pos;
+                if (foundFirstSentence) {
+                    body.add((DCTree) dt);
+                    continue;
+                }
+                switch (dt.getKind()) {
+                    case TEXT:
+                        DCText tt = (DCText) dt;
+                        String s = tt.getBody();
+                        DocTree peekedNext = itr.hasNext()
+                                ? alist.get(itr.nextIndex())
+                                : null;
+                        int sbreak = getSentenceBreak(s, peekedNext);
+                        if (sbreak > 0) {
+                            s = removeTrailingWhitespace(s.substring(0, sbreak));
+                            DCText text = this.at(spos).Text(s);
+                            fs.add(text);
+                            foundFirstSentence = true;
+                            int nwPos = skipWhiteSpace(tt.getBody(), sbreak);
+                            if (nwPos > 0) {
+                                DCText text2 = this.at(spos + nwPos).Text(tt.getBody().substring(nwPos));
+                                body.add(text2);
+                            }
+                            continue;
+                        } else if (itr.hasNext()) {
+                            // if the next doctree is a break, remove trailing spaces
+                            peekedNext = alist.get(itr.nextIndex());
+                            boolean sbrk = isSentenceBreak(peekedNext, false);
+                            if (sbrk) {
+                                DocTree next = itr.next();
+                                s = removeTrailingWhitespace(s);
+                                DCText text = this.at(spos).Text(s);
+                                fs.add(text);
+                                body.add((DCTree) next);
+                                foundFirstSentence = true;
+                                continue;
+                            }
+                        }
+                        break;
+                    default:
+                        if (isSentenceBreak(dt, isFirst)) {
+                            body.add((DCTree) dt);
+                            foundFirstSentence = true;
+                            continue;
+                        }
+                        break;
+                }
+                fs.add((DCTree) dt);
+            }
+            return new Tuple2<>(fs.toList(), body.toList());
+        } finally {
+            this.pos = savedpos;
+        }
+    }
+
+    private boolean isTextTree(DocTree tree) {
+        return tree.getKind() == Kind.TEXT;
+    }
+
+    /*
+     * Computes the first sentence break, a simple dot-space algorithm.
+     */
+    int defaultSentenceBreak(String s) {
+        // scan for period followed by whitespace
+        int period = -1;
+        for (int i = 0; i < s.length(); i++) {
+            switch (s.charAt(i)) {
+                case '.':
+                    period = i;
+                    break;
+
+                case ' ':
+                case '\f':
+                case '\n':
+                case '\r':
+                case '\t':
+                    if (period >= 0) {
+                        return i;
+                    }
+                    break;
+
+                default:
+                    period = -1;
+                    break;
+            }
+        }
+        return -1;
+    }
+
+    /*
+     * Computes the first sentence, if using a default breaker,
+     * the break is returned, if not then a -1, indicating that
+     * more doctree elements are required to be examined.
+     *
+     * BreakIterator.next points to the the start of the following sentence,
+     * and does not provide an easy way to disambiguate between "sentence break",
+     * "possible sentence break" and "not a sentence break" at the end of the input.
+     * For example, BreakIterator.next returns the index for the end
+     * of the string for all of these examples,
+     * using vertical bars to delimit the bounds of the example text
+     * |Abc|        (not a valid end of sentence break, if followed by more text)
+     * |Abc.|       (maybe a valid end of sentence break, depending on the following text)
+     * |Abc. |      (maybe a valid end of sentence break, depending on the following text)
+     * |"Abc." |    (maybe a valid end of sentence break, depending on the following text)
+     * |Abc.  |     (definitely a valid end of sentence break)
+     * |"Abc."  |   (definitely a valid end of sentence break)
+     * Therefore, we have to probe further to determine whether
+     * there really is a sentence break or not at the end of this run of text.
+     */
+    int getSentenceBreak(String s, DocTree dt) {
+        BreakIterator breakIterator = trees.getBreakIterator();
+        if (breakIterator == null) {
+            return defaultSentenceBreak(s);
+        }
+        breakIterator.setText(s);
+        final int sbrk = breakIterator.next();
+        // This is the last doctree, found the droid we are looking for
+        if (dt == null) {
+            return sbrk;
+        }
+
+        // If the break is well within the span of the string ie. not
+        // at EOL, then we have a clear break.
+        if (sbrk < s.length() - 1) {
+            return sbrk;
+        }
+
+        if (isTextTree(dt)) {
+            // Two adjacent text trees, a corner case, perhaps
+            // produced by a tool synthesizing a doctree. In
+            // this case, does the break lie within the first span,
+            // then we have the droid, otherwise allow the callers
+            // logic to handle the break in the adjacent doctree.
+            TextTree ttnext = (TextTree) dt;
+            String combined = s + ttnext.getBody();
+            breakIterator.setText(combined);
+            int sbrk2 = breakIterator.next();
+            if (sbrk < sbrk2) {
+                return sbrk;
+            }
+        }
+
+        // Is the adjacent tree a sentence breaker ?
+        if (isSentenceBreak(dt, false)) {
+            return sbrk;
+        }
+
+        // At this point the adjacent tree is either a javadoc tag ({@..),
+        // html tag (<..) or an entity (&..). Perform a litmus test, by
+        // concatenating a sentence, to validate the break earlier identified.
+        String combined = s + "Dummy Sentence.";
+        breakIterator.setText(combined);
+        int sbrk2 = breakIterator.next();
+        if (sbrk2 <= sbrk) {
+            return sbrk2;
+        }
+        return -1; // indeterminate at this time
+    }
+
+    boolean isSentenceBreak(javax.lang.model.element.Name tagName) {
+        return sentenceBreakTags.contains(get(tagName));
+    }
+
+    boolean isSentenceBreak(DocTree dt, boolean isFirstDocTree) {
+        switch (dt.getKind()) {
+            case START_ELEMENT:
+                    StartElementTree set = (StartElementTree)dt;
+                    return !isFirstDocTree && ((DCTree) dt).pos > 1 && isSentenceBreak(set.getName());
+            case END_ELEMENT:
+                    EndElementTree eet = (EndElementTree)dt;
+                    return !isFirstDocTree && ((DCTree) dt).pos > 1 && isSentenceBreak(eet.getName());
+            default:
+                return false;
+        }
+    }
+
+    /*
+     * Returns the position of the the first non-white space
+     */
+    int skipWhiteSpace(String s, int start) {
+        for (int i = start; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (!Character.isWhitespace(c)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    String removeTrailingWhitespace(String s) {
+        for (int i = s.length() - 1 ; i >= 0 ; i--) {
+            char ch = s.charAt(i);
+            if (!Character.isWhitespace(ch)) {
+                return s.substring(0, i + 1);
+            }
+        }
+        return s;
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Nov 24 00:42:53 2015 +0000
@@ -2714,8 +2714,8 @@
     /** (let int x = 3; in x+2) */
     public static class LetExpr extends JCExpression {
         public List<JCVariableDecl> defs;
-        public JCTree expr;
-        protected LetExpr(List<JCVariableDecl> defs, JCTree expr) {
+        public JCExpression expr;
+        protected LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
             this.defs = defs;
             this.expr = expr;
         }
@@ -2823,7 +2823,7 @@
         JCAnnotation Annotation(JCTree annotationType, List<JCExpression> args);
         JCModifiers Modifiers(long flags, List<JCAnnotation> annotations);
         JCErroneous Erroneous(List<? extends JCTree> errs);
-        LetExpr LetExpr(List<JCVariableDecl> defs, JCTree expr);
+        LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr);
     }
 
     /** A generic visitor class for trees.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Tue Nov 24 00:42:53 2015 +0000
@@ -512,7 +512,7 @@
             case LETEXPR: {
                 LetExpr t = (LetExpr) node;
                 List<JCVariableDecl> defs = copy(t.defs, p);
-                JCTree expr = copy(t.expr, p);
+                JCExpression expr = copy(t.expr, p);
                 return M.at(t.pos).LetExpr(defs, expr);
             }
             default:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Tue Nov 24 00:42:53 2015 +0000
@@ -564,7 +564,7 @@
         return tree;
     }
 
-    public LetExpr LetExpr(List<JCVariableDecl> defs, JCTree expr) {
+    public LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
         LetExpr tree = new LetExpr(defs, expr);
         tree.pos = pos;
         return tree;
@@ -585,7 +585,7 @@
                         defs);
     }
 
-    public LetExpr LetExpr(JCVariableDecl def, JCTree expr) {
+    public LetExpr LetExpr(JCVariableDecl def, JCExpression expr) {
         LetExpr tree = new LetExpr(List.of(def), expr);
         tree.pos = pos;
         return tree;
@@ -640,6 +640,12 @@
         return Ident(new VarSymbol(FINAL, names._this, t, t.tsym));
     }
 
+    /** Create a tree representing qualified `this' given its type
+     */
+    public JCExpression QualThis(Type t) {
+        return Select(Type(t), new VarSymbol(FINAL, names._this, t, t.tsym));
+    }
+
     /** Create a tree representing a class literal.
      */
     public JCExpression ClassLiteral(ClassSymbol clazz) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java	Tue Nov 24 00:42:53 2015 +0000
@@ -30,7 +30,7 @@
 import com.sun.tools.javac.code.Symbol.Completer;
 import com.sun.tools.javac.code.Symbol.CompletionFailure;
 import com.sun.tools.javac.main.JavaCompiler;
-import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.util.GraphUtils.DependencyKind;
 import com.sun.tools.javac.util.GraphUtils.DotVisitor;
 import com.sun.tools.javac.util.GraphUtils.NodeVisitor;
 
@@ -42,13 +42,13 @@
 import java.util.Collection;
 import java.util.EnumMap;
 import java.util.EnumSet;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.Set;
 import java.util.Stack;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import javax.tools.JavaFileObject;
 
@@ -78,69 +78,23 @@
     }
 
     /**
-     * This enum models different kinds of attribution actions triggered during
-     * symbol completion.
-     */
-    public enum AttributionKind {
-        /**
-         * Attribution of superclass (i.e. @{code extends} clause).
-         */
-        EXTENDS {
-            @Override
-            String format(JCTree tree) {
-                return "extends " + super.format(tree);
-            }
-        },
-        /**
-         * Attribution of superinterface (i.e. an type in the @{code interface} clause).
-         */
-        IMPLEMENTS {
-            @Override
-            String format(JCTree tree) {
-                return "implements " + super.format(tree);
-            }
-        },
-        /**
-         * Attribution of an import statement
-         */
-        IMPORT,
-        /**
-         * Attribution of type-variable bound
-         */
-        TVAR {
-            @Override
-            String format(JCTree tree) {
-                return "<" + super.format(tree) + ">";
-            }
-        };
-
-        String format(JCTree tree) {
-            return tree.toString();
-        }
-    }
-
-    /**
      * Push a new completion node on the stack.
      */
     abstract public void push(ClassSymbol s, CompletionCause phase);
 
     /**
-     * Push a new attribution node on the stack.
-     */
-    abstract public void push(AttributionKind ak, JCTree t);
-
-    /**
      * Remove current dependency node from the stack.
      */
     abstract public void pop();
 
-    public enum CompletionCause {
+    public enum CompletionCause implements GraphUtils.DependencyKind {
         CLASS_READER,
         HEADER_PHASE,
         HIERARCHY_PHASE,
         IMPORTS_PHASE,
         MEMBER_ENTER,
-        MEMBERS_PHASE;
+        MEMBERS_PHASE,
+        OTHER;
     }
 
     /**
@@ -163,13 +117,8 @@
         /**
          * Register a Context.Factory to create a Dependencies.
          */
-        public static void preRegister(final Context context) {
-            context.put(dependenciesKey, new Context.Factory<Dependencies>() {
-                public Dependencies make(Context c) {
-                    Dependencies deps = new GraphDependencies(context);
-                    return deps;
-                }
-            });
+        public static void preRegister(Context context) {
+            context.put(dependenciesKey, (Context.Factory<Dependencies>) GraphDependencies::new);
         }
 
         /**
@@ -195,12 +144,11 @@
         enum DependenciesMode {
             SOURCE("source"),
             CLASS("class"),
-            REDUNDANT("redundant"),
-            SIDE_EFFECTS("side-effects");
+            REDUNDANT("redundant");
 
             final String opt;
 
-            private DependenciesMode(String opt) {
+            DependenciesMode(String opt) {
                 this.opt = opt;
             }
 
@@ -228,46 +176,19 @@
         }
 
         /**
-         * Class representing a node in the dependency graph. Nodes are of two main
-         * kinds: (i) symbol nodes, corresponding to symbol completion requests
-         * (either from source or classfile); (ii) attribution nodes, corresponding to
-         * attribution actions triggered during (source) completion.
+         * Class representing a node in the dependency graph.
          */
-        public static abstract class Node extends GraphUtils.AbstractNode<String, Node>
-                implements GraphUtils.DottableNode<String, Node> {
-
-            /**
-             * Model the dependencies between nodes.
-             */
-            public enum DependencyKind implements GraphUtils.DependencyKind {
-                /**
-                 * standard dependency - i.e. completion of the source node depends
-                 * on completion of the sink node.
-                 */
-                REQUIRES("solid"),
-                /**
-                 * soft dependencies - i.e. completion of the source node depends
-                 * on side-effects of the source node. These dependencies are meant
-                 * to capture the order in which javac processes all dependants of a given node.
-                 */
-                SIDE_EFFECTS("dashed");
-
-                final String dotStyle;
-
-                DependencyKind(String dotStyle) {
-                    this.dotStyle = dotStyle;
-                }
-            }
-
+        public static abstract class Node extends GraphUtils.AbstractNode<ClassSymbol, Node>
+                implements GraphUtils.DottableNode<ClassSymbol, Node> {
             /**
              * dependant nodes grouped by kind
              */
-            EnumMap<DependencyKind, List<Node>> depsByKind;
+            EnumMap<CompletionCause, List<Node>> depsByKind;
 
-            Node(String value) {
+            Node(ClassSymbol value) {
                 super(value);
-                this.depsByKind = new EnumMap<>(DependencyKind.class);
-                for (DependencyKind depKind : DependencyKind.values()) {
+                this.depsByKind = new EnumMap<>(CompletionCause.class);
+                for (CompletionCause depKind : CompletionCause.values()) {
                     depsByKind.put(depKind, new ArrayList<Node>());
                 }
             }
@@ -281,8 +202,7 @@
 
             @Override
             public boolean equals(Object obj) {
-                return obj instanceof Node &&
-                        data.equals(((Node) obj).data);
+                return obj instanceof Node && data.equals(((Node) obj).data);
             }
 
             @Override
@@ -292,19 +212,12 @@
 
             @Override
             public GraphUtils.DependencyKind[] getSupportedDependencyKinds() {
-                return DependencyKind.values();
+                return CompletionCause.values();
             }
 
             @Override
-            public java.util.Collection<? extends Node> getDependenciesByKind(GraphUtils.DependencyKind dk) {
-                List<Node> deps = depsByKind.get(dk);
-                if (dk == DependencyKind.REQUIRES) {
-                    return deps;
-                } else {
-                    Set<Node> temp = new HashSet<>(deps);
-                    temp.removeAll(depsByKind.get(DependencyKind.REQUIRES));
-                    return temp;
-                }
+            public java.util.Collection<? extends Node> getDependenciesByKind(DependencyKind dk) {
+                return depsByKind.get(dk);
             }
 
             @Override
@@ -317,9 +230,14 @@
             @Override
             public Properties dependencyAttributes(Node to, GraphUtils.DependencyKind dk) {
                 Properties p = new Properties();
-                p.put("style", ((DependencyKind) dk).dotStyle);
+                p.put("label", dk);
                 return p;
             }
+
+            @Override
+            public String toString() {
+                return data.getQualifiedName().toString();
+            }
         }
 
         /**
@@ -349,11 +267,9 @@
             }
 
             final Kind ck;
-            final ClassSymbol sym;
 
             CompletionNode(ClassSymbol sym) {
-                super(sym.getQualifiedName().toString());
-                this.sym = sym;
+                super(sym);
                 //infer completion kind by looking at the symbol fields
                 boolean fromClass = (sym.classfile == null && sym.sourcefile == null) ||
                         (sym.classfile != null && sym.classfile.getKind() == JavaFileObject.Kind.CLASS);
@@ -371,27 +287,7 @@
             }
 
             public ClassSymbol getClassSymbol() {
-                return sym;
-            }
-        }
-
-        /**
-         * This is a dependency node used to model attribution actions triggered during
-         * source symbol completion. The possible kinds of attribution actions are
-         * captured in {@link AttributionNode}.
-         */
-        static class AttributionNode extends Node {
-
-            AttributionNode(AttributionKind ak, JCTree tree) {
-                super(ak.format(tree));
-            }
-
-            @Override
-            public Properties nodeAttributes() {
-                Properties p = super.nodeAttributes();
-                p.put("shape", "box");
-                p.put("style", "solid");
-                return p;
+                return data;
             }
         }
 
@@ -403,25 +299,20 @@
         /**
          * map containing all dependency nodes seen so far
          */
-        Map<String, Node> dependencyNodeMap = new LinkedHashMap<>();
+        Map<ClassSymbol, Node> dependencyNodeMap = new LinkedHashMap<>();
 
         @Override
         public void push(ClassSymbol s, CompletionCause phase) {
             Node n = new CompletionNode(s);
-            if (n == push(n)) {
+            if (n == push(n, phase)) {
                 s.completer = this;
             }
         }
 
-        @Override
-        public void push(AttributionKind ak, JCTree t) {
-            push(new AttributionNode(ak, t));
-        }
-
         /**
          * Push a new dependency on the stack.
          */
-        protected Node push(Node newNode) {
+        protected Node push(Node newNode, CompletionCause cc) {
             Node cachedNode = dependencyNodeMap.get(newNode.data);
             if (cachedNode == null) {
                 dependencyNodeMap.put(newNode.data, newNode);
@@ -430,7 +321,7 @@
             }
             if (!nodeStack.isEmpty()) {
                 Node currentNode = nodeStack.peek();
-                currentNode.addDependency(Node.DependencyKind.REQUIRES, newNode);
+                currentNode.addDependency(cc, newNode);
             }
             nodeStack.push(newNode);
             return newNode;
@@ -455,10 +346,6 @@
                 //filter source completions
                 new FilterVisitor(CompletionNode.Kind.CLASS).visit(dependencyNodeMap.values(), null);
             }
-            if (dependenciesModes.contains(DependenciesMode.SIDE_EFFECTS)) {
-                //add side-effects edges
-                new SideEffectVisitor().visit(dependencyNodeMap.values(), null);
-            }
             if (dependenciesFile != null) {
                 //write to file
                 try (FileWriter fw = new FileWriter(dependenciesFile)) {
@@ -469,7 +356,7 @@
 
         @Override
         public void complete(Symbol sym) throws CompletionFailure {
-            push((ClassSymbol) sym, null);
+            push((ClassSymbol)sym, CompletionCause.OTHER);
             pop();
             sym.completer = this;
         }
@@ -484,31 +371,9 @@
         }
 
         /**
-         * This visitor is used to generate the special side-effect dependencies
-         * given a graph containing only standard dependencies.
-         */
-        private static class SideEffectVisitor extends NodeVisitor<String, Node, Void> {
-            @Override
-            public void visitNode(Node node, Void arg) {
-                //do nothing
-            }
-
-            @Override
-            public void visitDependency(GraphUtils.DependencyKind dk, Node from, Node to, Void arg) {
-                //if we are adding multiple dependencies to same node
-                //make order explicit via special 'side-effect' dependencies
-                List<Node> deps = from.depsByKind.get(dk);
-                int pos = deps.indexOf(to);
-                if (dk == Node.DependencyKind.REQUIRES && pos > 0) {
-                    to.addDependency(Node.DependencyKind.SIDE_EFFECTS, deps.get(pos - 1));
-                }
-            }
-        }
-
-        /**
          * This visitor is used to prune the graph from spurious edges using some heuristics.
          */
-        private static class PruneVisitor extends NodeVisitor<String, Node, Void> {
+        private static class PruneVisitor extends NodeVisitor<ClassSymbol, Node, Void> {
             @Override
             public void visitNode(Node node, Void arg) {
                 //do nothing
@@ -517,8 +382,7 @@
             @Override
             public void visitDependency(GraphUtils.DependencyKind dk, Node from, Node to, Void arg) {
                 //heuristic - skips dependencies that are likely to be fake
-                if (from.equals(to) ||
-                        from.depsByKind.get(Node.DependencyKind.REQUIRES).contains(to)) {
+                if (from.equals(to)) {
                     to.depsByKind.get(dk).remove(from);
                 }
             }
@@ -527,7 +391,7 @@
         /**
          * This visitor is used to retain only completion nodes with given kind.
          */
-        private class FilterVisitor extends NodeVisitor<String, Node, Void> {
+        private class FilterVisitor extends NodeVisitor<ClassSymbol, Node, Void> {
 
             CompletionNode.Kind ck;
 
@@ -571,11 +435,6 @@
         }
 
         @Override
-        public void push(AttributionKind ak, JCTree t) {
-            //do nothing
-        }
-
-        @Override
         public void pop() {
             //do nothing
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Tue Nov 24 00:42:53 2015 +0000
@@ -184,6 +184,7 @@
     public final Name lambda;
     public final Name metafactory;
     public final Name altMetafactory;
+    public final Name dollarThis;
 
     public final Name.Table table;
 
@@ -242,6 +243,7 @@
         value = fromString("value");
         valueOf = fromString("valueOf");
         values = fromString("values");
+        dollarThis = fromString("$this");
         vminit = fromString("<vminit>");
 
         // class names
--- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java	Tue Nov 24 00:42:53 2015 +0000
@@ -527,7 +527,7 @@
      * Compare the javac_state recorded public apis of packages on the classpath
      * with the actual public apis on the classpath.
      */
-    public void taintPackagesDependingOnChangedClasspathPackages() {
+    public void taintPackagesDependingOnChangedClasspathPackages() throws IOException {
 
         // 1. Collect fully qualified names of all interesting classpath dependencies
         Set<String> fqDependencies = new HashSet<>();
@@ -549,6 +549,7 @@
         for (String cpDep : fqDependencies) {
             onDiskPubApi.put(cpDep, pubApiExtractor.getPubApi(cpDep));
         }
+        pubApiExtractor.close();
 
         // 3. Compare them with the public APIs as of last compilation (loaded from javac_state)
         nextPkg:
--- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/PubApiExtractor.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/PubApiExtractor.java	Tue Nov 24 00:42:53 2015 +0000
@@ -25,6 +25,7 @@
 
 package com.sun.tools.sjavac;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Arrays;
 
@@ -46,8 +47,10 @@
 public class PubApiExtractor {
     // Setup a compiler context for finding classes in the classpath
     // and to execute annotation processors.
-    Context context;
-    CompilationTask task;
+    final Context context;
+    final CompilationTask task;
+
+    final SmartFileManager fileManager;
 
     /**
      * Setup a compilation context, used for reading public apis of classes on the classpath
@@ -55,7 +58,7 @@
      */
     public PubApiExtractor(Options options) {
         JavacTool compiler = com.sun.tools.javac.api.JavacTool.create();
-        SmartFileManager fileManager = new SmartFileManager(compiler.getStandardFileManager(null, null, null));
+        fileManager = new SmartFileManager(compiler.getStandardFileManager(null, null, null));
         context = new com.sun.tools.javac.util.Context();
         String[] args = options.prepJavacArgs();
         task = compiler.getTask(new PrintWriter(System.err),
@@ -82,4 +85,8 @@
         v.visit(cs);
         return v.getCollectedPubApi();
     }
+
+    public void close() throws IOException {
+        fileManager.close();
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java	Tue Nov 24 00:42:53 2015 +0000
@@ -209,21 +209,20 @@
             // Go through all sources and taint all packages that miss artifacts.
             javac_state.taintPackagesThatMissArtifacts();
 
-            // Check recorded classpath public apis. Taint packages that depend on
-            // classpath classes whose public apis have changed.
-            javac_state.taintPackagesDependingOnChangedClasspathPackages();
+            try {
+                // Check recorded classpath public apis. Taint packages that depend on
+                // classpath classes whose public apis have changed.
+                javac_state.taintPackagesDependingOnChangedClasspathPackages();
 
-            // Now clean out all known artifacts belonging to tainted packages.
-            javac_state.deleteClassArtifactsInTaintedPackages();
-            // Copy files, for example property files, images files, xml files etc etc.
-            javac_state.performCopying(Util.pathToFile(options.getDestDir()), suffixRules);
-            // Translate files, for example compile properties or compile idls.
-            javac_state.performTranslation(Util.pathToFile(gensrc), suffixRules);
-            // Add any potentially generated java sources to the tobe compiled list.
-            // (Generated sources must always have a package.)
-            Map<String,Source> generated_sources = new HashMap<>();
-
-            try {
+                // Now clean out all known artifacts belonging to tainted packages.
+                javac_state.deleteClassArtifactsInTaintedPackages();
+                // Copy files, for example property files, images files, xml files etc etc.
+                javac_state.performCopying(Util.pathToFile(options.getDestDir()), suffixRules);
+                // Translate files, for example compile properties or compile idls.
+                javac_state.performTranslation(Util.pathToFile(gensrc), suffixRules);
+                // Add any potentially generated java sources to the tobe compiled list.
+                // (Generated sources must always have a package.)
+                Map<String,Source> generated_sources = new HashMap<>();
 
                 Source.scanRoot(Util.pathToFile(options.getGenSrcDir()), Util.set(".java"), null, null, null, null,
                         generated_sources, modules, current_module, false, true, false);
--- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/dependencies/NewDependencyCollector.java	Mon Nov 23 11:39:55 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/dependencies/NewDependencyCollector.java	Tue Nov 24 00:42:53 2015 +0000
@@ -26,11 +26,13 @@
 package com.sun.tools.sjavac.comp.dependencies;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import javax.tools.JavaFileManager.Location;
 import javax.tools.JavaFileObject;
@@ -38,7 +40,11 @@
 
 import com.sun.source.util.TaskEvent;
 import com.sun.source.util.TaskListener;
+import com.sun.tools.javac.code.Kinds.Kind;
+import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.TypeSymbol;
+import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -85,7 +91,6 @@
 
         return deps.getNodes()
                    .stream()
-                   .filter(n -> n instanceof CompletionNode)
                    .map(n -> (CompletionNode) n)
                    .filter(n -> n.getClassSymbol().fullname != null)
                    .filter(n -> explicits == explicitJFOs.contains(n.getClassSymbol().classfile))
@@ -128,31 +133,66 @@
             String depPkg = Util.pkgNameOfClassName(fqDep);
 
             Map<String, Set<String>> depsForThisClass = result.get(depPkg);
-            if (depsForThisClass == null)
+            if (depsForThisClass == null) {
                 result.put(depPkg, depsForThisClass = new HashMap<>());
+            }
 
-            for (Node<?,?> depNode : cnode.getDependenciesByKind(GraphDependencies.Node.DependencyKind.REQUIRES)) {
-                boolean isCompletionNode = depNode instanceof CompletionNode;
-                if (isCompletionNode) {
-                    CompletionNode cDepNode = (CompletionNode) depNode;
-                    if (cDepNode == cnode)
-                        continue;
-                    if (cDepNode.getClassSymbol().fullname == null) // Anonymous class
-                        continue;
-                    Location depLoc = getLocationOf(cDepNode.getClassSymbol());
-                    boolean relevant = (cp  && depLoc == StandardLocation.CLASS_PATH)
-                                    || (!cp && depLoc == StandardLocation.SOURCE_PATH);
-                    if (!relevant)
-                        continue;
+            Set<String> fqDeps = depsForThisClass.get(fqDep);
+            if (fqDeps == null) {
+                depsForThisClass.put(fqDep, fqDeps = new HashSet<>());
+            }
 
-                    Set<String> fqDeps = depsForThisClass.get(fqDep);
-                    if (fqDeps == null)
-                        depsForThisClass.put(fqDep, fqDeps = new HashSet<>());
+            for (Node<?,?> depNode : getAllDependencies(cnode)) {
+                CompletionNode cDepNode = (CompletionNode) depNode;
+                // Symbol is not regarded to depend on itself.
+                if (cDepNode == cnode) {
+                    continue;
+                }
+                // Skip anonymous classes
+                if (cDepNode.getClassSymbol().fullname == null) {
+                    continue;
+                }
+                if (isSymbolRelevant(cp, cDepNode.getClassSymbol())) {
                     fqDeps.add(cDepNode.getClassSymbol().outermostClass().flatname.toString());
                 }
             }
+
+            // The completion dependency graph is not transitively closed for inheritance relations.
+            // For sjavac's purposes however, a class depends on it's super super type, so below we
+            // make sure that we include super types.
+            for (ClassSymbol cs : allSupertypes(cnode.getClassSymbol())) {
+                if (isSymbolRelevant(cp, cs)) {
+                    fqDeps.add(cs.outermostClass().flatname.toString());
+                }
+            }
+
         }
         return result;
     }
 
+    public boolean isSymbolRelevant(boolean cp, ClassSymbol cs) {
+        Location csLoc = getLocationOf(cs);
+        Location relevantLocation = cp ? StandardLocation.CLASS_PATH : StandardLocation.SOURCE_PATH;
+        return csLoc == relevantLocation;
+    }
+
+    private Set<ClassSymbol> allSupertypes(TypeSymbol t) {
+        if (t == null || !(t instanceof ClassSymbol)) {
+            return Collections.emptySet();
+        }
+        Set<ClassSymbol> result = new HashSet<>();
+        ClassSymbol cs = (ClassSymbol) t;
+        result.add(cs);
+        result.addAll(allSupertypes(cs.getSuperclass().tsym));
+        for (Type it : cs.getInterfaces()) {
+            result.addAll(allSupertypes(it.tsym));
+        }
+        return result;
+    }
+
+    private Collection<? extends Node<?, ?>> getAllDependencies(CompletionNode cnode) {
+        return Stream.of(cnode.getSupportedDependencyKinds())
+                     .flatMap(dk -> cnode.getDependenciesByKind(dk).stream())
+                     .collect(Collectors.toSet());
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/debug/InternalDebugControl.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package jdk.internal.jshell.debug;
+
+import java.util.HashMap;
+import java.util.Map;
+import jdk.jshell.JShell;
+
+/**
+ * Used to externally control output messages for debugging the implementation
+ * of the JShell API.  This is NOT a supported interface,
+ * @author Robert Field
+ */
+public class InternalDebugControl {
+    public static final int DBG_GEN   = 0b0000001;
+    public static final int DBG_FMGR  = 0b0000010;
+    public static final int DBG_COMPA = 0b0000100;
+    public static final int DBG_DEP   = 0b0001000;
+    public static final int DBG_EVNT  = 0b0010000;
+
+    private static Map<JShell, Integer> debugMap = null;
+
+    public static void setDebugFlags(JShell state, int flags) {
+        if (debugMap == null) {
+            debugMap = new HashMap<>();
+        }
+        debugMap.put(state, flags);
+    }
+
+    public static boolean debugEnabled(JShell state, int flag) {
+        if (debugMap == null) {
+            return false;
+        }
+        Integer flags = debugMap.get(state);
+        if (flags == null) {
+            return false;
+        }
+        return (flags & flag) != 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2014, 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.internal.jshell.remote;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.Socket;
+
+import java.util.ArrayList;
+import java.util.List;
+import static jdk.internal.jshell.remote.RemoteCodes.*;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * The remote agent runs in the execution process (separate from the main JShell
+ * process.  This agent loads code over a socket from the main JShell process,
+ * executes the code, and other misc,
+ * @author Robert Field
+ */
+class RemoteAgent {
+
+    private final RemoteClassLoader loader = new RemoteClassLoader();
+    private final Map<String, Class<?>> klasses = new TreeMap<>();
+
+    public static void main(String[] args) throws Exception {
+        String loopBack = null;
+        Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
+        (new RemoteAgent()).commandLoop(socket);
+    }
+
+    void commandLoop(Socket socket) throws IOException {
+        // in before out -- so we don't hang the controlling process
+        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
+        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
+        while (true) {
+            int cmd = in.readInt();
+            switch (cmd) {
+                case CMD_EXIT:
+                    // Terminate this process
+                    return;
+                case CMD_LOAD:
+                    // Load a generated class file over the wire
+                    try {
+                        int count = in.readInt();
+                        List<String> names = new ArrayList<>(count);
+                        for (int i = 0; i < count; ++i) {
+                            String name = in.readUTF();
+                            byte[] kb = (byte[]) in.readObject();
+                            loader.delare(name, kb);
+                            names.add(name);
+                        }
+                        for (String name : names) {
+                            Class<?> klass = loader.loadClass(name);
+                            klasses.put(name, klass);
+                            // Get class loaded to the point of, at least, preparation
+                            klass.getDeclaredMethods();
+                        }
+                        out.writeInt(RESULT_SUCCESS);
+                        out.flush();
+                    } catch (IOException | ClassNotFoundException | ClassCastException ex) {
+                        debug("*** Load failure: %s\n", ex);
+                        out.writeInt(RESULT_FAIL);
+                        out.writeUTF(ex.toString());
+                        out.flush();
+                    }
+                    break;
+                case CMD_INVOKE: {
+                    // Invoke executable entry point in loaded code
+                    String name = in.readUTF();
+                    Class<?> klass = klasses.get(name);
+                    if (klass == null) {
+                        debug("*** Invoke failure: no such class loaded %s\n", name);
+                        out.writeInt(RESULT_FAIL);
+                        out.writeUTF("no such class loaded: " + name);
+                        out.flush();
+                        break;
+                    }
+                    Method doitMethod;
+                    try {
+                        doitMethod = klass.getDeclaredMethod(DOIT_METHOD_NAME, new Class<?>[0]);
+                        doitMethod.setAccessible(true);
+                        Object res;
+                        try {
+                            clientCodeEnter();
+                            res = doitMethod.invoke(null, new Object[0]);
+                        } catch (InvocationTargetException ex) {
+                            if (ex.getCause() instanceof StopExecutionException) {
+                                expectingStop = false;
+                                throw (StopExecutionException) ex.getCause();
+                            }
+                            throw ex;
+                        } catch (StopExecutionException ex) {
+                            expectingStop = false;
+                            throw ex;
+                        } finally {
+                            clientCodeLeave();
+                        }
+                        out.writeInt(RESULT_SUCCESS);
+                        out.writeUTF(valueString(res));
+                        out.flush();
+                    } catch (InvocationTargetException ex) {
+                        Throwable cause = ex.getCause();
+                        StackTraceElement[] elems = cause.getStackTrace();
+                        if (cause instanceof RemoteResolutionException) {
+                            out.writeInt(RESULT_CORRALLED);
+                            out.writeInt(((RemoteResolutionException) cause).id);
+                        } else {
+                            out.writeInt(RESULT_EXCEPTION);
+                            out.writeUTF(cause.getClass().getName());
+                            out.writeUTF(cause.getMessage() == null ? "<none>" : cause.getMessage());
+                        }
+                        out.writeInt(elems.length);
+                        for (StackTraceElement ste : elems) {
+                            out.writeUTF(ste.getClassName());
+                            out.writeUTF(ste.getMethodName());
+                            out.writeUTF(ste.getFileName() == null ? "<none>" : ste.getFileName());
+                            out.writeInt(ste.getLineNumber());
+                        }
+                        out.flush();
+                    } catch (NoSuchMethodException | IllegalAccessException ex) {
+                        debug("*** Invoke failure: %s -- %s\n", ex, ex.getCause());
+                        out.writeInt(RESULT_FAIL);
+                        out.writeUTF(ex.toString());
+                        out.flush();
+                    } catch (StopExecutionException ex) {
+                        try {
+                            out.writeInt(RESULT_KILLED);
+                            out.flush();
+                        } catch (IOException err) {
+                            debug("*** Error writing killed result: %s -- %s\n", ex, ex.getCause());
+                        }
+                    }
+                    System.out.flush();
+                    break;
+                }
+                case CMD_VARVALUE: {
+                    // Retrieve a variable value
+                    String classname = in.readUTF();
+                    String varname = in.readUTF();
+                    Class<?> klass = klasses.get(classname);
+                    if (klass == null) {
+                        debug("*** Var value failure: no such class loaded %s\n", classname);
+                        out.writeInt(RESULT_FAIL);
+                        out.writeUTF("no such class loaded: " + classname);
+                        out.flush();
+                        break;
+                    }
+                    try {
+                        Field var = klass.getDeclaredField(varname);
+                        var.setAccessible(true);
+                        Object res = var.get(null);
+                        out.writeInt(RESULT_SUCCESS);
+                        out.writeUTF(valueString(res));
+                        out.flush();
+                    } catch (Exception ex) {
+                        debug("*** Var value failure: no such field %s.%s\n", classname, varname);
+                        out.writeInt(RESULT_FAIL);
+                        out.writeUTF("no such field loaded: " + varname + " in class: " + classname);
+                        out.flush();
+                    }
+                    break;
+                }
+                case CMD_CLASSPATH: {
+                    // Append to the claspath
+                    String cp = in.readUTF();
+                    for (String path : cp.split(File.pathSeparator)) {
+                        loader.addURL(new File(path).toURI().toURL());
+                    }
+                    out.writeInt(RESULT_SUCCESS);
+                    out.flush();
+                    break;
+                }
+                default:
+                    debug("*** Bad command code: %d\n", cmd);
+                    break;
+            }
+        }
+    }
+
+    // These three variables are used by the main JShell process in interrupting
+    // the running process.  Access is via JDI, so the reference is not visible
+    // to code inspection.
+    private boolean inClientCode; // Queried by the main process
+    private boolean expectingStop; // Set by the main process
+
+    // thrown by the main process via JDI:
+    private final StopExecutionException stopException = new StopExecutionException();
+
+    @SuppressWarnings("serial")             // serialVersionUID intentionally omitted
+    private class StopExecutionException extends ThreadDeath {
+        @Override public synchronized Throwable fillInStackTrace() {
+            return this;
+        }
+    }
+
+    void clientCodeEnter() {
+        expectingStop = false;
+        inClientCode = true;
+    }
+
+    void clientCodeLeave() {
+        inClientCode = false;
+        while (expectingStop) {
+            try {
+                Thread.sleep(0);
+            } catch (InterruptedException ex) {
+                debug("*** Sleep interrupted while waiting for stop exception: %s\n", ex);
+            }
+        }
+    }
+
+    private void debug(String format, Object... args) {
+        System.err.printf("REMOTE: "+format, args);
+    }
+
+    static String valueString(Object value) {
+        if (value == null) {
+            return "null";
+        } else if (value instanceof String) {
+            return "\"" + expunge((String)value) + "\"";
+        } else if (value instanceof Character) {
+            return "'" + value + "'";
+        } else {
+            return expunge(value.toString());
+        }
+    }
+
+    static String expunge(String s) {
+        StringBuilder sb = new StringBuilder();
+        for (String comp : prefixPattern.split(s)) {
+            sb.append(comp);
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteClassLoader.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, 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.internal.jshell.remote;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Class loader wrapper which caches class files by name until requested.
+ * @author Robert Field
+ */
+class RemoteClassLoader extends URLClassLoader {
+
+    private final Map<String, byte[]> classObjects = new TreeMap<>();
+
+    RemoteClassLoader() {
+        super(new URL[0]);
+    }
+
+    void delare(String name, byte[] bytes) {
+        classObjects.put(name, bytes);
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        byte[] b = classObjects.get(name);
+        if (b == null) {
+            return super.findClass(name);
+        }
+        return super.defineClass(name, b, 0, b.length, (CodeSource) null);
+    }
+
+    @Override
+    public void addURL(URL url) {
+        super.addURL(url);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteCodes.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, 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.internal.jshell.remote;
+
+import java.util.regex.Pattern;
+
+/**
+ * Communication constants shared between the main process and the remote
+ * execution process
+ * @author Robert Field
+ */
+public class RemoteCodes {
+    // Command codes
+    public static final int CMD_EXIT       = 0;
+    public static final int CMD_LOAD       = 1;
+    public static final int CMD_INVOKE     = 3;
+    public static final int CMD_CLASSPATH  = 4;
+    public static final int CMD_VARVALUE   = 5;
+
+    // Return result codes
+    public static final int RESULT_SUCCESS   = 100;
+    public static final int RESULT_FAIL      = 101;
+    public static final int RESULT_EXCEPTION = 102;
+    public static final int RESULT_CORRALLED = 103;
+    public static final int RESULT_KILLED    = 104;
+
+    public static final String DOIT_METHOD_NAME = "do_it$";
+    public static final String replClass = "\\$REPL(?<num>\\d+)[A-Z]*";
+    public static final Pattern prefixPattern = Pattern.compile("(REPL\\.)?" + replClass + "[\\$\\.]?");
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteResolutionException.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,49 @@
+/*
+ * 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.internal.jshell.remote;
+
+/**
+ * The exception thrown on the remote side upon executing a
+ * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED}
+ * user method. This exception is not seen by the end user nor through the API.
+ * @author Robert Field
+ */
+@SuppressWarnings("serial")             // serialVersionUID intentionally omitted
+public class RemoteResolutionException extends RuntimeException {
+
+    final int id;
+
+    /**
+     * The throw of this exception is generated into the body of a
+     * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED}
+     * method.
+     * @param id An internal identifier of the specific method
+     */
+    public RemoteResolutionException(int id) {
+        super("RemoteResolutionException");
+        this.id = id;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,344 @@
+/*
+ * 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.internal.jshell.tool;
+
+import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
+import jdk.jshell.SourceCodeAnalysis.Suggestion;
+
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+import jdk.internal.jline.NoInterruptUnixTerminal;
+import jdk.internal.jline.Terminal;
+import jdk.internal.jline.TerminalFactory;
+import jdk.internal.jline.WindowsTerminal;
+import jdk.internal.jline.console.ConsoleReader;
+import jdk.internal.jline.console.KeyMap;
+import jdk.internal.jline.console.UserInterruptException;
+import jdk.internal.jline.console.completer.Completer;
+import jdk.internal.jshell.tool.StopDetectingInputStream.State;
+
+class ConsoleIOContext extends IOContext {
+
+    final JShellTool repl;
+    final StopDetectingInputStream input;
+    final ConsoleReader in;
+    final EditingHistory history;
+
+    String prefix = "";
+
+    ConsoleIOContext(JShellTool repl, InputStream cmdin, PrintStream cmdout) throws Exception {
+        this.repl = repl;
+        this.input = new StopDetectingInputStream(() -> repl.state.stop(), ex -> repl.hard("Error on input: %s", ex));
+        Terminal term;
+        if (System.getProperty("os.name").toLowerCase(Locale.US).contains(TerminalFactory.WINDOWS)) {
+            term = new JShellWindowsTerminal(input);
+        } else {
+            term = new JShellUnixTerminal(input);
+        }
+        term.init();
+        in = new ConsoleReader(cmdin, cmdout, term);
+        in.setExpandEvents(false);
+        in.setHandleUserInterrupt(true);
+        in.setHistory(history = new EditingHistory(JShellTool.PREFS) {
+            @Override protected CompletionInfo analyzeCompletion(String input) {
+                return repl.analysis.analyzeCompletion(input);
+            }
+        });
+        in.setBellEnabled(true);
+        in.addCompleter(new Completer() {
+            private String lastTest;
+            private int lastCursor;
+            private boolean allowSmart = false;
+            @Override public int complete(String test, int cursor, List<CharSequence> result) {
+                int[] anchor = new int[] {-1};
+                List<Suggestion> suggestions;
+                if (prefix.isEmpty() && test.trim().startsWith("/")) {
+                    suggestions = repl.commandCompletionSuggestions(test, cursor, anchor);
+                } else {
+                    int prefixLength = prefix.length();
+                    suggestions = repl.analysis.completionSuggestions(prefix + test, cursor + prefixLength, anchor);
+                    anchor[0] -= prefixLength;
+                }
+                if (!Objects.equals(lastTest, test) || lastCursor != cursor)
+                    allowSmart = true;
+
+                boolean smart = allowSmart &&
+                                suggestions.stream()
+                                           .anyMatch(s -> s.isSmart);
+
+                lastTest = test;
+                lastCursor = cursor;
+                allowSmart = !allowSmart;
+
+                suggestions.stream()
+                           .filter(s -> !smart || s.isSmart)
+                           .map(s -> s.continuation)
+                           .forEach(result::add);
+
+                boolean onlySmart = suggestions.stream()
+                                               .allMatch(s -> s.isSmart);
+
+                if (smart && !onlySmart) {
+                    Optional<String> prefix =
+                            suggestions.stream()
+                                       .map(s -> s.continuation)
+                                       .reduce(ConsoleIOContext::commonPrefix);
+
+                    String prefixStr = prefix.orElse("").substring(cursor - anchor[0]);
+                    try {
+                        in.putString(prefixStr);
+                        cursor += prefixStr.length();
+                    } catch (IOException ex) {
+                        throw new IllegalStateException(ex);
+                    }
+                    result.add("<press tab to see more>");
+                    return cursor; //anchor should not be used.
+                }
+
+                if (result.isEmpty()) {
+                    try {
+                        //provide "empty completion" feedback
+                        //XXX: this only works correctly when there is only one Completer:
+                        in.beep();
+                    } catch (IOException ex) {
+                        throw new UncheckedIOException(ex);
+                    }
+                }
+
+                return anchor[0];
+            }
+        });
+        bind(DOCUMENTATION_SHORTCUT, (ActionListener) evt -> documentation(repl));
+        bind(CTRL_UP, (ActionListener) evt -> moveHistoryToSnippet(((EditingHistory) in.getHistory())::previousSnippet));
+        bind(CTRL_DOWN, (ActionListener) evt -> moveHistoryToSnippet(((EditingHistory) in.getHistory())::nextSnippet));
+    }
+
+    @Override
+    public String readLine(String prompt, String prefix) throws IOException, InputInterruptedException {
+        this.prefix = prefix;
+        try {
+            return in.readLine(prompt);
+        } catch (UserInterruptException ex) {
+            throw (InputInterruptedException) new InputInterruptedException().initCause(ex);
+        }
+    }
+
+    @Override
+    public boolean interactiveOutput() {
+        return true;
+    }
+
+    @Override
+    public Iterable<String> currentSessionHistory() {
+        return history.currentSessionEntries();
+    }
+
+    @Override
+    public void close() throws IOException {
+        history.save();
+        in.shutdown();
+        try {
+            in.getTerminal().restore();
+        } catch (Exception ex) {
+            throw new IOException(ex);
+        }
+    }
+
+    private void moveHistoryToSnippet(Supplier<Boolean> action) {
+        if (!action.get()) {
+            try {
+                in.beep();
+            } catch (IOException ex) {
+                throw new IllegalStateException(ex);
+            }
+        } else {
+            try {
+                //could use:
+                //in.resetPromptLine(in.getPrompt(), in.getHistory().current().toString(), -1);
+                //but that would mean more re-writing on the screen, (and prints an additional
+                //empty line), so using setBuffer directly:
+                Method setBuffer = in.getClass().getDeclaredMethod("setBuffer", String.class);
+
+                setBuffer.setAccessible(true);
+                setBuffer.invoke(in, in.getHistory().current().toString());
+                in.flush();
+            } catch (ReflectiveOperationException | IOException ex) {
+                throw new IllegalStateException(ex);
+            }
+        }
+    }
+
+    private void bind(String shortcut, Object action) {
+        KeyMap km = in.getKeys();
+        for (int i = 0; i < shortcut.length(); i++) {
+            Object value = km.getBound(Character.toString(shortcut.charAt(i)));
+            if (value instanceof KeyMap) {
+                km = (KeyMap) value;
+            } else {
+                km.bind(shortcut.substring(i), action);
+            }
+        }
+    }
+
+    private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
+    private static final String CTRL_UP = "\033\133\061\073\065\101"; //Ctrl-UP
+    private static final String CTRL_DOWN = "\033\133\061\073\065\102"; //Ctrl-DOWN
+
+    private void documentation(JShellTool repl) {
+        String buffer = in.getCursorBuffer().buffer.toString();
+        int cursor = in.getCursorBuffer().cursor;
+        String doc;
+        if (prefix.isEmpty() && buffer.trim().startsWith("/")) {
+            doc = repl.commandDocumentation(buffer, cursor);
+        } else {
+            doc = repl.analysis.documentation(prefix + buffer, cursor + prefix.length());
+        }
+
+        try {
+            if (doc != null) {
+                in.println();
+                in.println(doc);
+                in.redrawLine();
+                in.flush();
+            } else {
+                in.beep();
+            }
+        } catch (IOException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    private static String commonPrefix(String str1, String str2) {
+        for (int i = 0; i < str2.length(); i++) {
+            if (!str1.startsWith(str2.substring(0, i + 1))) {
+                return str2.substring(0, i);
+            }
+        }
+
+        return str2;
+    }
+
+    @Override
+    public boolean terminalEditorRunning() {
+        Terminal terminal = in.getTerminal();
+        if (terminal instanceof JShellUnixTerminal)
+            return ((JShellUnixTerminal) terminal).isRaw();
+        return false;
+    }
+
+    @Override
+    public void suspend() {
+        try {
+            in.getTerminal().restore();
+        } catch (Exception ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    @Override
+    public void resume() {
+        try {
+            in.getTerminal().init();
+        } catch (Exception ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    public void beforeUserCode() {
+        input.setState(State.BUFFER);
+    }
+
+    public void afterUserCode() {
+        input.setState(State.WAIT);
+    }
+
+    @Override
+    public void replaceLastHistoryEntry(String source) {
+        history.fullHistoryReplace(source);
+    }
+
+    private static final class JShellUnixTerminal extends NoInterruptUnixTerminal {
+
+        private final StopDetectingInputStream input;
+
+        public JShellUnixTerminal(StopDetectingInputStream input) throws Exception {
+            this.input = input;
+        }
+
+        public boolean isRaw() {
+            try {
+                return getSettings().get("-a").contains("-icanon");
+            } catch (IOException | InterruptedException ex) {
+                return false;
+            }
+        }
+
+        @Override
+        public InputStream wrapInIfNeeded(InputStream in) throws IOException {
+            return input.setInputStream(super.wrapInIfNeeded(in));
+        }
+
+        @Override
+        public void disableInterruptCharacter() {
+        }
+
+        @Override
+        public void enableInterruptCharacter() {
+        }
+
+    }
+
+    private static final class JShellWindowsTerminal extends WindowsTerminal {
+
+        private final StopDetectingInputStream input;
+
+        public JShellWindowsTerminal(StopDetectingInputStream input) throws Exception {
+            this.input = input;
+        }
+
+        @Override
+        public void init() throws Exception {
+            super.init();
+            setAnsiSupported(false);
+        }
+
+        @Override
+        public InputStream wrapInIfNeeded(InputStream in) throws IOException {
+            return input.setInputStream(super.wrapInIfNeeded(in));
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditPad.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,129 @@
+/*
+ * 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.internal.jshell.tool;
+
+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.concurrent.CountDownLatch;
+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.
+ */
+@SuppressWarnings("serial")             // serialVersionUID intentionally omitted
+public class EditPad extends JFrame implements Runnable {
+    private final Consumer<String> errorHandler; // For possible future error handling
+    private final String initialText;
+    private final CountDownLatch closeLock;
+    private final Consumer<String> saveHandler;
+
+    EditPad(Consumer<String> errorHandler, String initialText,
+            CountDownLatch closeLock, Consumer<String> saveHandler) {
+        super("JShell Edit Pad");
+        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();
+                closeLock.countDown();
+            }
+        });
+        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();
+        closeLock.countDown();
+    }
+
+    public static void edit(Consumer<String> errorHandler, String initialText,
+            Consumer<String> saveHandler) {
+        CountDownLatch closeLock = new CountDownLatch(1);
+        SwingUtilities.invokeLater(
+                new EditPad(errorHandler, initialText, closeLock, saveHandler));
+        do {
+            try {
+                closeLock.await();
+                break;
+            } catch (InterruptedException ex) {
+                // ignore and loop
+            }
+        } while (true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditingHistory.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,381 @@
+/*
+ * 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.internal.jshell.tool;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.internal.jline.console.history.History;
+import jdk.internal.jline.console.history.History.Entry;
+import jdk.internal.jline.console.history.MemoryHistory;
+import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
+
+/*Public for tests (HistoryTest).
+ */
+public abstract class EditingHistory implements History {
+
+    private final Preferences prefs;
+    private final History fullHistory;
+    private History currentDelegate;
+
+    protected EditingHistory(Preferences prefs) {
+        this.prefs = prefs;
+        this.fullHistory = new MemoryHistory();
+        this.currentDelegate = fullHistory;
+        load();
+    }
+
+    @Override
+    public int size() {
+        return currentDelegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return currentDelegate.isEmpty();
+    }
+
+    @Override
+    public int index() {
+        return currentDelegate.index();
+    }
+
+    @Override
+    public void clear() {
+        if (currentDelegate != fullHistory)
+            throw new IllegalStateException("narrowed");
+        currentDelegate.clear();
+    }
+
+    @Override
+    public CharSequence get(int index) {
+        return currentDelegate.get(index);
+    }
+
+    @Override
+    public void add(CharSequence line) {
+        NarrowingHistoryLine currentLine = null;
+        int origIndex = fullHistory.index();
+        int fullSize;
+        try {
+            fullHistory.moveToEnd();
+            fullSize = fullHistory.index();
+            if (currentDelegate == fullHistory) {
+                if (origIndex < fullHistory.index()) {
+                    for (Entry entry : fullHistory) {
+                        if (!(entry.value() instanceof NarrowingHistoryLine))
+                            continue;
+                        int[] cluster = ((NarrowingHistoryLine) entry.value()).span;
+                        if (cluster[0] == origIndex && cluster[1] > cluster[0]) {
+                            currentDelegate = new MemoryHistory();
+                            for (int i = cluster[0]; i <= cluster[1]; i++) {
+                                currentDelegate.add(fullHistory.get(i));
+                            }
+                        }
+                    }
+                }
+            }
+            fullHistory.moveToEnd();
+            while (fullHistory.previous()) {
+                CharSequence c = fullHistory.current();
+                if (c instanceof NarrowingHistoryLine) {
+                    currentLine = (NarrowingHistoryLine) c;
+                    break;
+                }
+            }
+        } finally {
+            fullHistory.moveTo(origIndex);
+        }
+        if (currentLine == null || currentLine.span[1] != (-1)) {
+            line = currentLine = new NarrowingHistoryLine(line, fullSize);
+        }
+        StringBuilder complete = new StringBuilder();
+        for (int i = currentLine.span[0]; i < fullSize; i++) {
+            complete.append(fullHistory.get(i));
+        }
+        complete.append(line);
+        if (analyzeCompletion(complete.toString()).completeness.isComplete) {
+            currentLine.span[1] = fullSize; //TODO: +1?
+            currentDelegate = fullHistory;
+        }
+        fullHistory.add(line);
+    }
+
+    protected abstract CompletionInfo analyzeCompletion(String input);
+
+    @Override
+    public void set(int index, CharSequence item) {
+        if (currentDelegate != fullHistory)
+            throw new IllegalStateException("narrowed");
+        currentDelegate.set(index, item);
+    }
+
+    @Override
+    public CharSequence remove(int i) {
+        if (currentDelegate != fullHistory)
+            throw new IllegalStateException("narrowed");
+        return currentDelegate.remove(i);
+    }
+
+    @Override
+    public CharSequence removeFirst() {
+        if (currentDelegate != fullHistory)
+            throw new IllegalStateException("narrowed");
+        return currentDelegate.removeFirst();
+    }
+
+    @Override
+    public CharSequence removeLast() {
+        if (currentDelegate != fullHistory)
+            throw new IllegalStateException("narrowed");
+        return currentDelegate.removeLast();
+    }
+
+    @Override
+    public void replace(CharSequence item) {
+        if (currentDelegate != fullHistory)
+            throw new IllegalStateException("narrowed");
+        currentDelegate.replace(item);
+    }
+
+    @Override
+    public ListIterator<Entry> entries(int index) {
+        return currentDelegate.entries(index);
+    }
+
+    @Override
+    public ListIterator<Entry> entries() {
+        return currentDelegate.entries();
+    }
+
+    @Override
+    public Iterator<Entry> iterator() {
+        return currentDelegate.iterator();
+    }
+
+    @Override
+    public CharSequence current() {
+        return currentDelegate.current();
+    }
+
+    @Override
+    public boolean previous() {
+        return currentDelegate.previous();
+    }
+
+    @Override
+    public boolean next() {
+        return currentDelegate.next();
+    }
+
+    @Override
+    public boolean moveToFirst() {
+        return currentDelegate.moveToFirst();
+    }
+
+    @Override
+    public boolean moveToLast() {
+        return currentDelegate.moveToLast();
+    }
+
+    @Override
+    public boolean moveTo(int index) {
+        return currentDelegate.moveTo(index);
+    }
+
+    @Override
+    public void moveToEnd() {
+        currentDelegate.moveToEnd();
+    }
+
+    public boolean previousSnippet() {
+        for (int i = index() - 1; i >= 0; i--) {
+            if (get(i) instanceof NarrowingHistoryLine) {
+                moveTo(i);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public boolean nextSnippet() {
+        for (int i = index() + 1; i < size(); i++) {
+            if (get(i) instanceof NarrowingHistoryLine) {
+                moveTo(i);
+                return true;
+            }
+        }
+
+        if (index() < size()) {
+            moveToEnd();
+            return true;
+        }
+
+        return false;
+    }
+
+    private static final String HISTORY_LINE_PREFIX = "HISTORY_LINE_";
+    private static final String HISTORY_SNIPPET_START = "HISTORY_SNIPPET";
+
+    public final void load() {
+        try {
+            Set<Integer> snippetsStart = new HashSet<>();
+            for (String start : prefs.get(HISTORY_SNIPPET_START, "").split(";")) {
+                if (!start.isEmpty())
+                    snippetsStart.add(Integer.parseInt(start));
+            }
+            List<String> keys = Stream.of(prefs.keys()).sorted().collect(Collectors.toList());
+            NarrowingHistoryLine currentHistoryLine = null;
+            int currentLine = 0;
+            for (String key : keys) {
+                if (!key.startsWith(HISTORY_LINE_PREFIX))
+                    continue;
+                CharSequence line = prefs.get(key, "");
+                if (snippetsStart.contains(currentLine)) {
+                    class PersistentNarrowingHistoryLine extends NarrowingHistoryLine implements PersistentEntryMarker {
+                        public PersistentNarrowingHistoryLine(CharSequence delegate, int start) {
+                            super(delegate, start);
+                        }
+                    }
+                    line = currentHistoryLine = new PersistentNarrowingHistoryLine(line, currentLine);
+                } else {
+                    class PersistentLine implements CharSequence, PersistentEntryMarker {
+                        private final CharSequence delegate;
+                        public PersistentLine(CharSequence delegate) {
+                            this.delegate = delegate;
+                        }
+                        @Override public int length() {
+                            return delegate.length();
+                        }
+                        @Override public char charAt(int index) {
+                            return delegate.charAt(index);
+                        }
+                        @Override public CharSequence subSequence(int start, int end) {
+                            return delegate.subSequence(start, end);
+                        }
+                        @Override public String toString() {
+                            return delegate.toString();
+                        }
+                    }
+                    line = new PersistentLine(line);
+                }
+                if (currentHistoryLine != null)
+                    currentHistoryLine.span[1] = currentLine;
+                currentLine++;
+                fullHistory.add(line);
+            }
+            currentLine = 0;
+        } catch (BackingStoreException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    public void save() {
+        try {
+            for (String key : prefs.keys()) {
+                if (key.startsWith(HISTORY_LINE_PREFIX))
+                    prefs.remove(key);
+            }
+            Iterator<Entry> entries = fullHistory.iterator();
+            if (entries.hasNext()) {
+                int len = (int) Math.ceil(Math.log10(fullHistory.size()+1));
+                String format = HISTORY_LINE_PREFIX + "%0" + len + "d";
+                StringBuilder snippetStarts = new StringBuilder();
+                String snippetStartDelimiter = "";
+                while (entries.hasNext()) {
+                    Entry entry = entries.next();
+                    prefs.put(String.format(format, entry.index()), entry.value().toString());
+                    if (entry.value() instanceof NarrowingHistoryLine) {
+                        snippetStarts.append(snippetStartDelimiter);
+                        snippetStarts.append(entry.index());
+                        snippetStartDelimiter = ";";
+                    }
+                }
+                prefs.put(HISTORY_SNIPPET_START, snippetStarts.toString());
+            }
+        } catch (BackingStoreException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    public List<String> currentSessionEntries() {
+        List<String> result = new ArrayList<>();
+
+        for (Entry e : fullHistory) {
+            if (!(e.value() instanceof PersistentEntryMarker)) {
+                result.add(e.value().toString());
+            }
+        }
+
+        return result;
+    }
+
+    void fullHistoryReplace(String source) {
+        fullHistory.replace(source);
+    }
+
+    private class NarrowingHistoryLine implements CharSequence {
+        private final CharSequence delegate;
+        private final int[] span;
+
+        public NarrowingHistoryLine(CharSequence delegate, int start) {
+            this.delegate = delegate;
+            this.span = new int[] {start, -1};
+        }
+
+        @Override
+        public int length() {
+            return delegate.length();
+        }
+
+        @Override
+        public char charAt(int index) {
+            return delegate.charAt(index);
+        }
+
+        @Override
+        public CharSequence subSequence(int start, int end) {
+            return delegate.subSequence(start, end);
+        }
+
+        @Override
+        public String toString() {
+            return delegate.toString();
+        }
+
+    }
+
+    private interface PersistentEntryMarker {}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ExternalEditor.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,147 @@
+/*
+ * 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.internal.jshell.tool;
+
+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.function.Consumer;
+import java.util.stream.Collectors;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
+
+/**
+ * Wrapper for controlling an external editor.
+ */
+public class ExternalEditor {
+    private final Consumer<String> errorHandler;
+    private final Consumer<String> saveHandler;
+    private final IOContext input;
+
+    private WatchService watcher;
+    private Thread watchedThread;
+    private Path dir;
+    private Path tmpfile;
+
+    ExternalEditor(Consumer<String> errorHandler, Consumer<String> saveHandler, IOContext 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, ".repl");
+        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() {
+        try {
+            saveHandler.accept(Files.lines(tmpfile).collect(Collectors.joining("\n", "", "\n")));
+        } catch (IOException ex) {
+            errorHandler.accept("Failure in read edit file: " + ex.getMessage());
+        }
+    }
+
+    static void edit(String cmd, Consumer<String> errorHandler, String initialText,
+            Consumer<String> saveHandler, IOContext input) {
+        ExternalEditor ed = new ExternalEditor(errorHandler,  saveHandler, input);
+        ed.edit(cmd, initialText);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/IOContext.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,61 @@
+/*
+ * 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.internal.jshell.tool;
+
+import java.io.IOException;
+
+/**
+ * Interface for defining user interaction with the shell.
+ * @author Robert Field
+ */
+abstract class IOContext implements AutoCloseable {
+
+    @Override
+    public abstract void close() throws IOException;
+
+    public abstract String readLine(String prompt, String prefix) throws IOException, InputInterruptedException;
+
+    public abstract boolean interactiveOutput();
+
+    public abstract Iterable<String> currentSessionHistory();
+
+    public abstract  boolean terminalEditorRunning();
+
+    public abstract void suspend();
+
+    public abstract void resume();
+
+    public abstract void beforeUserCode();
+
+    public abstract void afterUserCode();
+
+    public abstract void replaceLastHistoryEntry(String source);
+
+    class InputInterruptedException extends Exception {
+        private static final long serialVersionUID = 1L;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,1813 @@
+/*
+ * Copyright (c) 2014, 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.internal.jshell.tool;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.prefs.Preferences;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import jdk.internal.jshell.debug.InternalDebugControl;
+import jdk.internal.jshell.tool.IOContext.InputInterruptedException;
+import jdk.jshell.Diag;
+import jdk.jshell.EvalException;
+import jdk.jshell.JShell;
+import jdk.jshell.Snippet;
+import jdk.jshell.DeclarationSnippet;
+import jdk.jshell.TypeDeclSnippet;
+import jdk.jshell.MethodSnippet;
+import jdk.jshell.PersistentSnippet;
+import jdk.jshell.VarSnippet;
+import jdk.jshell.ExpressionSnippet;
+import jdk.jshell.Snippet.Status;
+import jdk.jshell.SourceCodeAnalysis;
+import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
+import jdk.jshell.SourceCodeAnalysis.Suggestion;
+import jdk.jshell.SnippetEvent;
+import jdk.jshell.UnresolvedReferenceException;
+import jdk.jshell.Snippet.SubKind;
+import jdk.jshell.JShell.Subscription;
+
+import static java.nio.file.StandardOpenOption.CREATE;
+import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
+import static java.nio.file.StandardOpenOption.WRITE;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import static java.util.stream.Collectors.toList;
+
+/**
+ * Command line REPL tool for Java using the JShell API.
+ * @author Robert Field
+ */
+public class JShellTool {
+
+    private static final Pattern LINEBREAK = Pattern.compile("\\R");
+    private static final Pattern HISTORY_ALL_FILENAME = Pattern.compile(
+            "((?<cmd>(all|history))(\\z|\\p{javaWhitespace}+))?(?<filename>.*)");
+
+    final InputStream cmdin;
+    final PrintStream cmdout;
+    final PrintStream cmderr;
+    final PrintStream console;
+    final InputStream userin;
+    final PrintStream userout;
+    final PrintStream usererr;
+
+    /**
+     * The constructor for the tool (used by tool launch via main and by test
+     * harnesses to capture ins and outs.
+     * @param cmdin command line input -- snippets and commands
+     * @param cmdout command line output, feedback including errors
+     * @param cmderr start-up errors and debugging info
+     * @param console console control interaction
+     * @param userin code execution input (not yet functional)
+     * @param userout code execution output  -- System.out.printf("hi")
+     * @param usererr code execution error stream  -- System.err.printf("Oops")
+     */
+    public JShellTool(InputStream cmdin, PrintStream cmdout, PrintStream cmderr,
+            PrintStream console,
+            InputStream userin, PrintStream userout, PrintStream usererr) {
+        this.cmdin = cmdin;
+        this.cmdout = cmdout;
+        this.cmderr = cmderr;
+        this.console = console;
+        this.userin = userin;
+        this.userout = userout;
+        this.usererr = usererr;
+    }
+
+    private IOContext input = null;
+    private boolean regenerateOnDeath = true;
+    private boolean live = false;
+
+    SourceCodeAnalysis analysis;
+    JShell state = null;
+    Subscription shutdownSubscription = null;
+
+    private boolean debug = false;
+    private boolean displayPrompt = true;
+    public boolean testPrompt = false;
+    private Feedback feedback = Feedback.Default;
+    private String cmdlineClasspath = null;
+    private String cmdlineStartup = null;
+    private String editor = null;
+
+    static final Preferences PREFS = Preferences.userRoot().node("tool/REPL");
+
+    static final String STARTUP_KEY = "STARTUP";
+
+    static final String DEFAULT_STARTUP =
+            "\n" +
+            "import java.util.*;\n" +
+            "import java.io.*;\n" +
+            "import java.math.*;\n" +
+            "import java.net.*;\n" +
+            "import java.util.concurrent.*;\n" +
+            "import java.util.prefs.*;\n" +
+            "import java.util.regex.*;\n" +
+            "void printf(String format, Object... args) { System.out.printf(format, args); }\n";
+
+    // Tool id (tid) mapping
+    NameSpace mainNamespace;
+    NameSpace startNamespace;
+    NameSpace errorNamespace;
+    NameSpace currentNameSpace;
+    Map<Snippet,SnippetInfo> mapSnippet;
+
+    void debug(String format, Object... args) {
+        if (debug) {
+            cmderr.printf(format + "\n", args);
+        }
+    }
+
+    /**
+     * For more verbose feedback modes
+     * @param format printf format
+     * @param args printf args
+     */
+    void fluff(String format, Object... args) {
+        if (feedback() != Feedback.Off && feedback() != Feedback.Concise) {
+            hard(format, args);
+        }
+    }
+
+    /**
+     * For concise feedback mode only
+     * @param format printf format
+     * @param args printf args
+     */
+    void concise(String format, Object... args) {
+        if (feedback() == Feedback.Concise) {
+            hard(format, args);
+        }
+    }
+
+    /**
+     * For all feedback modes -- must show
+     * @param format printf format
+     * @param args printf args
+     */
+    void hard(String format, Object... args) {
+        cmdout.printf("|  " + format + "\n", args);
+    }
+
+    /**
+     * Trim whitespace off end of string
+     * @param s
+     * @return
+     */
+    static String trimEnd(String s) {
+        int last = s.length() - 1;
+        int i = last;
+        while (i >= 0 && Character.isWhitespace(s.charAt(i))) {
+            --i;
+        }
+        if (i != last) {
+            return s.substring(0, i + 1);
+        } else {
+            return s;
+        }
+    }
+
+    /**
+     * Normal start entry point
+     * @param args
+     * @throws Exception
+     */
+    public static void main(String[] args) throws Exception {
+        new JShellTool(System.in, System.out, System.err, System.out,
+                 new ByteArrayInputStream(new byte[0]), System.out, System.err)
+                .start(args);
+    }
+
+    public void start(String[] args) throws Exception {
+        List<String> loadList = processCommandArgs(args);
+        if (loadList == null) {
+            // Abort
+            return;
+        }
+        try (IOContext in = new ConsoleIOContext(this, cmdin, console)) {
+            start(in, loadList);
+        }
+    }
+
+    private void start(IOContext in, List<String> loadList) {
+        resetState(); // Initialize
+
+        for (String loadFile : loadList) {
+            cmdOpen(loadFile);
+        }
+
+        if (regenerateOnDeath) {
+            fluff("Welcome to JShell -- Version %s", version());
+            fluff("Type /help for help");
+        }
+
+        try {
+            while (regenerateOnDeath) {
+                if (!live) {
+                    resetState();
+                }
+                run(in);
+            }
+        } finally {
+            closeState();
+        }
+    }
+
+    /**
+     * 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) {
+        List<String> loadList = new ArrayList<>();
+        Iterator<String> ai = Arrays.asList(args).iterator();
+        while (ai.hasNext()) {
+            String arg = ai.next();
+            if (arg.startsWith("-")) {
+                switch (arg) {
+                    case "-classpath":
+                    case "-cp":
+                        if (cmdlineClasspath != null) {
+                            cmderr.printf("Conflicting -classpath option.\n");
+                            return null;
+                        }
+                        if (ai.hasNext()) {
+                            cmdlineClasspath = ai.next();
+                        } else {
+                            cmderr.printf("Argument to -classpath missing.\n");
+                            return null;
+                        }
+                        break;
+                    case "-help":
+                        printUsage();
+                        return null;
+                    case "-version":
+                        cmdout.printf("jshell %s\n", version());
+                        return null;
+                    case "-fullversion":
+                        cmdout.printf("jshell %s\n", fullVersion());
+                        return null;
+                    case "-startup":
+                        if (cmdlineStartup != null) {
+                            cmderr.printf("Conflicting -startup or -nostartup option.\n");
+                            return null;
+                        }
+                        if (ai.hasNext()) {
+                            String filename = ai.next();
+                            try {
+                                byte[] encoded = Files.readAllBytes(Paths.get(filename));
+                                cmdlineStartup = new String(encoded);
+                            } catch (AccessDeniedException e) {
+                                hard("File '%s' for start-up is not accessible.", filename);
+                            } catch (NoSuchFileException e) {
+                                hard("File '%s' for start-up is not found.", filename);
+                            } catch (Exception e) {
+                                hard("Exception while reading start-up file: %s", e);
+                            }
+                        } else {
+                            cmderr.printf("Argument to -startup missing.\n");
+                            return null;
+                        }
+                        break;
+                    case "-nostartup":
+                        if (cmdlineStartup != null && !cmdlineStartup.isEmpty()) {
+                            cmderr.printf("Conflicting -startup option.\n");
+                            return null;
+                        }
+                        cmdlineStartup = "";
+                        break;
+                    default:
+                        cmderr.printf("Unknown option: %s\n", arg);
+                        printUsage();
+                        return null;
+                }
+            } else {
+                loadList.add(arg);
+            }
+        }
+        return loadList;
+    }
+
+    private void printUsage() {
+        cmdout.printf("Usage:   jshell <options> <load files>\n");
+        cmdout.printf("where possible options include:\n");
+        cmdout.printf("  -classpath <path>          Specify where to find user class files\n");
+        cmdout.printf("  -cp <path>                 Specify where to find user class files\n");
+        cmdout.printf("  -startup <file>            One run replacement for the start-up definitions\n");
+        cmdout.printf("  -nostartup                 Do not run the start-up definitions\n");
+        cmdout.printf("  -help                      Print a synopsis of standard options\n");
+        cmdout.printf("  -version                   Version information\n");
+    }
+
+    private void resetState() {
+        closeState();
+
+        // Initialize tool id mapping
+        mainNamespace = new NameSpace("main", "");
+        startNamespace = new NameSpace("start", "s");
+        errorNamespace = new NameSpace("error", "e");
+        mapSnippet = new LinkedHashMap<>();
+        currentNameSpace = startNamespace;
+
+        state = JShell.builder()
+                .in(userin)
+                .out(userout)
+                .err(usererr)
+                .tempVariableNameGenerator(()-> "$" + currentNameSpace.tidNext())
+                .idGenerator((sn, i) -> (currentNameSpace == startNamespace || state.status(sn).isActive)
+                        ? currentNameSpace.tid(sn)
+                        : errorNamespace.tid(sn))
+                .build();
+        analysis = state.sourceCodeAnalysis();
+        shutdownSubscription = state.onShutdown((JShell deadState) -> {
+            if (deadState == state) {
+                hard("State engine terminated.  See /history");
+                live = false;
+            }
+        });
+        live = true;
+
+        if (cmdlineClasspath != null) {
+            state.addToClasspath(cmdlineClasspath);
+        }
+
+
+        String start;
+        if (cmdlineStartup == null) {
+            start = PREFS.get(STARTUP_KEY, "<nada>");
+            if (start.equals("<nada>")) {
+                start = DEFAULT_STARTUP;
+                PREFS.put(STARTUP_KEY, DEFAULT_STARTUP);
+            }
+        } else {
+            start = cmdlineStartup;
+        }
+        try (IOContext suin = new FileScannerIOContext(new StringReader(start))) {
+            run(suin);
+        } catch (Exception ex) {
+            hard("Unexpected exception reading start-up: %s\n", ex);
+        }
+        currentNameSpace = mainNamespace;
+    }
+
+    private void closeState() {
+        live = false;
+        JShell oldState = state;
+        if (oldState != null) {
+            oldState.unsubscribe(shutdownSubscription); // No notification
+            oldState.close();
+        }
+    }
+
+    /**
+     * Main loop
+     * @param in the line input/editing context
+     */
+    private void run(IOContext in) {
+        IOContext oldInput = input;
+        input = in;
+        try {
+            String incomplete = "";
+            while (live) {
+                String prompt;
+                if (in.interactiveOutput() && displayPrompt) {
+                    prompt = testPrompt
+                                    ? incomplete.isEmpty()
+                                            ? "\u0005" //ENQ
+                                            : "\u0006" //ACK
+                                    : incomplete.isEmpty()
+                                            ? feedback() == Feedback.Concise
+                                                    ? "-> "
+                                                    : "\n-> "
+                                            : ">> "
+                    ;
+                } else {
+                    prompt = "";
+                }
+                String raw;
+                try {
+                    raw = in.readLine(prompt, incomplete);
+                } catch (InputInterruptedException ex) {
+                    //input interrupted - clearing current state
+                    incomplete = "";
+                    continue;
+                }
+                if (raw == null) {
+                    //EOF
+                    if (in.interactiveOutput()) {
+                        // End after user ctrl-D
+                        regenerateOnDeath = false;
+                    }
+                    break;
+                }
+                String trimmed = trimEnd(raw);
+                if (!trimmed.isEmpty()) {
+                    String line = incomplete + trimmed;
+
+                    // No commands in the middle of unprocessed source
+                    if (incomplete.isEmpty() && line.startsWith("/") && !line.startsWith("//") && !line.startsWith("/*")) {
+                        processCommand(line.trim());
+                    } else {
+                        incomplete = processSourceCatchingReset(line);
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            hard("Unexpected exception: %s\n", ex);
+        } finally {
+            input = oldInput;
+        }
+    }
+
+    private String processSourceCatchingReset(String src) {
+        try {
+            input.beforeUserCode();
+            return processSource(src);
+        } catch (IllegalStateException ex) {
+            hard("Resetting...");
+            live = false; // Make double sure
+            return "";
+        } finally {
+            input.afterUserCode();
+        }
+    }
+
+    private void processCommand(String cmd) {
+        try {
+            //handle "/[number]"
+            cmdUseHistoryEntry(Integer.parseInt(cmd.substring(1)));
+            return ;
+        } catch (NumberFormatException ex) {
+            //ignore
+        }
+        String arg = "";
+        int idx = cmd.indexOf(' ');
+        if (idx > 0) {
+            arg = cmd.substring(idx + 1).trim();
+            cmd = cmd.substring(0, idx);
+        }
+        Command command = commands.get(cmd);
+        if (command == null || command.kind == CommandKind.HELP_ONLY) {
+            hard("No such command: %s", cmd);
+            fluff("Type /help for help.");
+        } else {
+            command.run.accept(arg);
+        }
+    }
+
+    private static Path toPathResolvingUserHome(String pathString) {
+        if (pathString.replace(File.separatorChar, '/').startsWith("~/"))
+            return Paths.get(System.getProperty("user.home"), pathString.substring(2));
+        else
+            return Paths.get(pathString);
+    }
+
+    static final class Command {
+        public final String[] aliases;
+        public final String params;
+        public final String description;
+        public final Consumer<String> run;
+        public final CompletionProvider completions;
+        public final CommandKind kind;
+
+        public Command(String command, String alias, String params, String description, Consumer<String> run, CompletionProvider completions) {
+            this(command, alias, params, description, run, completions, CommandKind.NORMAL);
+        }
+
+        public Command(String command, String alias, String params, String description, Consumer<String> run, CompletionProvider completions, CommandKind kind) {
+            this.aliases = alias != null ? new String[] {command, alias} : new String[] {command};
+            this.params = params;
+            this.description = description;
+            this.run = run;
+            this.completions = completions;
+            this.kind = kind;
+        }
+
+    }
+
+    interface CompletionProvider {
+        List<Suggestion> completionSuggestions(String input, int cursor, int[] anchor);
+    }
+
+    enum CommandKind {
+        NORMAL,
+        HIDDEN,
+        HELP_ONLY;
+    }
+
+    static final class FixedCompletionProvider implements CompletionProvider {
+
+        private final String[] alternatives;
+
+        public FixedCompletionProvider(String... alternatives) {
+            this.alternatives = alternatives;
+        }
+
+        @Override
+        public List<Suggestion> completionSuggestions(String input, int cursor, int[] anchor) {
+            List<Suggestion> result = new ArrayList<>();
+
+            for (String alternative : alternatives) {
+                if (alternative.startsWith(input)) {
+                    result.add(new Suggestion(alternative, false));
+                }
+            }
+
+            anchor[0] = 0;
+
+            return result;
+        }
+
+    }
+
+    private static final CompletionProvider EMPTY_COMPLETION_PROVIDER = new FixedCompletionProvider();
+    private static final CompletionProvider FILE_COMPLETION_PROVIDER = fileCompletions(p -> true);
+    private final Map<String, Command> commands = new LinkedHashMap<>();
+    private void registerCommand(Command cmd) {
+        for (String str : cmd.aliases) {
+            commands.put(str, cmd);
+        }
+    }
+    private static CompletionProvider fileCompletions(Predicate<Path> accept) {
+        return (code, cursor, anchor) -> {
+            int lastSlash = code.lastIndexOf('/');
+            String path = code.substring(0, lastSlash + 1);
+            String prefix = lastSlash != (-1) ? code.substring(lastSlash + 1) : code;
+            Path current = toPathResolvingUserHome(path);
+            List<Suggestion> result = new ArrayList<>();
+            try (Stream<Path> dir = Files.list(current)) {
+                dir.filter(f -> accept.test(f) && f.getFileName().toString().startsWith(prefix))
+                   .map(f -> new Suggestion(f.getFileName() + (Files.isDirectory(f) ? "/" : ""), false))
+                   .forEach(result::add);
+            } catch (IOException ex) {
+                //ignore...
+            }
+            if (path.isEmpty()) {
+                StreamSupport.stream(FileSystems.getDefault().getRootDirectories().spliterator(), false)
+                             .filter(root -> accept.test(root) && root.toString().startsWith(prefix))
+                             .map(root -> new Suggestion(root.toString(), false))
+                             .forEach(result::add);
+            }
+            anchor[0] = path.length();
+            return result;
+        };
+    }
+
+    private static CompletionProvider classPathCompletion() {
+        return fileCompletions(p -> Files.isDirectory(p) ||
+                                    p.getFileName().toString().endsWith(".zip") ||
+                                    p.getFileName().toString().endsWith(".jar"));
+    }
+
+    private CompletionProvider editCompletion() {
+        return (prefix, cursor, anchor) -> {
+            anchor[0] = 0;
+            return state.snippets()
+                        .stream()
+                        .flatMap(k -> (k instanceof DeclarationSnippet)
+                                ? Stream.of(String.valueOf(k.id()), ((DeclarationSnippet) k).name())
+                                : Stream.of(String.valueOf(k.id())))
+                        .filter(k -> k.startsWith(prefix))
+                        .map(k -> new Suggestion(k, false))
+                        .collect(Collectors.toList());
+        };
+    }
+
+    private static CompletionProvider saveCompletion() {
+        CompletionProvider keyCompletion = new FixedCompletionProvider("all ", "history ");
+        return (code, cursor, anchor) -> {
+            List<Suggestion> result = new ArrayList<>();
+            int space = code.indexOf(' ');
+            if (space == (-1)) {
+                result.addAll(keyCompletion.completionSuggestions(code, cursor, anchor));
+            }
+            result.addAll(FILE_COMPLETION_PROVIDER.completionSuggestions(code.substring(space + 1), cursor - space - 1, anchor));
+            anchor[0] += space + 1;
+            return result;
+        };
+    }
+
+    // Table of commands -- with command forms, argument kinds, help message, implementation, ...
+
+    {
+        registerCommand(new Command("/list", "/l", "[all]", "list the source you have typed",
+                                    arg -> cmdList(arg),
+                                    new FixedCompletionProvider("all")));
+        registerCommand(new Command("/seteditor", null, "<executable>", "set the external editor command to use",
+                                    arg -> cmdSetEditor(arg),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/edit", "/e", "<name or id>", "edit a source entry referenced by name or id",
+                                    arg -> cmdEdit(arg),
+                                    editCompletion()));
+        registerCommand(new Command("/drop", "/d", "<name or id>", "delete a source entry referenced by name or id",
+                                    arg -> cmdDrop(arg),
+                                    editCompletion()));
+        registerCommand(new Command("/save", "/s", "[all|history] <file>", "save the source you have typed",
+                                    arg -> cmdSave(arg),
+                                    saveCompletion()));
+        registerCommand(new Command("/open", "/o", "<file>", "open a file as source input",
+                                    arg -> cmdOpen(arg),
+                                    FILE_COMPLETION_PROVIDER));
+        registerCommand(new Command("/vars", "/v", null, "list the declared variables and their values",
+                                    arg -> cmdVars(),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/methods", "/m", null, "list the declared methods and their signatures",
+                                    arg -> cmdMethods(),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/classes", "/c", null, "list the declared classes",
+                                    arg -> cmdClasses(),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/imports", "/i", null, "list the imported items",
+                                    arg -> cmdImports(),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/exit", "/x", null, "exit the REPL",
+                                    arg -> cmdExit(),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/reset", "/r", null, "reset everything in the REPL",
+                                    arg -> cmdReset(),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/feedback", "/f", "<level>", "feedback information: off, concise, normal, verbose, default, or ?",
+                                    arg -> cmdFeedback(arg),
+                                    new FixedCompletionProvider("off", "concise", "normal", "verbose", "default", "?")));
+        registerCommand(new Command("/prompt", "/p", null, "toggle display of a prompt",
+                                    arg -> cmdPrompt(),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/classpath", "/cp", "<path>", "add a path to the classpath",
+                                    arg -> cmdClasspath(arg),
+                                    classPathCompletion()));
+        registerCommand(new Command("/history", "/h", null, "history of what you have typed",
+                                    arg -> cmdHistory(),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/setstart", null, "<file>", "read file and set as the new start-up definitions",
+                                    arg -> cmdSetStart(arg),
+                                    FILE_COMPLETION_PROVIDER));
+        registerCommand(new Command("/savestart", null, "<file>", "save the default start-up definitions to the file",
+                                    arg -> cmdSaveStart(arg),
+                                    FILE_COMPLETION_PROVIDER));
+        registerCommand(new Command("/debug", "/db", "", "toggle debugging of the REPL",
+                                    arg -> cmdDebug(arg),
+                                    EMPTY_COMPLETION_PROVIDER,
+                                    CommandKind.HIDDEN));
+        registerCommand(new Command("/help", "/?", "", "this help message",
+                                    arg -> cmdHelp(),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/!", null, "", "re-run last snippet",
+                                    arg -> cmdUseHistoryEntry(-1),
+                                    EMPTY_COMPLETION_PROVIDER));
+        registerCommand(new Command("/<n>", null, "", "re-run n-th snippet",
+                                    arg -> { throw new IllegalStateException(); },
+                                    EMPTY_COMPLETION_PROVIDER,
+                                    CommandKind.HELP_ONLY));
+        registerCommand(new Command("/-<n>", null, "", "re-run n-th previous snippet",
+                                    arg -> { throw new IllegalStateException(); },
+                                    EMPTY_COMPLETION_PROVIDER,
+                                    CommandKind.HELP_ONLY));
+    }
+
+    public List<Suggestion> commandCompletionSuggestions(String code, int cursor, int[] anchor) {
+        String prefix = code.substring(0, cursor);
+        int space = prefix.indexOf(' ');
+        Stream<Suggestion> result;
+
+        if (space == (-1)) {
+            result = commands.values()
+                             .stream()
+                             .distinct()
+                             .filter(cmd -> cmd.kind != CommandKind.HIDDEN && cmd.kind != CommandKind.HELP_ONLY)
+                             .map(cmd -> cmd.aliases[0])
+                             .filter(key -> key.startsWith(prefix))
+                             .map(key -> new Suggestion(key + " ", false));
+            anchor[0] = 0;
+        } else {
+            String arg = prefix.substring(space + 1);
+            String cmd = prefix.substring(0, space);
+            Command command = commands.get(cmd);
+            if (command != null) {
+                result = command.completions.completionSuggestions(arg, cursor - space, anchor).stream();
+                anchor[0] += space + 1;
+            } else {
+                result = Stream.empty();
+            }
+        }
+
+        return result.sorted((s1, s2) -> s1.continuation.compareTo(s2.continuation))
+                     .collect(Collectors.toList());
+    }
+
+    public String commandDocumentation(String code, int cursor) {
+        code = code.substring(0, cursor);
+        int space = code.indexOf(' ');
+
+        if (space != (-1)) {
+            String cmd = code.substring(0, space);
+            Command command = commands.get(cmd);
+            if (command != null) {
+                return command.description;
+            }
+        }
+
+        return null;
+    }
+
+    // --- Command implementations ---
+
+    void cmdSetEditor(String arg) {
+        if (arg.isEmpty()) {
+            hard("/seteditor requires a path argument");
+        } else {
+            editor = arg;
+            fluff("Editor set to: %s", arg);
+        }
+    }
+
+    void cmdClasspath(String arg) {
+        if (arg.isEmpty()) {
+            hard("/classpath requires a path argument");
+        } else {
+            state.addToClasspath(toPathResolvingUserHome(arg).toString());
+            fluff("Path %s added to classpath", arg);
+        }
+    }
+
+    void cmdDebug(String arg) {
+        if (arg.isEmpty()) {
+            debug = !debug;
+            InternalDebugControl.setDebugFlags(state, debug ? InternalDebugControl.DBG_GEN : 0);
+            fluff("Debugging %s", debug ? "on" : "off");
+        } else {
+            int flags = 0;
+            for (char ch : arg.toCharArray()) {
+                switch (ch) {
+                    case '0':
+                        flags = 0;
+                        debug = false;
+                        fluff("Debugging off");
+                        break;
+                    case 'r':
+                        debug = true;
+                        fluff("REPL tool debugging on");
+                        break;
+                    case 'g':
+                        flags |= InternalDebugControl.DBG_GEN;
+                        fluff("General debugging on");
+                        break;
+                    case 'f':
+                        flags |= InternalDebugControl.DBG_FMGR;
+                        fluff("File manager debugging on");
+                        break;
+                    case 'c':
+                        flags |= InternalDebugControl.DBG_COMPA;
+                        fluff("Completion analysis debugging on");
+                        break;
+                    case 'd':
+                        flags |= InternalDebugControl.DBG_DEP;
+                        fluff("Dependency debugging on");
+                        break;
+                    case 'e':
+                        flags |= InternalDebugControl.DBG_EVNT;
+                        fluff("Event debugging on");
+                        break;
+                    default:
+                        hard("Unknown debugging option: %c", ch);
+                        fluff("Use: 0 r g f c d");
+                        break;
+                }
+            }
+            InternalDebugControl.setDebugFlags(state, flags);
+        }
+    }
+
+    private void cmdExit() {
+        regenerateOnDeath = false;
+        live = false;
+        fluff("Goodbye\n");
+    }
+
+    private void cmdFeedback(String arg) {
+        switch (arg) {
+            case "":
+            case "d":
+            case "default":
+                feedback = Feedback.Default;
+                break;
+            case "o":
+            case "off":
+                feedback = Feedback.Off;
+                break;
+            case "c":
+            case "concise":
+                feedback = Feedback.Concise;
+                break;
+            case "n":
+            case "normal":
+                feedback = Feedback.Normal;
+                break;
+            case "v":
+            case "verbose":
+                feedback = Feedback.Verbose;
+                break;
+            default:
+                hard("Follow /feedback with of the following:");
+                hard("  off       (errors and critical output only)");
+                hard("  concise");
+                hard("  normal");
+                hard("  verbose");
+                hard("  default");
+                hard("You may also use just the first letter, for example: /f c");
+                hard("In interactive mode 'default' is the same as 'normal', from a file it is the same as 'off'");
+                return;
+        }
+        fluff("Feedback mode: %s", feedback.name().toLowerCase());
+    }
+
+    void cmdHelp() {
+        int synopsisLen = 0;
+        Map<String, String> synopsis2Description = new LinkedHashMap<>();
+        for (Command cmd : new LinkedHashSet<>(commands.values())) {
+            if (cmd.kind == CommandKind.HIDDEN)
+                continue;
+            StringBuilder synopsis = new StringBuilder();
+            if (cmd.aliases.length > 1) {
+                synopsis.append(String.format("%-3s or ", cmd.aliases[1]));
+            } else {
+                synopsis.append("       ");
+            }
+            synopsis.append(cmd.aliases[0]);
+            if (cmd.params != null)
+                synopsis.append(" ").append(cmd.params);
+            synopsis2Description.put(synopsis.toString(), cmd.description);
+            synopsisLen = Math.max(synopsisLen, synopsis.length());
+        }
+        cmdout.println("Type a Java language expression, statement, or declaration.");
+        cmdout.println("Or type one of the following commands:\n");
+        for (Entry<String, String> e : synopsis2Description.entrySet()) {
+            cmdout.print(String.format("%-" + synopsisLen + "s", e.getKey()));
+            cmdout.print(" -- ");
+            cmdout.println(e.getValue());
+        }
+        cmdout.println();
+        cmdout.println("Supported shortcuts include:");
+        cmdout.println("<tab>       -- show possible completions for the current text");
+        cmdout.println("Shift-<tab> -- for current method or constructor invocation, show a synopsis of the method/constructor");
+    }
+
+    private void cmdHistory() {
+        cmdout.println();
+        for (String s : input.currentSessionHistory()) {
+            // No number prefix, confusing with snippet ids
+            cmdout.printf("%s\n", s);
+        }
+    }
+
+    /**
+     * Convert a user argument to a list of snippets referenced by that
+     * argument (or lack of argument).
+     * @param arg The user's argument to the command
+     * @return a list of referenced snippets
+     */
+    private List<Snippet> argToSnippets(String arg) {
+        List<Snippet> snippets = new ArrayList<>();
+        if (arg.isEmpty()) {
+            // Default is all user snippets
+            for (Snippet sn : state.snippets()) {
+                if (notInStartUp(sn)) {
+                    snippets.add(sn);
+                }
+            }
+        } else {
+            // Look for all declarations with matching names
+            for (Snippet key : state.snippets()) {
+                switch (key.kind()) {
+                    case METHOD:
+                    case VAR:
+                    case TYPE_DECL:
+                        if (((DeclarationSnippet) key).name().equals(arg)) {
+                            snippets.add(key);
+                        }
+                        break;
+                }
+            }
+            // If no declarations found, look for an id of this name
+            if (snippets.isEmpty()) {
+                for (Snippet sn : state.snippets()) {
+                    if (sn.id().equals(arg)) {
+                        snippets.add(sn);
+                        break;
+                    }
+                }
+            }
+            // If still no matches found, give an error
+            if (snippets.isEmpty()) {
+                hard("No definition or id named %s found.  See /classes /methods /vars or /list", arg);
+                return null;
+            }
+        }
+        return snippets;
+    }
+
+    private void cmdDrop(String arg) {
+        if (arg.isEmpty()) {
+            hard("In the /drop argument, please specify an import, variable, method, or class to drop.");
+            hard("Specify by id or name. Use /list to see ids. Use /reset to reset all state.");
+            return;
+        }
+        List<Snippet> snippetSet = argToSnippets(arg);
+        if (snippetSet == null) {
+            return;
+        }
+        snippetSet = snippetSet.stream()
+                .filter(sn -> state.status(sn).isActive)
+                .collect(toList());
+        snippetSet.removeIf(sn -> !(sn instanceof PersistentSnippet));
+        if (snippetSet.isEmpty()) {
+            hard("The argument did not specify an import, variable, method, or class to drop.");
+            return;
+        }
+        if (snippetSet.size() > 1) {
+            hard("The argument references more than one import, variable, method, or class.");
+            hard("Try again with one of the ids below:");
+            for (Snippet sn : snippetSet) {
+                cmdout.printf("%4s : %s\n", sn.id(), sn.source().replace("\n", "\n       "));
+            }
+            return;
+        }
+        PersistentSnippet psn = (PersistentSnippet) snippetSet.iterator().next();
+        state.drop(psn).forEach(this::handleEvent);
+    }
+
+    private void cmdEdit(String arg) {
+        List<Snippet> snippetSet = argToSnippets(arg);
+        if (snippetSet == null) {
+            return;
+        }
+        Set<String> srcSet = new LinkedHashSet<>();
+        for (Snippet key : snippetSet) {
+            String src = key.source();
+            switch (key.subKind()) {
+                case VAR_VALUE_SUBKIND:
+                    break;
+                case ASSIGNMENT_SUBKIND:
+                case OTHER_EXPRESSION_SUBKIND:
+                case TEMP_VAR_EXPRESSION_SUBKIND:
+                    if (!src.endsWith(";")) {
+                        src = src + ";";
+                    }
+                    srcSet.add(src);
+                    break;
+                default:
+                    srcSet.add(src);
+                    break;
+            }
+        }
+        StringBuilder sb = new StringBuilder();
+        for (String s : srcSet) {
+            sb.append(s);
+            sb.append('\n');
+        }
+        String src = sb.toString();
+        Consumer<String> saveHandler = new SaveHandler(src, srcSet);
+        Consumer<String> errorHandler = s -> hard("Edit Error: %s", s);
+        if (editor == null) {
+            EditPad.edit(errorHandler, src, saveHandler);
+        } else {
+            ExternalEditor.edit(editor, errorHandler, src, saveHandler, input);
+        }
+    }
+    //where
+    // receives editor requests to save
+    private class SaveHandler implements Consumer<String> {
+
+        String src;
+        Set<String> currSrcs;
+
+        SaveHandler(String src, Set<String> ss) {
+            this.src = src;
+            this.currSrcs = ss;
+        }
+
+        @Override
+        public void accept(String s) {
+            if (!s.equals(src)) { // quick check first
+                src = s;
+                try {
+                    Set<String> nextSrcs = new LinkedHashSet<>();
+                    boolean failed = false;
+                    while (true) {
+                        CompletionInfo an = analysis.analyzeCompletion(s);
+                        if (!an.completeness.isComplete) {
+                            break;
+                        }
+                        String tsrc = trimNewlines(an.source);
+                        if (!failed && !currSrcs.contains(tsrc)) {
+                            failed = processCompleteSource(tsrc);
+                        }
+                        nextSrcs.add(tsrc);
+                        if (an.remaining.isEmpty()) {
+                            break;
+                        }
+                        s = an.remaining;
+                    }
+                    currSrcs = nextSrcs;
+                } catch (IllegalStateException ex) {
+                    hard("Resetting...");
+                    resetState();
+                    currSrcs = new LinkedHashSet<>(); // re-process everything
+                }
+            }
+        }
+
+        private String trimNewlines(String s) {
+            int b = 0;
+            while (b < s.length() && s.charAt(b) == '\n') {
+                ++b;
+            }
+            int e = s.length() -1;
+            while (e >= 0 && s.charAt(e) == '\n') {
+                --e;
+            }
+            return s.substring(b, e + 1);
+        }
+    }
+
+    private void cmdList(String arg) {
+        boolean all = false;
+        switch (arg) {
+            case "all":
+                all = true;
+                break;
+            case "history":
+                cmdHistory();
+                return;
+            case "":
+                break;
+            default:
+                hard("Invalid /list argument: %s", arg);
+                return;
+        }
+        boolean hasOutput = false;
+        for (Snippet sn : state.snippets()) {
+            if (all || (notInStartUp(sn) && state.status(sn).isActive)) {
+                if (!hasOutput) {
+                    cmdout.println();
+                    hasOutput = true;
+                }
+                cmdout.printf("%4s : %s\n", sn.id(), sn.source().replace("\n", "\n       "));
+
+            }
+        }
+    }
+
+    private void cmdOpen(String filename) {
+        if (filename.isEmpty()) {
+            hard("The /open command requires a filename argument.");
+        } else {
+            try {
+                run(new FileScannerIOContext(toPathResolvingUserHome(filename).toString()));
+            } catch (FileNotFoundException e) {
+                hard("File '%s' is not found: %s", filename, e.getMessage());
+            } catch (Exception e) {
+                hard("Exception while reading file: %s", e);
+            }
+        }
+    }
+
+    private void cmdPrompt() {
+        displayPrompt = !displayPrompt;
+        fluff("Prompt will %sdisplay. Use /prompt to toggle.", displayPrompt ? "" : "NOT ");
+        concise("Prompt: %s", displayPrompt ? "on" : "off");
+    }
+
+    private void cmdReset() {
+        live = false;
+        fluff("Resetting state.");
+    }
+
+    private void cmdSave(String arg_filename) {
+        Matcher mat = HISTORY_ALL_FILENAME.matcher(arg_filename);
+        if (!mat.find()) {
+            hard("Malformed argument to the /save command: %s", arg_filename);
+            return;
+        }
+        boolean useHistory = false;
+        boolean saveAll = false;
+        String cmd = mat.group("cmd");
+        if (cmd != null) switch (cmd) {
+            case "all":
+                saveAll = true;
+                break;
+            case "history":
+                useHistory = true;
+                break;
+        }
+        String filename = mat.group("filename");
+        if (filename == null ||filename.isEmpty()) {
+            hard("The /save command requires a filename argument.");
+            return;
+        }
+        try (BufferedWriter writer = Files.newBufferedWriter(toPathResolvingUserHome(filename),
+                Charset.defaultCharset(),
+                CREATE, TRUNCATE_EXISTING, WRITE)) {
+            if (useHistory) {
+                for (String s : input.currentSessionHistory()) {
+                    writer.write(s);
+                    writer.write("\n");
+                }
+            } else {
+                for (Snippet sn : state.snippets()) {
+                    if (saveAll || notInStartUp(sn)) {
+                        writer.write(sn.source());
+                        writer.write("\n");
+                    }
+                }
+            }
+        } catch (FileNotFoundException e) {
+            hard("File '%s' for save is not accessible: %s", filename, e.getMessage());
+        } catch (Exception e) {
+            hard("Exception while saving: %s", e);
+        }
+    }
+
+    private void cmdSetStart(String filename) {
+        if (filename.isEmpty()) {
+            hard("The /setstart command requires a filename argument.");
+        } else {
+            try {
+                byte[] encoded = Files.readAllBytes(toPathResolvingUserHome(filename));
+                String init = new String(encoded);
+                PREFS.put(STARTUP_KEY, init);
+            } catch (AccessDeniedException e) {
+                hard("File '%s' for /setstart is not accessible.", filename);
+            } catch (NoSuchFileException e) {
+                hard("File '%s' for /setstart is not found.", filename);
+            } catch (Exception e) {
+                hard("Exception while reading start set file: %s", e);
+            }
+        }
+    }
+
+    private void cmdSaveStart(String filename) {
+        if (filename.isEmpty()) {
+            hard("The /savestart command requires a filename argument.");
+        } else {
+            try {
+                Files.write(toPathResolvingUserHome(filename), DEFAULT_STARTUP.getBytes());
+            } catch (AccessDeniedException e) {
+                hard("File '%s' for /savestart is not accessible.", filename);
+            } catch (NoSuchFileException e) {
+                hard("File '%s' for /savestart cannot be located.", filename);
+            } catch (Exception e) {
+                hard("Exception while saving default startup file: %s", e);
+            }
+        }
+    }
+
+    private void cmdVars() {
+        for (VarSnippet vk : state.variables()) {
+            String val = state.status(vk) == Status.VALID
+                    ? state.varValue(vk)
+                    : "(not-active)";
+            hard("  %s %s = %s", vk.typeName(), vk.name(), val);
+        }
+    }
+
+    private void cmdMethods() {
+        for (MethodSnippet mk : state.methods()) {
+            hard("  %s %s", mk.name(), mk.signature());
+        }
+    }
+
+    private void cmdClasses() {
+        for (TypeDeclSnippet ck : state.types()) {
+            String kind;
+            switch (ck.subKind()) {
+                case INTERFACE_SUBKIND:
+                    kind = "interface";
+                    break;
+                case CLASS_SUBKIND:
+                    kind = "class";
+                    break;
+                case ENUM_SUBKIND:
+                    kind = "enum";
+                    break;
+                case ANNOTATION_TYPE_SUBKIND:
+                    kind = "@interface";
+                    break;
+                default:
+                    assert false : "Wrong kind" + ck.subKind();
+                    kind = "class";
+                    break;
+            }
+            hard("  %s %s", kind, ck.name());
+        }
+    }
+
+    private void cmdImports() {
+        state.imports().forEach(ik -> {
+            hard("  import %s%s", ik.isStatic() ? "static " : "", ik.fullname());
+        });
+    }
+
+    private void cmdUseHistoryEntry(int index) {
+        List<Snippet> keys = state.snippets();
+        if (index < 0)
+            index += keys.size();
+        else
+            index--;
+        if (index >= 0 && index < keys.size()) {
+            String source = keys.get(index).source();
+            cmdout.printf("%s\n", source);
+            input.replaceLastHistoryEntry(source);
+            processSourceCatchingReset(source);
+        } else {
+            hard("Cannot find snippet %d", index + 1);
+        }
+    }
+
+    /**
+     * Filter diagnostics for only errors (no warnings, ...)
+     * @param diagnostics input list
+     * @return filtered list
+     */
+    List<Diag> errorsOnly(List<Diag> diagnostics) {
+        return diagnostics.stream()
+                .filter(d -> d.isError())
+                .collect(toList());
+    }
+
+    void printDiagnostics(String source, List<Diag> diagnostics, boolean embed) {
+        String padding = embed? "    " : "";
+        for (Diag diag : diagnostics) {
+            //assert diag.getSource().equals(source);
+
+            if (!embed) {
+                if (diag.isError()) {
+                    hard("Error:");
+                } else {
+                    hard("Warning:");
+                }
+            }
+
+            for (String line : diag.getMessage(null).split("\\r?\\n")) {
+                if (!line.trim().startsWith("location:")) {
+                    hard("%s%s", padding, line);
+                }
+            }
+
+            int pstart = (int) diag.getStartPosition();
+            int pend = (int) diag.getEndPosition();
+            Matcher m = LINEBREAK.matcher(source);
+            int pstartl = 0;
+            int pendl = -2;
+            while (m.find(pstartl)) {
+                pendl = m.start();
+                if (pendl >= pstart) {
+                    break;
+                } else {
+                    pstartl = m.end();
+                }
+            }
+            if (pendl < pstart) {
+                pendl = source.length();
+            }
+            fluff("%s%s", padding, source.substring(pstartl, pendl));
+
+            StringBuilder sb = new StringBuilder();
+            int start = pstart - pstartl;
+            for (int i = 0; i < start; ++i) {
+                sb.append(' ');
+            }
+            sb.append('^');
+            boolean multiline = pend > pendl;
+            int end = (multiline ? pendl : pend) - pstartl - 1;
+            if (end > start) {
+                for (int i = start + 1; i < end; ++i) {
+                    sb.append('-');
+                }
+                if (multiline) {
+                    sb.append("-...");
+                } else {
+                    sb.append('^');
+                }
+            }
+            fluff("%s%s", padding, sb.toString());
+
+            debug("printDiagnostics start-pos = %d ==> %d -- wrap = %s", diag.getStartPosition(), start, this);
+            debug("Code: %s", diag.getCode());
+            debug("Pos: %d (%d - %d)", diag.getPosition(),
+                    diag.getStartPosition(), diag.getEndPosition());
+        }
+    }
+
+    private String processSource(String srcInput) throws IllegalStateException {
+        while (true) {
+            CompletionInfo an = analysis.analyzeCompletion(srcInput);
+            if (!an.completeness.isComplete) {
+                return an.remaining;
+            }
+            boolean failed = processCompleteSource(an.source);
+            if (failed || an.remaining.isEmpty()) {
+                return "";
+            }
+            srcInput = an.remaining;
+        }
+    }
+    //where
+    private boolean processCompleteSource(String source) throws IllegalStateException {
+        debug("Compiling: %s", source);
+        boolean failed = false;
+        List<SnippetEvent> events = state.eval(source);
+        for (SnippetEvent e : events) {
+            failed |= handleEvent(e);
+        }
+        return failed;
+    }
+
+    private boolean handleEvent(SnippetEvent ste) {
+        Snippet sn = ste.snippet();
+        if (sn == null) {
+            debug("Event with null key: %s", ste);
+            return false;
+        }
+        List<Diag> diagnostics = state.diagnostics(sn);
+        String source = sn.source();
+        if (ste.causeSnippet() == null) {
+            // main event
+            printDiagnostics(source, diagnostics, false);
+            if (ste.status().isActive) {
+                if (ste.exception() != null) {
+                    if (ste.exception() instanceof EvalException) {
+                        printEvalException((EvalException) ste.exception());
+                        return true;
+                    } else if (ste.exception() instanceof UnresolvedReferenceException) {
+                        printUnresolved((UnresolvedReferenceException) ste.exception());
+                    } else {
+                        hard("Unexpected execution exception: %s", ste.exception());
+                        return true;
+                    }
+                } else {
+                    displayDeclarationAndValue(ste, false, ste.value());
+                }
+            } else if (ste.status() == Status.REJECTED) {
+                if (diagnostics.isEmpty()) {
+                    hard("Failed.");
+                }
+                return true;
+            }
+        } else if (ste.status() == Status.REJECTED) {
+            //TODO -- I don't believe updates can cause failures any more
+            hard("Caused failure of dependent %s --", ((DeclarationSnippet) sn).name());
+            printDiagnostics(source, diagnostics, true);
+        } else {
+            // Update
+            SubKind subkind = sn.subKind();
+            if (sn instanceof DeclarationSnippet
+                    && (feedback() == Feedback.Verbose
+                    || ste.status() == Status.OVERWRITTEN
+                    || subkind == SubKind.VAR_DECLARATION_SUBKIND
+                    || subkind == SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)) {
+                // Under the conditions, display update information
+                displayDeclarationAndValue(ste, true, null);
+                List<Diag> other = errorsOnly(diagnostics);
+                if (other.size() > 0) {
+                    printDiagnostics(source, other, true);
+                }
+            }
+        }
+        return false;
+    }
+
+    @SuppressWarnings("fallthrough")
+    private void displayDeclarationAndValue(SnippetEvent ste, boolean update, String value) {
+        Snippet key = ste.snippet();
+        String declared;
+        Status status = ste.status();
+        switch (status) {
+            case VALID:
+            case RECOVERABLE_DEFINED:
+            case RECOVERABLE_NOT_DEFINED:
+                if (ste.previousStatus().isActive) {
+                    declared = ste.isSignatureChange()
+                        ? "Replaced"
+                        : "Modified";
+                } else {
+                    declared = "Added";
+                }
+                break;
+            case OVERWRITTEN:
+                declared = "Overwrote";
+                break;
+            case DROPPED:
+                declared = "Dropped";
+                break;
+            case REJECTED:
+                declared = "Rejected";
+                break;
+            case NONEXISTENT:
+            default:
+                // Should not occur
+                declared = ste.previousStatus().toString() + "=>" + status.toString();
+        }
+        if (update) {
+            declared = "  Update " + declared.toLowerCase();
+        }
+        String however;
+        if (key instanceof DeclarationSnippet && (status == Status.RECOVERABLE_DEFINED || status == Status.RECOVERABLE_NOT_DEFINED)) {
+            String cannotUntil = (status == Status.RECOVERABLE_NOT_DEFINED)
+                    ? " cannot be referenced until"
+                    : " cannot be invoked until";
+            however = (update? " which" : ", however, it") + cannotUntil + unresolved((DeclarationSnippet) key);
+        } else {
+            however = "";
+        }
+        switch (key.subKind()) {
+            case CLASS_SUBKIND:
+                fluff("%s class %s%s", declared, ((TypeDeclSnippet) key).name(), however);
+                break;
+            case INTERFACE_SUBKIND:
+                fluff("%s interface %s%s", declared, ((TypeDeclSnippet) key).name(), however);
+                break;
+            case ENUM_SUBKIND:
+                fluff("%s enum %s%s", declared, ((TypeDeclSnippet) key).name(), however);
+                break;
+            case ANNOTATION_TYPE_SUBKIND:
+                fluff("%s annotation interface %s%s", declared, ((TypeDeclSnippet) key).name(), however);
+                break;
+            case METHOD_SUBKIND:
+                fluff("%s method %s(%s)%s", declared, ((MethodSnippet) key).name(),
+                        ((MethodSnippet) key).parameterTypes(), however);
+                break;
+            case VAR_DECLARATION_SUBKIND:
+                if (!update) {
+                    VarSnippet vk = (VarSnippet) key;
+                    if (status == Status.RECOVERABLE_NOT_DEFINED) {
+                        fluff("%s variable %s%s", declared, vk.name(), however);
+                    } else {
+                        fluff("%s variable %s of type %s%s", declared, vk.name(), vk.typeName(), however);
+                    }
+                    break;
+                }
+            // Fall through
+            case VAR_DECLARATION_WITH_INITIALIZER_SUBKIND: {
+                VarSnippet vk = (VarSnippet) key;
+                if (status == Status.RECOVERABLE_NOT_DEFINED) {
+                    if (!update) {
+                        fluff("%s variable %s%s", declared, vk.name(), however);
+                        break;
+                    }
+                } else if (update) {
+                    if (ste.isSignatureChange()) {
+                        hard("%s variable %s, reset to null", declared, vk.name());
+                    }
+                } else {
+                    fluff("%s variable %s of type %s with initial value %s",
+                            declared, vk.name(), vk.typeName(), value);
+                    concise("%s : %s", vk.name(), value);
+                }
+                break;
+            }
+            case TEMP_VAR_EXPRESSION_SUBKIND: {
+                VarSnippet vk = (VarSnippet) key;
+                if (update) {
+                    hard("%s temporary variable %s, reset to null", declared, vk.name());
+                 } else {
+                    fluff("Expression value is: %s", (value));
+                    fluff("  assigned to temporary variable %s of type %s", vk.name(), vk.typeName());
+                    concise("%s : %s", vk.name(), value);
+                }
+                break;
+            }
+            case OTHER_EXPRESSION_SUBKIND:
+                fluff("Expression value is: %s", (value));
+                break;
+            case VAR_VALUE_SUBKIND: {
+                ExpressionSnippet ek = (ExpressionSnippet) key;
+                fluff("Variable %s of type %s has value %s", ek.name(), ek.typeName(), (value));
+                concise("%s : %s", ek.name(), value);
+                break;
+            }
+            case ASSIGNMENT_SUBKIND: {
+                ExpressionSnippet ek = (ExpressionSnippet) key;
+                fluff("Variable %s has been assigned the value %s", ek.name(), (value));
+                concise("%s : %s", ek.name(), value);
+                break;
+            }
+        }
+    }
+    //where
+    void printStackTrace(StackTraceElement[] stes) {
+        for (StackTraceElement ste : stes) {
+            StringBuilder sb = new StringBuilder();
+            String cn = ste.getClassName();
+            if (!cn.isEmpty()) {
+                int dot = cn.lastIndexOf('.');
+                if (dot > 0) {
+                    sb.append(cn.substring(dot + 1));
+                } else {
+                    sb.append(cn);
+                }
+                sb.append(".");
+            }
+            if (!ste.getMethodName().isEmpty()) {
+                sb.append(ste.getMethodName());
+                sb.append(" ");
+            }
+            String fileName = ste.getFileName();
+            int lineNumber = ste.getLineNumber();
+            String loc = ste.isNativeMethod()
+                    ? "Native Method"
+                    : fileName == null
+                            ? "Unknown Source"
+                            : lineNumber >= 0
+                                    ? fileName + ":" + lineNumber
+                                    : fileName;
+            hard("      at %s(%s)", sb, loc);
+
+        }
+    }
+    //where
+    void printUnresolved(UnresolvedReferenceException ex) {
+        MethodSnippet corralled =  ex.getMethodSnippet();
+        List<Diag> otherErrors = errorsOnly(state.diagnostics(corralled));
+        StringBuilder sb = new StringBuilder();
+        if (otherErrors.size() > 0) {
+            if (state.unresolvedDependencies(corralled).size() > 0) {
+                sb.append(" and");
+            }
+            if (otherErrors.size() == 1) {
+                sb.append(" this error is addressed --");
+            } else {
+                sb.append(" these errors are addressed --");
+            }
+        } else {
+            sb.append(".");
+        }
+
+        hard("Attempted to call %s which cannot be invoked until%s", corralled.name(),
+                unresolved(corralled), sb.toString());
+        if (otherErrors.size() > 0) {
+            printDiagnostics(corralled.source(), otherErrors, true);
+        }
+    }
+    //where
+    void printEvalException(EvalException ex) {
+        if (ex.getMessage() == null) {
+            hard("%s thrown", ex.getExceptionClassName());
+        } else {
+            hard("%s thrown: %s", ex.getExceptionClassName(), ex.getMessage());
+        }
+        printStackTrace(ex.getStackTrace());
+    }
+    //where
+    String unresolved(DeclarationSnippet key) {
+        List<String> unr = state.unresolvedDependencies(key);
+        StringBuilder sb = new StringBuilder();
+        int fromLast = unr.size();
+        if (fromLast > 0) {
+            sb.append(" ");
+        }
+        for (String u : unr) {
+            --fromLast;
+            sb.append(u);
+            if (fromLast == 0) {
+                // No suffix
+            } else if (fromLast == 1) {
+                sb.append(", and ");
+            } else {
+                sb.append(", ");
+            }
+        }
+        switch (unr.size()) {
+            case 0:
+                break;
+            case 1:
+                sb.append(" is declared");
+                break;
+            default:
+                sb.append(" are declared");
+                break;
+        }
+        return sb.toString();
+    }
+
+    enum Feedback {
+        Default,
+        Off,
+        Concise,
+        Normal,
+        Verbose
+    }
+
+    Feedback feedback() {
+        if (feedback == Feedback.Default) {
+            return input == null || input.interactiveOutput() ? Feedback.Normal : Feedback.Off;
+        }
+        return feedback;
+    }
+
+    boolean notInStartUp(Snippet sn) {
+        return mapSnippet.get(sn).space != startNamespace;
+    }
+
+    /** The current version number as a string.
+     */
+    static String version() {
+        return version("release");  // mm.nn.oo[-milestone]
+    }
+
+    /** The current full version number as a string.
+     */
+    static String fullVersion() {
+        return version("full"); // mm.mm.oo[-milestone]-build
+    }
+
+    private static final String versionRBName = "jdk.internal.jshell.tool.resources.version";
+    private static ResourceBundle versionRB;
+
+    private static String version(String key) {
+        if (versionRB == null) {
+            try {
+                versionRB = ResourceBundle.getBundle(versionRBName);
+            } catch (MissingResourceException e) {
+                return "(version info not available)";
+            }
+        }
+        try {
+            return versionRB.getString(key);
+        }
+        catch (MissingResourceException e) {
+            return "(version info not available)";
+        }
+    }
+
+    class NameSpace {
+        final String spaceName;
+        final String prefix;
+        private int nextNum;
+
+        NameSpace(String spaceName, String prefix) {
+            this.spaceName = spaceName;
+            this.prefix = prefix;
+            this.nextNum = 1;
+        }
+
+        String tid(Snippet sn) {
+            String tid = prefix + nextNum++;
+            mapSnippet.put(sn, new SnippetInfo(sn, this, tid));
+            return tid;
+        }
+
+        String tidNext() {
+            return prefix + nextNum;
+        }
+    }
+
+    static class SnippetInfo {
+        final Snippet snippet;
+        final NameSpace space;
+        final String tid;
+
+        SnippetInfo(Snippet snippet, NameSpace space, String tid) {
+            this.snippet = snippet;
+            this.space = space;
+            this.tid = tid;
+        }
+    }
+}
+
+class ScannerIOContext extends IOContext {
+
+    private final Scanner scannerIn;
+    private final PrintStream pStream;
+
+    public ScannerIOContext(Scanner scannerIn, PrintStream pStream) {
+        this.scannerIn = scannerIn;
+        this.pStream = pStream;
+    }
+
+    @Override
+    public String readLine(String prompt, String prefix) {
+        if (pStream != null && prompt != null) {
+            pStream.print(prompt);
+        }
+        if (scannerIn.hasNextLine()) {
+            return scannerIn.nextLine();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public boolean interactiveOutput() {
+        return true;
+    }
+
+    @Override
+    public Iterable<String> currentSessionHistory() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void close() {
+        scannerIn.close();
+    }
+
+    @Override
+    public boolean terminalEditorRunning() {
+        return false;
+    }
+
+    @Override
+    public void suspend() {
+    }
+
+    @Override
+    public void resume() {
+    }
+
+    @Override
+    public void beforeUserCode() {
+    }
+
+    @Override
+    public void afterUserCode() {
+    }
+
+    @Override
+    public void replaceLastHistoryEntry(String source) {
+    }
+}
+
+class FileScannerIOContext extends ScannerIOContext {
+
+    public FileScannerIOContext(String fn) throws FileNotFoundException {
+        this(new FileReader(fn));
+    }
+
+    public FileScannerIOContext(Reader rdr) throws FileNotFoundException {
+        super(new Scanner(rdr), null);
+    }
+
+    @Override
+    public boolean interactiveOutput() {
+        return false;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/StopDetectingInputStream.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,168 @@
+/*
+ * 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.internal.jshell.tool;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.function.Consumer;
+
+public final class StopDetectingInputStream extends InputStream {
+    public static final int INITIAL_SIZE = 128;
+
+    private final Runnable stop;
+    private final Consumer<Exception> errorHandler;
+
+    private boolean initialized;
+    private int[] buffer = new int[INITIAL_SIZE];
+    private int start;
+    private int end;
+    private State state = State.WAIT;
+
+    public StopDetectingInputStream(Runnable stop, Consumer<Exception> errorHandler) {
+        this.stop = stop;
+        this.errorHandler = errorHandler;
+    }
+
+    public synchronized InputStream setInputStream(InputStream input) {
+        if (initialized)
+            throw new IllegalStateException("Already initialized.");
+        initialized = true;
+
+        Thread reader = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    int read;
+                    while (true) {
+                        //to support external terminal editors, the "cmdin.read" must not run when
+                        //an external editor is running. At the same time, it needs to run while the
+                        //user's code is running (so Ctrl-C is detected). Hence waiting here until
+                        //there is a confirmed need for input.
+                        waitInputNeeded();
+                        if ((read = input.read()) == (-1)) {
+                            break;
+                        }
+                        if (read == 3 && state == StopDetectingInputStream.State.BUFFER) {
+                            stop.run();
+                        } else {
+                            write(read);
+                        }
+                    }
+                } catch (IOException ex) {
+                    errorHandler.accept(ex);
+                } finally {
+                    state = StopDetectingInputStream.State.CLOSED;
+                }
+            }
+        };
+        reader.setDaemon(true);
+        reader.start();
+
+        return this;
+    }
+
+    @Override
+    public synchronized int read() {
+        while (start == end) {
+            if (state == State.CLOSED) {
+                return -1;
+            }
+            if (state == State.WAIT) {
+                state = State.READ;
+            }
+            notifyAll();
+            try {
+                wait();
+            } catch (InterruptedException ex) {
+                //ignore
+            }
+        }
+        try {
+            return buffer[start];
+        } finally {
+            start = (start + 1) % buffer.length;
+        }
+    }
+
+    public synchronized void write(int b) {
+        if (state != State.BUFFER) {
+            state = State.WAIT;
+        }
+        int newEnd = (end + 1) % buffer.length;
+        if (newEnd == start) {
+            //overflow:
+            int[] newBuffer = new int[buffer.length * 2];
+            int rightPart = (end > start ? end : buffer.length) - start;
+            int leftPart = end > start ? 0 : start - 1;
+            System.arraycopy(buffer, start, newBuffer, 0, rightPart);
+            System.arraycopy(buffer, 0, newBuffer, rightPart, leftPart);
+            buffer = newBuffer;
+            start = 0;
+            end = rightPart + leftPart;
+            newEnd = end + 1;
+        }
+        buffer[end] = b;
+        end = newEnd;
+        notifyAll();
+    }
+
+    public synchronized void setState(State state) {
+        this.state = state;
+        notifyAll();
+    }
+
+    private synchronized void waitInputNeeded() {
+        while (state == State.WAIT) {
+            try {
+                wait();
+            } catch (InterruptedException ex) {
+                //ignore
+            }
+        }
+    }
+
+    public enum State {
+        /* No reading from the input should happen. This is the default state. The StopDetectingInput
+         * must be in this state when an external editor is being run, so that the external editor
+         * can read from the input.
+         */
+        WAIT,
+        /* A single input character should be read. Reading from the StopDetectingInput will move it
+         * into this state, and the state will be automatically changed back to WAIT when a single
+         * input character is obtained. This state is typically used while the user is editing the
+         * input line.
+         */
+        READ,
+        /* Continuously read from the input. Forward Ctrl-C ((int) 3) to the "stop" Runnable, buffer
+         * all other input. This state is typically used while the user's code is running, to provide
+         * the ability to detect Ctrl-C in order to stop the execution.
+         */
+        BUFFER,
+        /* The input is closed.
+        */
+        CLOSED
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/version.properties-template	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+jdk=$(JDK_VERSION)
+full=$(FULL_VERSION)
+release=$(RELEASE)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ClassTracker.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,97 @@
+/*
+ * 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.jshell;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import com.sun.jdi.ReferenceType;
+
+/**
+ * Tracks the state of a class through compilation and loading in the remote
+ * environment.
+ *
+ * @author Robert Field
+ */
+class ClassTracker {
+
+    private final JShell state;
+    private final HashMap<String, ClassInfo> map;
+
+    ClassTracker(JShell state) {
+        this.state = state;
+        this.map = new HashMap<>();
+    }
+
+    class ClassInfo {
+
+        private final String className;
+        private byte[] bytes;
+        private byte[] loadedBytes;
+        private ReferenceType rt;
+
+        private ClassInfo(String className) {
+            this.className = className;
+        }
+
+        String getClassName() {
+            return className;
+        }
+
+        byte[] getBytes() {
+            return bytes;
+        }
+
+        void setBytes(byte[] bytes) {
+            this.bytes = bytes;
+        }
+
+        void setLoaded() {
+            loadedBytes = bytes;
+        }
+
+        boolean isLoaded() {
+            return Arrays.equals(loadedBytes, bytes);
+        }
+
+        ReferenceType getReferenceTypeOrNull() {
+            if (rt == null) {
+                rt = state.executionControl().nameToRef(className);
+            }
+            return rt;
+        }
+    }
+
+    ClassInfo classInfo(String className, byte[] bytes) {
+        ClassInfo ci = map.computeIfAbsent(className, k -> new ClassInfo(k));
+        ci.setBytes(bytes);
+        return ci;
+    }
+
+    ClassInfo get(String className) {
+        return map.get(className);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,885 @@
+/*
+ * 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.jshell;
+
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.parser.Scanner;
+import com.sun.tools.javac.parser.ScannerFactory;
+import com.sun.tools.javac.parser.Tokens.Token;
+import com.sun.tools.javac.parser.Tokens.TokenKind;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.Log;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.EnumMap;
+import java.util.Iterator;
+import jdk.jshell.SourceCodeAnalysis.Completeness;
+import com.sun.source.tree.Tree;
+import static jdk.jshell.CompletenessAnalyzer.TK.*;
+import jdk.jshell.TaskFactory.ParseTask;
+import java.util.List;
+
+/**
+ * Low level scanner to determine completeness of input.
+ * @author Robert Field
+ */
+class CompletenessAnalyzer {
+
+    private final ScannerFactory scannerFactory;
+    private final JShell proc;
+
+    private static Completeness error() {
+        return Completeness.UNKNOWN;  // For breakpointing
+    }
+
+    static class CaInfo {
+
+        CaInfo(Completeness status, int unitEndPos) {
+            this.status = status;
+            this.unitEndPos = unitEndPos;
+        }
+        final int unitEndPos;
+        final Completeness status;
+    }
+
+    CompletenessAnalyzer(JShell proc) {
+        this.proc = proc;
+        Context context = new Context();
+        Log log = CaLog.createLog(context);
+        context.put(Log.class, log);
+        context.put(Source.class, Source.JDK1_9);
+        scannerFactory = ScannerFactory.instance(context);
+    }
+
+    CaInfo scan(String s) {
+        try {
+            Scanner scanner = scannerFactory.newScanner(s, false);
+            Matched in = new Matched(scanner);
+            Parser parser = new Parser(in, proc, s);
+            Completeness stat = parser.parseUnit();
+            int endPos = stat == Completeness.UNKNOWN
+                    ? s.length()
+                    : in.prevCT.endPos;
+            return new CaInfo(stat, endPos);
+        } catch (SyntaxException ex) {
+            return new CaInfo(error(), s.length());
+        }
+    }
+
+    @SuppressWarnings("serial")             // serialVersionUID intentionally omitted
+    private static class SyntaxException extends RuntimeException {
+    }
+
+    private static void die() {
+        throw new SyntaxException();
+    }
+
+    /**
+     * Subclass of Log used by compiler API to die on error and ignore
+     * other messages
+     */
+    private static class CaLog extends Log {
+
+        private static CaLog createLog(Context context) {
+            PrintWriter pw = new PrintWriter(new StringWriter());
+            CaLog log = new CaLog(context, pw, pw, pw);
+            context.put(outKey, pw);
+            context.put(logKey, log);
+            return log;
+        }
+
+        private CaLog(Context context, PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter) {
+            super(context, errWriter, warnWriter, noticeWriter);
+        }
+
+        @Override
+        public void error(String key, Object... args) {
+            die();
+        }
+
+        @Override
+        public void error(DiagnosticPosition pos, String key, Object... args) {
+            die();
+        }
+
+        @Override
+        public void error(DiagnosticFlag flag, DiagnosticPosition pos, String key, Object... args) {
+            die();
+        }
+
+        @Override
+        public void error(int pos, String key, Object... args) {
+            die();
+        }
+
+        @Override
+        public void error(DiagnosticFlag flag, int pos, String key, Object... args) {
+            die();
+        }
+
+        @Override
+        public void report(JCDiagnostic diagnostic) {
+            // Ignore
+        }
+    }
+
+    // Location position kinds -- a token is ...
+    private static final int XEXPR         = 0b1;                       // OK in expression (not first)
+    private static final int XDECL         = 0b10;                      // OK in declaration (not first)
+    private static final int XSTMT         = 0b100;                     // OK in statement framework (not first)
+    private static final int XEXPR1o       = 0b1000;                    // OK first in expression
+    private static final int XDECL1o       = 0b10000;                   // OK first in declaration
+    private static final int XSTMT1o       = 0b100000;                  // OK first or only in statement framework
+    private static final int XEXPR1        = XEXPR1o | XEXPR;           // OK in expression (anywhere)
+    private static final int XDECL1        = XDECL1o | XDECL;           // OK in declaration (anywhere)
+    private static final int XSTMT1        = XSTMT1o | XSTMT;           // OK in statement framework (anywhere)
+    private static final int XANY1         = XEXPR1o | XDECL1o | XSTMT1o;  // Mask: first in statement, declaration, or expression
+    private static final int XTERM         = 0b100000000;               // Can terminate (last before EOF)
+    private static final int XSTART        = 0b1000000000;              // Boundary, must be XTERM before
+    private static final int XERRO         = 0b10000000000;             // Is an error
+
+    /**
+     * An extension of the compiler's TokenKind which adds our combined/processed
+     * kinds. Also associates each TK with a union of acceptable kinds of code
+     * position it can occupy.  For example: IDENTIFER is XEXPR1|XDECL1|XTERM,
+     * meaning it can occur in expressions or declarations (but not in the
+     * framework of a statement and that can be the final (terminating) token
+     * in a snippet.
+     * <P>
+     * There must be a TK defined for each compiler TokenKind, an exception
+     * will
+     * be thrown if a TokenKind is defined and a corresponding TK is not. Add a
+     * new TK in the appropriate category. If it is like an existing category
+     * (e.g. a new modifier or type this may be all that is needed.  If it
+     * is bracketing or modifies the acceptable positions of other tokens,
+     * please closely examine the needed changes to this scanner.
+     */
+    static enum TK {
+
+        // Special
+        EOF(TokenKind.EOF, 0),  //
+        ERROR(TokenKind.ERROR, XERRO),  //
+        IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM),  //
+        UNDERSCORE(TokenKind.UNDERSCORE, XERRO),  //  _
+        CLASS(TokenKind.CLASS, XEXPR|XDECL1|XTERM),  //  class decl and .class
+        MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1),  //  @
+        IMPORT(TokenKind.IMPORT, XDECL1|XSTART),  //  import -- consider declaration
+        SEMI(TokenKind.SEMI, XSTMT1|XTERM|XSTART),  //  ;
+
+        // Shouldn't see -- error
+        PACKAGE(TokenKind.PACKAGE, XERRO),  //  package
+        CONST(TokenKind.CONST, XERRO),  //  reserved keyword -- const
+        GOTO(TokenKind.GOTO, XERRO),  //  reserved keyword -- goto
+        CUSTOM(TokenKind.CUSTOM, XERRO),  // No uses
+
+        // Declarations
+        ENUM(TokenKind.ENUM, XDECL1),  //  enum
+        IMPLEMENTS(TokenKind.IMPLEMENTS, XDECL),  //  implements
+        INTERFACE(TokenKind.INTERFACE, XDECL1),  //  interface
+        THROWS(TokenKind.THROWS, XDECL),  //  throws
+
+        // Primarive type names
+        BOOLEAN(TokenKind.BOOLEAN, XEXPR|XDECL1),  //  boolean
+        BYTE(TokenKind.BYTE, XEXPR|XDECL1),  //  byte
+        CHAR(TokenKind.CHAR, XEXPR|XDECL1),  //  char
+        DOUBLE(TokenKind.DOUBLE, XEXPR|XDECL1),  //  double
+        FLOAT(TokenKind.FLOAT, XEXPR|XDECL1),  //  float
+        INT(TokenKind.INT, XEXPR|XDECL1),  //  int
+        LONG(TokenKind.LONG, XEXPR|XDECL1),  //  long
+        SHORT(TokenKind.SHORT, XEXPR|XDECL1),  //  short
+        VOID(TokenKind.VOID, XEXPR|XDECL1),  //  void
+
+        // Modifiers keywords
+        ABSTRACT(TokenKind.ABSTRACT, XDECL1),  //  abstract
+        FINAL(TokenKind.FINAL, XDECL1),  //  final
+        NATIVE(TokenKind.NATIVE, XDECL1),  //  native
+        STATIC(TokenKind.STATIC, XDECL1),  //  static
+        STRICTFP(TokenKind.STRICTFP, XDECL1),  //  strictfp
+        PRIVATE(TokenKind.PRIVATE, XDECL1),  //  private
+        PROTECTED(TokenKind.PROTECTED, XDECL1),  //  protected
+        PUBLIC(TokenKind.PUBLIC, XDECL1),  //  public
+        TRANSIENT(TokenKind.TRANSIENT, XDECL1),  //  transient
+        VOLATILE(TokenKind.VOLATILE, XDECL1),  //  volatile
+
+        // Declarations and type parameters (thus expressions)
+        EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL),  //  extends
+        COMMA(TokenKind.COMMA, XEXPR|XDECL|XSTART),  //  ,
+        AMP(TokenKind.AMP, XEXPR|XDECL),  //  &
+        GT(TokenKind.GT, XEXPR|XDECL),  //  >
+        LT(TokenKind.LT, XEXPR|XDECL1),  //  <
+        LTLT(TokenKind.LTLT, XEXPR|XDECL1),  //  <<
+        GTGT(TokenKind.GTGT, XEXPR|XDECL),  //  >>
+        GTGTGT(TokenKind.GTGTGT, XEXPR|XDECL),  //  >>>
+        QUES(TokenKind.QUES, XEXPR|XDECL),  //  ?
+        DOT(TokenKind.DOT, XEXPR|XDECL),  //  .
+        STAR(TokenKind.STAR, XEXPR|XDECL|XTERM),  //  * -- import foo.* //TODO handle these case separately, XTERM
+
+        // Statement keywords
+        ASSERT(TokenKind.ASSERT, XSTMT1|XSTART),  //  assert
+        BREAK(TokenKind.BREAK, XSTMT1|XTERM|XSTART),  //  break
+        CATCH(TokenKind.CATCH, XSTMT1|XSTART),  //  catch
+        CONTINUE(TokenKind.CONTINUE, XSTMT1|XTERM|XSTART),  //  continue
+        DO(TokenKind.DO, XSTMT1|XSTART),  //  do
+        ELSE(TokenKind.ELSE, XSTMT1|XTERM|XSTART),  //  else
+        FINALLY(TokenKind.FINALLY, XSTMT1|XSTART),  //  finally
+        FOR(TokenKind.FOR, XSTMT1|XSTART),  //  for
+        IF(TokenKind.IF, XSTMT1|XSTART),  //  if
+        RETURN(TokenKind.RETURN, XSTMT1|XTERM|XSTART),  //  return
+        SWITCH(TokenKind.SWITCH, XSTMT1|XSTART),  //  switch
+        SYNCHRONIZED(TokenKind.SYNCHRONIZED, XSTMT1|XDECL),  //  synchronized
+        THROW(TokenKind.THROW, XSTMT1|XSTART),  //  throw
+        TRY(TokenKind.TRY, XSTMT1|XSTART),  //  try
+        WHILE(TokenKind.WHILE, XSTMT1|XSTART),  //  while
+
+        // Statement keywords that we shouldn't see -- inside braces
+        CASE(TokenKind.CASE, XSTMT|XSTART),  //  case
+        DEFAULT(TokenKind.DEFAULT, XSTMT|XSTART),  //  default method, default case -- neither we should see
+
+        // Expressions (can terminate)
+        INTLITERAL(TokenKind.INTLITERAL, XEXPR1|XTERM),  //
+        LONGLITERAL(TokenKind.LONGLITERAL, XEXPR1|XTERM),  //
+        FLOATLITERAL(TokenKind.FLOATLITERAL, XEXPR1|XTERM),  //
+        DOUBLELITERAL(TokenKind.DOUBLELITERAL, XEXPR1|XTERM),  //
+        CHARLITERAL(TokenKind.CHARLITERAL, XEXPR1|XTERM),  //
+        STRINGLITERAL(TokenKind.STRINGLITERAL, XEXPR1|XTERM),  //
+        TRUE(TokenKind.TRUE, XEXPR1|XTERM),  //  true
+        FALSE(TokenKind.FALSE, XEXPR1|XTERM),  //  false
+        NULL(TokenKind.NULL, XEXPR1|XTERM),  //  null
+        THIS(TokenKind.THIS, XEXPR1|XTERM),  //  this  -- shouldn't see
+
+        // Expressions maybe terminate  //TODO handle these case separately
+        PLUSPLUS(TokenKind.PLUSPLUS, XEXPR1|XTERM),  //  ++
+        SUBSUB(TokenKind.SUBSUB, XEXPR1|XTERM),  //  --
+
+        // Expressions cannot terminate
+        INSTANCEOF(TokenKind.INSTANCEOF, XEXPR),  //  instanceof
+        NEW(TokenKind.NEW, XEXPR1),  //  new
+        SUPER(TokenKind.SUPER, XEXPR1|XDECL),  //  super -- shouldn't see as rec. But in type parameters
+        ARROW(TokenKind.ARROW, XEXPR),  //  ->
+        COLCOL(TokenKind.COLCOL, XEXPR),  //  ::
+        LPAREN(TokenKind.LPAREN, XEXPR),  //  (
+        RPAREN(TokenKind.RPAREN, XEXPR),  //  )
+        LBRACE(TokenKind.LBRACE, XEXPR),  //  {
+        RBRACE(TokenKind.RBRACE, XEXPR),  //  }
+        LBRACKET(TokenKind.LBRACKET, XEXPR),  //  [
+        RBRACKET(TokenKind.RBRACKET, XEXPR),  //  ]
+        ELLIPSIS(TokenKind.ELLIPSIS, XEXPR),  //  ...
+        EQ(TokenKind.EQ, XEXPR),  //  =
+        BANG(TokenKind.BANG, XEXPR1),  //  !
+        TILDE(TokenKind.TILDE, XEXPR1),  //  ~
+        COLON(TokenKind.COLON, XEXPR|XTERM),  //  :
+        EQEQ(TokenKind.EQEQ, XEXPR),  //  ==
+        LTEQ(TokenKind.LTEQ, XEXPR),  //  <=
+        GTEQ(TokenKind.GTEQ, XEXPR),  //  >=
+        BANGEQ(TokenKind.BANGEQ, XEXPR),  //  !=
+        AMPAMP(TokenKind.AMPAMP, XEXPR),  //  &&
+        BARBAR(TokenKind.BARBAR, XEXPR),  //  ||
+        PLUS(TokenKind.PLUS, XEXPR1),  //  +
+        SUB(TokenKind.SUB, XEXPR1),  //  -
+        SLASH(TokenKind.SLASH, XEXPR),  //  /
+        BAR(TokenKind.BAR, XEXPR),  //  |
+        CARET(TokenKind.CARET, XEXPR),  //  ^
+        PERCENT(TokenKind.PERCENT, XEXPR),  //  %
+        PLUSEQ(TokenKind.PLUSEQ, XEXPR),  //  +=
+        SUBEQ(TokenKind.SUBEQ, XEXPR),  //  -=
+        STAREQ(TokenKind.STAREQ, XEXPR),  //  *=
+        SLASHEQ(TokenKind.SLASHEQ, XEXPR),  //  /=
+        AMPEQ(TokenKind.AMPEQ, XEXPR),  //  &=
+        BAREQ(TokenKind.BAREQ, XEXPR),  //  |=
+        CARETEQ(TokenKind.CARETEQ, XEXPR),  //  ^=
+        PERCENTEQ(TokenKind.PERCENTEQ, XEXPR),  //  %=
+        LTLTEQ(TokenKind.LTLTEQ, XEXPR),  //  <<=
+        GTGTEQ(TokenKind.GTGTEQ, XEXPR),  //  >>=
+        GTGTGTEQ(TokenKind.GTGTGTEQ, XEXPR),  //  >>>=
+
+        // combined/processed kinds
+        UNMATCHED(XERRO),
+        PARENS(XEXPR1|XDECL|XSTMT|XTERM),
+        BRACKETS(XEXPR|XDECL|XTERM),
+        BRACES(XSTMT1|XEXPR|XTERM);
+
+        static final EnumMap<TokenKind,TK> tokenKindToTKMap = new EnumMap<>(TokenKind.class);
+
+        final TokenKind tokenKind;
+        final int belongs;
+
+        TK(int b) {
+            this.tokenKind = null;
+            this.belongs = b;
+        }
+
+        TK(TokenKind tokenKind, int b) {
+            this.tokenKind = tokenKind;
+            this.belongs = b;
+        }
+
+        private static TK tokenKindToTK(TokenKind kind) {
+            TK tk = tokenKindToTKMap.get(kind);
+            if (tk == null) {
+                System.err.printf("No corresponding %s for %s: %s\n",
+                        TK.class.getCanonicalName(),
+                        TokenKind.class.getCanonicalName(),
+                        kind);
+                throw new InternalError("No corresponding TK for TokenKind: " + kind);
+            }
+            return tk;
+        }
+
+        boolean isOkToTerminate() {
+            return (belongs & XTERM) != 0;
+        }
+
+        boolean isExpression() {
+            return (belongs & XEXPR) != 0;
+        }
+
+        boolean isDeclaration() {
+            return (belongs & XDECL) != 0;
+        }
+
+        boolean isError() {
+            return (belongs & XERRO) != 0;
+        }
+
+        boolean isStart() {
+            return (belongs & XSTART) != 0;
+        }
+
+        /**
+         * After construction, check that all compiler TokenKind values have
+         * corresponding TK values.
+         */
+        static {
+            for (TK tk : TK.values()) {
+                if (tk.tokenKind != null) {
+                    tokenKindToTKMap.put(tk.tokenKind, tk);
+                }
+            }
+            for (TokenKind kind : TokenKind.values()) {
+                tokenKindToTK(kind); // assure they can be retrieved without error
+            }
+        }
+    }
+
+    /**
+     * A completeness scanner token.
+     */
+    private static class CT {
+
+        /** The token kind */
+        public final TK kind;
+
+        /** The end position of this token */
+        public final int endPos;
+
+        /** The error message **/
+        public final String message;
+
+        private CT(TK tk, Token tok, String msg) {
+            this.kind = tk;
+            this.endPos = tok.endPos;
+            this.message = msg;
+            //throw new InternalError(msg); /* for debugging */
+        }
+
+        private CT(TK tk, Token tok) {
+            this.kind = tk;
+            this.endPos = tok.endPos;
+            this.message = null;
+        }
+
+        private CT(TK tk, int endPos) {
+            this.kind = tk;
+            this.endPos = endPos;
+            this.message = null;
+        }
+    }
+
+    /**
+     * Look for matching tokens (like parens) and other special cases, like "new"
+     */
+    private static class Matched implements Iterator<CT> {
+
+        private final Scanner scanner;
+        private Token current;
+        private CT prevCT;
+        private CT currentCT;
+        private final Deque<Token> stack = new ArrayDeque<>();
+
+        Matched(Scanner scanner) {
+            this.scanner = scanner;
+            advance();
+            prevCT = currentCT = new CT(SEMI, 0); // So is valid for testing
+        }
+
+        @Override
+        public boolean hasNext() {
+            return currentCT.kind != EOF;
+        }
+
+        private Token advance() {
+            Token prev = current;
+            scanner.nextToken();
+            current = scanner.token();
+            return prev;
+        }
+
+        @Override
+        public CT next() {
+            prevCT = currentCT;
+            currentCT = nextCT();
+            return currentCT;
+        }
+
+        private CT match(TK tk, TokenKind open) {
+            Token tok = advance();
+            db("match desired-tk=%s, open=%s, seen-tok=%s", tk, open, tok.kind);
+            if (stack.isEmpty()) {
+                return new CT(ERROR, tok, "Encountered '" + tok + "' with no opening '" + open + "'");
+            }
+            Token p = stack.pop();
+            if (p.kind != open) {
+                return new CT(ERROR, tok, "No match for '" + p + "' instead encountered '" + tok + "'");
+            }
+            return new CT(tk, tok);
+        }
+
+        private void db(String format, Object ... args) {
+//            System.err.printf(format, args);
+//            System.err.printf(" -- stack(");
+//            if (stack.isEmpty()) {
+//
+//            } else {
+//                for (Token tok : stack) {
+//                    System.err.printf("%s ", tok.kind);
+//                }
+//            }
+//            System.err.printf(") current=%s / currentCT=%s\n", current.kind, currentCT.kind);
+        }
+
+        /**
+         * @return the next scanner token
+         */
+        private CT nextCT() {
+            // TODO Annotations?
+            TK prevTK = currentCT.kind;
+            while (true) {
+                db("nextCT");
+                CT ct;
+                switch (current.kind) {
+                    case EOF:
+                        db("eof");
+                        if (stack.isEmpty()) {
+                            ct = new CT(EOF, current);
+                        } else {
+                            TokenKind unmatched = stack.pop().kind;
+                            stack.clear(); // So we will get EOF next time
+                            ct = new CT(UNMATCHED, current, "Unmatched " + unmatched);
+                        }
+                        break;
+                    case LPAREN:
+                    case LBRACE:
+                    case LBRACKET:
+                        stack.push(advance());
+                        prevTK = SEMI; // new start
+                        continue;
+                    case RPAREN:
+                        ct = match(PARENS, TokenKind.LPAREN);
+                        break;
+                    case RBRACE:
+                        ct = match(BRACES, TokenKind.LBRACE);
+                        break;
+                    case RBRACKET:
+                        ct = match(BRACKETS, TokenKind.LBRACKET);
+                        break;
+                    default:
+                        ct = new CT(TK.tokenKindToTK(current.kind), advance());
+                        break;
+                }
+                if (ct.kind.isStart() && !prevTK.isOkToTerminate()) {
+                    return new CT(ERROR, current, "No '" + prevTK + "' before '" + ct.kind + "'");
+                }
+                if (stack.isEmpty() || ct.kind.isError()) {
+                    return ct;
+                }
+                prevTK = ct.kind;
+            }
+        }
+    }
+
+    /**
+     * Fuzzy parser based on token kinds
+     */
+    private static class Parser {
+
+        final Matched in;
+        CT token;
+        Completeness checkResult;
+
+        final JShell proc;
+        final String scannedInput;
+
+
+
+        Parser(Matched in, JShell proc, String scannedInput) {
+            this.in = in;
+            nextToken();
+
+            this.proc = proc;
+            this.scannedInput = scannedInput;
+        }
+
+        final void nextToken() {
+            in.next();
+            token = in.currentCT;
+        }
+
+        boolean shouldAbort(TK tk) {
+            if (token.kind == tk) {
+                nextToken();
+                return false;
+            }
+            switch (token.kind) {
+                case EOF:
+                    checkResult = ((tk == SEMI) && in.prevCT.kind.isOkToTerminate())
+                            ? Completeness.COMPLETE_WITH_SEMI
+                            : Completeness.DEFINITELY_INCOMPLETE;
+                    return true;
+                case UNMATCHED:
+                    checkResult = Completeness.DEFINITELY_INCOMPLETE;
+                    return true;
+                default:
+                    checkResult = error();
+                    return true;
+
+            }
+        }
+
+        Completeness lastly(TK tk) {
+            if (shouldAbort(tk))  return checkResult;
+            return Completeness.COMPLETE;
+        }
+
+        Completeness optionalFinalSemi() {
+            if (!shouldAbort(SEMI)) return Completeness.COMPLETE;
+            if (checkResult == Completeness.COMPLETE_WITH_SEMI) return Completeness.COMPLETE;
+            return checkResult;
+        }
+
+        boolean shouldAbort(Completeness flags) {
+            checkResult = flags;
+            return flags != Completeness.COMPLETE;
+        }
+
+        public Completeness parseUnit() {
+            //System.err.printf("%s:  belongs %o  XANY1 %o\n", token.kind, token.kind.belongs, token.kind.belongs & XANY1);
+            switch (token.kind.belongs & XANY1) {
+                case XEXPR1o:
+                    return parseExpressionOptionalSemi();
+                case XSTMT1o: {
+                    Completeness stat = parseSimpleStatement();
+                    return stat==null? error() : stat;
+                }
+                case XDECL1o:
+                    return parseDeclaration();
+                case XSTMT1o | XDECL1o:
+                case XEXPR1o | XDECL1o:
+                    return disambiguateDeclarationVsExpression();
+                case 0:
+                    if ((token.kind.belongs & XERRO) != 0) {
+                        return parseExpressionStatement(); // Let this gen the status
+                    }
+                    return error();
+                default:
+                    throw new InternalError("Case not covered " + token.kind.belongs + " in " + token.kind);
+            }
+        }
+
+        public Completeness parseDeclaration() {
+            boolean isImport = token.kind == IMPORT;
+            while (token.kind.isDeclaration()) {
+                nextToken();
+            }
+            switch (token.kind) {
+                case EQ:
+                    // Check for array initializer
+                    nextToken();
+                    if (token.kind == BRACES) {
+                        nextToken();
+                        return lastly(SEMI);
+                    }
+                    return parseExpressionStatement();
+                case BRACES:
+                case SEMI:
+                    nextToken();
+                    return Completeness.COMPLETE;
+                case UNMATCHED:
+                    nextToken();
+                    return Completeness.DEFINITELY_INCOMPLETE;
+                case EOF:
+                    switch (in.prevCT.kind) {
+                        case BRACES:
+                        case SEMI:
+                            return Completeness.COMPLETE;
+                        case IDENTIFIER:
+                        case BRACKETS:
+                            return Completeness.COMPLETE_WITH_SEMI;
+                        case STAR:
+                            if (isImport) {
+                                return Completeness.COMPLETE_WITH_SEMI;
+                            } else {
+                                return Completeness.DEFINITELY_INCOMPLETE;
+                            }
+                        default:
+                            return Completeness.DEFINITELY_INCOMPLETE;
+                    }
+                default:
+                    return error();
+            }
+        }
+
+        public Completeness disambiguateDeclarationVsExpression() {
+            // String folding messes up position information.
+            ParseTask pt = proc.taskFactory.new ParseTask(scannedInput);
+            List<? extends Tree> units = pt.units();
+            if (units.isEmpty()) {
+                return error();
+            }
+            Tree unitTree = units.get(0);
+            switch (unitTree.getKind()) {
+                case EXPRESSION_STATEMENT:
+                    return parseExpressionOptionalSemi();
+                case LABELED_STATEMENT:
+                    if (shouldAbort(IDENTIFIER))  return checkResult;
+                    if (shouldAbort(COLON))  return checkResult;
+                    return parseStatement();
+                case VARIABLE:
+                case IMPORT:
+                case CLASS:
+                case ENUM:
+                case ANNOTATION_TYPE:
+                case INTERFACE:
+                case METHOD:
+                    return parseDeclaration();
+                default:
+                    return error();
+            }
+        }
+
+//        public Status parseExpressionOrDeclaration() {
+//            if (token.kind == IDENTIFIER) {
+//                nextToken();
+//                switch (token.kind) {
+//                    case IDENTIFIER:
+//                        return parseDeclaration();
+//                }
+//            }
+//            while (token.kind.isExpressionOrDeclaration()) {
+//                if (!token.kind.isExpression()) {
+//                    return parseDeclaration();
+//                }
+//                if (!token.kind.isDeclaration()) {
+//                    // Expression not declaration
+//                    if (token.kind == EQ) {
+//                        // Check for array initializer
+//                        nextToken();
+//                        if (token.kind == BRACES) {
+//                            nextToken();
+//                            return lastly(SEMI);
+//                        }
+//                    }
+//                    return parseExpressionStatement();
+//                }
+//                nextToken();
+//            }
+//            switch (token.kind) {
+//                case BRACES:
+//                case SEMI:
+//                    nextToken();
+//                    return Status.COMPLETE;
+//                case UNMATCHED:
+//                    nextToken();
+//                    return Status.DEFINITELY_INCOMPLETE;
+//                case EOF:
+//                    if (in.prevCT.kind.isOkToTerminate()) {
+//                        return Status.COMPLETE_WITH_SEMI;
+//                    } else {
+//                        return Status.DEFINITELY_INCOMPLETE;
+//                    }
+//                default:
+//                    return error();
+//            }
+//        }
+
+        public Completeness parseExpressionStatement() {
+            if (shouldAbort(parseExpression()))  return checkResult;
+            return lastly(SEMI);
+        }
+
+        public Completeness parseExpressionOptionalSemi() {
+            if (shouldAbort(parseExpression())) return checkResult;
+            return optionalFinalSemi();
+        }
+
+        public Completeness parseExpression() {
+            while (token.kind.isExpression())
+                nextToken();
+            return Completeness.COMPLETE;
+        }
+
+        public Completeness parseStatement() {
+            Completeness stat = parseSimpleStatement();
+            if (stat == null) {
+                return parseExpressionStatement();
+            }
+            return stat;
+        }
+
+        /**
+         * Statement = Block | IF ParExpression Statement [ELSE Statement] | FOR
+         * "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement | FOR
+         * "(" FormalParameter : Expression ")" Statement | WHILE ParExpression
+         * Statement | DO Statement WHILE ParExpression ";" | TRY Block (
+         * Catches | [Catches] FinallyPart ) | TRY "(" ResourceSpecification
+         * ";"opt ")" Block [Catches] [FinallyPart] | SWITCH ParExpression "{"
+         * SwitchBlockStatementGroups "}" | SYNCHRONIZED ParExpression Block |
+         * RETURN [Expression] ";" | THROW Expression ";" | BREAK [Ident] ";" |
+         * CONTINUE [Ident] ";" | ASSERT Expression [ ":" Expression ] ";" | ";"
+         */
+        public Completeness parseSimpleStatement() {
+            switch (token.kind) {
+                case BRACES:
+                    return lastly(BRACES);
+                case IF: {
+                    nextToken();
+                    if (shouldAbort(PARENS))  return checkResult;
+                    Completeness thenpart = parseStatement();
+                    if (shouldAbort(thenpart)) return thenpart;
+                    if (token.kind == ELSE) {
+                        nextToken();
+                        return parseStatement();
+                    }
+                    return thenpart;
+
+                }
+                case FOR: {
+                    nextToken();
+                    if (shouldAbort(PARENS))  return checkResult;
+                    if (shouldAbort(parseStatement()))  return checkResult;
+                    return Completeness.COMPLETE;
+                }
+                case WHILE: {
+                    nextToken();
+                    if (shouldAbort(PARENS))  return error();
+                    return parseStatement();
+                }
+                case DO: {
+                    nextToken();
+                    switch (parseStatement()) {
+                        case DEFINITELY_INCOMPLETE:
+                        case CONSIDERED_INCOMPLETE:
+                        case COMPLETE_WITH_SEMI:
+                            return Completeness.DEFINITELY_INCOMPLETE;
+                        case UNKNOWN:
+                            return error();
+                        case COMPLETE:
+                            break;
+                    }
+                    if (shouldAbort(WHILE))  return checkResult;
+                    if (shouldAbort(PARENS)) return checkResult;
+                    return lastly(SEMI);
+                }
+                case TRY: {
+                    boolean hasResources = false;
+                    nextToken();
+                    if (token.kind == PARENS) {
+                        nextToken();
+                        hasResources = true;
+                    }
+                    if (shouldAbort(BRACES))  return checkResult;
+                    if (token.kind == CATCH || token.kind == FINALLY) {
+                        while (token.kind == CATCH) {
+                            if (shouldAbort(CATCH))  return checkResult;
+                            if (shouldAbort(PARENS)) return checkResult;
+                            if (shouldAbort(BRACES)) return checkResult;
+                        }
+                        if (token.kind == FINALLY) {
+                            if (shouldAbort(FINALLY))  return checkResult;
+                            if (shouldAbort(BRACES)) return checkResult;
+                        }
+                    } else if (!hasResources) {
+                        if (token.kind == EOF) {
+                            return Completeness.DEFINITELY_INCOMPLETE;
+                        } else {
+                            return error();
+                        }
+                    }
+                    return Completeness.COMPLETE;
+                }
+                case SWITCH: {
+                    nextToken();
+                    if (shouldAbort(PARENS))  return checkResult;
+                    return lastly(BRACES);
+                }
+                case SYNCHRONIZED: {
+                    nextToken();
+                    if (shouldAbort(PARENS))  return checkResult;
+                    return lastly(BRACES);
+                }
+                case THROW: {
+                    nextToken();
+                    if (shouldAbort(parseExpression()))  return checkResult;
+                    return lastly(SEMI);
+                }
+                case SEMI:
+                    return lastly(SEMI);
+                case ASSERT:
+                    nextToken();
+                    // Crude expression parsing just happily eats the optional colon
+                    return parseExpressionStatement();
+                case RETURN:
+                case BREAK:
+                case CONTINUE:
+                    nextToken();
+                    return parseExpressionStatement();
+                // What are these doing here?
+                case ELSE:
+                case FINALLY:
+                case CATCH:
+                    return error();
+                case EOF:
+                    return Completeness.CONSIDERED_INCOMPLETE;
+                default:
+                    return null;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/jshell/DeclarationSnippet.java	Tue Nov 24 00:42:53 2015 +0000
@@ -0,0 +1,88 @@
+/*
+ * 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.jshell;
+
+import java.util.Collection;
+import jdk.jshell.Key.DeclarationKey;
+
+/**
+ * Grouping for all declaration Snippets: variable declarations
+ * ({@link jdk.jshell.VarSnippet}), method declarations
+ * ({@link jdk.jshell.MethodSnippet}), and type declarations
+ * ({@link jdk.jshell.TypeDeclSnippet}).
+ * <p>
+ * Declaration snippets are unique in that they can be active
+ *  with unresolved references:
+ * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED} or
+ * {@link jdk.jshell.Snippet.Status#RECOVERABLE_NOT_DEFINED RECOVERABLE_NOT_DEFINED}.
+ * Unresolved references can be queried with
+ * {@link jdk.jshell.JShell#unresolvedDependencies(jdk.jshell.DeclarationSnippet)
+ * JShell.unresolvedDependencies(DeclarationSnippet)}.
+ * <p>
+ * <code>DeclarationSnippet</code> is immutable: an access to
+ * any of its methods will always return the same result.
+ * and thus is thread-safe.
+ */
+public abstract class DeclarationSnippet extends PersistentSnippet {
+
+    private final Wrap corralled;
+    private final Collection<String> declareReferences;
+    private final Collection<String> bodyReferences;
+
+    DeclarationSnippet(DeclarationKey key, String userSource, Wrap guts,
+            String unitName, SubKind subkind, Wrap corralled,
+            Collection<String> declareReferences,
+            Collection<String> bodyReferences) {
+        super(key, userSource, guts, unitName, subkind);
+        this.corralled = corralled;
+        this.declareReferences = declareReferences;
+        this.bodyReferences = bodyReferences;
+    }
+
+    /**** internal access ****/
+
+    /**
+     * @return the corralled guts
+     */
+    @Override
+    Wrap corralled() {
+        return corralled;
+    }
+
+    @Override
+    Collection<String> declareReferences() {
+        return declareReferences;
+    }
+
+    @Override
+    Collection<String> bodyReferences() {
+        return bodyReferences;
+    }
+
+    @Override
+    String importLine(JShell state) {
+        return "import static " + state.maps.classFullName(this) + "." + name() + ";\n";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Diag.java	Tue Nov 24 00:42:53 2015 +0000
@@ -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.jshell;
+
+import java.util.Locale;
+import javax.tools.Diagnostic;
+
+/**
+ * Diagnostic information for a Snippet.
+ * @see jdk.jshell.JShell#diagnostics(jdk.jshell.Snippet)
+ */
+public abstract class Diag {
+    // Simplified view on compiler Diagnostic.
+
+    /**
+     * Used to signal that no position is available.
+     */
+    public final static long NOPOS = Diagnostic.NOPOS;
+
+    /**
+     * Is this diagnostic and error (as opposed to a warning or note)
+     * @return true if this diagnostic is an error
+     */
+    public abstract boolean isError();
+
+    /**
+     * Returns a character offset from the beginning of the source object
+     * associated with this diagnostic that indicates the location of
+     * the problem.  In addition, the following must be true:
+     *
+     * <p>{@code getStartPostion() <= getPosition()}
+     * <p>{@code getPosition() <= getEndPosition()}
+     *
+     * @return character offset from beginning of source; {@link
+     * #NOPOS} if {@link #getSource()} would return {@code null} or if
+     * no location is suitable
+     */
+    public abstract long getPosition();
+
+    /**
+     * Returns the character offset from the beginning of the file
+     * associated with this diagnostic that indicates the start of the
+     * problem.
+     *
+     * @return offset from beginning of file; {@link #NOPOS} if and
+     * only if {@link #getPosition()} returns {@link #NOPOS}
+     */
+    public abstract long getStartPosition();
+
+    /**
+     * Returns the character offset from the beginning of the file
+     * associated with this diagnostic that indicates the end of the
+     * problem.
+     *
+     * @return offset from beginning of file; {@link #NOPOS} if and
+     * only if {@link #getPosition()} returns {@link #NOPOS}
+     */
+    public abstract long getEndPosition();
+
+    /**
+     * Returns a diagnostic code indicating the type of diagnostic.  The
+     * code is implementation-dependent and might be {@code null}.
+     *
+     * @return a diagnostic code
+     */
+    public abstract String getCode();
+
+    /**
+     * Returns a localized message for the given locale.  The actual
+     * message is implementation-dependent.  If the locale is {@code
+     * null} use the default locale.
+     *
+     * @param locale a locale; might be {@code null}
+     * @return a localized message
+