Merge
diff --git a/langtools/.hgtags b/langtools/.hgtags
index a116158..164659c 100644
--- a/langtools/.hgtags
+++ b/langtools/.hgtags
@@ -382,3 +382,4 @@
 dd56c243c199a540c9f1fbff4855f0934b32a9d0 jdk-9+137
 90dd93e668a521642382561c47abe96ee2e065b7 jdk-9+138
 17a82cb0e4b480e97021691d39917f15e3f7b653 jdk-9+139
+6842e63d6c3971172214b411f29965852ca175d1 jdk-9+140
diff --git a/langtools/make/build.properties b/langtools/make/build.properties
index c65ccb6..4deb152 100644
--- a/langtools/make/build.properties
+++ b/langtools/make/build.properties
@@ -24,11 +24,12 @@
 #
 
 #javac configuration for "normal build" (these will be passed to the bootstrap compiler):
-javac.opts = -XDignore.symbol.file=true -Xlint:all,-deprecation,-options -Werror -g:source,lines,vars
+javac.opts = -XDignore.symbol.file=true -Xlint:all,-deprecation,-options,-exports -Werror -g:source,lines,vars
 javac.source = 9
 javac.target = 9
 
 #version used to compile build tools
+javac.build.opts = -XDignore.symbol.file=true -Xlint:all,-deprecation,-options -Werror -g:source,lines,vars
 javac.build.source = 8
 javac.build.target = 8
 
diff --git a/langtools/make/build.xml b/langtools/make/build.xml
index 3fec57e..94a9aee 100644
--- a/langtools/make/build.xml
+++ b/langtools/make/build.xml
@@ -275,7 +275,7 @@
                classpath="${ant.core.lib}"
                bootclasspath="${langtools.jdk.home}/jre/lib/rt.jar"
                includeantruntime="false">
-            <compilerarg line="${javac.opts} -XDstringConcat=inline"/>
+            <compilerarg line="${javac.build.opts} -XDstringConcat=inline"/>
         </javac>
         <taskdef name="pparse"
                  classname="anttasks.PropertiesParserTask"
@@ -291,7 +291,7 @@
                destdir="${build.dir}/toolclasses/"
                classpath="${ant.core.lib}"
                includeantruntime="false">
-            <compilerarg line="${javac.opts} -XDstringConcat=inline"/>
+            <compilerarg line="${javac.build.opts} -XDstringConcat=inline"/>
         </javac>
         <taskdef name="pcompile"
                  classname="anttasks.CompilePropertiesTask"
diff --git a/langtools/make/gensrc/GensrcCommon.gmk b/langtools/make/gensrc/GensrcCommon.gmk
index 8a14a02..96aed34 100644
--- a/langtools/make/gensrc/GensrcCommon.gmk
+++ b/langtools/make/gensrc/GensrcCommon.gmk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2016, 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
diff --git a/langtools/make/intellij/misc.xml b/langtools/make/intellij/misc.xml
index edc8298..ac40c95 100644
--- a/langtools/make/intellij/misc.xml
+++ b/langtools/make/intellij/misc.xml
@@ -4,14 +4,17 @@
     <entry_points version="2.0" />
   </component>
   <component name="JTRegService">
-    <option name="JTRegDir" value="@IDEA_JTREG_HOME@" />
-    <option name="JTRegOptions" value='@XPATCH@' />
-    <option name="alternativeJrePath" value="@IDEA_TARGET_JDK@" />
-    <option name="alternativeJrePathEnabled" value="true" />
-    <option name="workDir" value="build" />
+    <path>@IDEA_JTREG_HOME@</path>
+    <workDir>build</workDir>
+    <jre alt="true" value="@IDEA_TARGET_JDK@" />
+    <options>@XPATCH@</options>
+    <ant>
+      <target file="file://$PROJECT_DIR$/.idea/build.xml" name="build-all-classes" />
+    </ant>
   </component>
   <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/.idea/out" />
   </component>
 </project>
 
+
diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java
index 3eafa56..bce8bb7 100644
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java
@@ -949,6 +949,7 @@
 
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
         public java.util.List<Directive> getDirectives() {
+            complete();
             completeUsesProvides();
             return Collections.unmodifiableList(directives);
         }
diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
index d8f6cf5..cd72973 100644
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
@@ -30,6 +30,7 @@
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.function.BiPredicate;
@@ -468,89 +469,14 @@
          * and return-type substitutable with each method in the original list.
          */
         private FunctionDescriptor mergeDescriptors(TypeSymbol origin, List<Symbol> methodSyms) {
-            //pick argument types - simply take the signature that is a
-            //subsignature of all other signatures in the list (as per JLS 8.4.2)
-            List<Symbol> mostSpecific = List.nil();
-            outer: for (Symbol msym1 : methodSyms) {
-                Type mt1 = memberType(origin.type, msym1);
-                for (Symbol msym2 : methodSyms) {
-                    Type mt2 = memberType(origin.type, msym2);
-                    if (!isSubSignature(mt1, mt2)) {
-                        continue outer;
-                    }
-                }
-                mostSpecific = mostSpecific.prepend(msym1);
-            }
-            if (mostSpecific.isEmpty()) {
-                return null;
-            }
-
-
-            //pick return types - this is done in two phases: (i) first, the most
-            //specific return type is chosen using strict subtyping; if this fails,
-            //a second attempt is made using return type substitutability (see JLS 8.4.5)
-            boolean phase2 = false;
-            Symbol bestSoFar = null;
-            while (bestSoFar == null) {
-                outer: for (Symbol msym1 : mostSpecific) {
-                    Type mt1 = memberType(origin.type, msym1);
-                    for (Symbol msym2 : methodSyms) {
-                        Type mt2 = memberType(origin.type, msym2);
-                        if (phase2 ?
-                                !returnTypeSubstitutable(mt1, mt2) :
-                                !isSubtypeInternal(mt1.getReturnType(), mt2.getReturnType())) {
-                            continue outer;
+            return mergeAbstracts(methodSyms, origin.type, false)
+                    .map(bestSoFar -> new FunctionDescriptor(bestSoFar.baseSymbol()) {
+                        @Override
+                        public Type getType(Type origin) {
+                            Type mt = memberType(origin, getSymbol());
+                            return createMethodTypeWithThrown(mt, bestSoFar.type.getThrownTypes());
                         }
-                    }
-                    bestSoFar = msym1;
-                }
-                if (phase2) {
-                    break;
-                } else {
-                    phase2 = true;
-                }
-            }
-            if (bestSoFar == null) return null;
-
-            //merge thrown types - form the intersection of all the thrown types in
-            //all the signatures in the list
-            List<Type> thrown = null;
-            Type mt1 = memberType(origin.type, bestSoFar);
-            boolean toErase = !mt1.hasTag(FORALL);
-            for (Symbol msym2 : methodSyms) {
-                Type mt2 = memberType(origin.type, msym2);
-                List<Type> thrown_mt2 = mt2.getThrownTypes();
-                if (toErase) {
-                    thrown_mt2 = erasure(thrown_mt2);
-                } else {
-                    /* If bestSoFar is generic then all the methods are generic.
-                     * The opposite is not true: a non generic method can override
-                     * a generic method (raw override) so it's safe to cast mt1 and
-                     * mt2 to ForAll.
-                     */
-                    ForAll fa1 = (ForAll)mt1;
-                    ForAll fa2 = (ForAll)mt2;
-                    thrown_mt2 = subst(thrown_mt2, fa2.tvars, fa1.tvars);
-                }
-                thrown = (thrown == null) ?
-                    thrown_mt2 :
-                    chk.intersect(thrown_mt2, thrown);
-            }
-
-            final List<Type> thrown1 = thrown;
-            return new FunctionDescriptor(bestSoFar) {
-                @Override
-                public Type getType(Type origin) {
-                    Type mt = memberType(origin, getSymbol());
-                    return createMethodTypeWithThrown(mt, thrown1);
-                }
-            };
-        }
-
-        boolean isSubtypeInternal(Type s, Type t) {
-            return (s.isPrimitive() && t.isPrimitive()) ?
-                    isSameType(t, s) :
-                    isSubtype(s, t);
+                    }).orElse(null);
         }
 
         FunctionDescriptorLookupError failure(String msg, Object... args) {
@@ -2604,6 +2530,106 @@
         return false;
     }
 
+    /**
+     * This enum defines the strategy for implementing most specific return type check
+     * during the most specific and functional interface checks.
+     */
+    public enum MostSpecificReturnCheck {
+        /**
+         * Return r1 is more specific than r2 if {@code r1 <: r2}. Extra care required for (i) handling
+         * method type variables (if either method is generic) and (ii) subtyping should be replaced
+         * by type-equivalence for primitives. This is essentially an inlined version of
+         * {@link Types#resultSubtype(Type, Type, Warner)}, where the assignability check has been
+         * replaced with a strict subtyping check.
+         */
+        BASIC() {
+            @Override
+            public boolean test(Type mt1, Type mt2, Types types) {
+                List<Type> tvars = mt1.getTypeArguments();
+                List<Type> svars = mt2.getTypeArguments();
+                Type t = mt1.getReturnType();
+                Type s = types.subst(mt2.getReturnType(), svars, tvars);
+                return types.isSameType(t, s) ||
+                    !t.isPrimitive() &&
+                    !s.isPrimitive() &&
+                    types.isSubtype(t, s);
+            }
+        },
+        /**
+         * Return r1 is more specific than r2 if r1 is return-type-substitutable for r2.
+         */
+        RTS() {
+            @Override
+            public boolean test(Type mt1, Type mt2, Types types) {
+                return types.returnTypeSubstitutable(mt1, mt2);
+            }
+        };
+
+        public abstract boolean test(Type mt1, Type mt2, Types types);
+    }
+
+    /**
+     * Merge multiple abstract methods. The preferred method is a method that is a subsignature
+     * of all the other signatures and whose return type is more specific {@see MostSpecificReturnCheck}.
+     * The resulting preferred method has a thrown clause that is the intersection of the merged
+     * methods' clauses.
+     */
+    public Optional<Symbol> mergeAbstracts(List<Symbol> ambiguousInOrder, Type site, boolean sigCheck) {
+        //first check for preconditions
+        boolean shouldErase = false;
+        List<Type> erasedParams = ambiguousInOrder.head.erasure(this).getParameterTypes();
+        for (Symbol s : ambiguousInOrder) {
+            if ((s.flags() & ABSTRACT) == 0 ||
+                    (sigCheck && !isSameTypes(erasedParams, s.erasure(this).getParameterTypes()))) {
+                return Optional.empty();
+            } else if (s.type.hasTag(FORALL)) {
+                shouldErase = true;
+            }
+        }
+        //then merge abstracts
+        for (MostSpecificReturnCheck mostSpecificReturnCheck : MostSpecificReturnCheck.values()) {
+            outer: for (Symbol s : ambiguousInOrder) {
+                Type mt = memberType(site, s);
+                List<Type> allThrown = mt.getThrownTypes();
+                for (Symbol s2 : ambiguousInOrder) {
+                    if (s != s2) {
+                        Type mt2 = memberType(site, s2);
+                        if (!isSubSignature(mt, mt2) ||
+                                !mostSpecificReturnCheck.test(mt, mt2, this)) {
+                            //ambiguity cannot be resolved
+                            continue outer;
+                        } else {
+                            List<Type> thrownTypes2 = mt2.getThrownTypes();
+                            if (!mt.hasTag(FORALL) && shouldErase) {
+                                thrownTypes2 = erasure(thrownTypes2);
+                            } else if (mt.hasTag(FORALL)) {
+                                //subsignature implies that if most specific is generic, then all other
+                                //methods are too
+                                Assert.check(mt2.hasTag(FORALL));
+                                // if both are generic methods, adjust thrown types ahead of intersection computation
+                                thrownTypes2 = subst(thrownTypes2, mt2.getTypeArguments(), mt.getTypeArguments());
+                            }
+                            allThrown = chk.intersect(allThrown, thrownTypes2);
+                        }
+                    }
+                }
+                return (allThrown == mt.getThrownTypes()) ?
+                        Optional.of(s) :
+                        Optional.of(new MethodSymbol(
+                                s.flags(),
+                                s.name,
+                                createMethodTypeWithThrown(s.type, allThrown),
+                                s.owner) {
+                            @Override
+                            public Symbol baseSymbol() {
+                                return s;
+                            }
+                        });
+            }
+        }
+        return Optional.empty();
+    }
+
     // <editor-fold defaultstate="collapsed" desc="Determining method implementation in given site">
     class ImplementationCache {
 
diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
index bf919e8..49f8489 100644
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
@@ -1691,28 +1691,6 @@
         }
     }
     //where
-    Type mostSpecificReturnType(Type mt1, Type mt2) {
-        Type rt1 = mt1.getReturnType();
-        Type rt2 = mt2.getReturnType();
-
-        if (mt1.hasTag(FORALL) && mt2.hasTag(FORALL)) {
-            //if both are generic methods, adjust return type ahead of subtyping check
-            rt1 = types.subst(rt1, mt1.getTypeArguments(), mt2.getTypeArguments());
-        }
-        //first use subtyping, then return type substitutability
-        if (types.isSubtype(rt1, rt2)) {
-            return mt1;
-        } else if (types.isSubtype(rt2, rt1)) {
-            return mt2;
-        } else if (types.returnTypeSubstitutable(mt1, mt2)) {
-            return mt1;
-        } else if (types.returnTypeSubstitutable(mt2, mt1)) {
-            return mt2;
-        } else {
-            return null;
-        }
-    }
-    //where
     Symbol ambiguityError(Symbol m1, Symbol m2) {
         if (((m1.flags() | m2.flags()) & CLASH) != 0) {
             return (m1.flags() & CLASH) == 0 ? m1 : m2;
@@ -4112,43 +4090,7 @@
          */
         Symbol mergeAbstracts(Type site) {
             List<Symbol> ambiguousInOrder = ambiguousSyms.reverse();
-            for (Symbol s : ambiguousInOrder) {
-                Type mt = types.memberType(site, s);
-                boolean found = true;
-                List<Type> allThrown = mt.getThrownTypes();
-                for (Symbol s2 : ambiguousInOrder) {
-                    Type mt2 = types.memberType(site, s2);
-                    if ((s2.flags() & ABSTRACT) == 0 ||
-                        !types.overrideEquivalent(mt, mt2) ||
-                        !types.isSameTypes(s.erasure(types).getParameterTypes(),
-                                       s2.erasure(types).getParameterTypes())) {
-                        //ambiguity cannot be resolved
-                        return this;
-                    }
-                    Type mst = mostSpecificReturnType(mt, mt2);
-                    if (mst == null || mst != mt) {
-                        found = false;
-                        break;
-                    }
-                    List<Type> thrownTypes2 = mt2.getThrownTypes();
-                    if (mt.hasTag(FORALL) && mt2.hasTag(FORALL)) {
-                        // if both are generic methods, adjust thrown types ahead of intersection computation
-                        thrownTypes2 = types.subst(thrownTypes2, mt2.getTypeArguments(), mt.getTypeArguments());
-                    }
-                    allThrown = chk.intersect(allThrown, thrownTypes2);
-                }
-                if (found) {
-                    //all ambiguous methods were abstract and one method had
-                    //most specific return type then others
-                    return (allThrown == mt.getThrownTypes()) ?
-                            s : new MethodSymbol(
-                                s.flags(),
-                                s.name,
-                                types.createMethodTypeWithThrown(s.type, allThrown),
-                                s.owner);
-                }
-            }
-            return this;
+            return types.mergeAbstracts(ambiguousInOrder, site, true).orElse(this);
         }
 
         @Override
diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js
index ada2c64..6e4ea9b 100644
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js
@@ -30,6 +30,9 @@
 var catTypes = "Types";
 var catMembers = "Members";
 var catSearchTags = "SearchTags";
+var highlight = "<span class=\"resultHighlight\">$&</span>";
+var camelCaseRegexp = "";
+var secondaryMatcher = "";
 function getName(name) {
     var anchor = "";
     var ch = '';
@@ -65,27 +68,35 @@
     }
     return anchor;
 }
+function getHighlightedText(item) {
+    var ccMatcher = new RegExp(camelCaseRegexp);
+    var label = item.replace(ccMatcher, highlight);
+    if (label === item) {
+        label = item.replace(secondaryMatcher, highlight);
+    }
+    return label;
+}
 var watermark = 'Search';
 $(function() {
     $("#search").prop("disabled", false);
     $("#reset").prop("disabled", false);
     $("#search").val(watermark).addClass('watermark');
-    $("#search").blur(function(){
+    $("#search").blur(function() {
         if ($(this).val().length == 0) {
             $(this).val(watermark).addClass('watermark');
         }
     });
-    $("#search").keydown(function(){
-       if ($(this).val() == watermark) {
+    $("#search").keydown(function() {
+        if ($(this).val() == watermark) {
             $(this).val('').removeClass('watermark');
         }
     });
-    $("#reset").click(function(){
-       $("#search").val('');
-       $("#search").focus();
+    $("#reset").click(function() {
+        $("#search").val('');
+        $("#search").focus();
     });
     $("#search").focus();
-    $("#search")[0].setSelectionRange(0,0);
+    $("#search")[0].setSelectionRange(0, 0);
 });
 $.widget("custom.catcomplete", $.ui.autocomplete, {
     _create: function() {
@@ -112,22 +123,19 @@
         });
     },
     _renderItem: function(ul, item) {
-        var result = this.element.val();
-        var regexp = new RegExp($.ui.autocomplete.escapeRegex(result), "i");
-        highlight = "<span class=\"resultHighlight\">$&</span>";
         var label = "";
         if (item.category === catModules) {
-            label = item.l.replace(regexp, highlight);
+            label = getHighlightedText(item.l);
         } else if (item.category === catPackages) {
             label = (item.m)
-                    ? (item.m + "/" + item.l).replace(regexp, highlight)
-                    : item.l.replace(regexp, highlight);
+                    ? getHighlightedText(item.m + "/" + item.l)
+                    : getHighlightedText(item.l);
         } else if (item.category === catTypes) {
-            label += (item.p + "." + item.l).replace(regexp, highlight);
+            label = getHighlightedText(item.p + "." + item.l);
         } else if (item.category === catMembers) {
-            label += item.p + "." + (item.c + "." + item.l).replace(regexp, highlight);
+            label = getHighlightedText(item.p + "." + (item.c + "." + item.l));
         } else if (item.category === catSearchTags) {
-            label = item.l.replace(regexp, highlight);
+            label = getHighlightedText(item.l);
         } else {
             label = item.l;
         }
@@ -163,7 +171,9 @@
             var tgresult = new Array();
             var displayCount = 0;
             var exactMatcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(request.term) + "$", "i");
-            var secondaryMatcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
+            camelCaseRegexp = ($.ui.autocomplete.escapeRegex(request.term)).split(/(?=[A-Z])/).join("([a-z0-9_$]*?)");
+            var camelCaseMatcher = new RegExp("^" + camelCaseRegexp);
+            secondaryMatcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
             if (moduleSearchIndex) {
                 var mdleCount = 0;
                 $.each(moduleSearchIndex, function(index, item) {
@@ -171,6 +181,8 @@
                     if (exactMatcher.test(item.l)) {
                         result.unshift(item);
                         mdleCount++;
+                    } else if (camelCaseMatcher.test(item.l)) {
+                        result.unshift(item);
                     } else if (secondaryMatcher.test(item.l)) {
                         result.push(item);
                     }
@@ -188,6 +200,8 @@
                     if (exactMatcher.test(item.l)) {
                         presult.unshift(item);
                         pCount++;
+                    } else if (camelCaseMatcher.test(pkg)) {
+                        presult.unshift(item);
                     } else if (secondaryMatcher.test(pkg)) {
                         presult.push(item);
                     }
@@ -202,6 +216,8 @@
                     if (exactMatcher.test(item.l)) {
                         tresult.unshift(item);
                         tCount++;
+                    } else if (camelCaseMatcher.test(item.l)) {
+                        tresult.unshift(item);
                     } else if (secondaryMatcher.test(item.p + "." + item.l)) {
                         tresult.push(item);
                     }
@@ -216,6 +232,8 @@
                     if (exactMatcher.test(item.l)) {
                         mresult.unshift(item);
                         mCount++;
+                    } else if (camelCaseMatcher.test(item.l)) {
+                        mresult.unshift(item);
                     } else if (secondaryMatcher.test(item.c + "." + item.l)) {
                         mresult.push(item);
                     }
@@ -294,4 +312,4 @@
             }
         }
     });
-});
+});
\ No newline at end of file
diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java
index fd05a76..87e872e 100644
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java
@@ -384,14 +384,14 @@
                      .collect(toList()));
         } else {
             // TODO: kind of a hack...
-            // Create a throwaway compilation task with options "-release N"
+            // Create a throwaway compilation task with options "--release N"
             // which has the side effect of setting the file manager's
             // PLATFORM_CLASS_PATH to the right value.
             JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
             StandardJavaFileManager fm =
                 compiler.getStandardFileManager(this, null, StandardCharsets.UTF_8);
             JavaCompiler.CompilationTask task =
-                compiler.getTask(null, fm, this, List.of("-release", release), null, null);
+                compiler.getTask(null, fm, this, List.of("--release", release), null, null);
             List<Path> paths = new ArrayList<>();
             for (Path p : fm.getLocationAsPaths(StandardLocation.PLATFORM_CLASS_PATH)) {
                 try (Stream<Path> str = Files.walk(p)) {
diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java
index 9f7e0d2..1c3e61d 100644
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java
@@ -680,20 +680,21 @@
     private boolean genModuleInfo(JdepsConfiguration config) throws IOException {
         // check if any JAR file contains unnamed package
         for (String arg : inputArgs) {
-            Optional<String> classInUnnamedPackage =
-                ClassFileReader.newInstance(Paths.get(arg))
-                    .entries().stream()
-                    .filter(n -> n.endsWith(".class"))
-                    .filter(cn -> toPackageName(cn).isEmpty())
-                    .findFirst();
+            try (ClassFileReader reader = ClassFileReader.newInstance(Paths.get(arg))) {
+                Optional<String> classInUnnamedPackage =
+                    reader.entries().stream()
+                        .filter(n -> n.endsWith(".class"))
+                        .filter(cn -> toPackageName(cn).isEmpty())
+                        .findFirst();
 
-            if (classInUnnamedPackage.isPresent()) {
-                if (classInUnnamedPackage.get().equals("module-info.class")) {
-                    reportError("err.genmoduleinfo.not.jarfile", arg);
-                } else {
-                    reportError("err.genmoduleinfo.unnamed.package", arg);
+                if (classInUnnamedPackage.isPresent()) {
+                    if (classInUnnamedPackage.get().equals("module-info.class")) {
+                        reportError("err.genmoduleinfo.not.jarfile", arg);
+                    } else {
+                        reportError("err.genmoduleinfo.unnamed.package", arg);
+                    }
+                    return false;
                 }
-                return false;
             }
         }
 
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
index 6cfb6e1..ad075af 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
@@ -73,7 +73,6 @@
 import jdk.jshell.JShell;
 import jdk.jshell.JShell.Subscription;
 import jdk.jshell.MethodSnippet;
-import jdk.jshell.PersistentSnippet;
 import jdk.jshell.Snippet;
 import jdk.jshell.Snippet.Status;
 import jdk.jshell.SnippetEvent;
@@ -1137,10 +1136,9 @@
         return state.snippets();
     }
 
-    Stream<PersistentSnippet> dropableSnippets() {
+    Stream<Snippet> dropableSnippets() {
         return state.snippets()
-                .filter(sn -> state.status(sn).isActive() && sn instanceof PersistentSnippet)
-                .map(sn -> (PersistentSnippet) sn);
+                .filter(sn -> state.status(sn).isActive());
     }
 
     Stream<VarSnippet> allVarSnippets() {
@@ -1761,13 +1759,13 @@
             errormsg("jshell.err.drop.arg");
             return false;
         }
-        Stream<PersistentSnippet> stream = argsToSnippets(this::dropableSnippets, args);
+        Stream<Snippet> stream = argsToSnippets(this::dropableSnippets, args);
         if (stream == null) {
             // Snippet not found. Error already printed
             fluffmsg("jshell.msg.see.classes.etc");
             return false;
         }
-        List<PersistentSnippet> snippets = stream.collect(toList());
+        List<Snippet> snippets = stream.collect(toList());
         if (snippets.size() > args.size()) {
             // One of the args references more thean one snippet
             errormsg("jshell.err.drop.ambiguous");
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/StopDetectingInputStream.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/StopDetectingInputStream.java
index 934d27b..e61be49 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/StopDetectingInputStream.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/StopDetectingInputStream.java
@@ -77,9 +77,7 @@
                 } catch (IOException ex) {
                     errorHandler.accept(ex);
                 } finally {
-                    synchronized (StopDetectingInputStream.this) {
-                        state = StopDetectingInputStream.State.CLOSED;
-                    }
+                    shutdown();
                 }
             }
         };
@@ -140,8 +138,10 @@
     }
 
     public synchronized void setState(State state) {
-        this.state = state;
-        notifyAll();
+        if (this.state != State.CLOSED) {
+            this.state = state;
+            notifyAll();
+        }
     }
 
     private synchronized State waitInputNeeded() {
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties
index beb1f0f..a179a3c 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties
@@ -743,7 +743,7 @@
 /set format verbose result '{name} ==> {value}{post}'                                        added,modified,replaced-ok-primary    \n\
 \n\
 /set format verbose display '{result}{pre}created scratch variable {name} : {type}{post}'    expression-added,modified,replaced-primary    \n\
-/set format verbose display '{result}{pre}value of {name} : {type}{post}'                    varvalue-primary    \n\
+/set format verbose display '{result}{pre}value of {name} : {type}{post}'                    varvalue-added,modified,replaced-primary    \n\
 /set format verbose display '{result}{pre}assigned to {name} : {type}{post}'                 assignment-primary    \n\
 /set format verbose display '{result}{pre}{action} variable {name} : {type}{resolve}{post}'  varinit,vardecl    \n\
 /set format verbose display '{pre}{action} variable {name}{resolve}{post}'                   vardecl,varinit-notdefined    \n\
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
index 79b8b22..ba5ff7b 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
@@ -521,10 +521,13 @@
 
     List<SnippetEvent> drop(Snippet si) {
         Unit c = new Unit(state, si);
-
-        Set<Unit> ins = c.dependents().collect(toSet());
-        Set<Unit> outs = compileAndLoad(ins);
-
+        Set<Unit> outs;
+        if (si instanceof PersistentSnippet) {
+            Set<Unit> ins = c.dependents().collect(toSet());
+            outs = compileAndLoad(ins);
+        } else {
+            outs = Collections.emptySet();
+        }
         return events(c, outs, null, null);
     }
 
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java
index fd97832..e45ec1b 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java
@@ -58,7 +58,7 @@
  * API.  A {@code JShell} instance holds the evolving compilation and
  * execution state.  The state is changed with the instance methods
  * {@link jdk.jshell.JShell#eval(java.lang.String) eval(String)},
- * {@link jdk.jshell.JShell#drop(jdk.jshell.PersistentSnippet) drop(PersistentSnippet)} and
+ * {@link jdk.jshell.JShell#drop(jdk.jshell.Snippet) drop(Snippet)} and
  * {@link jdk.jshell.JShell#addToClasspath(java.lang.String) addToClasspath(String)}.
  * The majority of methods query the state.
  * A {@code JShell} instance also allows registering for events with
@@ -428,7 +428,12 @@
     }
 
     /**
-     * Remove a declaration from the state.
+     * Remove a declaration from the state.  That is, if the snippet is an
+     * {@linkplain jdk.jshell.Snippet.Status#isActive() active}
+     * {@linkplain jdk.jshell.PersistentSnippet persistent} snippet, remove the
+     * snippet and update the JShell evaluation state accordingly.
+     * For all active snippets, change the {@linkplain #status status} to
+     * {@link jdk.jshell.Snippet.Status#DROPPED DROPPED}.
      * @param snippet The snippet to remove
      * @return The list of events from updating declarations dependent on the
      * dropped snippet.
@@ -436,7 +441,7 @@
      * @throws IllegalArgumentException if the snippet is not associated with
      * this {@code JShell} instance.
      */
-    public List<SnippetEvent> drop(PersistentSnippet snippet) throws IllegalStateException {
+    public List<SnippetEvent> drop(Snippet snippet) throws IllegalStateException {
         checkIfAlive();
         checkValidSnippet(snippet);
         List<SnippetEvent> events = eval.drop(snippet);
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Key.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Key.java
index 5779493..eb837a1 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Key.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Key.java
@@ -74,7 +74,7 @@
     /**
      * Grouping for snippets which persist and influence future code.
      * They are keyed off at least the name.  They may be Modified/Replaced
-     * with new input and can be dropped (JShell#drop).
+     * with new input.
      */
     static abstract class PersistentKey extends Key {
 
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/PersistentSnippet.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/PersistentSnippet.java
index 985c833..b615c78 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/PersistentSnippet.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/PersistentSnippet.java
@@ -28,8 +28,8 @@
 /**
  * Grouping for Snippets which persist and influence future code.
  * A persistent snippet can be
- * {@linkplain jdk.jshell.Snippet.Status#OVERWRITTEN overwritten)}
- * with new input and can be dropped {@link JShell#drop}.
+ * {@linkplain jdk.jshell.Snippet.Status#OVERWRITTEN overwritten}
+ * with new input.
  * <p>
  * <code>PersistentSnippet</code> is immutable: an access to
  * any of its methods will always return the same result.
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java
index 955f836..3268dd6 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Snippet.java
@@ -443,9 +443,7 @@
 
         /**
          * The snippet is inactive because of an explicit call to
-         * the {@link JShell#drop(PersistentSnippet)}.
-         * Only a {@link jdk.jshell.PersistentSnippet} can have this
-         * {@code Status}.
+         * the {@link JShell#drop(Snippet)}.
          * <p>
          * The snippet is not visible to other snippets
          * ({@link Status#isDefined() isDefined() == false})
@@ -525,10 +523,11 @@
 
         /**
          * Indicates whether the Snippet is active, that is,
-         * will the snippet be re-evaluated when a new
+         * will a {@linkplain jdk.jshell.PersistentSnippet persistent}
+         * snippet be re-evaluated when a new
          * {@link JShell#eval(java.lang.String) JShell.eval(String)} or
-         * {@link JShell#drop(jdk.jshell.PersistentSnippet)
-         * JShell.drop(PersistentSnippet)} that could change
+         * {@link JShell#drop(jdk.jshell.Snippet)
+         * JShell.drop(Snippet)} that could change
          * its status is invoked.  This is more broad than
          * {@link Status#isDefined()} since a Snippet which is
          * {@link Status#RECOVERABLE_NOT_DEFINED}
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java
index 47bb1b1..683038b 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java
@@ -30,7 +30,7 @@
 /**
  * A description of a change to a Snippet. These are generated by direct changes
  * to state with {@link JShell#eval(java.lang.String) JShell.eval(String)} or
- * {@link JShell#drop(jdk.jshell.PersistentSnippet) JShell.drop(PersistentSnippet)},
+ * {@link JShell#drop(jdk.jshell.Snippet) JShell.drop(Snippet)},
  * or indirectly by these same methods as
  * dependencies change or Snippets are overwritten. For direct changes, the
  * {@link SnippetEvent#causeSnippet()} is {@code null}.
@@ -108,7 +108,7 @@
      * creation of a new Snippet via
      * {@link jdk.jshell.JShell#eval(java.lang.String) eval} or it is the
      * explicit drop of a Snippet with
-     * {@link jdk.jshell.JShell#drop(jdk.jshell.PersistentSnippet) drop}.
+     * {@link jdk.jshell.JShell#drop(jdk.jshell.Snippet) drop}.
      *
      * @return the Snippet which caused this change or {@code null} if
      * directly caused by an API action.
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
index 309f4b4..ce7fd0e 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
@@ -116,6 +116,7 @@
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.QualifiedNameable;
+import javax.lang.model.element.TypeParameterElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.ArrayType;
 import javax.lang.model.type.ExecutableType;
@@ -132,6 +133,7 @@
 import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME;
 import static java.util.stream.Collectors.joining;
 import static jdk.jshell.SourceCodeAnalysis.Completeness.DEFINITELY_INCOMPLETE;
+import static jdk.jshell.TreeDissector.printType;
 
 /**
  * The concrete implementation of SourceCodeAnalysis.
@@ -1185,7 +1187,7 @@
             proc.debug(ex, "SourceCodeAnalysisImpl.element2String(..., " + el + ")");
         }
 
-        return Util.expunge(elementHeader(el));
+        return Util.expunge(elementHeader(sourceCache.originalTask, el, !hasSyntheticParameterNames(el)));
     }
 
     private boolean hasSyntheticParameterNames(Element el) {
@@ -1248,7 +1250,7 @@
                 topLevelName2Signature2Method.put(binaryName, cache = createMethodCache(binaryName));
             }
 
-            String handle = elementHeader(method, false);
+            String handle = elementHeader(originalTask, method, false);
 
             return cache.getOrDefault(handle, method);
         }
@@ -1276,7 +1278,7 @@
                     Element currentMethod = trees.getElement(getCurrentPath());
 
                     if (currentMethod != null) {
-                        signature2Method.put(elementHeader(currentMethod, false), currentMethod);
+                        signature2Method.put(elementHeader(originalTask, currentMethod, false), currentMethod);
                     }
 
                     return null;
@@ -1331,39 +1333,79 @@
         return availableSources = result;
     }
 
-    private String elementHeader(Element el) {
-        return elementHeader(el, true);
+    private String elementHeader(AnalyzeTask at, Element el) {
+        return elementHeader(at, el, true);
     }
 
-    private String elementHeader(Element el, boolean includeParameterNames) {
+    private String elementHeader(AnalyzeTask at, Element el, boolean includeParameterNames) {
         switch (el.getKind()) {
-            case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE:
-                return ((TypeElement) el).getQualifiedName().toString();
+            case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE: {
+                TypeElement type = (TypeElement)el;
+                String fullname = type.getQualifiedName().toString();
+                Element pkg = at.getElements().getPackageOf(el);
+                String name = pkg == null ? fullname :
+                        proc.maps.fullClassNameAndPackageToClass(fullname, ((PackageElement)pkg).getQualifiedName().toString());
+
+                return name + typeParametersOpt(at, type.getTypeParameters());
+            }
+            case TYPE_PARAMETER: {
+                TypeParameterElement tp = (TypeParameterElement)el;
+                String name = tp.getSimpleName().toString();
+
+                List<? extends TypeMirror> bounds = tp.getBounds();
+                boolean boundIsObject = bounds.isEmpty() ||
+                        bounds.size() == 1 && at.getTypes().isSameType(bounds.get(0), Symtab.instance(at.getContext()).objectType);
+
+                return boundIsObject
+                        ? name
+                        : name + " extends " + bounds.stream()
+                                .map(bound -> printType(at, proc, bound))
+                                .collect(joining(" & "));
+            }
             case FIELD:
-                return elementHeader(el.getEnclosingElement()) + "." + el.getSimpleName() + ":" + el.asType();
+                return elementHeader(at, el.getEnclosingElement()) + "." + el.getSimpleName() + ":" + el.asType();
             case ENUM_CONSTANT:
-                return elementHeader(el.getEnclosingElement()) + "." + el.getSimpleName();
+                return elementHeader(at, el.getEnclosingElement()) + "." + el.getSimpleName();
             case EXCEPTION_PARAMETER: case LOCAL_VARIABLE: case PARAMETER: case RESOURCE_VARIABLE:
                 return el.getSimpleName() + ":" + el.asType();
-            case CONSTRUCTOR: case METHOD:
+            case CONSTRUCTOR: case METHOD: {
                 StringBuilder header = new StringBuilder();
-                header.append(elementHeader(el.getEnclosingElement()));
-                if (el.getKind() == ElementKind.METHOD) {
-                    header.append(".");
-                    header.append(el.getSimpleName());
+
+                boolean isMethod = el.getKind() == ElementKind.METHOD;
+                ExecutableElement method = (ExecutableElement) el;
+
+                if (isMethod) {
+                    // return type
+                    header.append(printType(at, proc, method.getReturnType())).append(" ");
+                } else {
+                    // type parameters for the constructor
+                    String typeParameters = typeParametersOpt(at, method.getTypeParameters());
+                    if (!typeParameters.isEmpty()) {
+                        header.append(typeParameters).append(" ");
+                    }
                 }
+
+                // receiver type
+                String clazz = elementHeader(at, el.getEnclosingElement());
+                header.append(clazz);
+
+                if (isMethod) {
+                    //method name with type parameters
+                    (clazz.isEmpty() ? header : header.append("."))
+                            .append(typeParametersOpt(at, method.getTypeParameters()))
+                            .append(el.getSimpleName());
+                }
+
+                // arguments
                 header.append("(");
                 String sep = "";
-                ExecutableElement method = (ExecutableElement) el;
                 for (Iterator<? extends VariableElement> i = method.getParameters().iterator(); i.hasNext();) {
                     VariableElement p = i.next();
                     header.append(sep);
                     if (!i.hasNext() && method.isVarArgs()) {
-                        header.append(unwrapArrayType(p.asType()));
-                        header.append("...");
-
+                        header.append(printType(at, proc, unwrapArrayType(p.asType()))).append("...");
                     } else {
-                        header.append(p.asType());
+                        header.append(printType(at, proc, p.asType()));
                     }
                     if (includeParameterNames) {
                         header.append(" ");
@@ -1372,8 +1414,18 @@
                     sep = ", ";
                 }
                 header.append(")");
+
+                // throws
+                List<? extends TypeMirror> thrownTypes = method.getThrownTypes();
+                if (!thrownTypes.isEmpty()) {
+                    header.append(" throws ")
+                            .append(thrownTypes.stream()
+                                    .map(type -> printType(at, proc, type))
+                                    .collect(joining(", ")));
+                }
                 return header.toString();
-           default:
+            }
+            default:
                 return el.toString();
         }
     }
@@ -1383,6 +1435,12 @@
         }
         return arrayType;
     }
+    private String typeParametersOpt(AnalyzeTask at, List<? extends TypeParameterElement> typeParameters) {
+        return typeParameters.isEmpty() ? ""
+                : typeParameters.stream()
+                        .map(tp -> elementHeader(at, tp))
+                        .collect(joining(", ", "<", ">"));
+    }
 
     @Override
     public String analyzeType(String code, int cursor) {
diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/package-info.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/package-info.java
index 3556132..7e96546 100644
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/package-info.java
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/package-info.java
@@ -46,7 +46,7 @@
  * {@link jdk.jshell.SnippetEvent}.  There are three major kinds of
  * changes to the status of a snippet: it can created with <code>eval</code>,
  * it can be dropped from the active source state with
- * {@link jdk.jshell.JShell#drop(jdk.jshell.PersistentSnippet)}, and it can have
+ * {@link jdk.jshell.JShell#drop(jdk.jshell.Snippet)}, and it can have
  * its status updated as a result of a status change in another snippet.
  * For
  * example: given <code>js</code>, an instance of <code>JShell</code>, executing
diff --git a/langtools/test/Makefile b/langtools/test/Makefile
index f92e761..ca9cd57 100644
--- a/langtools/test/Makefile
+++ b/langtools/test/Makefile
@@ -321,6 +321,7 @@
 	  $(JTREG_EXCLUSIONS) \
 	  $(JTREG_OPTIONS) \
 	  $(JTREG_TESTDIRS) \
+	    2>&1 | tee $(JTREG_OUTPUT_DIR)/output.txt \
 	|| ( $(call EXIT_IF_FATAL,$(FATAL_JTREG_EXIT)) ; \
 	    echo $$status > $(JTREG_OUTPUT_DIR)/status.txt \
 	)
diff --git a/langtools/test/jdk/javadoc/doclet/testSearch/TestSearch.java b/langtools/test/jdk/javadoc/doclet/testSearch/TestSearch.java
index ba6ff3a..14f12cd 100644
--- a/langtools/test/jdk/javadoc/doclet/testSearch/TestSearch.java
+++ b/langtools/test/jdk/javadoc/doclet/testSearch/TestSearch.java
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8141492 8071982
+ * @bug 8141492 8071982 8141636
  * @summary Test the search feature of javadoc.
  * @author bpatel
  * @library ../lib
@@ -45,6 +45,7 @@
         checkExit(Exit.OK);
         checkSearchOutput("UnnamedPkgClass.html", true);
         checkJqueryAndImageFiles(true);
+        checkSearchJS();
         checkFiles(false,
                 "package-search-index.zip",
                 "tag-search-index.zip");
@@ -62,6 +63,7 @@
         checkSearchOutput(true);
         checkSingleIndex(true);
         checkJqueryAndImageFiles(true);
+        checkSearchJS();
         checkFiles(true,
                 "member-search-index.zip",
                 "package-search-index.zip",
@@ -78,6 +80,7 @@
         checkSearchOutput(true);
         checkSingleIndex(true);
         checkJqueryAndImageFiles(true);
+        checkSearchJS();
         checkFiles(true,
                 "member-search-index.zip",
                 "package-search-index.zip",
@@ -110,6 +113,7 @@
         checkSearchOutput(true);
         checkSingleIndex(true);
         checkJqueryAndImageFiles(true);
+        checkSearchJS();
         checkFiles(true,
                 "member-search-index.zip",
                 "package-search-index.zip",
@@ -142,6 +146,7 @@
         checkSearchOutput(true);
         checkIndexNoComment();
         checkJqueryAndImageFiles(true);
+        checkSearchJS();
         checkFiles(true,
                 "member-search-index.zip",
                 "package-search-index.zip",
@@ -158,6 +163,7 @@
         checkSearchOutput(true);
         checkIndexNoDeprecated();
         checkJqueryAndImageFiles(true);
+        checkSearchJS();
         checkFiles(true,
                 "member-search-index.zip",
                 "package-search-index.zip",
@@ -174,6 +180,7 @@
         checkSearchOutput(true);
         checkSplitIndex();
         checkJqueryAndImageFiles(true);
+        checkSearchJS();
         checkFiles(true,
                 "member-search-index.zip",
                 "package-search-index.zip",
@@ -189,6 +196,7 @@
         checkSearchOutput(true);
         checkJavaFXOutput();
         checkJqueryAndImageFiles(true);
+        checkSearchJS();
         checkFiles(false,
                 "tag-search-index.zip");
         checkFiles(true,
@@ -420,4 +428,11 @@
                 "resources/x.png",
                 "resources/glass.png");
     }
+
+    void checkSearchJS() {
+        checkOutput("search.js", true,
+                "camelCaseRegexp = ($.ui.autocomplete.escapeRegex(request.term)).split(/(?=[A-Z])/).join(\"([a-z0-9_$]*?)\");",
+                "var camelCaseMatcher = new RegExp(\"^\" + camelCaseRegexp);",
+                "camelCaseMatcher.test(item.l)");
+    }
 }
diff --git a/langtools/test/jdk/jshell/CompletionSuggestionTest.java b/langtools/test/jdk/jshell/CompletionSuggestionTest.java
index b3a40be..eb21ff6 100644
--- a/langtools/test/jdk/jshell/CompletionSuggestionTest.java
+++ b/langtools/test/jdk/jshell/CompletionSuggestionTest.java
@@ -23,8 +23,8 @@
 
 /*
  * @test
- * @bug 8131025 8141092 8153761
- * @summary Test Completion
+ * @bug 8131025 8141092 8153761 8145263
+ * @summary Test Completion and Documentation
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
  *          jdk.jdeps/com.sun.tools.javap
@@ -43,6 +43,8 @@
 import java.util.Collections;
 import java.util.Set;
 import java.util.HashSet;
+import java.util.function.BiFunction;
+import java.util.function.Function;
 import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
 
@@ -304,35 +306,35 @@
     public void testDocumentation() throws Exception {
         dontReadParameterNamesFromClassFile();
         assertDocumentation("System.getProperty(|",
-                "java.lang.System.getProperty(java.lang.String key)",
-                "java.lang.System.getProperty(java.lang.String key, java.lang.String def)");
+                "String System.getProperty(String key)",
+                "String System.getProperty(String key, String def)");
         assertEval("char[] chars = null;");
         assertDocumentation("new String(chars, |",
-                "java.lang.String(char[] arg0, int arg1, int arg2)");
+                "String(char[], int, int)");
         assertDocumentation("String.format(|",
-                "java.lang.String.format(java.lang.String arg0, java.lang.Object... arg1)",
-                "java.lang.String.format(java.util.Locale arg0, java.lang.String arg1, java.lang.Object... arg2)");
-        assertDocumentation("\"\".getBytes(\"\"|", "java.lang.String.getBytes(int arg0, int arg1, byte[] arg2, int arg3)",
-                                                    "java.lang.String.getBytes(java.lang.String arg0)",
-                                                    "java.lang.String.getBytes(java.nio.charset.Charset arg0)");
-        assertDocumentation("\"\".getBytes(\"\" |", "java.lang.String.getBytes(int arg0, int arg1, byte[] arg2, int arg3)",
-                                                     "java.lang.String.getBytes(java.lang.String arg0)",
-                                                     "java.lang.String.getBytes(java.nio.charset.Charset arg0)");
+                "String String.format(String, Object...)",
+                "String String.format(java.util.Locale, String, Object...)");
+        assertDocumentation("\"\".getBytes(\"\"|", "void String.getBytes(int, int, byte[], int)",
+                                                    "byte[] String.getBytes(String) throws java.io.UnsupportedEncodingException",
+                                                    "byte[] String.getBytes(java.nio.charset.Charset)");
+        assertDocumentation("\"\".getBytes(\"\" |", "void String.getBytes(int, int, byte[], int)",
+                                                     "byte[] String.getBytes(String) throws java.io.UnsupportedEncodingException",
+                                                     "byte[] String.getBytes(java.nio.charset.Charset)");
     }
 
     public void testMethodsWithNoArguments() throws Exception {
         dontReadParameterNamesFromClassFile();
         assertDocumentation("System.out.println(|",
-                "java.io.PrintStream.println()",
-                "java.io.PrintStream.println(boolean arg0)",
-                "java.io.PrintStream.println(char arg0)",
-                "java.io.PrintStream.println(int arg0)",
-                "java.io.PrintStream.println(long arg0)",
-                "java.io.PrintStream.println(float arg0)",
-                "java.io.PrintStream.println(double arg0)",
-                "java.io.PrintStream.println(char[] arg0)",
-                "java.io.PrintStream.println(java.lang.String arg0)",
-                "java.io.PrintStream.println(java.lang.Object arg0)");
+                "void java.io.PrintStream.println()",
+                "void java.io.PrintStream.println(boolean)",
+                "void java.io.PrintStream.println(char)",
+                "void java.io.PrintStream.println(int)",
+                "void java.io.PrintStream.println(long)",
+                "void java.io.PrintStream.println(float)",
+                "void java.io.PrintStream.println(double)",
+                "void java.io.PrintStream.println(char[])",
+                "void java.io.PrintStream.println(String)",
+                "void java.io.PrintStream.println(Object)");
     }
 
     public void testErroneous() {
@@ -472,14 +474,14 @@
 
     public void testDocumentationOfUserDefinedMethods() {
         assertEval("void f() {}");
-        assertDocumentation("f(|", "f()");
+        assertDocumentation("f(|", "void f()");
         assertEval("void f(int i) {}");
-        assertDocumentation("f(|", "f()", "f(int i)");
+        assertDocumentation("f(|", "void f()", "void f(int i)");
         assertEval("<T> void f(T... ts) {}", DiagCheck.DIAG_WARNING, DiagCheck.DIAG_OK);
-        assertDocumentation("f(|", "f()", "f(int i)", "f(T... ts)");
+        assertDocumentation("f(|", "void f()", "void f(int i)", "void <T>f(T... ts)");
         assertEval("class A {}");
         assertEval("void f(A a) {}");
-        assertDocumentation("f(|", "f()", "f(int i)", "f(T... ts)", "f(A a)");
+        assertDocumentation("f(|", "void f()", "void f(int i)", "void <T>f(T... ts)", "void f(A a)");
     }
 
     public void testDocumentationOfUserDefinedConstructors() {
@@ -489,25 +491,25 @@
                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
                 ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET)));
         assertDocumentation("new A(|", "A()", "A(int i)");
-        assertEval("class A<T> { A(T t) {} A(int i) {}}",
+        assertEval("class A<T> { A(T a) {} A(int i) {} <U> A(T t, U u) {}}",
                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
                 ste(a2, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
-        assertDocumentation("new A(|", "A(T t)", "A(int i)");
+        assertDocumentation("new A(|", "A<T>(T a)", "A<T>(int i)", "<U> A<T>(T t, U u)");
     }
 
     public void testDocumentationOfOverriddenMethods() throws Exception {
         dontReadParameterNamesFromClassFile();
         assertDocumentation("\"\".wait(|",
-            "java.lang.Object.wait(long arg0)",
-            "java.lang.Object.wait(long arg0, int arg1)",
-            "java.lang.Object.wait()");
+            "void Object.wait(long) throws InterruptedException",
+            "void Object.wait(long, int) throws InterruptedException",
+            "void Object.wait() throws InterruptedException");
         assertEval("class Base {void method() {}}");
         Snippet e = classKey(assertEval("class Extend extends Base {}"));
-        assertDocumentation("new Extend().method(|", "Base.method()");
+        assertDocumentation("new Extend().method(|", "void Base.method()");
         assertEval("class Extend extends Base {void method() {}}",
                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
                 ste(e, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
-        assertDocumentation("new Extend().method(|", "Extend.method()");
+        assertDocumentation("new Extend().method(|", "void Extend.method()");
     }
 
     public void testDocumentationOfInvisibleMethods() {
@@ -534,13 +536,67 @@
         assertEval("void method(int n, Object o) { }");
         assertEval("void method(Object n, int o) { }");
         assertDocumentation("method(primitive,|",
-                "method(int n, java.lang.Object o)",
-                "method(java.lang.Object n, int o)");
+                "void method(int n, Object o)",
+                "void method(Object n, int o)");
         assertDocumentation("method(boxed,|",
-                "method(int n, java.lang.Object o)",
-                "method(java.lang.Object n, int o)");
+                "void method(int n, Object o)",
+                "void method(Object n, int o)");
         assertDocumentation("method(object,|",
-                "method(java.lang.Object n, int o)");
+                "void method(Object n, int o)");
+    }
+
+    public void testDocumentationWithGenerics() {
+        class TestDocumentationWithGenerics {
+            private final Function<Integer, String> codeFacotry;
+            private final BiFunction<String, Integer, String> evalFormatter;
+            private final BiFunction<String, Integer, String> docFormatter;
+            int count;
+
+            TestDocumentationWithGenerics(
+                    Function<Integer, String> codeFactory,
+                    BiFunction<String, Integer, String> evalFormatter,
+                    BiFunction<String, Integer, String> documentationFormatter) {
+                this.codeFacotry = codeFactory;
+                this.evalFormatter = evalFormatter;
+                this.docFormatter = documentationFormatter;
+            }
+
+            void assertDoc(String generics) {
+                assertDoc(generics, generics);
+            }
+
+            void assertDoc(String generics, String expectedGenerics) {
+                assertEval(evalFormatter.apply(generics, count));
+                assertDocumentation(codeFacotry.apply(count), docFormatter.apply(expectedGenerics, count));
+                count++;
+            }
+        }
+
+        TestDocumentationWithGenerics[] tests = {
+            new TestDocumentationWithGenerics(
+                    i -> "f" + i + "(|",
+                    (g, i) -> "<" + g + "> void f" + i + "() {}",
+                    (g, i) -> "void <" + g + ">f" + i + "()"
+            ),
+            new TestDocumentationWithGenerics(
+                    i -> "new C" + i + "().f(|",
+                    (g, i) -> "class C" + i + "<" + g + "> { void f() {} }",
+                    (g, i) -> "void C" + i + "<" + g + ">.f()"
+            )
+        };
+
+        Arrays.stream(tests).forEach(t -> {
+                t.assertDoc("T");
+                t.assertDoc("T extends Object",
+                        "T");
+                t.assertDoc("T extends String");
+                t.assertDoc("T extends java.lang.String",
+                        "T extends String");
+                t.assertDoc("T extends Number & Comparable<T>");
+                t.assertDoc("T extends java.io.Serializable & CharSequence");
+                t.assertDoc("K, D, M extends java.util.Map<K, D>",
+                        "K, D, M extends java.util.Map<K,D>");
+        });
     }
 
     public void testVarArgs() {
diff --git a/langtools/test/jdk/jshell/DropTest.java b/langtools/test/jdk/jshell/DropTest.java
index d00003f..134922f 100644
--- a/langtools/test/jdk/jshell/DropTest.java
+++ b/langtools/test/jdk/jshell/DropTest.java
@@ -23,14 +23,14 @@
 
 /*
  * @test
- * @bug 8081431 8080069
+ * @bug 8081431 8080069 8167128
  * @summary Test of JShell#drop().
  * @build KullaTesting TestingInputStream
  * @run testng DropTest
  */
 
 import jdk.jshell.DeclarationSnippet;
-import jdk.jshell.PersistentSnippet;
+import jdk.jshell.Snippet;
 import jdk.jshell.VarSnippet;
 import org.testng.annotations.Test;
 
@@ -40,9 +40,9 @@
 public class DropTest extends KullaTesting {
 
     public void testDrop() {
-        PersistentSnippet var = varKey(assertEval("int x;"));
-        PersistentSnippet method = methodKey(assertEval("int mu() { return x * 4; }"));
-        PersistentSnippet clazz = classKey(assertEval("class C { String v() { return \"#\" + mu(); } }"));
+        Snippet var = varKey(assertEval("int x;"));
+        Snippet method = methodKey(assertEval("int mu() { return x * 4; }"));
+        Snippet clazz = classKey(assertEval("class C { String v() { return \"#\" + mu(); } }"));
         assertDrop(var,
                 ste(var, VALID, DROPPED, true, null),
                 ste(method, VALID, RECOVERABLE_DEFINED, false, var));
@@ -62,7 +62,7 @@
         assertEval("int x = 10;", "10",
                 added(VALID),
                 ste(method, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET));
-        PersistentSnippet c0 = varKey(assertEval("C c0 = new C();"));
+        Snippet c0 = varKey(assertEval("C c0 = new C();"));
         assertEval("c0.v();", "\"#40\"");
         assertEval("C c = new C();",
                 ste(MAIN_SNIPPET, VALID, VALID, false, null),
@@ -88,8 +88,8 @@
     }
 
     public void testDropImport() {
-        PersistentSnippet imp = importKey(assertEval("import java.util.*;"));
-        PersistentSnippet decl = varKey(
+        Snippet imp = importKey(assertEval("import java.util.*;"));
+        Snippet decl = varKey(
                 assertEval("List<Integer> list = Arrays.asList(1, 2, 3);", "[1, 2, 3]"));
         assertEval("list;", "[1, 2, 3]");
         assertDrop(imp,
@@ -100,8 +100,13 @@
         assertDeclareFail("list;", "compiler.err.cant.resolve.location");
     }
 
+    public void testDropStatement() {
+        Snippet x = key(assertEval("if (true);"));
+        assertDrop(x, ste(x, VALID, DROPPED, true, null));
+    }
+
     public void testDropVarToMethod() {
-        PersistentSnippet x = varKey(assertEval("int x;"));
+        Snippet x = varKey(assertEval("int x;"));
         DeclarationSnippet method = methodKey(assertEval("double mu() { return x * 4; }"));
         assertEval("x == 0;", "true");
         assertEval("mu() == 0.0;", "true");
@@ -118,7 +123,7 @@
     }
 
     public void testDropMethodToMethod() {
-        PersistentSnippet a = methodKey(assertEval("double a() { return 2; }"));
+        Snippet a = methodKey(assertEval("double a() { return 2; }"));
         DeclarationSnippet b = methodKey(assertEval("double b() { return a() * 10; }"));
         assertEval("double c() { return b() * 3; }");
         DeclarationSnippet d = methodKey(assertEval("double d() { return c() + 1000; }"));
@@ -134,7 +139,7 @@
     }
 
     public void testDropClassToMethod() {
-        PersistentSnippet c = classKey(assertEval("class C { int f() { return 7; } }"));
+        Snippet c = classKey(assertEval("class C { int f() { return 7; } }"));
         DeclarationSnippet m = methodKey(assertEval("int m() { return new C().f(); }"));
         assertDrop(c,
                 ste(c, VALID, DROPPED, true, null),
@@ -145,7 +150,7 @@
     }
 
     public void testDropVarToClass() {
-        PersistentSnippet x = varKey(assertEval("int x;"));
+        Snippet x = varKey(assertEval("int x;"));
         DeclarationSnippet a = classKey(assertEval("class A { double a = 4 * x; }"));
         assertDrop(x,
                 DiagCheck.DIAG_OK,
@@ -160,7 +165,7 @@
     }
 
     public void testDropMethodToClass() {
-        PersistentSnippet x = methodKey(assertEval("int x() { return 0; }"));
+        Snippet x = methodKey(assertEval("int x() { return 0; }"));
         DeclarationSnippet a = classKey(assertEval("class A { double a = 4 * x(); }"));
         assertDrop(x,
                 DiagCheck.DIAG_OK,
@@ -174,10 +179,10 @@
     }
 
     public void testDropClassToClass() {
-        PersistentSnippet a = classKey(assertEval("class A {}"));
-        PersistentSnippet b = classKey(assertEval("class B extends A {}"));
-        PersistentSnippet c = classKey(assertEval("class C extends B {}"));
-        PersistentSnippet d = classKey(assertEval("class D extends C {}"));
+        Snippet a = classKey(assertEval("class A {}"));
+        Snippet b = classKey(assertEval("class B extends A {}"));
+        Snippet c = classKey(assertEval("class C extends B {}"));
+        Snippet d = classKey(assertEval("class D extends C {}"));
         assertDrop(a,
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
@@ -201,9 +206,9 @@
     public void testDropNoUpdate() {
         String as1 = "class A {}";
         String as2 = "class A extends java.util.ArrayList<Boolean> {}";
-        PersistentSnippet a = classKey(assertEval(as1, added(VALID)));
-        PersistentSnippet b = classKey(assertEval("class B extends A {}", added(VALID)));
-        PersistentSnippet ax = classKey(assertEval(as2,
+        Snippet a = classKey(assertEval(as1, added(VALID)));
+        Snippet b = classKey(assertEval("class B extends A {}", added(VALID)));
+        Snippet ax = classKey(assertEval(as2,
                 ste(MAIN_SNIPPET, VALID, VALID, true, null),
                 ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET),
                 ste(b, VALID, VALID, true, MAIN_SNIPPET)));
diff --git a/langtools/test/jdk/jshell/IdGeneratorTest.java b/langtools/test/jdk/jshell/IdGeneratorTest.java
index 38ccc1b..23727ae 100644
--- a/langtools/test/jdk/jshell/IdGeneratorTest.java
+++ b/langtools/test/jdk/jshell/IdGeneratorTest.java
@@ -35,7 +35,6 @@
 
 import jdk.jshell.EvalException;
 import jdk.jshell.JShell;
-import jdk.jshell.PersistentSnippet;
 import jdk.jshell.SnippetEvent;
 import jdk.jshell.UnresolvedReferenceException;
 import jdk.jshell.VarSnippet;
@@ -88,7 +87,7 @@
         try (JShell jShell = builder.build()) {
             List<SnippetEvent> eval = jShell.eval("int a, b;");
             checkIds(eval);
-            checkIds(jShell.drop((PersistentSnippet) eval.get(0).snippet()));
+            checkIds(jShell.drop(eval.get(0).snippet()));
         }
     }
 
diff --git a/langtools/test/jdk/jshell/IllegalArgumentExceptionTest.java b/langtools/test/jdk/jshell/IllegalArgumentExceptionTest.java
index 86fd431..3ba5910 100644
--- a/langtools/test/jdk/jshell/IllegalArgumentExceptionTest.java
+++ b/langtools/test/jdk/jshell/IllegalArgumentExceptionTest.java
@@ -31,7 +31,6 @@
 import java.util.function.Consumer;
 
 import jdk.jshell.DeclarationSnippet;
-import jdk.jshell.PersistentSnippet;
 import jdk.jshell.Snippet;
 import jdk.jshell.VarSnippet;
 import org.testng.annotations.Test;
@@ -64,7 +63,7 @@
     }
 
     public void testDrop() {
-        testIllegalArgumentException((key) -> getState().drop((PersistentSnippet) key));
+        testIllegalArgumentException((key) -> getState().drop(key));
     }
 
     public void testUnresolved() {
diff --git a/langtools/test/jdk/jshell/JShellStateClosedTest.java b/langtools/test/jdk/jshell/JShellStateClosedTest.java
index 5ab8678..2f8d121 100644
--- a/langtools/test/jdk/jshell/JShellStateClosedTest.java
+++ b/langtools/test/jdk/jshell/JShellStateClosedTest.java
@@ -33,7 +33,6 @@
 import jdk.jshell.DeclarationSnippet;
 import jdk.jshell.ImportSnippet;
 import jdk.jshell.MethodSnippet;
-import jdk.jshell.PersistentSnippet;
 import jdk.jshell.Snippet;
 import jdk.jshell.TypeDeclSnippet;
 import jdk.jshell.VarSnippet;
@@ -127,7 +126,7 @@
     }
 
     public void testDrop() {
-        testStateClosedException((key) -> getState().drop((PersistentSnippet) key));
+        testStateClosedException((key) -> getState().drop(key));
     }
 
     public void testUnresolved() {
diff --git a/langtools/test/jdk/jshell/KullaTesting.java b/langtools/test/jdk/jshell/KullaTesting.java
index c5062c4..1cf81441 100644
--- a/langtools/test/jdk/jshell/KullaTesting.java
+++ b/langtools/test/jdk/jshell/KullaTesting.java
@@ -54,7 +54,6 @@
 import jdk.jshell.ImportSnippet;
 import jdk.jshell.Snippet.Kind;
 import jdk.jshell.MethodSnippet;
-import jdk.jshell.PersistentSnippet;
 import jdk.jshell.Snippet.Status;
 import jdk.jshell.Snippet.SubKind;
 import jdk.jshell.TypeDeclSnippet;
@@ -733,15 +732,15 @@
         assertEquals(expectedSubKind.kind(), expectedKind, "Checking kind: ");
     }
 
-    public void assertDrop(PersistentSnippet key, STEInfo mainInfo, STEInfo... updates) {
+    public void assertDrop(Snippet key, STEInfo mainInfo, STEInfo... updates) {
         assertDrop(key, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, mainInfo, updates);
     }
 
-    public void assertDrop(PersistentSnippet key, DiagCheck diagMain, DiagCheck diagUpdates, STEInfo mainInfo, STEInfo... updates) {
+    public void assertDrop(Snippet key, DiagCheck diagMain, DiagCheck diagUpdates, STEInfo mainInfo, STEInfo... updates) {
         assertDrop(key, diagMain, diagUpdates, new EventChain(mainInfo, null, null, updates));
     }
 
-    public void assertDrop(PersistentSnippet key, DiagCheck diagMain, DiagCheck diagUpdates, EventChain... eventChains) {
+    public void assertDrop(Snippet key, DiagCheck diagMain, DiagCheck diagUpdates, EventChain... eventChains) {
         checkEvents(() -> getState().drop(key), "drop(" + key + ")", diagMain, diagUpdates, eventChains);
     }
 
diff --git a/langtools/test/jdk/jshell/ReplaceTest.java b/langtools/test/jdk/jshell/ReplaceTest.java
index ca04958..7b57649 100644
--- a/langtools/test/jdk/jshell/ReplaceTest.java
+++ b/langtools/test/jdk/jshell/ReplaceTest.java
@@ -33,7 +33,6 @@
 import java.util.stream.Stream;
 import jdk.jshell.Snippet;
 import jdk.jshell.MethodSnippet;
-import jdk.jshell.PersistentSnippet;
 import jdk.jshell.TypeDeclSnippet;
 import jdk.jshell.VarSnippet;
 import jdk.jshell.DeclarationSnippet;
@@ -585,14 +584,14 @@
     }
 
     public void testForwardSingleImportMethodToClass1() {
-        PersistentSnippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }",
+        Snippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }",
                 added(RECOVERABLE_DEFINED)));
         assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.String.format;",
                 added(VALID),
                 ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("new A().s;", "\"10\"");
-        PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }",
+        Snippet format = methodKey(assertEval("void format(String s, int d) { }",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -605,14 +604,14 @@
     }
 
     public void testForwardSingleImportMethodToClass2() {
-        PersistentSnippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }",
+        Snippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }",
                 added(RECOVERABLE_DEFINED)));
         assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.String.format;",
                 added(VALID),
                 ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("new A().s();", "\"10\"");
-        PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }",
+        Snippet format = methodKey(assertEval("void format(String s, int d) { }",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -625,7 +624,7 @@
     }
 
     public void testForwardSingleImportClassToClass1() {
-        PersistentSnippet a = classKey(assertEval("class A { static List<Integer> list; }",
+        Snippet a = classKey(assertEval("class A { static List<Integer> list; }",
                 added(RECOVERABLE_NOT_DEFINED)));
         assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
         assertEval("import java.util.List;",
@@ -634,7 +633,7 @@
         assertEval("import java.util.Arrays;", added(VALID));
         assertEval("A.list = Arrays.asList(1, 2, 3);", "[1, 2, 3]");
 
-        PersistentSnippet list = classKey(assertEval("class List {}",
+        Snippet list = classKey(assertEval("class List {}",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -647,7 +646,7 @@
     }
 
     public void testForwardSingleImportClassToClass2() {
-        PersistentSnippet clsA = classKey(assertEval("class A extends ArrayList<Integer> { }",
+        Snippet clsA = classKey(assertEval("class A extends ArrayList<Integer> { }",
                 added(RECOVERABLE_NOT_DEFINED)));
         assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
         assertEval("import java.util.ArrayList;",
@@ -655,7 +654,7 @@
                 ste(clsA, RECOVERABLE_NOT_DEFINED, VALID, true, MAIN_SNIPPET));
         Snippet vara = varKey(assertEval("A a = new A();", "[]"));
 
-        PersistentSnippet arraylist = classKey(assertEval("class ArrayList {}",
+        Snippet arraylist = classKey(assertEval("class ArrayList {}",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -671,7 +670,7 @@
     }
 
     public void testForwardImportOnDemandMethodToClass1() {
-        PersistentSnippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }",
+        Snippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }",
                 added(RECOVERABLE_DEFINED)));
         assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.String.*;",
@@ -679,7 +678,7 @@
                 ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("A x = new A();");
         assertEval("x.s;", "\"10\"");
-        PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }",
+        Snippet format = methodKey(assertEval("void format(String s, int d) { }",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -693,14 +692,14 @@
     }
 
     public void testForwardImportOnDemandMethodToClass2() {
-        PersistentSnippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }",
+        Snippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }",
                 added(RECOVERABLE_DEFINED)));
         assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.String.*;",
                 added(VALID),
                 ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("new A().s();", "\"10\"");
-        PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }",
+        Snippet format = methodKey(assertEval("void format(String s, int d) { }",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -713,7 +712,7 @@
     }
 
     public void testForwardImportOnDemandClassToClass1() {
-        PersistentSnippet a = classKey(assertEval("class A { static List<Integer> list; }",
+        Snippet a = classKey(assertEval("class A { static List<Integer> list; }",
                 added(RECOVERABLE_NOT_DEFINED)));
         assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
         assertEval("import java.util.*;",
@@ -721,7 +720,7 @@
                 ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null));
         assertEval("A.list = Arrays.asList(1, 2, 3);", "[1, 2, 3]");
 
-        PersistentSnippet list = classKey(assertEval("class List {}",
+        Snippet list = classKey(assertEval("class List {}",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -734,7 +733,7 @@
     }
 
     public void testForwardImportOnDemandClassToClass2() {
-        PersistentSnippet clsA = classKey(assertEval("class A extends ArrayList<Integer> { }",
+        Snippet clsA = classKey(assertEval("class A extends ArrayList<Integer> { }",
                 added(RECOVERABLE_NOT_DEFINED)));
         assertDeclareFail("new A();", "compiler.err.cant.resolve.location");
         assertEval("import java.util.*;",
@@ -742,7 +741,7 @@
                 ste(clsA, RECOVERABLE_NOT_DEFINED, VALID, true, MAIN_SNIPPET));
         Snippet vara = varKey(assertEval("A a = new A();", "[]"));
 
-        PersistentSnippet arraylist = classKey(assertEval("class ArrayList {}",
+        Snippet arraylist = classKey(assertEval("class ArrayList {}",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -757,7 +756,7 @@
     }
 
     public void testForwardSingleImportFieldToClass1() {
-        PersistentSnippet a = classKey(assertEval("class A { static double pi() { return PI; } }",
+        Snippet a = classKey(assertEval("class A { static double pi() { return PI; } }",
                 added(RECOVERABLE_DEFINED)));
         assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.Math.PI;",
@@ -765,7 +764,7 @@
                 ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("Math.abs(A.pi() - 3.1415) < 0.001;", "true");
 
-        PersistentSnippet list = varKey(assertEval("String PI;",
+        Snippet list = varKey(assertEval("String PI;",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -778,7 +777,7 @@
     }
 
     public void testForwardSingleImportFieldToClass2() {
-        PersistentSnippet a = classKey(assertEval("class A { static double pi = PI; }",
+        Snippet a = classKey(assertEval("class A { static double pi = PI; }",
                 added(RECOVERABLE_DEFINED)));
         assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.Math.PI;",
@@ -786,7 +785,7 @@
                 ste(a, RECOVERABLE_DEFINED, VALID, true, null));
         assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true");
 
-        PersistentSnippet list = varKey(assertEval("String PI;",
+        Snippet list = varKey(assertEval("String PI;",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -799,7 +798,7 @@
     }
 
     public void testForwardImportOnDemandFieldToClass1() {
-        PersistentSnippet a = classKey(assertEval("class A { static double pi() { return PI; } }",
+        Snippet a = classKey(assertEval("class A { static double pi() { return PI; } }",
                 added(RECOVERABLE_DEFINED)));
         assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.Math.*;",
@@ -807,7 +806,7 @@
                 ste(a, RECOVERABLE_DEFINED, VALID, false, null));
         assertEval("Math.abs(A.pi() - 3.1415) < 0.001;", "true");
 
-        PersistentSnippet list = varKey(assertEval("String PI;",
+        Snippet list = varKey(assertEval("String PI;",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
@@ -820,7 +819,7 @@
     }
 
     public void testForwardImportOnDemandFieldToClass2() {
-        PersistentSnippet a = classKey(assertEval("class A { static double pi = PI; }",
+        Snippet a = classKey(assertEval("class A { static double pi = PI; }",
                 added(RECOVERABLE_DEFINED)));
         assertEvalUnresolvedException("new A();", "A", 1, 0);
         assertEval("import static java.lang.Math.*;",
@@ -828,7 +827,7 @@
                 ste(a, RECOVERABLE_DEFINED, VALID, true, null));
         assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true");
 
-        PersistentSnippet list = varKey(assertEval("String PI;",
+        Snippet list = varKey(assertEval("String PI;",
                 DiagCheck.DIAG_OK,
                 DiagCheck.DIAG_ERROR,
                 added(VALID),
diff --git a/langtools/test/jdk/jshell/ToolCommandOptionTest.java b/langtools/test/jdk/jshell/ToolCommandOptionTest.java
index 96efdb0..14d4b6e 100644
--- a/langtools/test/jdk/jshell/ToolCommandOptionTest.java
+++ b/langtools/test/jdk/jshell/ToolCommandOptionTest.java
@@ -23,7 +23,7 @@
 
  /*
  * @test
- * @bug 8157395 8157393 8157517 8158738
+ * @bug 8157395 8157393 8157517 8158738  8167128
  * @summary Tests of jshell comand options, and undoing operations
  * @modules jdk.jshell/jdk.internal.jshell.tool
  * @build ToolCommandOptionTest ReplToolTesting
@@ -101,13 +101,17 @@
                         "|  Unknown option: -all -- /drop -all"),
                 (a) -> assertCommandOutputStartsWith(a, "/drop z",
                         "|  No such snippet: z"),
-                (a) -> assertCommandOutputStartsWith(a, "/drop 2",
-                        "|  This command does not accept the snippet '2' : x"),
+                (a) -> assertCommand(a, "/drop 2",
+                        ""),
+                (a) -> assertCommandOutputStartsWith(a, "23qwl",
+                        "|  Error:"),
+                (a) -> assertCommandOutputStartsWith(a, "/drop e1",
+                        "|  This command does not accept the snippet 'e1' : 23qwl"),
                 (a) -> assertCommand(a, "/dr x y",
                         "|  dropped variable x\n" +
                         "|  dropped variable y"),
                 (a) -> assertCommand(a, "/list",
-                        "2 : x")
+                        "")
         );
     }
 
diff --git a/langtools/test/jdk/jshell/ToolSimpleTest.java b/langtools/test/jdk/jshell/ToolSimpleTest.java
index 1b0f77d..160a08f 100644
--- a/langtools/test/jdk/jshell/ToolSimpleTest.java
+++ b/langtools/test/jdk/jshell/ToolSimpleTest.java
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897
+ * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128
  * @summary Simple jshell tool tests
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -217,6 +217,9 @@
                 a -> dropClass(a, "/drop 3", "class A", "|  dropped class A"),
                 a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
                 a -> dropImport(a, "/drop 4", "import java.util.stream.*", ""),
+                a -> assertCommand(a, "for (int i = 0; i < 10; ++i) {}", ""),
+                a -> assertCommand(a, "/drop 5", ""),
+                a -> assertCommand(a, "/list", ""),
                 a -> assertCommandCheckOutput(a, "/vars", assertVariables()),
                 a -> assertCommandCheckOutput(a, "/methods", assertMethods()),
                 a -> assertCommandCheckOutput(a, "/types", assertClasses()),
@@ -244,6 +247,7 @@
                         assertStartsWith("|  In the /drop argument, please specify an import, variable, method, or class to drop.")),
                 a -> assertVariable(a, "int", "a"),
                 a -> assertCommand(a, "a", "a ==> 0"),
+                a -> assertCommand(a, "/drop 2", ""),
                 a -> assertCommand(a, "/drop 2",
                         "|  This command does not accept the snippet '2' : a\n" +
                         "|  See /types, /methods, /vars, or /list")
diff --git a/langtools/test/tools/javac/8167000/T8167000.java b/langtools/test/tools/javac/8167000/T8167000.java
new file mode 100644
index 0000000..40576c5
--- /dev/null
+++ b/langtools/test/tools/javac/8167000/T8167000.java
@@ -0,0 +1,34 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8167000
+ * @summary Refine handling of multiple maximally specific abstract methods
+ * @compile/fail/ref=T8167000.out -XDrawDiagnostics -Werror -Xlint:unchecked T8167000.java
+ */
+
+import java.util.*;
+
+class T8167000 {
+
+    interface J {
+        List<Number> getAll(String str);
+    }
+
+    interface K {
+        Collection<Integer> getAll(String str);
+    }
+
+    interface L {
+        List getAll(String str);
+    }
+
+    interface M {
+        Collection getAll(String str);
+    }
+
+
+    static abstract class E implements J, K, L, M {
+        void test() {
+            List<String> l = getAll(""); //check that we get an unchecked warning here
+        }
+    }
+}
diff --git a/langtools/test/tools/javac/8167000/T8167000.out b/langtools/test/tools/javac/8167000/T8167000.out
new file mode 100644
index 0000000..de6b691
--- /dev/null
+++ b/langtools/test/tools/javac/8167000/T8167000.out
@@ -0,0 +1,4 @@
+T8167000.java:31:36: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List<java.lang.String>
+- compiler.err.warnings.and.werror
+1 error
+1 warning
diff --git a/langtools/test/tools/javac/8167000/T8167000b.java b/langtools/test/tools/javac/8167000/T8167000b.java
new file mode 100644
index 0000000..d29575c
--- /dev/null
+++ b/langtools/test/tools/javac/8167000/T8167000b.java
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8167000
+ * @summary Refine handling of multiple maximally specific abstract methods
+ * @compile/fail/ref=T8167000b.out -XDrawDiagnostics T8167000b.java
+ */
+public class T8167000b {
+    interface A {
+        Integer m() throws Throwable;
+    }
+
+    interface B<X extends Throwable> {
+        Object m() throws X;
+    }
+
+    static abstract class E<T extends Throwable> implements A, B<T> {
+        void test() {
+            Integer l = m(); //error: unhandled T
+        }
+    }
+}
diff --git a/langtools/test/tools/javac/8167000/T8167000b.out b/langtools/test/tools/javac/8167000/T8167000b.out
new file mode 100644
index 0000000..0f7b93d
--- /dev/null
+++ b/langtools/test/tools/javac/8167000/T8167000b.out
@@ -0,0 +1,2 @@
+T8167000b.java:18:26: compiler.err.unreported.exception.need.to.catch.or.throw: T
+1 error
diff --git a/langtools/test/tools/javac/8167000/T8167000c.java b/langtools/test/tools/javac/8167000/T8167000c.java
new file mode 100644
index 0000000..fbbcd1f
--- /dev/null
+++ b/langtools/test/tools/javac/8167000/T8167000c.java
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8167000
+ * @summary Refine handling of multiple maximally specific abstract methods
+ * @compile/fail/ref=T8167000c.out -XDrawDiagnostics T8167000c.java
+ */
+public class T8167000c<X extends Throwable> {
+    interface A {
+        Integer m() throws Throwable;
+    }
+
+    interface B<X extends Throwable> {
+        Object m() throws X;
+    }
+
+    interface E<T extends Throwable> extends A, B<T> { }
+
+    void test() {
+        E<X> ex = () -> { throw new Throwable(); };
+    }
+}
diff --git a/langtools/test/tools/javac/8167000/T8167000c.out b/langtools/test/tools/javac/8167000/T8167000c.out
new file mode 100644
index 0000000..ac86f9f
--- /dev/null
+++ b/langtools/test/tools/javac/8167000/T8167000c.out
@@ -0,0 +1,4 @@
+T8167000c.java:19:27: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Throwable
+- compiler.note.unchecked.filename: T8167000c.java
+- compiler.note.unchecked.recompile
+1 error
diff --git a/langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java b/langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java
index 2fbf0b7..771df1d 100644
--- a/langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java
+++ b/langtools/test/tools/javac/generics/rawOverride/7062745/GenericOverrideTest.java
@@ -120,10 +120,10 @@
             }
         }
 
-        boolean moreSpecificThan(TypeArgumentKind that, boolean strict) {
+        boolean moreSpecificThan(TypeArgumentKind that) {
             switch (this) {
                 case NONE:
-                    return that == this || !strict;
+                    return that == this;
                 case UNBOUND:
                     return that == this || that == NONE;
                 case INTEGER:
@@ -198,6 +198,7 @@
 
     void check(Result<?> res) {
         boolean errorExpected = false;
+        boolean loose = false;
         int mostSpecific = 0;
 
         //first check that either |R1| <: |R2| or |R2| <: |R1|
@@ -208,39 +209,43 @@
             } else {
                 mostSpecific = rets[0].moreSpecificThan(rets[1]) ? 1 : 2;
             }
+        } else if (sigs[0] != sigs[1]) {
+            mostSpecific = sigs[0] == SignatureKind.GENERIC ? 2 : 1;
+            loose = true;
         }
 
         //check that either TA1 <= TA2 or TA2 <= TA1 (unless most specific return found above is raw)
         if (!errorExpected) {
             if (targs[0] != targs[1]) {
-                boolean useStrictCheck = targs[0].moreSpecificThan(targs[1], true) ||
-                        targs[1].moreSpecificThan(targs[0], true);
-                if (!targs[0].moreSpecificThan(targs[1], useStrictCheck) &&
-                        !targs[1].moreSpecificThan(targs[0], useStrictCheck)) {
+                boolean ta1ms = targs[0].moreSpecificThan(targs[1]);
+                boolean ta2ms = targs[1].moreSpecificThan(targs[0]);
+                if (!ta1ms && !ta2ms) {
                     errorExpected = true;
+                } else if (mostSpecific != 0) {
+                    errorExpected = !loose && targs[mostSpecific - 1] != TypeArgumentKind.NONE &&
+                            (mostSpecific == 1 ? !ta1ms : !ta2ms);
                 } else {
-                    int mostSpecific2 = targs[0].moreSpecificThan(targs[1], useStrictCheck) ? 1 : 2;
-                    if (mostSpecific != 0 && mostSpecific2 != mostSpecific) {
-                        errorExpected = mostSpecific == 1 ?
-                                targs[0] != TypeArgumentKind.NONE :
-                                targs[1] != TypeArgumentKind.NONE;
-                    } else {
-                        mostSpecific = mostSpecific2;
-                    }
+                    mostSpecific = ta1ms ? 1 : 2;
                 }
-            } else if (mostSpecific == 0) {
-                //when no signature is better than the other, an arbitrary choice
-                //must be made - javac always picks the second signature
-                mostSpecific = 2;
             }
         }
 
-        //finally, check that most specific return type is compatible with expected type
+        if (mostSpecific == 0) {
+            //when no signature is better than the other, an arbitrary choice
+            //must be made - javac always picks the second signature
+            mostSpecific = 2;
+        }
+
         if (!errorExpected) {
             ReturnTypeKind msrt = mostSpecific == 1 ? rets[0] : rets[1];
             TypeArgumentKind msta = mostSpecific == 1 ? targs[0] : targs[1];
             SignatureKind mssig = mostSpecific == 1 ? sigs[0] : sigs[1];
 
+            //check that most specific is subsignature
+            errorExpected = sigs[0] != sigs[1] &&
+                    mssig == SignatureKind.GENERIC;
+
+            //finally, check that most specific return type is compatible with expected type
             if (!msrt.moreSpecificThan(rets[2]) ||
                     !msta.assignableTo(targs[2], mssig, level)) {
                 errorExpected = true;
diff --git a/langtools/test/tools/javac/modules/EdgeCases.java b/langtools/test/tools/javac/modules/EdgeCases.java
index 214115a..13af55f 100644
--- a/langtools/test/tools/javac/modules/EdgeCases.java
+++ b/langtools/test/tools/javac/modules/EdgeCases.java
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8154283
+ * @bug 8154283 8167320
  * @summary tests for multi-module mode compilation
  * @library /tools/lib
  * @modules
@@ -54,6 +54,7 @@
 //import com.sun.source.util.JavacTask; // conflicts with toolbox.JavacTask
 import com.sun.tools.javac.api.JavacTaskImpl;
 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
+import com.sun.tools.javac.code.Symtab;
 
 import toolbox.JarTask;
 import toolbox.JavacTask;
@@ -449,4 +450,12 @@
         }
     }
 
+    @Test
+    public void testGetDirectivesComplete(Path base) throws Exception {
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        JavacTaskImpl task = (JavacTaskImpl) compiler.getTask(null, null, null, null, null, null);
+        Symtab syms = Symtab.instance(task.getContext());
+
+        syms.java_base.getDirectives();
+    }
 }
diff --git a/langtools/test/tools/javac/modules/ModulePathTest.java b/langtools/test/tools/javac/modules/ModulePathTest.java
index 06785ee..ba7c48d 100644
--- a/langtools/test/tools/javac/modules/ModulePathTest.java
+++ b/langtools/test/tools/javac/modules/ModulePathTest.java
@@ -29,7 +29,7 @@
  *      jdk.compiler/com.sun.tools.javac.api
  *      jdk.compiler/com.sun.tools.javac.main
  *      jdk.jdeps/com.sun.tools.javap
- *      jdk.jlink/jdk.tools.jmod
+ *      jdk.jlink
  * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.ModuleBuilder
  *      ModuleTestBase
  * @run main ModulePathTest
@@ -39,6 +39,7 @@
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.spi.ToolProvider;
 
 import toolbox.JarTask;
 import toolbox.JavacTask;
@@ -420,6 +421,9 @@
                 "--class-path", dir.toString(),
                 jmod.toString()
         };
-        jdk.tools.jmod.Main.run(args, System.out);
+        ToolProvider jmodTool = ToolProvider.findFirst("jmod").orElseThrow(() ->
+                new RuntimeException("jmod tool not found")
+        );
+        jmodTool.run(System.out, System.err, args);
     }
 }
diff --git a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestRelease.java b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestRelease.java
new file mode 100644
index 0000000..d1c833e
--- /dev/null
+++ b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestRelease.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/*
+ * @test
+ * @bug 8167965
+ * @summary Test proper handling of the --release option.
+ * @modules jdk.jdeps/com.sun.tools.jdeprscan
+ * @build jdk.jdeprscan.TestRelease
+ * @run testng jdk.jdeprscan.TestRelease
+ */
+
+package jdk.jdeprscan;
+
+import com.sun.tools.jdeprscan.Main;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+public class TestRelease {
+    static boolean invoke(String arg) {
+        return Main.call(System.out, System.err, "--list", "--release", arg);
+    }
+
+    @Test
+    public void testSuccess() {
+        assertTrue(invoke("6"));
+        assertTrue(invoke("7"));
+        assertTrue(invoke("8"));
+        assertTrue(invoke("9"));
+    }
+
+    @Test
+    public void testFailure() {
+        assertFalse(invoke("5"));
+    }
+}