--- a/.hgtags Wed Oct 04 11:52:07 2017 -0700
+++ b/.hgtags Wed Oct 04 20:01:19 2017 +0000
@@ -449,3 +449,4 @@
e5357aa85dadacc6562175ff74714fecfb4470cf jdk-10+22
22850b3a55240253841b9a425ad60a7fcdb22d47 jdk-10+23
3b201865d5c1f244f555cad58da599c9261286d8 jdk-10+24
+8eb5e3ccee560c28ac9b1df2670adac2b3d36fad jdk-10+25
--- a/bin/jib.sh Wed Oct 04 11:52:07 2017 -0700
+++ b/bin/jib.sh Wed Oct 04 20:01:19 2017 +0000
@@ -28,8 +28,8 @@
mydir="$(dirname "${BASH_SOURCE[0]}")"
myname="$(basename "${BASH_SOURCE[0]}")"
-installed_jib_script=${mydir}/../../.jib/jib
-install_data=${mydir}/../../.jib/.data
+installed_jib_script=${mydir}/../.jib/jib
+install_data=${mydir}/../.jib/.data
setup_url() {
if [ -f ~/.config/jib/jib.conf ]; then
@@ -42,7 +42,7 @@
jib_revision="2.0-SNAPSHOT"
jib_ext="jib.sh.gz"
- closed_script="${mydir}/../../../closed/conf/jib-install.conf"
+ closed_script="${mydir}/../../closed/make/conf/jib-install.conf"
if [ -f "${closed_script}" ]; then
source "${closed_script}"
fi
--- a/doc/nashorn/JavaScriptingProgrammersGuide.html Wed Oct 04 11:52:07 2017 -0700
+++ b/doc/nashorn/JavaScriptingProgrammersGuide.html Wed Oct 04 20:01:19 2017 +0000
@@ -127,7 +127,7 @@
<hr>
<span><a name="package" id="package"></a></span>
<h2><span>Scripting Package</span></h2>
-<p><span>The Java Scripting functionality is in the <code><a href="http://docs.oracle.com/javase/6/docs/api/javax/script/package-summary.html">javax.script</a></code>
+<p><span>The Java Scripting functionality is in the <code><a href="http://docs.oracle.com/javase/9/docs/api/javax/script/package-summary.html">javax.script</a></code>
package. This is a relatively small, simple API. The starting point
of the scripting API is the <code>ScriptEngineManager</code> class.
A ScriptEngineManager object can discover script engines through
--- a/make/BuildNashorn.gmk Wed Oct 04 11:52:07 2017 -0700
+++ b/make/BuildNashorn.gmk Wed Oct 04 20:01:19 2017 +0000
@@ -41,7 +41,7 @@
$(eval $(call SetupJavaCompiler, GENERATE_NEWBYTECODE_DEBUG, \
JVM := $(JAVA_JAVAC), \
JAVAC := $(NEW_JAVAC), \
- FLAGS := -g -source 9 -target 9 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
+ FLAGS := -g -source 10 -target 10 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
--system none --module-source-path $(call GetModuleSrcPath), \
SERVER_DIR := $(SJAVAC_SERVER_DIR), \
SERVER_JVM := $(SJAVAC_SERVER_JAVA)))
--- a/make/InitSupport.gmk Wed Oct 04 11:52:07 2017 -0700
+++ b/make/InitSupport.gmk Wed Oct 04 20:01:19 2017 +0000
@@ -36,7 +36,7 @@
# Include the corresponding closed file, if present.
# Normal hook mechanism cannot be used since we have no SPEC.
- -include $(topdir)/closed/make/InitSupport.gmk
+ -include $(topdir)/../closed/make/InitSupport.gmk
##############################################################################
# Helper functions for the initial part of Init.gmk, before the spec file is
--- a/make/autoconf/flags.m4 Wed Oct 04 11:52:07 2017 -0700
+++ b/make/autoconf/flags.m4 Wed Oct 04 20:01:19 2017 +0000
@@ -1311,6 +1311,7 @@
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDK}"
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
+ $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
$2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \
-libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@@ -1388,6 +1389,7 @@
AC_SUBST($2JDKEXE_LIBS)
AC_SUBST($2LDFLAGS_CXX_JDK)
AC_SUBST($2LDFLAGS_HASH_STYLE)
+ AC_SUBST($2LDFLAGS_NO_EXEC_STACK)
AC_SUBST($2JVM_CFLAGS)
AC_SUBST($2JVM_LDFLAGS)
--- a/make/autoconf/generated-configure.sh Wed Oct 04 11:52:07 2017 -0700
+++ b/make/autoconf/generated-configure.sh Wed Oct 04 20:01:19 2017 +0000
@@ -723,6 +723,7 @@
OPENJDK_BUILD_JVM_ASFLAGS
OPENJDK_BUILD_JVM_LDFLAGS
OPENJDK_BUILD_JVM_CFLAGS
+OPENJDK_BUILD_LDFLAGS_NO_EXEC_STACK
OPENJDK_BUILD_LDFLAGS_HASH_STYLE
OPENJDK_BUILD_LDFLAGS_CXX_JDK
OPENJDK_BUILD_JDKEXE_LIBS
@@ -738,6 +739,7 @@
JVM_ASFLAGS
JVM_LDFLAGS
JVM_CFLAGS
+LDFLAGS_NO_EXEC_STACK
LDFLAGS_HASH_STYLE
LDFLAGS_CXX_JDK
JDKEXE_LIBS
@@ -5115,7 +5117,7 @@
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1506333008
+DATE_WHEN_GENERATED=1506397140
###############################################################################
#
@@ -52024,6 +52026,7 @@
LDFLAGS_JDKLIB="${LDFLAGS_JDK}"
LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
+ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \
-libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@@ -52109,6 +52112,7 @@
+
# Special extras...
if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
if test "x$OPENJDK_BUILD_CPU_ARCH" = "xsparc"; then
@@ -52903,6 +52907,7 @@
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDK}"
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
+ OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \
-libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@@ -52988,6 +52993,7 @@
+
# Tests are only ever compiled for TARGET
# Flags for compiling test libraries
CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"
--- a/make/autoconf/spec.gmk.in Wed Oct 04 11:52:07 2017 -0700
+++ b/make/autoconf/spec.gmk.in Wed Oct 04 20:01:19 2017 +0000
@@ -387,6 +387,7 @@
CXXFLAGS_JDKEXE:=@CXXFLAGS_JDKEXE@
LDFLAGS_HASH_STYLE := @LDFLAGS_HASH_STYLE@
+LDFLAGS_NO_EXEC_STACK := @LDFLAGS_NO_EXEC_STACK@
JVM_CFLAGS := @JVM_CFLAGS@
JVM_CFLAGS_SYMBOLS := @JVM_CFLAGS_SYMBOLS@
--- a/make/common/Modules.gmk Wed Oct 04 11:52:07 2017 -0700
+++ b/make/common/Modules.gmk Wed Oct 04 20:01:19 2017 +0000
@@ -58,7 +58,6 @@
java.rmi \
java.security.sasl \
java.xml \
- jdk.httpserver \
jdk.internal.vm.ci \
jdk.management \
jdk.management.agent \
@@ -112,6 +111,7 @@
jdk.crypto.cryptoki \
jdk.crypto.ec \
jdk.dynalink \
+ jdk.httpserver \
jdk.incubator.httpclient \
jdk.internal.vm.compiler.management \
jdk.jsobject \
--- a/make/conf/jib-profiles.js Wed Oct 04 11:52:07 2017 -0700
+++ b/make/conf/jib-profiles.js Wed Oct 04 20:01:19 2017 +0000
@@ -900,6 +900,45 @@
}
},
+ "windows-x64-open": {
+ artifacts: {
+ jdk: {
+ local: "bundles/\\(jdk.*bin.tar.gz\\)",
+ remote: [
+ "bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+ + "_windows-x64_bin.tar.gz",
+ "bundles/openjdk/GPL/windows-x64/\\1"
+ ],
+ subdir: "jdk-" + data.version
+ },
+ jre: {
+ local: "bundles/\\(jre.*bin.tar.gz\\)",
+ remote: "bundles/openjdk/GPL/windows-x64/\\1"
+ },
+ test: {
+ local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
+ remote: [
+ "bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+ + "_windows-x64_bin-tests.tar.gz",
+ "bundles/openjdk/GPL/windows-x64/\\1"
+ ]
+ },
+ jdk_symbols: {
+ local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
+ remote: [
+ "bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+ + "_windows-x64_bin-symbols.tar.gz",
+ "bundles/openjdk/GPL/windows-x64/\\1"
+ ],
+ subdir: "jdk-" + data.version
+ },
+ jre_symbols: {
+ local: "bundles/\\(jre.*bin-symbols.tar.gz\\)",
+ remote: "bundles/openjdk/GPL/windows-x64/\\1",
+ }
+ }
+ },
+
"linux-x86-open-debug": {
artifacts: {
jdk: {
@@ -929,9 +968,10 @@
profiles["linux-x86-ri-debug"] = clone(profiles["linux-x86-open-debug"]);
profiles["macosx-x64-ri"] = clone(profiles["macosx-x64-open"]);
profiles["windows-x86-ri"] = clone(profiles["windows-x86-open"]);
+ profiles["windows-x64-ri"] = clone(profiles["windows-x64-open"]);
// Generate artifacts for ri profiles
- [ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri" ]
+ [ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri", "windows-x64-ri" ]
.forEach(function (name) {
// Rewrite all remote dirs to "bundles/openjdk/BCL/..."
for (artifactName in profiles[name].artifacts) {
@@ -947,6 +987,11 @@
configure_args: "--with-freetype-license="
+ input.get("freetype", "install_path")
+ "/freetype-2.7.1-v120-x86/freetype.md"
+ },
+ "windows-x64-ri": {
+ configure_args: "--with-freetype-license="
+ + input.get("freetype", "install_path")
+ + "/freetype-2.7.1-v120-x64/freetype.md"
}
};
profiles = concatObjects(profiles, profilesRiFreetype);
--- a/make/hotspot/lib/CompileLibjsig.gmk Wed Oct 04 11:52:07 2017 -0700
+++ b/make/hotspot/lib/CompileLibjsig.gmk Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, 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
@@ -36,7 +36,7 @@
ifeq ($(STATIC_BUILD), false)
ifeq ($(OPENJDK_TARGET_OS), linux)
LIBJSIG_CFLAGS := -fPIC -D_GNU_SOURCE -D_REENTRANT $(EXTRA_CFLAGS)
- LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) $(EXTRA_CFLAGS)
+ LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) ${LDFLAGS_NO_EXEC_STACK} $(EXTRA_CFLAGS)
LIBJSIG_LIBS := $(LIBDL)
# NOTE: The old build compiled this library without -soname.
--- a/make/langtools/src/classes/build/tools/symbolgenerator/TransitiveDependencies.java Wed Oct 04 11:52:07 2017 -0700
+++ b/make/langtools/src/classes/build/tools/symbolgenerator/TransitiveDependencies.java Wed Oct 04 20:01:19 2017 +0000
@@ -57,8 +57,8 @@
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
- List<String> options = Arrays.asList("-source", "9",
- "-target", "9",
+ List<String> options = Arrays.asList("-source", "10",
+ "-target", "10",
"-proc:only",
"--system", "none",
"--module-source-path", args[0],
--- a/make/nashorn/build.xml Wed Oct 04 11:52:07 2017 -0700
+++ b/make/nashorn/build.xml Wed Oct 04 20:01:19 2017 +0000
@@ -174,8 +174,6 @@
<target name="compile" depends="prepare" description="Compiles nashorn">
<javac srcdir="${dynalink.module.src.dir}"
destdir="${dynalink.module.classes.dir}"
- source="${javac.source}"
- target="${javac.target}"
debug="${javac.debug}"
encoding="${javac.encoding}"
includeantruntime="false" fork="true">
@@ -190,8 +188,6 @@
</delete>
<javac srcdir="${nashorn.module.src.dir}"
destdir="${nashorn.module.classes.dir}"
- source="${javac.source}"
- target="${javac.target}"
debug="${javac.debug}"
encoding="${javac.encoding}"
includeantruntime="false" fork="true">
@@ -207,8 +203,6 @@
</delete>
<javac srcdir="${nashorn.shell.module.src.dir}"
destdir="${nashorn.shell.module.classes.dir}"
- source="${javac.source}"
- target="${javac.target}"
debug="${javac.debug}"
encoding="${javac.encoding}"
includeantruntime="false" fork="true">
@@ -342,8 +336,6 @@
<javac srcdir="${test.src.dir}"
destdir="${build.test.classes.dir}"
classpath="${javac.test.classpath}"
- source="${javac.source}"
- target="${javac.target}"
debug="${javac.debug}"
encoding="${javac.encoding}"
includeantruntime="false" fork="true">
@@ -351,7 +343,7 @@
<compilerarg value="-Xlint:unchecked"/>
<compilerarg value="-Xlint:deprecation"/>
<compilerarg value="-Xdiags:verbose"/>
- <compilerarg line="${test.module.imports}"/>
+ <compilerarg line="${test.module.imports.compile.time}"/>
</javac>
<copy todir="${build.test.classes.dir}/META-INF/services">
--- a/make/nashorn/buildtools/nasgen/project.properties Wed Oct 04 11:52:07 2017 -0700
+++ b/make/nashorn/buildtools/nasgen/project.properties Wed Oct 04 20:01:19 2017 +0000
@@ -24,8 +24,6 @@
# source and target levels
build.compiler=modern
-javac.source=1.7
-javac.target=1.7
# This directory is removed when the project is cleaned:
nasgen.build.dir=../../../../build/nashorn/nasgen
--- a/make/nashorn/buildtools/nashorntask/project.properties Wed Oct 04 11:52:07 2017 -0700
+++ b/make/nashorn/buildtools/nashorntask/project.properties Wed Oct 04 20:01:19 2017 +0000
@@ -24,8 +24,6 @@
# source and target levels
build.compiler=modern
-javac.source=1.8
-javac.target=1.8
# This directory is removed when the project is cleaned:
nashorntask.build.dir=../../../../build/nashorn/nashorntask
--- a/make/nashorn/project.properties Wed Oct 04 11:52:07 2017 -0700
+++ b/make/nashorn/project.properties Wed Oct 04 20:01:19 2017 +0000
@@ -32,8 +32,6 @@
# source and target levels
build.compiler=modern
-javac.source=1.9
-javac.target=1.9
javadoc.option=\
-tag "implSpec:a:Implementation Requirements:" \
@@ -146,7 +144,7 @@
${file.reference.bsh.jar}${path.separator}\
${file.reference.snakeyaml.jar}
-test.module.imports=\
+test.module.imports.compile.time=\
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.ir=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.codegen=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.parser=ALL-UNNAMED \
@@ -159,7 +157,10 @@
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp.joni=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.tools=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
+ --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
+
+test.module.imports.runtime=\
+ ${test.module.imports.compile.time} \
--add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime=ALL-UNNAMED \
--add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv=ALL-UNNAMED
@@ -359,7 +360,7 @@
run.test.jvmargs.common=\
-server \
- ${test.module.imports} \
+ ${test.module.imports.runtime} \
${run.test.jvmargs.external} \
--add-modules jdk.scripting.nashorn.shell \
${nashorn.override.option} \
--- a/src/hotspot/share/prims/whitebox.cpp Wed Oct 04 11:52:07 2017 -0700
+++ b/src/hotspot/share/prims/whitebox.cpp Wed Oct 04 20:01:19 2017 +0000
@@ -73,6 +73,9 @@
#include "utilities/nativeCallStack.hpp"
#endif // INCLUDE_NMT
+#ifdef LINUX
+#include "utilities/elfFile.hpp"
+#endif
#define SIZE_T_MAX_VALUE ((size_t) -1)
@@ -1823,6 +1826,20 @@
DirectivesStack::pop(count);
WB_END
+// Checks that the library libfile has the noexecstack bit set.
+WB_ENTRY(jboolean, WB_CheckLibSpecifiesNoexecstack(JNIEnv* env, jobject o, jstring libfile))
+ jboolean ret = false;
+#ifdef LINUX
+ // Can't be in VM when we call JNI.
+ ThreadToNativeFromVM ttnfv(thread);
+ const char* lf = env->GetStringUTFChars(libfile, NULL);
+ CHECK_JNI_EXCEPTION_(env, 0);
+ ret = (jboolean) ElfFile::specifies_noexecstack(lf);
+ env->ReleaseStringUTFChars(libfile, lf);
+#endif
+ return ret;
+WB_END
+
#define CC (char*)
static JNINativeMethod methods[] = {
@@ -2027,6 +2044,8 @@
(void*)&WB_GetConcurrentGCPhases},
{CC"requestConcurrentGCPhase0", CC"(Ljava/lang/String;)Z",
(void*)&WB_RequestConcurrentGCPhase},
+ {CC"checkLibSpecifiesNoexecstack", CC"(Ljava/lang/String;)Z",
+ (void*)&WB_CheckLibSpecifiesNoexecstack},
};
#undef CC
--- a/src/java.base/share/classes/java/lang/ClassLoader.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java Wed Oct 04 20:01:19 2017 +0000
@@ -2160,10 +2160,12 @@
* if a package of the given {@code name} is already
* defined by this class loader
*
+ *
* @since 1.2
* @revised 9
* @spec JPMS
*
+ * @jvms 5.3 Run-time package
* @see <a href="{@docRoot}/../specs/jar/jar.html#sealing">
* The JAR File Specification: Package Sealing</a>
*/
@@ -2186,17 +2188,19 @@
}
/**
- * Returns a {@code Package} of the given <a href="#name">name</a> that has been
- * defined by this class loader.
+ * Returns a {@code Package} of the given <a href="#name">name</a> that
+ * has been defined by this class loader.
*
* @param name The <a href="#name">package name</a>
*
- * @return The {@code Package} of the given name defined by this class loader,
- * or {@code null} if not found
+ * @return The {@code Package} of the given name that has been defined
+ * by this class loader, or {@code null} if not found
*
* @throws NullPointerException
* if {@code name} is {@code null}.
*
+ * @jvms 5.3 Run-time package
+ *
* @since 9
* @spec JPMS
*/
@@ -2211,14 +2215,18 @@
}
/**
- * Returns all of the {@code Package}s defined by this class loader.
- * The returned array has no duplicated {@code Package}s of the same name.
+ * Returns all of the {@code Package}s that have been defined by
+ * this class loader. The returned array has no duplicated {@code Package}s
+ * of the same name.
*
* @apiNote This method returns an array rather than a {@code Set} or {@code Stream}
* for consistency with the existing {@link #getPackages} method.
*
- * @return The array of {@code Package} objects defined by this class loader;
- * or an zero length array if no package has been defined by this class loader.
+ * @return The array of {@code Package} objects that have been defined by
+ * this class loader; or an zero length array if no package has been
+ * defined by this class loader.
+ *
+ * @jvms 5.3 Run-time package
*
* @since 9
* @spec JPMS
@@ -2244,7 +2252,7 @@
* @param name
* The <a href="#name">package name</a>
*
- * @return The {@code Package} corresponding to the given name defined by
+ * @return The {@code Package} of the given name that has been defined by
* this class loader or its ancestors, or {@code null} if not found.
*
* @throws NullPointerException
@@ -2263,6 +2271,8 @@
* {@link ClassLoader#getDefinedPackage} method which returns
* a {@code Package} for the specified class loader.
*
+ * @see ClassLoader#getDefinedPackage(String)
+ *
* @since 1.2
* @revised 9
* @spec JPMS
@@ -2281,10 +2291,10 @@
}
/**
- * Returns all of the {@code Package}s defined by this class loader
- * and its ancestors. The returned array may contain more than one
- * {@code Package} object of the same package name, each defined by
- * a different class loader in the class loader hierarchy.
+ * Returns all of the {@code Package}s that have been defined by
+ * this class loader and its ancestors. The returned array may contain
+ * more than one {@code Package} object of the same package name, each
+ * defined by a different class loader in the class loader hierarchy.
*
* @apiNote The {@link #getPlatformClassLoader() platform class loader}
* may delegate to the application class loader. In other words,
@@ -2294,8 +2304,10 @@
* when invoked on the platform class loader, this method will not
* return any packages defined to the application class loader.
*
- * @return The array of {@code Package} objects defined by this
- * class loader and its ancestors
+ * @return The array of {@code Package} objects that have been defined by
+ * this class loader and its ancestors
+ *
+ * @see ClassLoader#getDefinedPackages()
*
* @since 1.2
* @revised 9
--- a/src/java.base/share/classes/java/lang/StackFrameInfo.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/StackFrameInfo.java Wed Oct 04 20:01:19 2017 +0000
@@ -29,6 +29,7 @@
import static java.lang.StackWalker.Option.*;
import java.lang.StackWalker.StackFrame;
+import java.lang.invoke.MethodType;
class StackFrameInfo implements StackFrame {
private final static JavaLangInvokeAccess JLIA =
@@ -79,6 +80,17 @@
}
@Override
+ public MethodType getMethodType() {
+ walker.ensureAccessEnabled(RETAIN_CLASS_REFERENCE);
+ return JLIA.getMethodType(memberName);
+ }
+
+ @Override
+ public String getDescriptor() {
+ return JLIA.getMethodDescriptor(memberName);
+ }
+
+ @Override
public int getByteCodeIndex() {
// bci not available for native methods
if (isNativeMethod())
--- a/src/java.base/share/classes/java/lang/StackWalker.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/StackWalker.java Wed Oct 04 20:01:19 2017 +0000
@@ -26,10 +26,12 @@
import jdk.internal.reflect.CallerSensitive;
-import java.util.*;
+import java.lang.invoke.MethodType;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
-import java.util.function.Predicate;
import java.util.stream.Stream;
/**
@@ -96,7 +98,7 @@
* @since 9
* @jvms 2.6
*/
- public static interface StackFrame {
+ public interface StackFrame {
/**
* Gets the <a href="ClassLoader.html#name">binary name</a>
* of the declaring class of the method represented by this stack frame.
@@ -128,6 +130,47 @@
public Class<?> getDeclaringClass();
/**
+ * Returns the {@link MethodType} representing the parameter types and
+ * the return type for the method represented by this stack frame.
+ *
+ * @implSpec
+ * The default implementation throws {@code UnsupportedOperationException}.
+ *
+ * @return the {@code MethodType} for this stack frame
+ *
+ * @throws UnsupportedOperationException if this {@code StackWalker}
+ * is not configured with {@link Option#RETAIN_CLASS_REFERENCE
+ * Option.RETAIN_CLASS_REFERENCE}.
+ *
+ * @since 10
+ */
+ public default MethodType getMethodType() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the <i>descriptor</i> of the method represented by
+ * this stack frame as defined by
+ * <cite>The Java Virtual Machine Specification</cite>.
+ *
+ * @implSpec
+ * The default implementation throws {@code UnsupportedOperationException}.
+ *
+ * @return the descriptor of the method represented by
+ * this stack frame
+ *
+ * @see MethodType#fromMethodDescriptorString(String, ClassLoader)
+ * @see MethodType#toMethodDescriptorString()
+ * @jvms 4.3.3 Method Descriptor
+ *
+ * @since 10
+ */
+ public default String getDescriptor() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ /**
* Returns the index to the code array of the {@code Code} attribute
* containing the execution point represented by this stack frame.
* The code array gives the actual bytes of Java Virtual Machine code
--- a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java Wed Oct 04 20:01:19 2017 +0000
@@ -28,6 +28,7 @@
import java.util.Arrays;
import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.LambdaForm.Kind.*;
+import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
import static java.lang.invoke.MethodHandleStatics.*;
/**
@@ -158,8 +159,11 @@
static final NamedFunction NF_getTarget;
static {
try {
- NF_getTarget = new NamedFunction(DelegatingMethodHandle.class
- .getDeclaredMethod("getTarget"));
+ MemberName member = new MemberName(DelegatingMethodHandle.class, "getTarget",
+ MethodType.methodType(MethodHandle.class), REF_invokeVirtual);
+ NF_getTarget = new NamedFunction(
+ MemberName.getFactory()
+ .resolveOrFail(REF_invokeVirtual, member, DelegatingMethodHandle.class, NoSuchMethodException.class));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
--- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Wed Oct 04 20:01:19 2017 +0000
@@ -753,42 +753,38 @@
return nf;
}
+ private static final MethodType OBJ_OBJ_TYPE = MethodType.methodType(Object.class, Object.class);
+
+ private static final MethodType LONG_OBJ_TYPE = MethodType.methodType(long.class, Object.class);
+
private static NamedFunction createFunction(byte func) {
try {
switch (func) {
case NF_internalMemberName:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("internalMemberName", Object.class));
+ return getNamedFunction("internalMemberName", OBJ_OBJ_TYPE);
case NF_internalMemberNameEnsureInit:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
+ return getNamedFunction("internalMemberNameEnsureInit", OBJ_OBJ_TYPE);
case NF_ensureInitialized:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("ensureInitialized", Object.class));
+ return getNamedFunction("ensureInitialized", MethodType.methodType(void.class, Object.class));
case NF_fieldOffset:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("fieldOffset", Object.class));
+ return getNamedFunction("fieldOffset", LONG_OBJ_TYPE);
case NF_checkBase:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("checkBase", Object.class));
+ return getNamedFunction("checkBase", OBJ_OBJ_TYPE);
case NF_staticBase:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("staticBase", Object.class));
+ return getNamedFunction("staticBase", OBJ_OBJ_TYPE);
case NF_staticOffset:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("staticOffset", Object.class));
+ return getNamedFunction("staticOffset", LONG_OBJ_TYPE);
case NF_checkCast:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("checkCast", Object.class, Object.class));
+ return getNamedFunction("checkCast", MethodType.methodType(Object.class, Object.class, Object.class));
case NF_allocateInstance:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("allocateInstance", Object.class));
+ return getNamedFunction("allocateInstance", OBJ_OBJ_TYPE);
case NF_constructorMethod:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("constructorMethod", Object.class));
+ return getNamedFunction("constructorMethod", OBJ_OBJ_TYPE);
case NF_UNSAFE:
- return new NamedFunction(new MemberName(MethodHandleStatics.class
- .getDeclaredField("UNSAFE")));
+ MemberName member = new MemberName(MethodHandleStatics.class, "UNSAFE", Unsafe.class, REF_getField);
+ return new NamedFunction(
+ MemberName.getFactory()
+ .resolveOrFail(REF_getField, member, DirectMethodHandle.class, NoSuchMethodException.class));
default:
throw newInternalError("Unknown function: " + func);
}
@@ -797,6 +793,15 @@
}
}
+ private static NamedFunction getNamedFunction(String name, MethodType type)
+ throws ReflectiveOperationException
+ {
+ MemberName member = new MemberName(DirectMethodHandle.class, name, type, REF_invokeStatic);
+ return new NamedFunction(
+ MemberName.getFactory()
+ .resolveOrFail(REF_invokeStatic, member, DirectMethodHandle.class, NoSuchMethodException.class));
+ }
+
static {
// The Holder class will contain pre-generated DirectMethodHandles resolved
// speculatively using MemberName.getFactory().resolveOrNull. However, that
--- a/src/java.base/share/classes/java/lang/invoke/Invokers.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java Wed Oct 04 20:01:19 2017 +0000
@@ -611,23 +611,17 @@
try {
switch (func) {
case NF_checkExactType:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkExactType", MethodHandle.class, MethodType.class));
+ return getNamedFunction("checkExactType", MethodType.methodType(void.class, MethodHandle.class, MethodType.class));
case NF_checkGenericType:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkGenericType", MethodHandle.class, MethodType.class));
+ return getNamedFunction("checkGenericType", MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
case NF_getCallSiteTarget:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("getCallSiteTarget", CallSite.class));
+ return getNamedFunction("getCallSiteTarget", MethodType.methodType(MethodHandle.class, CallSite.class));
case NF_checkCustomized:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkCustomized", MethodHandle.class));
+ return getNamedFunction("checkCustomized", MethodType.methodType(void.class, MethodHandle.class));
case NF_checkVarHandleGenericType:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class));
+ return getNamedFunction("checkVarHandleGenericType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
case NF_checkVarHandleExactType:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class));
+ return getNamedFunction("checkVarHandleExactType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
default:
throw newInternalError("Unknown function: " + func);
}
@@ -636,6 +630,15 @@
}
}
+ private static NamedFunction getNamedFunction(String name, MethodType type)
+ throws ReflectiveOperationException
+ {
+ MemberName member = new MemberName(Invokers.class, name, type, REF_invokeStatic);
+ return new NamedFunction(
+ MemberName.getFactory()
+ .resolveOrFail(REF_invokeStatic, member, Invokers.class, NoSuchMethodException.class));
+ }
+
private static class Lazy {
private static final MethodHandle MH_asSpreader;
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java Wed Oct 04 20:01:19 2017 +0000
@@ -162,6 +162,29 @@
return (MethodType) type;
}
+ /** Return the descriptor of this member, which
+ * must be a method or constructor.
+ */
+ String getMethodDescriptor() {
+ if (type == null) {
+ expandFromVM();
+ if (type == null) {
+ return null;
+ }
+ }
+ if (!isInvocable()) {
+ throw newIllegalArgumentException("not invocable, no method type");
+ }
+
+ // Get a snapshot of type which doesn't get changed by racing threads.
+ final Object type = this.type;
+ if (type instanceof String) {
+ return (String) type;
+ } else {
+ return getMethodType().toMethodDescriptorString();
+ }
+ }
+
/** Return the actual type under which this method or constructor must be invoked.
* For non-static methods or constructors, this is the type with a leading parameter,
* a reference to declaring class. For static methods, it is the same as the declared type.
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Oct 04 20:01:19 2017 +0000
@@ -1786,6 +1786,18 @@
}
@Override
+ public MethodType getMethodType(Object mname) {
+ MemberName memberName = (MemberName)mname;
+ return memberName.getMethodType();
+ }
+
+ @Override
+ public String getMethodDescriptor(Object mname) {
+ MemberName memberName = (MemberName)mname;
+ return memberName.getMethodDescriptor();
+ }
+
+ @Override
public boolean isNative(Object mname) {
MemberName memberName = (MemberName)mname;
return memberName.isNative();
--- a/src/java.base/share/classes/java/util/ArrayDeque.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/ArrayDeque.java Wed Oct 04 20:01:19 2017 +0000
@@ -211,7 +211,7 @@
}
/**
- * Increments i, mod modulus.
+ * Circularly increments i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int inc(int i, int modulus) {
@@ -220,7 +220,7 @@
}
/**
- * Decrements i, mod modulus.
+ * Circularly decrements i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int dec(int i, int modulus) {
@@ -233,7 +233,7 @@
* Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
* @return index 0 <= i < modulus
*/
- static final int add(int i, int distance, int modulus) {
+ static final int inc(int i, int distance, int modulus) {
if ((i += distance) - modulus >= 0) i -= modulus;
return i;
}
@@ -825,7 +825,7 @@
final int i, n;
return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0)
? null
- : new DeqSpliterator(i, cursor = add(i, n, es.length));
+ : new DeqSpliterator(i, cursor = inc(i, n, es.length));
}
public void forEachRemaining(Consumer<? super E> action) {
--- a/src/java.base/share/classes/java/util/HashMap.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/HashMap.java Wed Oct 04 20:01:19 2017 +0000
@@ -490,7 +490,7 @@
}
/**
- * Implements Map.putAll and Map constructor
+ * Implements Map.putAll and Map constructor.
*
* @param m the map
* @param evict false when initially constructing this map, else
@@ -557,7 +557,7 @@
}
/**
- * Implements Map.get and related methods
+ * Implements Map.get and related methods.
*
* @param hash hash for key
* @param key the key
@@ -612,7 +612,7 @@
}
/**
- * Implements Map.put and related methods
+ * Implements Map.put and related methods.
*
* @param hash hash for key
* @param key the key
@@ -700,7 +700,7 @@
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
+ Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
@@ -800,7 +800,7 @@
}
/**
- * Implements Map.remove and related methods
+ * Implements Map.remove and related methods.
*
* @param hash hash for key
* @param key the key
@@ -875,7 +875,7 @@
public boolean containsValue(Object value) {
Node<K,V>[] tab; V v;
if ((tab = table) != null && size > 0) {
- for (Node<K, V> e : tab) {
+ for (Node<K,V> e : tab) {
for (; e != null; e = e.next) {
if ((v = e.value) == value ||
(value != null && value.equals(v)))
@@ -927,7 +927,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node<K, V> e : tab) {
+ for (Node<K,V> e : tab) {
for (; e != null; e = e.next)
action.accept(e.key);
}
@@ -975,7 +975,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node<K, V> e : tab) {
+ for (Node<K,V> e : tab) {
for (; e != null; e = e.next)
action.accept(e.value);
}
@@ -1038,7 +1038,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node<K, V> e : tab) {
+ for (Node<K,V> e : tab) {
for (; e != null; e = e.next)
action.accept(e);
}
@@ -1335,7 +1335,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node<K, V> e : tab) {
+ for (Node<K,V> e : tab) {
for (; e != null; e = e.next)
action.accept(e.key, e.value);
}
@@ -1351,7 +1351,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node<K, V> e : tab) {
+ for (Node<K,V> e : tab) {
for (; e != null; e = e.next) {
e.value = function.apply(e.key, e.value);
}
@@ -1394,9 +1394,10 @@
}
/**
- * Save the state of the {@code HashMap} instance to a stream (i.e.,
- * serialize it).
+ * Saves this map to a stream (that is, serializes it).
*
+ * @param s the stream
+ * @throws IOException if an I/O error occurs
* @serialData The <i>capacity</i> of the HashMap (the length of the
* bucket array) is emitted (int), followed by the
* <i>size</i> (an int, the number of key-value
@@ -1415,8 +1416,11 @@
}
/**
- * Reconstitute the {@code HashMap} instance from a stream (i.e.,
- * deserialize it).
+ * Reconstitutes this map from a stream (that is, deserializes it).
+ * @param s the stream
+ * @throws ClassNotFoundException if the class of a serialized object
+ * could not be found
+ * @throws IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
@@ -1445,7 +1449,7 @@
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
@SuppressWarnings({"rawtypes","unchecked"})
- Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
+ Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
table = tab;
// Read the keys and values, and put the mappings in the HashMap
@@ -1830,7 +1834,7 @@
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
Node<K,V>[] tab;
if (size > 0 && (tab = table) != null) {
- for (Node<K, V> e : tab) {
+ for (Node<K,V> e : tab) {
for (; e != null; e = e.next) {
s.writeObject(e.key);
s.writeObject(e.value);
@@ -1951,7 +1955,6 @@
/**
* Forms tree of the nodes linked from this node.
- * @return root of tree
*/
final void treeify(Node<K,V>[] tab) {
TreeNode<K,V> root = null;
@@ -2089,8 +2092,11 @@
return;
if (root.parent != null)
root = root.root();
- if (root == null || root.right == null ||
- (rl = root.left) == null || rl.left == null) {
+ if (root == null
+ || (movable
+ && (root.right == null
+ || (rl = root.left) == null
+ || rl.left == null))) {
tab[index] = first.untreeify(map); // too small
return;
}
@@ -2319,7 +2325,7 @@
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
TreeNode<K,V> x) {
- for (TreeNode<K,V> xp, xpl, xpr;;) {
+ for (TreeNode<K,V> xp, xpl, xpr;;) {
if (x == null || x == root)
return root;
else if ((xp = x.parent) == null) {
--- a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Wed Oct 04 20:01:19 2017 +0000
@@ -2490,13 +2490,13 @@
for (Completion p = stack; p != null; p = p.next)
++count;
return super.toString() +
- ((r == null) ?
- ((count == 0) ?
- "[Not completed]" :
- "[Not completed, " + count + " dependents]") :
- (((r instanceof AltResult) && ((AltResult)r).ex != null) ?
- "[Completed exceptionally]" :
- "[Completed normally]"));
+ ((r == null)
+ ? ((count == 0)
+ ? "[Not completed]"
+ : "[Not completed, " + count + " dependents]")
+ : (((r instanceof AltResult) && ((AltResult)r).ex != null)
+ ? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
+ : "[Completed normally]"));
}
// jdk9 additions
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Wed Oct 04 20:01:19 2017 +0000
@@ -1394,8 +1394,8 @@
}
/**
- * Saves the state of the {@code ConcurrentHashMap} instance to a
- * stream (i.e., serializes it).
+ * Saves this map to a stream (that is, serializes it).
+ *
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
* @serialData
@@ -1439,7 +1439,7 @@
}
/**
- * Reconstitutes the instance from a stream (that is, deserializes it).
+ * Reconstitutes this map from a stream (that is, deserializes it).
* @param s the stream
* @throws ClassNotFoundException if the class of a serialized object
* could not be found
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Wed Oct 04 20:01:19 2017 +0000
@@ -58,6 +58,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.concurrent.atomic.LongAdder;
/**
* A scalable concurrent {@link ConcurrentNavigableMap} implementation.
@@ -86,12 +87,7 @@
* associated map using {@code put}, {@code putIfAbsent}, or
* {@code replace}, depending on exactly which effect you need.)
*
- * <p>Beware that, unlike in most collections, the {@code size}
- * method is <em>not</em> a constant-time operation. Because of the
- * asynchronous nature of these maps, determining the current number
- * of elements requires a traversal of the elements, and so may report
- * inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code putAll}, {@code equals},
+ * <p>Beware that bulk operations {@code putAll}, {@code equals},
* {@code toArray}, {@code containsValue}, and {@code clear} are
* <em>not</em> guaranteed to be performed atomically. For example, an
* iterator operating concurrently with a {@code putAll} operation
@@ -158,42 +154,35 @@
* be slow and space-intensive using AtomicMarkedReference), nodes
* use direct CAS'able next pointers. On deletion, instead of
* marking a pointer, they splice in another node that can be
- * thought of as standing for a marked pointer (indicating this by
- * using otherwise impossible field values). Using plain nodes
- * acts roughly like "boxed" implementations of marked pointers,
- * but uses new nodes only when nodes are deleted, not for every
- * link. This requires less space and supports faster
- * traversal. Even if marked references were better supported by
- * JVMs, traversal using this technique might still be faster
- * because any search need only read ahead one more node than
- * otherwise required (to check for trailing marker) rather than
- * unmasking mark bits or whatever on each read.
+ * thought of as standing for a marked pointer (see method
+ * unlinkNode). Using plain nodes acts roughly like "boxed"
+ * implementations of marked pointers, but uses new nodes only
+ * when nodes are deleted, not for every link. This requires less
+ * space and supports faster traversal. Even if marked references
+ * were better supported by JVMs, traversal using this technique
+ * might still be faster because any search need only read ahead
+ * one more node than otherwise required (to check for trailing
+ * marker) rather than unmasking mark bits or whatever on each
+ * read.
*
* This approach maintains the essential property needed in the HM
* algorithm of changing the next-pointer of a deleted node so
* that any other CAS of it will fail, but implements the idea by
- * changing the pointer to point to a different node, not by
- * marking it. While it would be possible to further squeeze
- * space by defining marker nodes not to have key/value fields, it
- * isn't worth the extra type-testing overhead. The deletion
- * markers are rarely encountered during traversal and are
- * normally quickly garbage collected. (Note that this technique
- * would not work well in systems without garbage collection.)
+ * changing the pointer to point to a different node (with
+ * otherwise illegal null fields), not by marking it. While it
+ * would be possible to further squeeze space by defining marker
+ * nodes not to have key/value fields, it isn't worth the extra
+ * type-testing overhead. The deletion markers are rarely
+ * encountered during traversal, are easily detected via null
+ * checks that are needed anyway, and are normally quickly garbage
+ * collected. (Note that this technique would not work well in
+ * systems without garbage collection.)
*
* In addition to using deletion markers, the lists also use
* nullness of value fields to indicate deletion, in a style
* similar to typical lazy-deletion schemes. If a node's value is
* null, then it is considered logically deleted and ignored even
- * though it is still reachable. This maintains proper control of
- * concurrent replace vs delete operations -- an attempted replace
- * must fail if a delete beat it by nulling field, and a delete
- * must return the last non-null value held in the field. (Note:
- * Null, rather than some special marker, is used for value fields
- * here because it just so happens to mesh with the Map API
- * requirement that method get returns null if there is no
- * mapping, which allows nodes to remain concurrently readable
- * even when deleted. Using any other marker value here would be
- * messy at best.)
+ * though it is still reachable.
*
* Here's the sequence of events for a deletion of node n with
* predecessor b and successor f, initially:
@@ -203,9 +192,8 @@
* +------+ +------+ +------+
*
* 1. CAS n's value field from non-null to null.
- * From this point on, no public operations encountering
- * the node consider this mapping to exist. However, other
- * ongoing insertions and deletions might still modify
+ * Traversals encountering a node with null value ignore it.
+ * However, ongoing insertions and deletions might still modify
* n's next pointer.
*
* 2. CAS n's next pointer to point to a new marker node.
@@ -228,12 +216,7 @@
* thread noticed during a traversal a node with null value and
* helped out by marking and/or unlinking. This helping-out
* ensures that no thread can become stuck waiting for progress of
- * the deleting thread. The use of marker nodes slightly
- * complicates helping-out code because traversals must track
- * consistent reads of up to four nodes (b, n, marker, f), not
- * just (b, n, f), although the next field of a marker is
- * immutable, and once a next field is CAS'ed to point to a
- * marker, it never again changes, so this requires less care.
+ * the deleting thread.
*
* Skip lists add indexing to this scheme, so that the base-level
* traversals start close to the locations being found, inserted
@@ -243,113 +226,101 @@
* b) that are not (structurally) deleted, otherwise retrying
* after processing the deletion.
*
- * Index levels are maintained as lists with volatile next fields,
- * using CAS to link and unlink. Races are allowed in index-list
- * operations that can (rarely) fail to link in a new index node
- * or delete one. (We can't do this of course for data nodes.)
- * However, even when this happens, the index lists remain sorted,
- * so correctly serve as indices. This can impact performance,
- * but since skip lists are probabilistic anyway, the net result
- * is that under contention, the effective "p" value may be lower
- * than its nominal value. And race windows are kept small enough
- * that in practice these failures are rare, even under a lot of
- * contention.
+ * Index levels are maintained using CAS to link and unlink
+ * successors ("right" fields). Races are allowed in index-list
+ * operations that can (rarely) fail to link in a new index node.
+ * (We can't do this of course for data nodes.) However, even
+ * when this happens, the index lists correctly guide search.
+ * This can impact performance, but since skip lists are
+ * probabilistic anyway, the net result is that under contention,
+ * the effective "p" value may be lower than its nominal value.
*
- * The fact that retries (for both base and index lists) are
- * relatively cheap due to indexing allows some minor
- * simplifications of retry logic. Traversal restarts are
- * performed after most "helping-out" CASes. This isn't always
- * strictly necessary, but the implicit backoffs tend to help
- * reduce other downstream failed CAS's enough to outweigh restart
- * cost. This worsens the worst case, but seems to improve even
- * highly contended cases.
- *
- * Unlike most skip-list implementations, index insertion and
- * deletion here require a separate traversal pass occurring after
- * the base-level action, to add or remove index nodes. This adds
- * to single-threaded overhead, but improves contended
- * multithreaded performance by narrowing interference windows,
- * and allows deletion to ensure that all index nodes will be made
- * unreachable upon return from a public remove operation, thus
- * avoiding unwanted garbage retention. This is more important
- * here than in some other data structures because we cannot null
- * out node fields referencing user keys since they might still be
- * read by other ongoing traversals.
+ * Index insertion and deletion sometimes require a separate
+ * traversal pass occurring after the base-level action, to add or
+ * remove index nodes. This adds to single-threaded overhead, but
+ * improves contended multithreaded performance by narrowing
+ * interference windows, and allows deletion to ensure that all
+ * index nodes will be made unreachable upon return from a public
+ * remove operation, thus avoiding unwanted garbage retention.
*
* Indexing uses skip list parameters that maintain good search
* performance while using sparser-than-usual indices: The
- * hardwired parameters k=1, p=0.5 (see method doPut) mean
- * that about one-quarter of the nodes have indices. Of those that
- * do, half have one level, a quarter have two, and so on (see
- * Pugh's Skip List Cookbook, sec 3.4). The expected total space
- * requirement for a map is slightly less than for the current
- * implementation of java.util.TreeMap.
+ * hardwired parameters k=1, p=0.5 (see method doPut) mean that
+ * about one-quarter of the nodes have indices. Of those that do,
+ * half have one level, a quarter have two, and so on (see Pugh's
+ * Skip List Cookbook, sec 3.4), up to a maximum of 62 levels
+ * (appropriate for up to 2^63 elements). The expected total
+ * space requirement for a map is slightly less than for the
+ * current implementation of java.util.TreeMap.
*
* Changing the level of the index (i.e, the height of the
- * tree-like structure) also uses CAS. The head index has initial
- * level/height of one. Creation of an index with height greater
- * than the current level adds a level to the head index by
- * CAS'ing on a new top-most head. To maintain good performance
- * after a lot of removals, deletion methods heuristically try to
- * reduce the height if the topmost levels appear to be empty.
- * This may encounter races in which it possible (but rare) to
- * reduce and "lose" a level just as it is about to contain an
- * index (that will then never be encountered). This does no
- * structural harm, and in practice appears to be a better option
- * than allowing unrestrained growth of levels.
+ * tree-like structure) also uses CAS. Creation of an index with
+ * height greater than the current level adds a level to the head
+ * index by CAS'ing on a new top-most head. To maintain good
+ * performance after a lot of removals, deletion methods
+ * heuristically try to reduce the height if the topmost levels
+ * appear to be empty. This may encounter races in which it is
+ * possible (but rare) to reduce and "lose" a level just as it is
+ * about to contain an index (that will then never be
+ * encountered). This does no structural harm, and in practice
+ * appears to be a better option than allowing unrestrained growth
+ * of levels.
*
- * The code for all this is more verbose than you'd like. Most
- * operations entail locating an element (or position to insert an
- * element). The code to do this can't be nicely factored out
- * because subsequent uses require a snapshot of predecessor
- * and/or successor and/or value fields which can't be returned
- * all at once, at least not without creating yet another object
- * to hold them -- creating such little objects is an especially
- * bad idea for basic internal search operations because it adds
- * to GC overhead. (This is one of the few times I've wished Java
- * had macros.) Instead, some traversal code is interleaved within
- * insertion and removal operations. The control logic to handle
- * all the retry conditions is sometimes twisty. Most search is
- * broken into 2 parts. findPredecessor() searches index nodes
- * only, returning a base-level predecessor of the key. findNode()
- * finishes out the base-level search. Even with this factoring,
- * there is a fair amount of near-duplication of code to handle
- * variants.
+ * This class provides concurrent-reader-style memory consistency,
+ * ensuring that read-only methods report status and/or values no
+ * staler than those holding at method entry. This is done by
+ * performing all publication and structural updates using
+ * (volatile) CAS, placing an acquireFence in a few access
+ * methods, and ensuring that linked objects are transitively
+ * acquired via dependent reads (normally once) unless performing
+ * a volatile-mode CAS operation (that also acts as an acquire and
+ * release). This form of fence-hoisting is similar to RCU and
+ * related techniques (see McKenney's online book
+ * https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html)
+ * It minimizes overhead that may otherwise occur when using so
+ * many volatile-mode reads. Using explicit acquireFences is
+ * logistically easier than targeting particular fields to be read
+ * in acquire mode: fences are just hoisted up as far as possible,
+ * to the entry points or loop headers of a few methods. A
+ * potential disadvantage is that these few remaining fences are
+ * not easily optimized away by compilers under exclusively
+ * single-thread use. It requires some care to avoid volatile
+ * mode reads of other fields. (Note that the memory semantics of
+ * a reference dependently read in plain mode exactly once are
+ * equivalent to those for atomic opaque mode.) Iterators and
+ * other traversals encounter each node and value exactly once.
+ * Other operations locate an element (or position to insert an
+ * element) via a sequence of dereferences. This search is broken
+ * into two parts. Method findPredecessor (and its specialized
+ * embeddings) searches index nodes only, returning a base-level
+ * predecessor of the key. Callers carry out the base-level
+ * search, restarting if encountering a marker preventing link
+ * modification. In some cases, it is possible to encounter a
+ * node multiple times while descending levels. For mutative
+ * operations, the reported value is validated using CAS (else
+ * retrying), preserving linearizability with respect to each
+ * other. Others may return any (non-null) value holding in the
+ * course of the method call. (Search-based methods also include
+ * some useless-looking explicit null checks designed to allow
+ * more fields to be nulled out upon removal, to reduce floating
+ * garbage, but which is not currently done, pending discovery of
+ * a way to do this with less impact on other operations.)
*
* To produce random values without interference across threads,
* we use within-JDK thread local random support (via the
* "secondary seed", to avoid interference with user-level
* ThreadLocalRandom.)
*
- * A previous version of this class wrapped non-comparable keys
- * with their comparators to emulate Comparables when using
- * comparators vs Comparables. However, JVMs now appear to better
- * handle infusing comparator-vs-comparable choice into search
- * loops. Static method cpr(comparator, x, y) is used for all
- * comparisons, which works well as long as the comparator
- * argument is set up outside of loops (thus sometimes passed as
- * an argument to internal methods) to avoid field re-reads.
- *
* For explanation of algorithms sharing at least a couple of
* features with this one, see Mikhail Fomitchev's thesis
* (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
* (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
* thesis (http://www.cs.chalmers.se/~phs/).
*
- * Given the use of tree-like index nodes, you might wonder why
- * this doesn't use some kind of search tree instead, which would
- * support somewhat faster search operations. The reason is that
- * there are no known efficient lock-free insertion and deletion
- * algorithms for search trees. The immutability of the "down"
- * links of index nodes (as opposed to mutable "left" fields in
- * true trees) makes this tractable using only CAS operations.
- *
* Notation guide for local variables
- * Node: b, n, f for predecessor, node, successor
+ * Node: b, n, f, p for predecessor, node, successor, aux
* Index: q, r, d for index node, right, down.
- * t for another index node
* Head: h
- * Levels: j
* Keys: k, key
* Values: v, value
* Comparisons: c
@@ -358,16 +329,6 @@
private static final long serialVersionUID = -8627078645895051609L;
/**
- * Special value used to identify base-level header.
- */
- static final Object BASE_HEADER = new Object();
-
- /**
- * The topmost head index of the skiplist.
- */
- private transient volatile HeadIndex<K,V> head;
-
- /**
* The comparator used to maintain order in this map, or null if
* using natural ordering. (Non-private to simplify access in
* nested classes.)
@@ -375,311 +336,152 @@
*/
final Comparator<? super K> comparator;
+ /** Lazily initialized topmost index of the skiplist. */
+ private transient Index<K,V> head;
+ /** Lazily initialized element count */
+ private transient LongAdder adder;
/** Lazily initialized key set */
private transient KeySet<K,V> keySet;
/** Lazily initialized values collection */
private transient Values<K,V> values;
/** Lazily initialized entry set */
private transient EntrySet<K,V> entrySet;
- /** Lazily initialized descending key set */
+ /** Lazily initialized descending map */
private transient SubMap<K,V> descendingMap;
/**
- * Initializes or resets state. Needed by constructors, clone,
- * clear, readObject. and ConcurrentSkipListSet.clone.
- * (Note that comparator must be separately initialized.)
- */
- private void initialize() {
- keySet = null;
- entrySet = null;
- values = null;
- descendingMap = null;
- head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
- null, null, 1);
- }
-
- /**
- * compareAndSet head node.
- */
- private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
- return HEAD.compareAndSet(this, cmp, val);
- }
-
- /* ---------------- Nodes -------------- */
-
- /**
* Nodes hold keys and values, and are singly linked in sorted
* order, possibly with some intervening marker nodes. The list is
- * headed by a dummy node accessible as head.node. The value field
- * is declared only as Object because it takes special non-V
- * values for marker and header nodes.
+ * headed by a header node accessible as head.node. Headers and
+ * marker nodes have null keys. The val field (but currently not
+ * the key field) is nulled out upon deletion.
*/
static final class Node<K,V> {
- final K key;
- volatile Object value;
- volatile Node<K,V> next;
-
- /**
- * Creates a new regular node.
- */
- Node(K key, Object value, Node<K,V> next) {
+ final K key; // currently, never detached
+ V val;
+ Node<K,V> next;
+ Node(K key, V value, Node<K,V> next) {
this.key = key;
- this.value = value;
- this.next = next;
- }
-
- /**
- * Creates a new marker node. A marker is distinguished by
- * having its value field point to itself. Marker nodes also
- * have null keys, a fact that is exploited in a few places,
- * but this doesn't distinguish markers from the base-level
- * header node (head.node), which also has a null key.
- */
- Node(Node<K,V> next) {
- this.key = null;
- this.value = this;
+ this.val = value;
this.next = next;
}
-
- /**
- * compareAndSet value field.
- */
- boolean casValue(Object cmp, Object val) {
- return VALUE.compareAndSet(this, cmp, val);
- }
-
- /**
- * compareAndSet next field.
- */
- boolean casNext(Node<K,V> cmp, Node<K,V> val) {
- return NEXT.compareAndSet(this, cmp, val);
- }
-
- /**
- * Returns true if this node is a marker. This method isn't
- * actually called in any current code checking for markers
- * because callers will have already read value field and need
- * to use that read (not another done here) and so directly
- * test if value points to node.
- *
- * @return true if this node is a marker node
- */
- boolean isMarker() {
- return value == this;
- }
-
- /**
- * Returns true if this node is the header of base-level list.
- * @return true if this node is header node
- */
- boolean isBaseHeader() {
- return value == BASE_HEADER;
- }
-
- /**
- * Tries to append a deletion marker to this node.
- * @param f the assumed current successor of this node
- * @return true if successful
- */
- boolean appendMarker(Node<K,V> f) {
- return casNext(f, new Node<K,V>(f));
- }
-
- /**
- * Helps out a deletion by appending marker or unlinking from
- * predecessor. This is called during traversals when value
- * field seen to be null.
- * @param b predecessor
- * @param f successor
- */
- void helpDelete(Node<K,V> b, Node<K,V> f) {
- /*
- * Rechecking links and then doing only one of the
- * help-out stages per call tends to minimize CAS
- * interference among helping threads.
- */
- if (f == next && this == b.next) {
- if (f == null || f.value != f) // not already marked
- casNext(f, new Node<K,V>(f));
- else
- b.casNext(this, f.next);
- }
- }
-
- /**
- * Returns value if this node contains a valid key-value pair,
- * else null.
- * @return this node's value if it isn't a marker or header or
- * is deleted, else null
- */
- V getValidValue() {
- Object v = value;
- if (v == this || v == BASE_HEADER)
- return null;
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
-
- /**
- * Creates and returns a new SimpleImmutableEntry holding current
- * mapping if this node holds a valid value, else null.
- * @return new entry or null
- */
- AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
- Object v = value;
- if (v == null || v == this || v == BASE_HEADER)
- return null;
- @SuppressWarnings("unchecked") V vv = (V)v;
- return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
- }
-
- // VarHandle mechanics
- private static final VarHandle VALUE;
- private static final VarHandle NEXT;
- static {
- try {
- MethodHandles.Lookup l = MethodHandles.lookup();
- VALUE = l.findVarHandle(Node.class, "value", Object.class);
- NEXT = l.findVarHandle(Node.class, "next", Node.class);
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
}
- /* ---------------- Indexing -------------- */
-
/**
- * Index nodes represent the levels of the skip list. Note that
- * even though both Nodes and Indexes have forward-pointing
- * fields, they have different types and are handled in different
- * ways, that can't nicely be captured by placing field in a
- * shared abstract class.
+ * Index nodes represent the levels of the skip list.
*/
- static class Index<K,V> {
- final Node<K,V> node;
+ static final class Index<K,V> {
+ final Node<K,V> node; // currently, never detached
final Index<K,V> down;
- volatile Index<K,V> right;
-
- /**
- * Creates index node with given values.
- */
+ Index<K,V> right;
Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
this.node = node;
this.down = down;
this.right = right;
}
-
- /**
- * compareAndSet right field.
- */
- final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
- return RIGHT.compareAndSet(this, cmp, val);
- }
-
- /**
- * Returns true if the node this indexes has been deleted.
- * @return true if indexed node is known to be deleted
- */
- final boolean indexesDeletedNode() {
- return node.value == null;
- }
-
- /**
- * Tries to CAS newSucc as successor. To minimize races with
- * unlink that may lose this index node, if the node being
- * indexed is known to be deleted, it doesn't try to link in.
- * @param succ the expected current successor
- * @param newSucc the new successor
- * @return true if successful
- */
- final boolean link(Index<K,V> succ, Index<K,V> newSucc) {
- Node<K,V> n = node;
- newSucc.right = succ;
- return n.value != null && casRight(succ, newSucc);
- }
-
- /**
- * Tries to CAS right field to skip over apparent successor
- * succ. Fails (forcing a retraversal by caller) if this node
- * is known to be deleted.
- * @param succ the expected current successor
- * @return true if successful
- */
- final boolean unlink(Index<K,V> succ) {
- return node.value != null && casRight(succ, succ.right);
- }
-
- // VarHandle mechanics
- private static final VarHandle RIGHT;
- static {
- try {
- MethodHandles.Lookup l = MethodHandles.lookup();
- RIGHT = l.findVarHandle(Index.class, "right", Index.class);
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
}
- /* ---------------- Head nodes -------------- */
-
- /**
- * Nodes heading each level keep track of their level.
- */
- static final class HeadIndex<K,V> extends Index<K,V> {
- final int level;
- HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) {
- super(node, down, right);
- this.level = level;
- }
- }
-
- /* ---------------- Comparison utilities -------------- */
+ /* ---------------- Utilities -------------- */
/**
* Compares using comparator or natural ordering if null.
* Called only by methods that have performed required type checks.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
- static final int cpr(Comparator c, Object x, Object y) {
+ static int cpr(Comparator c, Object x, Object y) {
return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y);
}
+ /**
+ * Returns the header for base node list, or null if uninitialized
+ */
+ final Node<K,V> baseHead() {
+ Index<K,V> h;
+ VarHandle.acquireFence();
+ return ((h = head) == null) ? null : h.node;
+ }
+
+ /**
+ * Tries to unlink deleted node n from predecessor b (if both
+ * exist), by first splicing in a marker if not already present.
+ * Upon return, node n is sure to be unlinked from b, possibly
+ * via the actions of some other thread.
+ *
+ * @param b if nonnull, predecessor
+ * @param n if nonnull, node known to be deleted
+ */
+ static <K,V> void unlinkNode(Node<K,V> b, Node<K,V> n) {
+ if (b != null && n != null) {
+ Node<K,V> f, p;
+ for (;;) {
+ if ((f = n.next) != null && f.key == null) {
+ p = f.next; // already marked
+ break;
+ }
+ else if (NEXT.compareAndSet(n, f,
+ new Node<K,V>(null, null, f))) {
+ p = f; // add marker
+ break;
+ }
+ }
+ NEXT.compareAndSet(b, n, p);
+ }
+ }
+
+ /**
+ * Adds to element count, initializing adder if necessary
+ *
+ * @param c count to add
+ */
+ private void addCount(long c) {
+ LongAdder a;
+ do {} while ((a = adder) == null &&
+ !ADDER.compareAndSet(this, null, a = new LongAdder()));
+ a.add(c);
+ }
+
+ /**
+ * Returns element count, initializing adder if necessary.
+ */
+ final long getAdderCount() {
+ LongAdder a; long c;
+ do {} while ((a = adder) == null &&
+ !ADDER.compareAndSet(this, null, a = new LongAdder()));
+ return ((c = a.sum()) <= 0L) ? 0L : c; // ignore transient negatives
+ }
+
/* ---------------- Traversal -------------- */
/**
- * Returns a base-level node with key strictly less than given key,
- * or the base-level header if there is no such node. Also
- * unlinks indexes to deleted nodes found along the way. Callers
- * rely on this side-effect of clearing indices to deleted nodes.
- * @param key the key
- * @return a predecessor of key
+ * Returns an index node with key strictly less than given key.
+ * Also unlinks indexes to deleted nodes found along the way.
+ * Callers rely on this side-effect of clearing indices to deleted
+ * nodes.
+ *
+ * @param key if nonnull the key
+ * @return a predecessor node of key, or null if uninitialized or null key
*/
private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) {
- if (key == null)
- throw new NullPointerException(); // don't postpone errors
- for (;;) {
- for (Index<K,V> q = head, r = q.right, d;;) {
- if (r != null) {
- Node<K,V> n = r.node;
- K k = n.key;
- if (n.value == null) {
- if (!q.unlink(r))
- break; // restart
- r = q.right; // reread r
- continue;
- }
- if (cpr(cmp, key, k) > 0) {
+ Index<K,V> q;
+ VarHandle.acquireFence();
+ if ((q = head) == null || key == null)
+ return null;
+ else {
+ for (Index<K,V> r, d;;) {
+ while ((r = q.right) != null) {
+ Node<K,V> p; K k;
+ if ((p = r.node) == null || (k = p.key) == null ||
+ p.val == null) // unlink index to deleted node
+ RIGHT.compareAndSet(q, r, r.right);
+ else if (cpr(cmp, key, k) > 0)
q = r;
- r = r.right;
- continue;
- }
+ else
+ break;
}
- if ((d = q.down) == null)
+ if ((d = q.down) != null)
+ q = d;
+ else
return q.node;
- q = d;
- r = d.right;
}
}
}
@@ -689,41 +491,11 @@
* deleted nodes seen along the way. Repeatedly traverses at
* base-level looking for key starting at predecessor returned
* from findPredecessor, processing base-level deletions as
- * encountered. Some callers rely on this side-effect of clearing
- * deleted nodes.
- *
- * Restarts occur, at traversal step centered on node n, if:
- *
- * (1) After reading n's next field, n is no longer assumed
- * predecessor b's current successor, which means that
- * we don't have a consistent 3-node snapshot and so cannot
- * unlink any subsequent deleted nodes encountered.
- *
- * (2) n's value field is null, indicating n is deleted, in
- * which case we help out an ongoing structural deletion
- * before retrying. Even though there are cases where such
- * unlinking doesn't require restart, they aren't sorted out
- * here because doing so would not usually outweigh cost of
- * restarting.
- *
- * (3) n is a marker or n's predecessor's value field is null,
- * indicating (among other possibilities) that
- * findPredecessor returned a deleted node. We can't unlink
- * the node because we don't know its predecessor, so rely
- * on another call to findPredecessor to notice and return
- * some earlier predecessor, which it will do. This check is
- * only strictly needed at beginning of loop, (and the
- * b.value check isn't strictly needed at all) but is done
- * each iteration to help avoid contention with other
- * threads by callers that will fail to be able to change
- * links, and so will retry anyway.
- *
- * The traversal loops in doPut, doRemove, and findNear all
- * include the same three kinds of checks. And specialized
- * versions appear in findFirst, and findLast and their variants.
- * They can't easily share code because each uses the reads of
- * fields held in locals occurring in the orders they were
- * performed.
+ * encountered. Restarts occur, at traversal step encountering
+ * node n, if n's key field is null, indicating it is a marker, so
+ * its predecessor is deleted before continuing, which we help do
+ * by re-finding a valid predecessor. The traversal loops in
+ * doPut, doRemove, and findNear all include the same checks.
*
* @param key the key
* @return node holding key, or null if no such
@@ -732,67 +504,81 @@
if (key == null)
throw new NullPointerException(); // don't postpone errors
Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v; int c;
- if (n == null)
+ Node<K,V> b;
+ outer: while ((b = findPredecessor(key, cmp)) != null) {
+ for (;;) {
+ Node<K,V> n; K k; V v; int c;
+ if ((n = b.next) == null)
+ break outer; // empty
+ else if ((k = n.key) == null)
+ break; // b is deleted
+ else if ((v = n.val) == null)
+ unlinkNode(b, n); // n is deleted
+ else if ((c = cpr(cmp, key, k)) > 0)
+ b = n;
+ else if (c == 0)
+ return n;
+ else
break outer;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- if ((c = cpr(cmp, key, n.key)) == 0)
- return n;
- if (c < 0)
- break outer;
- b = n;
- n = f;
}
}
return null;
}
/**
- * Gets value for key. Almost the same as findNode, but returns
- * the found value (to avoid retries during re-reads)
+ * Gets value for key. Same idea as findNode, except skips over
+ * deletions and markers, and returns first encountered value to
+ * avoid possibly inconsistent rereads.
*
* @param key the key
* @return the value, or null if absent
*/
private V doGet(Object key) {
+ Index<K,V> q;
+ VarHandle.acquireFence();
if (key == null)
throw new NullPointerException();
Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v; int c;
- if (n == null)
- break outer;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
+ V result = null;
+ if ((q = head) != null) {
+ outer: for (Index<K,V> r, d;;) {
+ while ((r = q.right) != null) {
+ Node<K,V> p; K k; V v; int c;
+ if ((p = r.node) == null || (k = p.key) == null ||
+ (v = p.val) == null)
+ RIGHT.compareAndSet(q, r, r.right);
+ else if ((c = cpr(cmp, key, k)) > 0)
+ q = r;
+ else if (c == 0) {
+ result = v;
+ break outer;
+ }
+ else
+ break;
+ }
+ if ((d = q.down) != null)
+ q = d;
+ else {
+ Node<K,V> b, n;
+ if ((b = q.node) != null) {
+ while ((n = b.next) != null) {
+ V v; int c;
+ K k = n.key;
+ if ((v = n.val) == null || k == null ||
+ (c = cpr(cmp, key, k)) > 0)
+ b = n;
+ else {
+ if (c == 0)
+ result = v;
+ break;
+ }
+ }
+ }
break;
}
- if (b.value == null || v == n) // b is deleted
- break;
- if ((c = cpr(cmp, key, n.key)) == 0) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
- if (c < 0)
- break outer;
- b = n;
- n = f;
}
}
- return null;
+ return result;
}
/* ---------------- Insertion -------------- */
@@ -800,129 +586,160 @@
/**
* Main insertion method. Adds element if not present, or
* replaces value if present and onlyIfAbsent is false.
+ *
* @param key the key
* @param value the value that must be associated with key
* @param onlyIfAbsent if should not insert if already present
* @return the old value, or null if newly inserted
*/
private V doPut(K key, V value, boolean onlyIfAbsent) {
- Node<K,V> z; // added node
if (key == null)
throw new NullPointerException();
Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- if (n != null) {
- Object v; int c;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- if ((c = cpr(cmp, key, n.key)) > 0) {
- b = n;
- n = f;
- continue;
- }
- if (c == 0) {
- if (onlyIfAbsent || n.casValue(v, value)) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
- break; // restart if lost race to replace value
+ for (;;) {
+ Index<K,V> h; Node<K,V> b;
+ VarHandle.acquireFence();
+ int levels = 0; // number of levels descended
+ if ((h = head) == null) { // try to initialize
+ Node<K,V> base = new Node<K,V>(null, null, null);
+ h = new Index<K,V>(base, null, null);
+ b = (HEAD.compareAndSet(this, null, h)) ? base : null;
+ }
+ else {
+ for (Index<K,V> q = h, r, d;;) { // count while descending
+ while ((r = q.right) != null) {
+ Node<K,V> p; K k;
+ if ((p = r.node) == null || (k = p.key) == null ||
+ p.val == null)
+ RIGHT.compareAndSet(q, r, r.right);
+ else if (cpr(cmp, key, k) > 0)
+ q = r;
+ else
+ break;
}
- // else c < 0; fall through
- } else if (b == head.node) {
- // map is empty, so type check key now
- cpr(cmp, key, key);
- }
-
- z = new Node<K,V>(key, value, n);
- if (!b.casNext(n, z))
- break; // restart if lost race to append to b
- break outer;
- }
- }
-
- int rnd = ThreadLocalRandom.nextSecondarySeed();
- if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
- int level = 1, max;
- while (((rnd >>>= 1) & 1) != 0)
- ++level;
- Index<K,V> idx = null;
- HeadIndex<K,V> h = head;
- if (level <= (max = h.level)) {
- for (int i = 1; i <= level; ++i)
- idx = new Index<K,V>(z, idx, null);
- }
- else { // try to grow by one level
- level = max + 1; // hold in array and later pick the one to use
- @SuppressWarnings("unchecked")Index<K,V>[] idxs =
- (Index<K,V>[])new Index<?,?>[level+1];
- for (int i = 1; i <= level; ++i)
- idxs[i] = idx = new Index<K,V>(z, idx, null);
- for (;;) {
- h = head;
- int oldLevel = h.level;
- if (level <= oldLevel) // lost race to add level
- break;
- HeadIndex<K,V> newh = h;
- Node<K,V> oldbase = h.node;
- for (int j = oldLevel+1; j <= level; ++j)
- newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
- if (casHead(h, newh)) {
- h = newh;
- idx = idxs[level = oldLevel];
+ if ((d = q.down) != null) {
+ ++levels;
+ q = d;
+ }
+ else {
+ b = q.node;
break;
}
}
}
- // find insertion points and splice in
- splice: for (int insertionLevel = level;;) {
- int j = h.level;
- for (Index<K,V> q = h, r = q.right, t = idx;;) {
- if (q == null || t == null)
- break splice;
- if (r != null) {
- Node<K,V> n = r.node;
- // compare before deletion check avoids needing recheck
- int c = cpr(cmp, key, n.key);
- if (n.value == null) {
- if (!q.unlink(r))
+ if (b != null) {
+ Node<K,V> z = null; // new node, if inserted
+ for (;;) { // find insertion point
+ Node<K,V> n, p; K k; V v; int c;
+ if ((n = b.next) == null) {
+ if (b.key == null) // if empty, type check key now
+ cpr(cmp, key, key);
+ c = -1;
+ }
+ else if ((k = n.key) == null)
+ break; // can't append; restart
+ else if ((v = n.val) == null) {
+ unlinkNode(b, n);
+ c = 1;
+ }
+ else if ((c = cpr(cmp, key, k)) > 0)
+ b = n;
+ else if (c == 0 &&
+ (onlyIfAbsent || VAL.compareAndSet(n, v, value)))
+ return v;
+
+ if (c < 0 &&
+ NEXT.compareAndSet(b, n,
+ p = new Node<K,V>(key, value, n))) {
+ z = p;
+ break;
+ }
+ }
+
+ if (z != null) {
+ int lr = ThreadLocalRandom.nextSecondarySeed();
+ if ((lr & 0x3) == 0) { // add indices with 1/4 prob
+ int hr = ThreadLocalRandom.nextSecondarySeed();
+ long rnd = ((long)hr << 32) | ((long)lr & 0xffffffffL);
+ int skips = levels; // levels to descend before add
+ Index<K,V> x = null;
+ for (;;) { // create at most 62 indices
+ x = new Index<K,V>(z, x, null);
+ if (rnd >= 0L || --skips < 0)
break;
- r = q.right;
- continue;
+ else
+ rnd <<= 1;
}
- if (c > 0) {
- q = r;
- r = r.right;
- continue;
+ if (addIndices(h, skips, x, cmp) && skips < 0 &&
+ head == h) { // try to add new level
+ Index<K,V> hx = new Index<K,V>(z, x, null);
+ Index<K,V> nh = new Index<K,V>(h.node, h, hx);
+ HEAD.compareAndSet(this, h, nh);
}
+ if (z.val == null) // deleted while adding indices
+ findPredecessor(key, cmp); // clean
}
-
- if (j == insertionLevel) {
- if (!q.link(r, t))
- break; // restart
- if (t.node.value == null) {
- findNode(key);
- break splice;
- }
- if (--insertionLevel == 0)
- break splice;
- }
-
- if (--j >= insertionLevel && j < level)
- t = t.down;
- q = q.down;
- r = q.right;
+ addCount(1L);
+ return null;
}
}
}
- return null;
+ }
+
+ /**
+ * Add indices after an insertion. Descends iteratively to the
+ * highest level of insertion, then recursively, to chain index
+ * nodes to lower ones. Returns null on (staleness) failure,
+ * disabling higher-level insertions. Recursion depths are
+ * exponentially less probable.
+ *
+ * @param q starting index for current level
+ * @param skips levels to skip before inserting
+ * @param x index for this insertion
+ * @param cmp comparator
+ */
+ static <K,V> boolean addIndices(Index<K,V> q, int skips, Index<K,V> x,
+ Comparator<? super K> cmp) {
+ Node<K,V> z; K key;
+ if (x != null && (z = x.node) != null && (key = z.key) != null &&
+ q != null) { // hoist checks
+ boolean retrying = false;
+ for (;;) { // find splice point
+ Index<K,V> r, d; int c;
+ if ((r = q.right) != null) {
+ Node<K,V> p; K k;
+ if ((p = r.node) == null || (k = p.key) == null ||
+ p.val == null) {
+ RIGHT.compareAndSet(q, r, r.right);
+ c = 0;
+ }
+ else if ((c = cpr(cmp, key, k)) > 0)
+ q = r;
+ else if (c == 0)
+ break; // stale
+ }
+ else
+ c = -1;
+
+ if (c < 0) {
+ if ((d = q.down) != null && skips > 0) {
+ --skips;
+ q = d;
+ }
+ else if (d != null && !retrying &&
+ !addIndices(d, 0, x.down, cmp))
+ break;
+ else {
+ x.right = r;
+ if (RIGHT.compareAndSet(q, r, x))
+ return true;
+ else
+ retrying = true; // re-find splice point
+ }
+ }
+ }
+ }
+ return false;
}
/* ---------------- Deletion -------------- */
@@ -932,15 +749,6 @@
* deletion marker, unlinks predecessor, removes associated index
* nodes, and possibly reduces head index level.
*
- * Index nodes are cleared out simply by calling findPredecessor.
- * which unlinks indexes to deleted nodes found along path to key,
- * which will include the indexes to this node. This is done
- * unconditionally. We can't check beforehand whether there are
- * index nodes because it might be the case that some or all
- * indexes hadn't been inserted yet for this node during initial
- * search for it, and we'd like to ensure lack of garbage
- * retention, so must call to be sure.
- *
* @param key the key
* @param value if non-null, the value that must be
* associated with key
@@ -950,43 +758,36 @@
if (key == null)
throw new NullPointerException();
Comparator<? super K> cmp = comparator;
- outer: for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v; int c;
- if (n == null)
- break outer;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- if ((c = cpr(cmp, key, n.key)) < 0)
+ V result = null;
+ Node<K,V> b;
+ outer: while ((b = findPredecessor(key, cmp)) != null &&
+ result == null) {
+ for (;;) {
+ Node<K,V> n; K k; V v; int c;
+ if ((n = b.next) == null)
break outer;
- if (c > 0) {
- b = n;
- n = f;
- continue;
- }
- if (value != null && !value.equals(v))
- break outer;
- if (!n.casValue(v, null))
+ else if ((k = n.key) == null)
break;
- if (!n.appendMarker(f) || !b.casNext(n, f))
- findNode(key); // retry via findNode
- else {
- findPredecessor(key, cmp); // clean index
- if (head.right == null)
- tryReduceLevel();
+ else if ((v = n.val) == null)
+ unlinkNode(b, n);
+ else if ((c = cpr(cmp, key, k)) > 0)
+ b = n;
+ else if (c < 0)
+ break outer;
+ else if (value != null && !value.equals(v))
+ break outer;
+ else if (VAL.compareAndSet(n, v, null)) {
+ result = v;
+ unlinkNode(b, n);
+ break; // loop to clean up
}
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
}
}
- return null;
+ if (result != null) {
+ tryReduceLevel();
+ addCount(-1L);
+ }
+ return result;
}
/**
@@ -1010,77 +811,132 @@
* reduction.
*/
private void tryReduceLevel() {
- HeadIndex<K,V> h = head;
- HeadIndex<K,V> d;
- HeadIndex<K,V> e;
- if (h.level > 3 &&
- (d = (HeadIndex<K,V>)h.down) != null &&
- (e = (HeadIndex<K,V>)d.down) != null &&
- e.right == null &&
- d.right == null &&
- h.right == null &&
- casHead(h, d) && // try to set
- h.right != null) // recheck
- casHead(d, h); // try to backout
+ Index<K,V> h, d, e;
+ if ((h = head) != null && h.right == null &&
+ (d = h.down) != null && d.right == null &&
+ (e = d.down) != null && e.right == null &&
+ HEAD.compareAndSet(this, h, d) &&
+ h.right != null) // recheck
+ HEAD.compareAndSet(this, d, h); // try to backout
}
/* ---------------- Finding and removing first element -------------- */
/**
- * Specialized variant of findNode to get first valid node.
+ * Gets first valid node, unlinking deleted nodes if encountered.
* @return first node or null if empty
*/
final Node<K,V> findFirst() {
- for (Node<K,V> b, n;;) {
- if ((n = (b = head.node).next) == null)
- return null;
- if (n.value != null)
- return n;
- n.helpDelete(b, n.next);
+ Node<K,V> b, n;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if (n.val == null)
+ unlinkNode(b, n);
+ else
+ return n;
+ }
}
+ return null;
+ }
+
+ /**
+ * Entry snapshot version of findFirst
+ */
+ final AbstractMap.SimpleImmutableEntry<K,V> findFirstEntry() {
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) == null)
+ unlinkNode(b, n);
+ else
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+ }
+ }
+ return null;
}
/**
* Removes first entry; returns its snapshot.
* @return null if empty, else snapshot of first entry
*/
- private Map.Entry<K,V> doRemoveFirstEntry() {
- for (Node<K,V> b, n;;) {
- if ((n = (b = head.node).next) == null)
- return null;
- Node<K,V> f = n.next;
- if (n != b.next)
- continue;
- Object v = n.value;
- if (v == null) {
- n.helpDelete(b, f);
- continue;
+ private AbstractMap.SimpleImmutableEntry<K,V> doRemoveFirstEntry() {
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) == null || VAL.compareAndSet(n, v, null)) {
+ K k = n.key;
+ unlinkNode(b, n);
+ if (v != null) {
+ tryReduceLevel();
+ findPredecessor(k, comparator); // clean index
+ addCount(-1L);
+ return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+ }
+ }
}
- if (!n.casValue(v, null))
- continue;
- if (!n.appendMarker(f) || !b.casNext(n, f))
- findFirst(); // retry
- clearIndexToFirst();
- @SuppressWarnings("unchecked") V vv = (V)v;
- return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, vv);
}
+ return null;
+ }
+
+ /* ---------------- Finding and removing last element -------------- */
+
+ /**
+ * Specialized version of find to get last valid node.
+ * @return last node or null if empty
+ */
+ final Node<K,V> findLast() {
+ outer: for (;;) {
+ Index<K,V> q; Node<K,V> b;
+ VarHandle.acquireFence();
+ if ((q = head) == null)
+ break;
+ for (Index<K,V> r, d;;) {
+ while ((r = q.right) != null) {
+ Node<K,V> p;
+ if ((p = r.node) == null || p.val == null)
+ RIGHT.compareAndSet(q, r, r.right);
+ else
+ q = r;
+ }
+ if ((d = q.down) != null)
+ q = d;
+ else {
+ b = q.node;
+ break;
+ }
+ }
+ if (b != null) {
+ for (;;) {
+ Node<K,V> n;
+ if ((n = b.next) == null) {
+ if (b.key == null) // empty
+ break outer;
+ else
+ return b;
+ }
+ else if (n.key == null)
+ break;
+ else if (n.val == null)
+ unlinkNode(b, n);
+ else
+ b = n;
+ }
+ }
+ }
+ return null;
}
/**
- * Clears out index nodes associated with deleted first entry.
+ * Entry version of findLast
+ * @return Entry for last node or null if empty
*/
- private void clearIndexToFirst() {
+ final AbstractMap.SimpleImmutableEntry<K,V> findLastEntry() {
for (;;) {
- for (Index<K,V> q = head;;) {
- Index<K,V> r = q.right;
- if (r != null && r.indexesDeletedNode() && !q.unlink(r))
- break;
- if ((q = q.down) == null) {
- if (head.right == null)
- tryReduceLevel();
- return;
- }
- }
+ Node<K,V> n; V v;
+ if ((n = findLast()) == null)
+ return null;
+ if ((v = n.val) != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
}
@@ -1090,121 +946,54 @@
* @return null if empty, else snapshot of last entry
*/
private Map.Entry<K,V> doRemoveLastEntry() {
- for (;;) {
- Node<K,V> b = findPredecessorOfLast();
- Node<K,V> n = b.next;
- if (n == null) {
- if (b.isBaseHeader()) // empty
- return null;
- else
- continue; // all b's successors are deleted; retry
- }
+ outer: for (;;) {
+ Index<K,V> q; Node<K,V> b;
+ VarHandle.acquireFence();
+ if ((q = head) == null)
+ break;
for (;;) {
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- Object v = n.value;
- if (v == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- if (f != null) {
- b = n;
- n = f;
- continue;
- }
- if (!n.casValue(v, null))
- break;
- K key = n.key;
- if (!n.appendMarker(f) || !b.casNext(n, f))
- findNode(key); // retry via findNode
- else { // clean index
- findPredecessor(key, comparator);
- if (head.right == null)
- tryReduceLevel();
- }
- @SuppressWarnings("unchecked") V vv = (V)v;
- return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
- }
- }
- }
-
- /* ---------------- Finding and removing last element -------------- */
-
- /**
- * Specialized version of find to get last valid node.
- * @return last node or null if empty
- */
- final Node<K,V> findLast() {
- /*
- * findPredecessor can't be used to traverse index level
- * because this doesn't use comparisons. So traversals of
- * both levels are folded together.
- */
- Index<K,V> q = head;
- for (;;) {
- Index<K,V> d, r;
- if ((r = q.right) != null) {
- if (r.indexesDeletedNode()) {
- q.unlink(r);
- q = head; // restart
- }
- else
- q = r;
- } else if ((d = q.down) != null) {
- q = d;
- } else {
- for (Node<K,V> b = q.node, n = b.next;;) {
- if (n == null)
- return b.isBaseHeader() ? null : b;
- Node<K,V> f = n.next; // inconsistent read
- if (n != b.next)
+ Index<K,V> d, r; Node<K,V> p;
+ while ((r = q.right) != null) {
+ if ((p = r.node) == null || p.val == null)
+ RIGHT.compareAndSet(q, r, r.right);
+ else if (p.next != null)
+ q = r; // continue only if a successor
+ else
break;
- Object v = n.value;
- if (v == null) { // n is deleted
- n.helpDelete(b, f);
- break;
- }
- if (b.value == null || v == n) // b is deleted
- break;
- b = n;
- n = f;
- }
- q = head; // restart
- }
- }
- }
-
- /**
- * Specialized variant of findPredecessor to get predecessor of last
- * valid node. Needed when removing the last entry. It is possible
- * that all successors of returned node will have been deleted upon
- * return, in which case this method can be retried.
- * @return likely predecessor of last node
- */
- private Node<K,V> findPredecessorOfLast() {
- for (;;) {
- for (Index<K,V> q = head;;) {
- Index<K,V> d, r;
- if ((r = q.right) != null) {
- if (r.indexesDeletedNode()) {
- q.unlink(r);
- break; // must restart
- }
- // proceed as far across as possible without overshooting
- if (r.node.next != null) {
- q = r;
- continue;
- }
}
if ((d = q.down) != null)
q = d;
- else
- return q.node;
+ else {
+ b = q.node;
+ break;
+ }
+ }
+ if (b != null) {
+ for (;;) {
+ Node<K,V> n; K k; V v;
+ if ((n = b.next) == null) {
+ if (b.key == null) // empty
+ break outer;
+ else
+ break; // retry
+ }
+ else if ((k = n.key) == null)
+ break;
+ else if ((v = n.val) == null)
+ unlinkNode(b, n);
+ else if (n.next != null)
+ b = n;
+ else if (VAL.compareAndSet(n, v, null)) {
+ unlinkNode(b, n);
+ tryReduceLevel();
+ findPredecessor(k, comparator); // clean index
+ addCount(-1L);
+ return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+ }
+ }
}
}
+ return null;
}
/* ---------------- Relational operations -------------- */
@@ -1224,47 +1013,52 @@
final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
if (key == null)
throw new NullPointerException();
- for (;;) {
- for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
- Object v;
- if (n == null)
- return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
- Node<K,V> f = n.next;
- if (n != b.next) // inconsistent read
- break;
- if ((v = n.value) == null) { // n is deleted
- n.helpDelete(b, f);
+ Node<K,V> result;
+ outer: for (Node<K,V> b;;) {
+ if ((b = findPredecessor(key, cmp)) == null) {
+ result = null;
+ break; // empty
+ }
+ for (;;) {
+ Node<K,V> n; K k; int c;
+ if ((n = b.next) == null) {
+ result = ((rel & LT) != 0 && b.key != null) ? b : null;
+ break outer;
+ }
+ else if ((k = n.key) == null)
break;
+ else if (n.val == null)
+ unlinkNode(b, n);
+ else if (((c = cpr(cmp, key, k)) == 0 && (rel & EQ) != 0) ||
+ (c < 0 && (rel & LT) == 0)) {
+ result = n;
+ break outer;
}
- if (b.value == null || v == n) // b is deleted
- break;
- int c = cpr(cmp, key, n.key);
- if ((c == 0 && (rel & EQ) != 0) ||
- (c < 0 && (rel & LT) == 0))
- return n;
- if ( c <= 0 && (rel & LT) != 0)
- return b.isBaseHeader() ? null : b;
- b = n;
- n = f;
+ else if (c <= 0 && (rel & LT) != 0) {
+ result = (b.key != null) ? b : null;
+ break outer;
+ }
+ else
+ b = n;
}
}
+ return result;
}
/**
- * Returns SimpleImmutableEntry for results of findNear.
+ * Variant of findNear returning SimpleImmutableEntry
* @param key the key
* @param rel the relation -- OR'ed combination of EQ, LT, GT
* @return Entry fitting relation, or null if no such
*/
- final AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
- Comparator<? super K> cmp = comparator;
+ final AbstractMap.SimpleImmutableEntry<K,V> findNearEntry(K key, int rel,
+ Comparator<? super K> cmp) {
for (;;) {
- Node<K,V> n = findNear(key, rel, cmp);
- if (n == null)
+ Node<K,V> n; V v;
+ if ((n = findNear(key, rel, cmp)) == null)
return null;
- AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
+ if ((v = n.val) != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
}
@@ -1276,7 +1070,6 @@
*/
public ConcurrentSkipListMap() {
this.comparator = null;
- initialize();
}
/**
@@ -1289,7 +1082,6 @@
*/
public ConcurrentSkipListMap(Comparator<? super K> comparator) {
this.comparator = comparator;
- initialize();
}
/**
@@ -1305,7 +1097,6 @@
*/
public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {
this.comparator = null;
- initialize();
putAll(m);
}
@@ -1320,8 +1111,7 @@
*/
public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {
this.comparator = m.comparator();
- initialize();
- buildFromSorted(m);
+ buildFromSorted(m); // initializes transients
}
/**
@@ -1335,7 +1125,10 @@
@SuppressWarnings("unchecked")
ConcurrentSkipListMap<K,V> clone =
(ConcurrentSkipListMap<K,V>) super.clone();
- clone.initialize();
+ clone.keySet = null;
+ clone.entrySet = null;
+ clone.values = null;
+ clone.descendingMap = null;
clone.buildFromSorted(this);
return clone;
} catch (CloneNotSupportedException e) {
@@ -1351,58 +1144,49 @@
private void buildFromSorted(SortedMap<K, ? extends V> map) {
if (map == null)
throw new NullPointerException();
-
- HeadIndex<K,V> h = head;
- Node<K,V> basepred = h.node;
-
- // Track the current rightmost node at each level. Uses an
- // ArrayList to avoid committing to initial or maximum level.
- ArrayList<Index<K,V>> preds = new ArrayList<>();
-
- // initialize
- for (int i = 0; i <= h.level; ++i)
- preds.add(null);
- Index<K,V> q = h;
- for (int i = h.level; i > 0; --i) {
- preds.set(i, q);
- q = q.down;
- }
-
Iterator<? extends Map.Entry<? extends K, ? extends V>> it =
map.entrySet().iterator();
+
+ /*
+ * Add equally spaced indices at log intervals, using the bits
+ * of count during insertion. The maximum possible resulting
+ * level is less than the number of bits in a long (64). The
+ * preds array tracks the current rightmost node at each
+ * level.
+ */
+ @SuppressWarnings("unchecked")
+ Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+ Node<K,V> bp = new Node<K,V>(null, null, null);
+ Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+ long count = 0;
+
while (it.hasNext()) {
Map.Entry<? extends K, ? extends V> e = it.next();
- int rnd = ThreadLocalRandom.current().nextInt();
- int j = 0;
- if ((rnd & 0x80000001) == 0) {
- do {
- ++j;
- } while (((rnd >>>= 1) & 1) != 0);
- if (j > h.level) j = h.level + 1;
- }
K k = e.getKey();
V v = e.getValue();
if (k == null || v == null)
throw new NullPointerException();
Node<K,V> z = new Node<K,V>(k, v, null);
- basepred.next = z;
- basepred = z;
- if (j > 0) {
- Index<K,V> idx = null;
- for (int i = 1; i <= j; ++i) {
+ bp = bp.next = z;
+ if ((++count & 3L) == 0L) {
+ long m = count >>> 2;
+ int i = 0;
+ Index<K,V> idx = null, q;
+ do {
idx = new Index<K,V>(z, idx, null);
- if (i > h.level)
- h = new HeadIndex<K,V>(h.node, h, idx, i);
-
- if (i < preds.size()) {
- preds.get(i).right = idx;
- preds.set(i, idx);
- } else
- preds.add(idx);
- }
+ if ((q = preds[i]) == null)
+ preds[i] = h = new Index<K,V>(h.node, h, idx);
+ else
+ preds[i] = q.right = idx;
+ } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
}
}
- head = h;
+ if (count != 0L) {
+ VarHandle.releaseFence(); // emulate volatile stores
+ addCount(count);
+ head = h;
+ VarHandle.fullFence();
+ }
}
/* ---------------- Serialization -------------- */
@@ -1424,11 +1208,14 @@
s.defaultWriteObject();
// Write out keys and values (alternating)
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- V v = n.getValidValue();
- if (v != null) {
- s.writeObject(n.key);
- s.writeObject(v);
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null) {
+ s.writeObject(n.key);
+ s.writeObject(v);
+ }
+ b = n;
}
}
s.writeObject(null);
@@ -1446,64 +1233,47 @@
throws java.io.IOException, ClassNotFoundException {
// Read in the Comparator and any hidden stuff
s.defaultReadObject();
- // Reset transients
- initialize();
- /*
- * This is nearly identical to buildFromSorted, but is
- * distinct because readObject calls can't be nicely adapted
- * as the kind of iterator needed by buildFromSorted. (They
- * can be, but doing so requires type cheats and/or creation
- * of adapter classes.) It is simpler to just adapt the code.
- */
-
- HeadIndex<K,V> h = head;
- Node<K,V> basepred = h.node;
- ArrayList<Index<K,V>> preds = new ArrayList<>();
- for (int i = 0; i <= h.level; ++i)
- preds.add(null);
- Index<K,V> q = h;
- for (int i = h.level; i > 0; --i) {
- preds.set(i, q);
- q = q.down;
- }
+ // Same idea as buildFromSorted
+ @SuppressWarnings("unchecked")
+ Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+ Node<K,V> bp = new Node<K,V>(null, null, null);
+ Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+ Comparator<? super K> cmp = comparator;
+ K prevKey = null;
+ long count = 0;
for (;;) {
- Object k = s.readObject();
+ K k = (K)s.readObject();
if (k == null)
break;
- Object v = s.readObject();
+ V v = (V)s.readObject();
if (v == null)
throw new NullPointerException();
- K key = (K) k;
- V val = (V) v;
- int rnd = ThreadLocalRandom.current().nextInt();
- int j = 0;
- if ((rnd & 0x80000001) == 0) {
+ if (prevKey != null && cpr(cmp, prevKey, k) > 0)
+ throw new IllegalStateException("out of order");
+ prevKey = k;
+ Node<K,V> z = new Node<K,V>(k, v, null);
+ bp = bp.next = z;
+ if ((++count & 3L) == 0L) {
+ long m = count >>> 2;
+ int i = 0;
+ Index<K,V> idx = null, q;
do {
- ++j;
- } while (((rnd >>>= 1) & 1) != 0);
- if (j > h.level) j = h.level + 1;
- }
- Node<K,V> z = new Node<K,V>(key, val, null);
- basepred.next = z;
- basepred = z;
- if (j > 0) {
- Index<K,V> idx = null;
- for (int i = 1; i <= j; ++i) {
idx = new Index<K,V>(z, idx, null);
- if (i > h.level)
- h = new HeadIndex<K,V>(h.node, h, idx, i);
-
- if (i < preds.size()) {
- preds.get(i).right = idx;
- preds.set(i, idx);
- } else
- preds.add(idx);
- }
+ if ((q = preds[i]) == null)
+ preds[i] = h = new Index<K,V>(h.node, h, idx);
+ else
+ preds[i] = q.right = idx;
+ } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
}
}
- head = h;
+ if (count != 0L) {
+ VarHandle.releaseFence();
+ addCount(count);
+ head = h;
+ VarHandle.fullFence();
+ }
}
/* ------ Map API methods ------ */
@@ -1604,42 +1374,30 @@
public boolean containsValue(Object value) {
if (value == null)
throw new NullPointerException();
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- V v = n.getValidValue();
- if (v != null && value.equals(v))
- return true;
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null && value.equals(v))
+ return true;
+ else
+ b = n;
+ }
}
return false;
}
/**
- * Returns the number of key-value mappings in this map. If this map
- * contains more than {@code Integer.MAX_VALUE} elements, it
- * returns {@code Integer.MAX_VALUE}.
- *
- * <p>Beware that, unlike in most collections, this method is
- * <em>NOT</em> a constant-time operation. Because of the
- * asynchronous nature of these maps, determining the current
- * number of elements requires traversing them all to count them.
- * Additionally, it is possible for the size to change during
- * execution of this method, in which case the returned result
- * will be inaccurate. Thus, this method is typically not very
- * useful in concurrent applications.
- *
- * @return the number of elements in this map
+ * {@inheritDoc}
*/
public int size() {
- long count = 0;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- if (n.getValidValue() != null)
- ++count;
- }
- return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
+ long c;
+ return ((baseHead() == null) ? 0 :
+ ((c = getAdderCount()) >= Integer.MAX_VALUE) ?
+ Integer.MAX_VALUE : (int) c);
}
/**
- * Returns {@code true} if this map contains no key-value mappings.
- * @return {@code true} if this map contains no key-value mappings
+ * {@inheritDoc}
*/
public boolean isEmpty() {
return findFirst() == null;
@@ -1649,23 +1407,32 @@
* Removes all of the mappings from this map.
*/
public void clear() {
- for (;;) {
- Node<K,V> b, n;
- HeadIndex<K,V> h = head, d = (HeadIndex<K,V>)h.down;
- if (d != null)
- casHead(h, d); // remove levels
- else if ((b = h.node) != null && (n = b.next) != null) {
- Node<K,V> f = n.next; // remove values
- if (n == b.next) {
- Object v = n.value;
- if (v == null)
- n.helpDelete(b, f);
- else if (n.casValue(v, null) && n.appendMarker(f))
- b.casNext(n, f);
+ Index<K,V> h, r, d; Node<K,V> b;
+ VarHandle.acquireFence();
+ while ((h = head) != null) {
+ if ((r = h.right) != null) // remove indices
+ RIGHT.compareAndSet(h, r, null);
+ else if ((d = h.down) != null) // remove levels
+ HEAD.compareAndSet(this, h, d);
+ else {
+ long count = 0L;
+ if ((b = h.node) != null) { // remove nodes
+ Node<K,V> n; V v;
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null &&
+ VAL.compareAndSet(n, v, null)) {
+ --count;
+ v = null;
+ }
+ if (v == null)
+ unlinkNode(b, n);
+ }
}
+ if (count != 0L)
+ addCount(count);
+ else
+ break;
}
- else
- break;
}
}
@@ -1712,16 +1479,15 @@
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
- Node<K,V> n; Object v;
+ Node<K,V> n; V v;
while ((n = findNode(key)) != null) {
- if ((v = n.value) != null) {
- @SuppressWarnings("unchecked") V vv = (V) v;
- V r = remappingFunction.apply(key, vv);
+ if ((v = n.val) != null) {
+ V r = remappingFunction.apply(key, v);
if (r != null) {
- if (n.casValue(vv, r))
+ if (VAL.compareAndSet(n, v, r))
return r;
}
- else if (doRemove(key, vv) != null)
+ else if (doRemove(key, v) != null)
break;
}
}
@@ -1746,20 +1512,19 @@
if (key == null || remappingFunction == null)
throw new NullPointerException();
for (;;) {
- Node<K,V> n; Object v; V r;
+ Node<K,V> n; V v; V r;
if ((n = findNode(key)) == null) {
if ((r = remappingFunction.apply(key, null)) == null)
break;
if (doPut(key, r, true) == null)
return r;
}
- else if ((v = n.value) != null) {
- @SuppressWarnings("unchecked") V vv = (V) v;
- if ((r = remappingFunction.apply(key, vv)) != null) {
- if (n.casValue(vv, r))
+ else if ((v = n.val) != null) {
+ if ((r = remappingFunction.apply(key, v)) != null) {
+ if (VAL.compareAndSet(n, v, r))
return r;
}
- else if (doRemove(key, vv) != null)
+ else if (doRemove(key, v) != null)
break;
}
}
@@ -1786,18 +1551,17 @@
if (key == null || value == null || remappingFunction == null)
throw new NullPointerException();
for (;;) {
- Node<K,V> n; Object v; V r;
+ Node<K,V> n; V v; V r;
if ((n = findNode(key)) == null) {
if (doPut(key, value, true) == null)
return value;
}
- else if ((v = n.value) != null) {
- @SuppressWarnings("unchecked") V vv = (V) v;
- if ((r = remappingFunction.apply(vv, value)) != null) {
- if (n.casValue(vv, r))
+ else if ((v = n.val) != null) {
+ if ((r = remappingFunction.apply(v, value)) != null) {
+ if (VAL.compareAndSet(n, v, r))
return r;
}
- else if (doRemove(key, vv) != null)
+ else if (doRemove(key, v) != null)
return null;
}
}
@@ -1946,16 +1710,60 @@
return false;
Map<?,?> m = (Map<?,?>) o;
try {
- for (Map.Entry<K,V> e : this.entrySet())
- if (! e.getValue().equals(m.get(e.getKey())))
- return false;
- for (Map.Entry<?,?> e : m.entrySet()) {
- Object k = e.getKey();
- Object v = e.getValue();
- if (k == null || v == null || !v.equals(get(k)))
- return false;
+ Comparator<? super K> cmp = comparator;
+ @SuppressWarnings("unchecked")
+ Iterator<Map.Entry<?,?>> it =
+ (Iterator<Map.Entry<?,?>>)m.entrySet().iterator();
+ if (m instanceof SortedMap &&
+ ((SortedMap<?,?>)m).comparator() == cmp) {
+ Node<K,V> b, n;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ K k; V v;
+ if ((v = n.val) != null && (k = n.key) != null) {
+ if (!it.hasNext())
+ return false;
+ Map.Entry<?,?> e = it.next();
+ Object mk = e.getKey();
+ Object mv = e.getValue();
+ if (mk == null || mv == null)
+ return false;
+ try {
+ if (cpr(cmp, k, mk) != 0)
+ return false;
+ } catch (ClassCastException cce) {
+ return false;
+ }
+ if (!mv.equals(v))
+ return false;
+ }
+ b = n;
+ }
+ }
+ return !it.hasNext();
}
- return true;
+ else {
+ while (it.hasNext()) {
+ V v;
+ Map.Entry<?,?> e = it.next();
+ Object mk = e.getKey();
+ Object mv = e.getValue();
+ if (mk == null || mv == null ||
+ (v = get(mk)) == null || !v.equals(mv))
+ return false;
+ }
+ Node<K,V> b, n;
+ if ((b = baseHead()) != null) {
+ K k; V v; Object mv;
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null && (k = n.key) != null &&
+ ((mv = m.get(k)) == null || !mv.equals(v)))
+ return false;
+ b = n;
+ }
+ }
+ return true;
+ }
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
@@ -2004,13 +1812,13 @@
if (key == null || oldValue == null || newValue == null)
throw new NullPointerException();
for (;;) {
- Node<K,V> n; Object v;
+ Node<K,V> n; V v;
if ((n = findNode(key)) == null)
return false;
- if ((v = n.value) != null) {
+ if ((v = n.val) != null) {
if (!oldValue.equals(v))
return false;
- if (n.casValue(v, newValue))
+ if (VAL.compareAndSet(n, v, newValue))
return true;
}
}
@@ -2029,13 +1837,11 @@
if (key == null || value == null)
throw new NullPointerException();
for (;;) {
- Node<K,V> n; Object v;
+ Node<K,V> n; V v;
if ((n = findNode(key)) == null)
return null;
- if ((v = n.value) != null && n.casValue(v, value)) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
+ if ((v = n.val) != null && VAL.compareAndSet(n, v, value))
+ return v;
}
}
@@ -2145,7 +1951,7 @@
* @throws NullPointerException if the specified key is null
*/
public Map.Entry<K,V> lowerEntry(K key) {
- return getNear(key, LT);
+ return findNearEntry(key, LT, comparator);
}
/**
@@ -2168,7 +1974,7 @@
* @throws NullPointerException if the specified key is null
*/
public Map.Entry<K,V> floorEntry(K key) {
- return getNear(key, LT|EQ);
+ return findNearEntry(key, LT|EQ, comparator);
}
/**
@@ -2191,7 +1997,7 @@
* @throws NullPointerException if the specified key is null
*/
public Map.Entry<K,V> ceilingEntry(K key) {
- return getNear(key, GT|EQ);
+ return findNearEntry(key, GT|EQ, comparator);
}
/**
@@ -2214,7 +2020,7 @@
* @throws NullPointerException if the specified key is null
*/
public Map.Entry<K,V> higherEntry(K key) {
- return getNear(key, GT);
+ return findNearEntry(key, GT, comparator);
}
/**
@@ -2234,14 +2040,7 @@
* the {@code Entry.setValue} method.
*/
public Map.Entry<K,V> firstEntry() {
- for (;;) {
- Node<K,V> n = findFirst();
- if (n == null)
- return null;
- AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
- }
+ return findFirstEntry();
}
/**
@@ -2251,14 +2050,7 @@
* the {@code Entry.setValue} method.
*/
public Map.Entry<K,V> lastEntry() {
- for (;;) {
- Node<K,V> n = findLast();
- if (n == null)
- return null;
- AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
- }
+ return findLastEntry();
}
/**
@@ -2281,11 +2073,10 @@
return doRemoveLastEntry();
}
-
/* ---------------- Iterators -------------- */
/**
- * Base of iterator classes:
+ * Base of iterator classes
*/
abstract class Iter<T> implements Iterator<T> {
/** the last node returned by next() */
@@ -2297,14 +2088,7 @@
/** Initializes ascending iterator for entire range. */
Iter() {
- while ((next = findFirst()) != null) {
- Object x = next.value;
- if (x != null && x != next) {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- break;
- }
- }
+ advance(baseHead());
}
public final boolean hasNext() {
@@ -2312,54 +2096,58 @@
}
/** Advances next to higher entry. */
- final void advance() {
- if (next == null)
- throw new NoSuchElementException();
- lastReturned = next;
- while ((next = next.next) != null) {
- Object x = next.value;
- if (x != null && x != next) {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- break;
- }
+ final void advance(Node<K,V> b) {
+ Node<K,V> n = null;
+ V v = null;
+ if ((lastReturned = b) != null) {
+ while ((n = b.next) != null && (v = n.val) == null)
+ b = n;
}
+ nextValue = v;
+ next = n;
}
- public void remove() {
- Node<K,V> l = lastReturned;
- if (l == null)
+ public final void remove() {
+ Node<K,V> n; K k;
+ if ((n = lastReturned) == null || (k = n.key) == null)
throw new IllegalStateException();
// It would not be worth all of the overhead to directly
// unlink from here. Using remove is fast enough.
- ConcurrentSkipListMap.this.remove(l.key);
+ ConcurrentSkipListMap.this.remove(k);
lastReturned = null;
}
-
}
final class ValueIterator extends Iter<V> {
public V next() {
- V v = nextValue;
- advance();
+ V v;
+ if ((v = nextValue) == null)
+ throw new NoSuchElementException();
+ advance(next);
return v;
}
}
final class KeyIterator extends Iter<K> {
public K next() {
- Node<K,V> n = next;
- advance();
- return n.key;
+ Node<K,V> n;
+ if ((n = next) == null)
+ throw new NoSuchElementException();
+ K k = n.key;
+ advance(n);
+ return k;
}
}
final class EntryIterator extends Iter<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
- Node<K,V> n = next;
+ Node<K,V> n;
+ if ((n = next) == null)
+ throw new NoSuchElementException();
+ K k = n.key;
V v = nextValue;
- advance();
- return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+ advance(n);
+ return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
}
}
@@ -2725,38 +2513,34 @@
Map.Entry<K,V> lowestEntry() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
- ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
- if (!isBeforeEnd(n, cmp))
+ ConcurrentSkipListMap.Node<K,V> n; V v;
+ if ((n = loNode(cmp)) == null || !isBeforeEnd(n, cmp))
return null;
- Map.Entry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
+ else if ((v = n.val) != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
}
Map.Entry<K,V> highestEntry() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
- ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
- if (n == null || !inBounds(n.key, cmp))
+ ConcurrentSkipListMap.Node<K,V> n; V v;
+ if ((n = hiNode(cmp)) == null || !inBounds(n.key, cmp))
return null;
- Map.Entry<K,V> e = n.createSnapshot();
- if (e != null)
- return e;
+ else if ((v = n.val) != null)
+ return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
}
Map.Entry<K,V> removeLowest() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
- Node<K,V> n = loNode(cmp);
- if (n == null)
+ ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+ if ((n = loNode(cmp)) == null)
return null;
- K k = n.key;
- if (!inBounds(k, cmp))
+ else if (!inBounds((k = n.key), cmp))
return null;
- V v = m.doRemove(k, null);
- if (v != null)
+ else if ((v = m.doRemove(k, null)) != null)
return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
}
}
@@ -2764,20 +2548,18 @@
Map.Entry<K,V> removeHighest() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
- Node<K,V> n = hiNode(cmp);
- if (n == null)
+ ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+ if ((n = hiNode(cmp)) == null)
return null;
- K k = n.key;
- if (!inBounds(k, cmp))
+ else if (!inBounds((k = n.key), cmp))
return null;
- V v = m.doRemove(k, null);
- if (v != null)
+ else if ((v = m.doRemove(k, null)) != null)
return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
}
}
/**
- * Submap version of ConcurrentSkipListMap.getNearEntry.
+ * Submap version of ConcurrentSkipListMap.findNearEntry.
*/
Map.Entry<K,V> getNearEntry(K key, int rel) {
Comparator<? super K> cmp = m.comparator;
@@ -2791,15 +2573,12 @@
return ((rel & LT) != 0) ? null : lowestEntry();
if (tooHigh(key, cmp))
return ((rel & LT) != 0) ? highestEntry() : null;
- for (;;) {
- Node<K,V> n = m.findNear(key, rel, cmp);
- if (n == null || !inBounds(n.key, cmp))
- return null;
- K k = n.key;
- V v = n.getValidValue();
- if (v != null)
- return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
- }
+ AbstractMap.SimpleImmutableEntry<K,V> e =
+ m.findNearEntry(key, rel, cmp);
+ if (e == null || !inBounds(e.getKey(), cmp))
+ return null;
+ else
+ return e;
}
// Almost the same as getNearEntry, except for keys
@@ -2834,10 +2613,8 @@
Node<K,V> n = m.findNear(key, rel, cmp);
if (n == null || !inBounds(n.key, cmp))
return null;
- K k = n.key;
- V v = n.getValidValue();
- if (v != null)
- return k;
+ if (n.val != null)
+ return n.key;
}
}
@@ -2868,7 +2645,7 @@
for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
isBeforeEnd(n, cmp);
n = n.next) {
- if (n.getValidValue() != null)
+ if (n.val != null)
++count;
}
return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
@@ -2886,7 +2663,7 @@
for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
isBeforeEnd(n, cmp);
n = n.next) {
- V v = n.getValidValue();
+ V v = n.val;
if (v != null && value.equals(v))
return true;
}
@@ -2898,7 +2675,7 @@
for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
isBeforeEnd(n, cmp);
n = n.next) {
- if (n.getValidValue() != null)
+ if (n.val != null)
m.remove(n.key);
}
}
@@ -3112,19 +2889,18 @@
V nextValue;
SubMapIter() {
+ VarHandle.acquireFence();
Comparator<? super K> cmp = m.comparator;
for (;;) {
next = isDescending ? hiNode(cmp) : loNode(cmp);
if (next == null)
break;
- Object x = next.value;
- if (x != null && x != next) {
+ V x = next.val;
+ if (x != null) {
if (! inBounds(next.key, cmp))
next = null;
- else {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- }
+ else
+ nextValue = x;
break;
}
}
@@ -3150,14 +2926,12 @@
next = next.next;
if (next == null)
break;
- Object x = next.value;
- if (x != null && x != next) {
+ V x = next.val;
+ if (x != null) {
if (tooHigh(next.key, cmp))
next = null;
- else {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- }
+ else
+ nextValue = x;
break;
}
}
@@ -3169,14 +2943,12 @@
next = m.findNear(lastReturned.key, LT, cmp);
if (next == null)
break;
- Object x = next.value;
- if (x != null && x != next) {
+ V x = next.val;
+ if (x != null) {
if (tooLow(next.key, cmp))
next = null;
- else {
- @SuppressWarnings("unchecked") V vv = (V)x;
- nextValue = vv;
- }
+ else
+ nextValue = x;
break;
}
}
@@ -3256,22 +3028,28 @@
public void forEach(BiConsumer<? super K, ? super V> action) {
if (action == null) throw new NullPointerException();
- V v;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- if ((v = n.getValidValue()) != null)
- action.accept(n.key, v);
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null)
+ action.accept(n.key, v);
+ b = n;
+ }
}
}
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
if (function == null) throw new NullPointerException();
- V v;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- while ((v = n.getValidValue()) != null) {
- V r = function.apply(n.key, v);
- if (r == null) throw new NullPointerException();
- if (n.casValue(v, r))
- break;
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ while ((v = n.val) != null) {
+ V r = function.apply(n.key, v);
+ if (r == null) throw new NullPointerException();
+ if (VAL.compareAndSet(n, v, r))
+ break;
+ }
+ b = n;
}
}
}
@@ -3282,13 +3060,16 @@
boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
if (function == null) throw new NullPointerException();
boolean removed = false;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- V v;
- if ((v = n.getValidValue()) != null) {
- K k = n.key;
- Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
- if (function.test(e) && remove(k, v))
- removed = true;
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null) {
+ K k = n.key;
+ Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+ if (function.test(e) && remove(k, v))
+ removed = true;
+ }
+ b = n;
}
}
return removed;
@@ -3300,12 +3081,12 @@
boolean removeValueIf(Predicate<? super V> function) {
if (function == null) throw new NullPointerException();
boolean removed = false;
- for (Node<K,V> n = findFirst(); n != null; n = n.next) {
- V v;
- if ((v = n.getValidValue()) != null) {
- K k = n.key;
- if (function.test(v) && remove(k, v))
+ Node<K,V> b, n; V v;
+ if ((b = baseHead()) != null) {
+ while ((n = b.next) != null) {
+ if ((v = n.val) != null && function.test(v) && remove(n.key, v))
removed = true;
+ b = n;
}
}
return removed;
@@ -3323,30 +3104,27 @@
* off, or the end of row is encountered. Control of the number of
* splits relies on some statistical estimation: The expected
* remaining number of elements of a skip list when advancing
- * either across or down decreases by about 25%. To make this
- * observation useful, we need to know initial size, which we
- * don't. But we can just use Integer.MAX_VALUE so that we
- * don't prematurely zero out while splitting.
+ * either across or down decreases by about 25%.
*/
abstract static class CSLMSpliterator<K,V> {
final Comparator<? super K> comparator;
final K fence; // exclusive upper bound for keys, or null if to end
Index<K,V> row; // the level to split out
Node<K,V> current; // current traversal node; initialize at origin
- int est; // pseudo-size estimate
+ long est; // size estimate
CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row,
- Node<K,V> origin, K fence, int est) {
+ Node<K,V> origin, K fence, long est) {
this.comparator = comparator; this.row = row;
this.current = origin; this.fence = fence; this.est = est;
}
- public final long estimateSize() { return (long)est; }
+ public final long estimateSize() { return est; }
}
static final class KeySpliterator<K,V> extends CSLMSpliterator<K,V>
implements Spliterator<K> {
KeySpliterator(Comparator<? super K> comparator, Index<K,V> row,
- Node<K,V> origin, K fence, int est) {
+ Node<K,V> origin, K fence, long est) {
super(comparator, row, origin, fence, est);
}
@@ -3358,7 +3136,7 @@
for (Index<K,V> q = row; q != null; q = row = q.down) {
Index<K,V> s; Node<K,V> b, n; K sk;
if ((s = q.right) != null && (b = s.node) != null &&
- (n = b.next) != null && n.value != null &&
+ (n = b.next) != null && n.val != null &&
(sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
(f == null || cpr(cmp, sk, f) < 0)) {
current = n;
@@ -3379,10 +3157,10 @@
Node<K,V> e = current;
current = null;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
break;
- if ((v = e.value) != null && v != e)
+ if (e.val != null)
action.accept(k);
}
}
@@ -3393,12 +3171,12 @@
K f = fence;
Node<K,V> e = current;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
e = null;
break;
}
- if ((v = e.value) != null && v != e) {
+ if (e.val != null) {
current = e.next;
action.accept(k);
return true;
@@ -3420,21 +3198,23 @@
}
// factory method for KeySpliterator
final KeySpliterator<K,V> keySpliterator() {
- Comparator<? super K> cmp = comparator;
- for (;;) { // ensure h corresponds to origin p
- HeadIndex<K,V> h; Node<K,V> p;
- Node<K,V> b = (h = head).node;
- if ((p = b.next) == null || p.value != null)
- return new KeySpliterator<K,V>(cmp, h, p, null, (p == null) ?
- 0 : Integer.MAX_VALUE);
- p.helpDelete(b, p.next);
+ Index<K,V> h; Node<K,V> n; long est;
+ VarHandle.acquireFence();
+ if ((h = head) == null) {
+ n = null;
+ est = 0L;
}
+ else {
+ n = h.node;
+ est = getAdderCount();
+ }
+ return new KeySpliterator<K,V>(comparator, h, n, null, est);
}
static final class ValueSpliterator<K,V> extends CSLMSpliterator<K,V>
implements Spliterator<V> {
ValueSpliterator(Comparator<? super K> comparator, Index<K,V> row,
- Node<K,V> origin, K fence, int est) {
+ Node<K,V> origin, K fence, long est) {
super(comparator, row, origin, fence, est);
}
@@ -3446,7 +3226,7 @@
for (Index<K,V> q = row; q != null; q = row = q.down) {
Index<K,V> s; Node<K,V> b, n; K sk;
if ((s = q.right) != null && (b = s.node) != null &&
- (n = b.next) != null && n.value != null &&
+ (n = b.next) != null && n.val != null &&
(sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
(f == null || cpr(cmp, sk, f) < 0)) {
current = n;
@@ -3467,13 +3247,11 @@
Node<K,V> e = current;
current = null;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k; V v;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
break;
- if ((v = e.value) != null && v != e) {
- @SuppressWarnings("unchecked") V vv = (V)v;
- action.accept(vv);
- }
+ if ((v = e.val) != null)
+ action.accept(v);
}
}
@@ -3483,15 +3261,14 @@
K f = fence;
Node<K,V> e = current;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k; V v;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
e = null;
break;
}
- if ((v = e.value) != null && v != e) {
+ if ((v = e.val) != null) {
current = e.next;
- @SuppressWarnings("unchecked") V vv = (V)v;
- action.accept(vv);
+ action.accept(v);
return true;
}
}
@@ -3507,21 +3284,23 @@
// Almost the same as keySpliterator()
final ValueSpliterator<K,V> valueSpliterator() {
- Comparator<? super K> cmp = comparator;
- for (;;) {
- HeadIndex<K,V> h; Node<K,V> p;
- Node<K,V> b = (h = head).node;
- if ((p = b.next) == null || p.value != null)
- return new ValueSpliterator<K,V>(cmp, h, p, null, (p == null) ?
- 0 : Integer.MAX_VALUE);
- p.helpDelete(b, p.next);
+ Index<K,V> h; Node<K,V> n; long est;
+ VarHandle.acquireFence();
+ if ((h = head) == null) {
+ n = null;
+ est = 0L;
}
+ else {
+ n = h.node;
+ est = getAdderCount();
+ }
+ return new ValueSpliterator<K,V>(comparator, h, n, null, est);
}
static final class EntrySpliterator<K,V> extends CSLMSpliterator<K,V>
implements Spliterator<Map.Entry<K,V>> {
EntrySpliterator(Comparator<? super K> comparator, Index<K,V> row,
- Node<K,V> origin, K fence, int est) {
+ Node<K,V> origin, K fence, long est) {
super(comparator, row, origin, fence, est);
}
@@ -3533,7 +3312,7 @@
for (Index<K,V> q = row; q != null; q = row = q.down) {
Index<K,V> s; Node<K,V> b, n; K sk;
if ((s = q.right) != null && (b = s.node) != null &&
- (n = b.next) != null && n.value != null &&
+ (n = b.next) != null && n.val != null &&
(sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
(f == null || cpr(cmp, sk, f) < 0)) {
current = n;
@@ -3554,13 +3333,12 @@
Node<K,V> e = current;
current = null;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k; V v;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
break;
- if ((v = e.value) != null && v != e) {
- @SuppressWarnings("unchecked") V vv = (V)v;
+ if ((v = e.val) != null) {
action.accept
- (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+ (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
}
}
}
@@ -3571,16 +3349,15 @@
K f = fence;
Node<K,V> e = current;
for (; e != null; e = e.next) {
- K k; Object v;
+ K k; V v;
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
e = null;
break;
}
- if ((v = e.value) != null && v != e) {
+ if ((v = e.val) != null) {
current = e.next;
- @SuppressWarnings("unchecked") V vv = (V)v;
action.accept
- (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+ (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
return true;
}
}
@@ -3611,24 +3388,35 @@
// Almost the same as keySpliterator()
final EntrySpliterator<K,V> entrySpliterator() {
- Comparator<? super K> cmp = comparator;
- for (;;) { // almost same as key version
- HeadIndex<K,V> h; Node<K,V> p;
- Node<K,V> b = (h = head).node;
- if ((p = b.next) == null || p.value != null)
- return new EntrySpliterator<K,V>(cmp, h, p, null, (p == null) ?
- 0 : Integer.MAX_VALUE);
- p.helpDelete(b, p.next);
+ Index<K,V> h; Node<K,V> n; long est;
+ VarHandle.acquireFence();
+ if ((h = head) == null) {
+ n = null;
+ est = 0L;
}
+ else {
+ n = h.node;
+ est = getAdderCount();
+ }
+ return new EntrySpliterator<K,V>(comparator, h, n, null, est);
}
// VarHandle mechanics
private static final VarHandle HEAD;
+ private static final VarHandle ADDER;
+ private static final VarHandle NEXT;
+ private static final VarHandle VAL;
+ private static final VarHandle RIGHT;
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
HEAD = l.findVarHandle(ConcurrentSkipListMap.class, "head",
- HeadIndex.class);
+ Index.class);
+ ADDER = l.findVarHandle(ConcurrentSkipListMap.class, "adder",
+ LongAdder.class);
+ NEXT = l.findVarHandle(Node.class, "next", Node.class);
+ VAL = l.findVarHandle(Node.class, "val", Object.class);
+ RIGHT = l.findVarHandle(Index.class, "right", Index.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
--- a/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java Wed Oct 04 20:01:19 2017 +0000
@@ -174,6 +174,10 @@
this.completionQueue = completionQueue;
}
+ /**
+ * @throws RejectedExecutionException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
@@ -181,6 +185,10 @@
return f;
}
+ /**
+ * @throws RejectedExecutionException {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
public Future<V> submit(Runnable task, V result) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task, result);
--- a/src/java.base/share/classes/java/util/concurrent/Executors.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/Executors.java Wed Oct 04 20:01:19 2017 +0000
@@ -514,6 +514,9 @@
task.run();
return result;
}
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + task + "]";
+ }
}
/**
@@ -540,6 +543,10 @@
throw e.getException();
}
}
+
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + task + "]";
+ }
}
/**
@@ -592,6 +599,10 @@
throw e.getException();
}
}
+
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + task + "]";
+ }
}
/**
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java Wed Oct 04 20:01:19 2017 +0000
@@ -1375,6 +1375,9 @@
public final void setRawResult(T v) { result = v; }
public final boolean exec() { runnable.run(); return true; }
public final void run() { invoke(); }
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + runnable + "]";
+ }
private static final long serialVersionUID = 5232453952276885070L;
}
@@ -1392,6 +1395,9 @@
public final void setRawResult(Void v) { }
public final boolean exec() { runnable.run(); return true; }
public final void run() { invoke(); }
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + runnable + "]";
+ }
private static final long serialVersionUID = 5232453952276885070L;
}
@@ -1437,6 +1443,9 @@
}
}
public final void run() { invoke(); }
+ public String toString() {
+ return super.toString() + "[Wrapped task = " + callable + "]";
+ }
private static final long serialVersionUID = 2838392045355241008L;
}
--- a/src/java.base/share/classes/java/util/concurrent/FutureTask.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/FutureTask.java Wed Oct 04 20:01:19 2017 +0000
@@ -480,6 +480,41 @@
}
}
+ /**
+ * Returns a string representation of this FutureTask.
+ *
+ * @implSpec
+ * The default implementation returns a string identifying this
+ * FutureTask, as well as its completion state. The state, in
+ * brackets, contains one of the strings {@code "Completed Normally"},
+ * {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
+ * "Not completed"}.
+ *
+ * @return a string representation of this FutureTask
+ */
+ public String toString() {
+ final String status;
+ switch (state) {
+ case NORMAL:
+ status = "[Completed normally]";
+ break;
+ case EXCEPTIONAL:
+ status = "[Completed exceptionally: " + outcome + "]";
+ break;
+ case CANCELLED:
+ case INTERRUPTING:
+ case INTERRUPTED:
+ status = "[Cancelled]";
+ break;
+ default:
+ final Callable<?> callable = this.callable;
+ status = (callable == null)
+ ? "[Not completed]"
+ : "[Not completed, task = " + callable + "]";
+ }
+ return super.toString() + status;
+ }
+
// VarHandle mechanics
private static final VarHandle STATE;
private static final VarHandle RUNNER;
--- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java Wed Oct 04 20:01:19 2017 +0000
@@ -383,7 +383,7 @@
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
- private static final int CAPACITY = (1 << COUNT_BITS) - 1;
+ private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
@@ -393,8 +393,8 @@
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
- private static int runStateOf(int c) { return c & ~CAPACITY; }
- private static int workerCountOf(int c) { return c & CAPACITY; }
+ private static int runStateOf(int c) { return c & ~COUNT_MASK; }
+ private static int workerCountOf(int c) { return c & COUNT_MASK; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
/*
@@ -434,7 +434,7 @@
* decrements are performed within getTask.
*/
private void decrementWorkerCount() {
- do {} while (! compareAndDecrementWorkerCount(ctl.get()));
+ ctl.addAndGet(-1);
}
/**
@@ -538,12 +538,17 @@
* Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero.
+ *
+ * Since the worker count is actually stored in COUNT_BITS bits,
+ * the effective limit is {@code corePoolSize & COUNT_MASK}.
*/
private volatile int corePoolSize;
/**
- * Maximum pool size. Note that the actual maximum is internally
- * bounded by CAPACITY.
+ * Maximum pool size.
+ *
+ * Since the worker count is actually stored in COUNT_BITS bits,
+ * the effective limit is {@code maximumPoolSize & COUNT_MASK}.
*/
private volatile int maximumPoolSize;
@@ -705,7 +710,7 @@
int c = ctl.get();
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
- (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+ (runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
return;
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
@@ -744,17 +749,12 @@
* specially.
*/
private void checkShutdownAccess() {
+ // assert mainLock.isHeldByCurrentThread();
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm);
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- for (Worker w : workers)
- security.checkAccess(w.thread);
- } finally {
- mainLock.unlock();
- }
+ for (Worker w : workers)
+ security.checkAccess(w.thread);
}
}
@@ -763,14 +763,9 @@
* (in which case some threads may remain uninterrupted).
*/
private void interruptWorkers() {
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- for (Worker w : workers)
- w.interruptIfStarted();
- } finally {
- mainLock.unlock();
- }
+ // assert mainLock.isHeldByCurrentThread();
+ for (Worker w : workers)
+ w.interruptIfStarted();
}
/**
@@ -896,26 +891,22 @@
*/
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
- for (;;) {
- int c = ctl.get();
- int rs = runStateOf(c);
-
+ for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
- if (rs >= SHUTDOWN &&
- ! (rs == SHUTDOWN &&
- firstTask == null &&
- ! workQueue.isEmpty()))
+ if (runStateAtLeast(c, SHUTDOWN)
+ && (runStateAtLeast(c, STOP)
+ || firstTask != null
+ || workQueue.isEmpty()))
return false;
for (;;) {
- int wc = workerCountOf(c);
- if (wc >= CAPACITY ||
- wc >= (core ? corePoolSize : maximumPoolSize))
+ if (workerCountOf(c)
+ >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
- if (runStateOf(c) != rs)
+ if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
@@ -934,10 +925,10 @@
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
- int rs = runStateOf(ctl.get());
+ int c = ctl.get();
- if (rs < SHUTDOWN ||
- (rs == SHUTDOWN && firstTask == null)) {
+ if (isRunning(c) ||
+ (runStateLessThan(c, STOP) && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
@@ -1044,10 +1035,10 @@
for (;;) {
int c = ctl.get();
- int rs = runStateOf(c);
// Check if queue empty only if necessary.
- if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+ if (runStateAtLeast(c, SHUTDOWN)
+ && (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
@@ -1140,17 +1131,12 @@
wt.interrupt();
try {
beforeExecute(wt, task);
- Throwable thrown = null;
try {
task.run();
- } catch (RuntimeException x) {
- thrown = x; throw x;
- } catch (Error x) {
- thrown = x; throw x;
- } catch (Throwable x) {
- thrown = x; throw new Error(x);
- } finally {
- afterExecute(task, thrown);
+ afterExecute(task, null);
+ } catch (Throwable ex) {
+ afterExecute(task, ex);
+ throw ex;
}
} finally {
task = null;
@@ -1331,7 +1317,7 @@
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
- * the task is handled by the current {@code RejectedExecutionHandler}.
+ * the task is handled by the current {@link RejectedExecutionHandler}.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
@@ -1438,7 +1424,7 @@
}
public boolean isShutdown() {
- return ! isRunning(ctl.get());
+ return runStateAtLeast(ctl.get(), SHUTDOWN);
}
/** Used by ScheduledThreadPoolExecutor. */
@@ -1459,7 +1445,7 @@
*/
public boolean isTerminating() {
int c = ctl.get();
- return ! isRunning(c) && runStateLessThan(c, TERMINATED);
+ return runStateAtLeast(c, SHUTDOWN) && runStateLessThan(c, TERMINATED);
}
public boolean isTerminated() {
@@ -1472,7 +1458,7 @@
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
- while (!runStateAtLeast(ctl.get(), TERMINATED)) {
+ while (runStateLessThan(ctl.get(), TERMINATED)) {
if (nanos <= 0L)
return false;
nanos = termination.awaitNanos(nanos);
@@ -1951,7 +1937,7 @@
}
int c = ctl.get();
String runState =
- runStateLessThan(c, SHUTDOWN) ? "Running" :
+ isRunning(c) ? "Running" :
runStateAtLeast(c, TERMINATED) ? "Terminated" :
"Shutting down";
return super.toString() +
--- a/src/java.base/share/classes/java/util/concurrent/TimeUnit.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/TimeUnit.java Wed Oct 04 20:01:19 2017 +0000
@@ -342,11 +342,13 @@
* using:
*
* <pre> {@code
- * public synchronized Object poll(long timeout, TimeUnit unit)
+ * public E poll(long timeout, TimeUnit unit)
* throws InterruptedException {
- * while (empty) {
- * unit.timedWait(this, timeout);
- * ...
+ * synchronized (lock) {
+ * while (isEmpty()) {
+ * unit.timedWait(lock, timeout);
+ * ...
+ * }
* }
* }}</pre>
*
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Wed Oct 04 20:01:19 2017 +0000
@@ -67,11 +67,11 @@
private static final long serialVersionUID = 7373984972572414692L;
/*
- To keep sources in sync, the remainder of this source file is
- exactly cloned from AbstractQueuedSynchronizer, replacing class
- name and changing ints related with sync state to longs. Please
- keep it that way.
- */
+ * To keep sources in sync, the remainder of this source file is
+ * exactly cloned from AbstractQueuedSynchronizer, replacing class
+ * name and changing ints related with sync state to longs. Please
+ * keep it that way.
+ */
/**
* Creates a new {@code AbstractQueuedLongSynchronizer} instance
@@ -725,8 +725,7 @@
/**
* Returns {@code true} if synchronization is held exclusively with
* respect to the current (calling) thread. This method is invoked
- * upon each call to a non-waiting {@link ConditionObject} method.
- * (Waiting methods instead invoke {@link #release}.)
+ * upon each call to a {@link ConditionObject} method.
*
* <p>The default implementation throws {@link
* UnsupportedOperationException}. This method is invoked
@@ -1366,9 +1365,8 @@
}
/**
- * Condition implementation for a {@link
- * AbstractQueuedLongSynchronizer} serving as the basis of a {@link
- * Lock} implementation.
+ * Condition implementation for a {@link AbstractQueuedLongSynchronizer}
+ * serving as the basis of a {@link Lock} implementation.
*
* <p>Method documentation for this class describes mechanics,
* not behavioral specifications from the point of view of Lock
@@ -1401,6 +1399,8 @@
* @return its new wait node
*/
private Node addConditionWaiter() {
+ if (!isHeldExclusively())
+ throw new IllegalMonitorStateException();
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Wed Oct 04 20:01:19 2017 +0000
@@ -194,19 +194,13 @@
* represent the locked state. While a non-reentrant lock
* does not strictly require recording of the current owner
* thread, this class does so anyway to make usage easier to monitor.
- * It also supports conditions and exposes
- * one of the instrumentation methods:
+ * It also supports conditions and exposes some instrumentation methods:
*
* <pre> {@code
* class Mutex implements Lock, java.io.Serializable {
*
* // Our internal helper class
* private static class Sync extends AbstractQueuedSynchronizer {
- * // Reports whether in locked state
- * protected boolean isHeldExclusively() {
- * return getState() == 1;
- * }
- *
* // Acquires the lock if state is zero
* public boolean tryAcquire(int acquires) {
* assert acquires == 1; // Otherwise unused
@@ -220,14 +214,27 @@
* // Releases the lock by setting state to zero
* protected boolean tryRelease(int releases) {
* assert releases == 1; // Otherwise unused
- * if (getState() == 0) throw new IllegalMonitorStateException();
+ * if (!isHeldExclusively())
+ * throw new IllegalMonitorStateException();
* setExclusiveOwnerThread(null);
* setState(0);
* return true;
* }
*
+ * // Reports whether in locked state
+ * public boolean isLocked() {
+ * return getState() != 0;
+ * }
+ *
+ * public boolean isHeldExclusively() {
+ * // a data race, but safe due to out-of-thin-air guarantees
+ * return getExclusiveOwnerThread() == Thread.currentThread();
+ * }
+ *
* // Provides a Condition
- * Condition newCondition() { return new ConditionObject(); }
+ * public Condition newCondition() {
+ * return new ConditionObject();
+ * }
*
* // Deserializes properly
* private void readObject(ObjectInputStream s)
@@ -240,12 +247,17 @@
* // The sync object does all the hard work. We just forward to it.
* private final Sync sync = new Sync();
*
- * public void lock() { sync.acquire(1); }
- * public boolean tryLock() { return sync.tryAcquire(1); }
- * public void unlock() { sync.release(1); }
- * public Condition newCondition() { return sync.newCondition(); }
- * public boolean isLocked() { return sync.isHeldExclusively(); }
- * public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
+ * public void lock() { sync.acquire(1); }
+ * public boolean tryLock() { return sync.tryAcquire(1); }
+ * public void unlock() { sync.release(1); }
+ * public Condition newCondition() { return sync.newCondition(); }
+ * public boolean isLocked() { return sync.isLocked(); }
+ * public boolean isHeldByCurrentThread() {
+ * return sync.isHeldExclusively();
+ * }
+ * public boolean hasQueuedThreads() {
+ * return sync.hasQueuedThreads();
+ * }
* public void lockInterruptibly() throws InterruptedException {
* sync.acquireInterruptibly(1);
* }
@@ -1193,8 +1205,7 @@
/**
* Returns {@code true} if synchronization is held exclusively with
* respect to the current (calling) thread. This method is invoked
- * upon each call to a non-waiting {@link ConditionObject} method.
- * (Waiting methods instead invoke {@link #release}.)
+ * upon each call to a {@link ConditionObject} method.
*
* <p>The default implementation throws {@link
* UnsupportedOperationException}. This method is invoked
@@ -1834,9 +1845,8 @@
}
/**
- * Condition implementation for a {@link
- * AbstractQueuedSynchronizer} serving as the basis of a {@link
- * Lock} implementation.
+ * Condition implementation for a {@link AbstractQueuedSynchronizer}
+ * serving as the basis of a {@link Lock} implementation.
*
* <p>Method documentation for this class describes mechanics,
* not behavioral specifications from the point of view of Lock
@@ -1867,6 +1877,8 @@
* @return its new wait node
*/
private Node addConditionWaiter() {
+ if (!isHeldExclusively())
+ throw new IllegalMonitorStateException();
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
--- a/src/java.base/share/classes/java/util/concurrent/locks/Condition.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/Condition.java Wed Oct 04 20:01:19 2017 +0000
@@ -73,7 +73,7 @@
* available in the buffer. This can be achieved using two
* {@link Condition} instances.
* <pre>
- * class BoundedBuffer {
+ * class BoundedBuffer<E> {
* <b>final Lock lock = new ReentrantLock();</b>
* final Condition notFull = <b>lock.newCondition(); </b>
* final Condition notEmpty = <b>lock.newCondition(); </b>
@@ -81,7 +81,7 @@
* final Object[] items = new Object[100];
* int putptr, takeptr, count;
*
- * public void put(Object x) throws InterruptedException {
+ * public void put(E x) throws InterruptedException {
* <b>lock.lock();
* try {</b>
* while (count == items.length)
@@ -95,12 +95,12 @@
* }</b>
* }
*
- * public Object take() throws InterruptedException {
+ * public E take() throws InterruptedException {
* <b>lock.lock();
* try {</b>
* while (count == 0)
* <b>notEmpty.await();</b>
- * Object x = items[takeptr];
+ * E x = (E) items[takeptr];
* if (++takeptr == items.length) takeptr = 0;
* --count;
* <b>notFull.signal();</b>
@@ -310,7 +310,8 @@
* the following form:
*
* <pre> {@code
- * boolean aMethod(long timeout, TimeUnit unit) {
+ * boolean aMethod(long timeout, TimeUnit unit)
+ * throws InterruptedException {
* long nanos = unit.toNanos(timeout);
* lock.lock();
* try {
@@ -320,6 +321,7 @@
* nanos = theCondition.awaitNanos(nanos);
* }
* // ...
+ * return true;
* } finally {
* lock.unlock();
* }
@@ -410,7 +412,8 @@
* <p>The return value indicates whether the deadline has elapsed,
* which can be used as follows:
* <pre> {@code
- * boolean aMethod(Date deadline) {
+ * boolean aMethod(Date deadline)
+ * throws InterruptedException {
* boolean stillWaiting = true;
* lock.lock();
* try {
@@ -420,6 +423,7 @@
* stillWaiting = theCondition.awaitUntil(deadline);
* }
* // ...
+ * return true;
* } finally {
* lock.unlock();
* }
--- a/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java Wed Oct 04 20:01:19 2017 +0000
@@ -151,18 +151,20 @@
* }
*
* double distanceFromOrigin() { // A read-only method
+ * double currentX, currentY;
* long stamp = sl.tryOptimisticRead();
- * double currentX = x, currentY = y;
- * if (!sl.validate(stamp)) {
- * stamp = sl.readLock();
+ * do {
+ * if (stamp == 0L)
+ * stamp = sl.readLock();
* try {
+ * // possibly racy reads
* currentX = x;
* currentY = y;
* } finally {
- * sl.unlockRead(stamp);
+ * stamp = sl.tryConvertToOptimisticRead(stamp);
* }
- * }
- * return Math.sqrt(currentX * currentX + currentY * currentY);
+ * } while (stamp == 0);
+ * return Math.hypot(currentX, currentY);
* }
*
* void moveIfAtOrigin(double newX, double newY) { // upgrade
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java Wed Oct 04 20:01:19 2017 +0000
@@ -40,6 +40,18 @@
String getName(Object mname);
/**
+ * Returns the {@code MethodType} for the given MemberName.
+ * Used by {@see StackFrameInfo}.
+ */
+ MethodType getMethodType(Object mname);
+
+ /**
+ * Returns the descriptor for the given MemberName.
+ * Used by {@see StackFrameInfo}.
+ */
+ String getMethodDescriptor(Object mname);
+
+ /**
* Returns {@code true} if the given MemberName is a native method. Used by
* {@see StackFrameInfo}.
*/
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Oct 04 20:01:19 2017 +0000
@@ -1802,7 +1802,12 @@
try {
readRecord(true);
} catch (SocketTimeoutException e) {
- // if time out, ignore the exception and continue
+ if ((debug != null) && Debug.isOn("ssl")) {
+ System.out.println(
+ Thread.currentThread().getName() +
+ ", received Exception: " + e);
+ }
+ fatal((byte)(-1), "Did not receive close_notify from peer", e);
}
}
} catch (IOException e) {
--- a/src/java.base/share/classes/sun/security/util/ManifestDigester.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/sun/security/util/ManifestDigester.java Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -28,6 +28,7 @@
import java.security.*;
import java.util.HashMap;
import java.io.ByteArrayOutputStream;
+import static java.nio.charset.StandardCharsets.UTF_8;
/**
* This class is used to compute digests on sections of the Manifest.
@@ -112,8 +113,6 @@
rawBytes = bytes;
entries = new HashMap<>();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
Position pos = new Position();
if (!findSection(0, pos))
@@ -131,50 +130,41 @@
if (len > 6) {
if (isNameAttr(bytes, start)) {
- StringBuilder nameBuf = new StringBuilder(sectionLen);
-
- try {
- nameBuf.append(
- new String(bytes, start+6, len-6, "UTF8"));
+ ByteArrayOutputStream nameBuf = new ByteArrayOutputStream();
+ nameBuf.write(bytes, start+6, len-6);
- int i = start + len;
- if ((i-start) < sectionLen) {
- if (bytes[i] == '\r') {
- i += 2;
- } else {
- i += 1;
- }
+ int i = start + len;
+ if ((i-start) < sectionLen) {
+ if (bytes[i] == '\r') {
+ i += 2;
+ } else {
+ i += 1;
}
+ }
- while ((i-start) < sectionLen) {
- if (bytes[i++] == ' ') {
- // name is wrapped
- int wrapStart = i;
- while (((i-start) < sectionLen)
- && (bytes[i++] != '\n'));
- if (bytes[i-1] != '\n')
- return; // XXX: exception?
- int wrapLen;
- if (bytes[i-2] == '\r')
- wrapLen = i-wrapStart-2;
- else
- wrapLen = i-wrapStart-1;
+ while ((i-start) < sectionLen) {
+ if (bytes[i++] == ' ') {
+ // name is wrapped
+ int wrapStart = i;
+ while (((i-start) < sectionLen)
+ && (bytes[i++] != '\n'));
+ if (bytes[i-1] != '\n')
+ return; // XXX: exception?
+ int wrapLen;
+ if (bytes[i-2] == '\r')
+ wrapLen = i-wrapStart-2;
+ else
+ wrapLen = i-wrapStart-1;
- nameBuf.append(new String(bytes, wrapStart,
- wrapLen, "UTF8"));
- } else {
- break;
- }
+ nameBuf.write(bytes, wrapStart, wrapLen);
+ } else {
+ break;
}
+ }
- entries.put(nameBuf.toString(),
- new Entry(start, sectionLen, sectionLenWithBlank,
+ entries.put(new String(nameBuf.toByteArray(), UTF_8),
+ new Entry(start, sectionLen, sectionLenWithBlank,
rawBytes));
-
- } catch (java.io.UnsupportedEncodingException uee) {
- throw new IllegalStateException(
- "UTF8 not available on platform");
- }
}
}
start = pos.startOfNext;
--- a/src/java.base/share/lib/security/default.policy Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/lib/security/default.policy Wed Oct 04 20:01:19 2017 +0000
@@ -142,6 +142,10 @@
permission java.security.AllPermission;
};
+grant codeBase "jrt:/jdk.httpserver" {
+ permission java.security.AllPermission;
+};
+
grant codeBase "jrt:/jdk.internal.le" {
permission java.security.AllPermission;
};
--- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c Wed Oct 04 20:01:19 2017 +0000
@@ -679,14 +679,16 @@
}
/* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */
- currNanoTime = JVM_NanoTime(env, 0);
- nanoTimeout -= (currNanoTime - prevNanoTime);
- if (nanoTimeout < NET_NSEC_PER_MSEC) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "Accept timed out");
- return;
+ if (nanoTimeout >= NET_NSEC_PER_MSEC) {
+ currNanoTime = JVM_NanoTime(env, 0);
+ nanoTimeout -= (currNanoTime - prevNanoTime);
+ if (nanoTimeout < NET_NSEC_PER_MSEC) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+ "Accept timed out");
+ return;
+ }
+ prevNanoTime = currNanoTime;
}
- prevNanoTime = currNanoTime;
}
if (newfd < 0) {
--- a/src/java.base/windows/native/libjava/io_util_md.c Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/windows/native/libjava/io_util_md.c Wed Oct 04 20:01:19 2017 +0000
@@ -550,10 +550,10 @@
fileDescriptorClose(JNIEnv *env, jobject this)
{
FD fd = (*env)->GetLongField(env, this, IO_handle_fdID);
+ HANDLE h = (HANDLE)fd;
if ((*env)->ExceptionOccurred(env)) {
return;
}
- HANDLE h = (HANDLE)fd;
if (h == INVALID_HANDLE_VALUE) {
return;
--- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java Wed Oct 04 20:01:19 2017 +0000
@@ -216,8 +216,9 @@
* Character#isJavaIdentifierStart(int)} returns {@code true},
* followed only by characters for which {@link
* Character#isJavaIdentifierPart(int)} returns {@code true}.
- * This pattern matches regular identifiers, keywords, and the
- * literals {@code "true"}, {@code "false"}, and {@code "null"}.
+ * This pattern matches regular identifiers, keywords, restricted
+ * keywords, and the literals {@code "true"}, {@code "false"}, and
+ * {@code "null"}.
* The method returns {@code false} for all other strings.
*
* @param name the string to check
@@ -251,10 +252,13 @@
* qualified name in the latest source version. Unlike {@link
* #isIdentifier isIdentifier}, this method returns {@code false}
* for keywords, boolean literals, and the null literal.
+ * This method returns {@code true} for <i>restricted
+ * keywords</i>.
*
* @param name the string to check
* @return {@code true} if this string is a
* syntactically valid name, {@code false} otherwise.
+ * @jls 3.9 Keywords
* @jls 6.2 Names and Identifiers
*/
public static boolean isName(CharSequence name) {
@@ -266,11 +270,14 @@
* qualified name in the given source version. Unlike {@link
* #isIdentifier isIdentifier}, this method returns {@code false}
* for keywords, boolean literals, and the null literal.
+ * This method returns {@code true} for <i>restricted
+ * keywords</i>.
*
* @param name the string to check
* @param version the version to use
* @return {@code true} if this string is a
* syntactically valid name, {@code false} otherwise.
+ * @jls 3.9 Keywords
* @jls 6.2 Names and Identifiers
* @since 9
*/
@@ -287,6 +294,8 @@
/**
* Returns whether or not {@code s} is a keyword, boolean literal,
* or null literal in the latest source version.
+ * This method returns {@code false} for <i>restricted
+ * keywords</i>.
*
* @param s the string to check
* @return {@code true} if {@code s} is a keyword, or boolean
@@ -302,6 +311,8 @@
/**
* Returns whether or not {@code s} is a keyword, boolean literal,
* or null literal in the given source version.
+ * This method returns {@code false} for <i>restricted
+ * keywords</i>.
*
* @param s the string to check
* @param version the version to use
--- a/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java Wed Oct 04 20:01:19 2017 +0000
@@ -87,7 +87,7 @@
*
* @return {@code true} if this is an open module and {@code
* false} otherwise
- */ // TODO: add @jls to unnamed module section
+ */
boolean isOpen();
/**
@@ -96,7 +96,9 @@
*
* @return {@code true} if this is an unnamed module and {@code
* false} otherwise
- */ // TODO: add @jls to unnamed module section
+ *
+ * @jls 7.7.5 Unnamed Modules
+ */
boolean isUnnamed();
/**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java Wed Oct 04 20:01:19 2017 +0000
@@ -71,6 +71,7 @@
HIDDEN(Category.RESOLUTION_TARGET), // not overloaded non-target
STATICERR(Category.RESOLUTION_TARGET), // overloaded? target
MISSING_ENCL(Category.RESOLUTION), // not overloaded non-target
+ BAD_VAR(Category.RESOLUTION), // not overloaded non-target
ABSENT_VAR(Category.RESOLUTION_TARGET, KindName.VAR), // not overloaded non-target
WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD), // overloaded target
WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD), // not overloaded target
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Wed Oct 04 20:01:19 2017 +0000
@@ -227,6 +227,7 @@
return compareTo(JDK1_8) <= 0;
}
public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
+ public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
public static SourceVersion toSourceVersion(Source source) {
switch(source) {
case JDK1_2:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java Wed Oct 04 20:01:19 2017 +0000
@@ -1616,6 +1616,7 @@
public TypeVar(Name name, Symbol owner, Type lower) {
super(null, TypeMetadata.EMPTY);
+ Assert.checkNonNull(lower);
tsym = new TypeVariableSymbol(0, name, this, owner);
this.bound = null;
this.lower = lower;
@@ -1628,6 +1629,7 @@
public TypeVar(TypeSymbol tsym, Type bound, Type lower,
TypeMetadata metadata) {
super(tsym, metadata);
+ Assert.checkNonNull(lower);
this.bound = bound;
this.lower = lower;
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Wed Oct 04 20:01:19 2017 +0000
@@ -1247,7 +1247,9 @@
final TypeAnnotationPosition pos =
TypeAnnotationPosition.localVariable(currentLambda,
tree.pos);
- separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
+ if (!tree.isImplicitlyTyped()) {
+ separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
+ }
} else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
final TypeAnnotationPosition pos =
TypeAnnotationPosition.exceptionParameter(currentLambda,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Wed Oct 04 20:01:19 2017 +0000
@@ -190,6 +190,245 @@
}
// </editor-fold>
+ // <editor-fold defaultstate="collapsed" desc="projections">
+
+ /**
+ * A projection kind. See {@link TypeProjection}
+ */
+ enum ProjectionKind {
+ UPWARDS() {
+ @Override
+ ProjectionKind complement() {
+ return DOWNWARDS;
+ }
+ },
+ DOWNWARDS() {
+ @Override
+ ProjectionKind complement() {
+ return UPWARDS;
+ }
+ };
+
+ abstract ProjectionKind complement();
+ }
+
+ /**
+ * This visitor performs upwards and downwards projections on types.
+ *
+ * A projection is defined as a function that takes a type T, a set of type variables V and that
+ * produces another type S.
+ *
+ * An upwards projection maps a type T into a type S such that (i) T has no variables in V,
+ * and (ii) S is an upper bound of T.
+ *
+ * A downwards projection maps a type T into a type S such that (i) T has no variables in V,
+ * and (ii) S is a lower bound of T.
+ *
+ * Note that projections are only allowed to touch variables in V. Theferore it is possible for
+ * a projection to leave its input type unchanged if it does not contain any variables in V.
+ *
+ * Moreover, note that while an upwards projection is always defined (every type as an upper bound),
+ * a downwards projection is not always defined.
+ *
+ * Examples:
+ *
+ * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
+ * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
+ * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
+ * {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
+ */
+ class TypeProjection extends StructuralTypeMapping<ProjectionKind> {
+
+ List<Type> vars;
+ Set<Type> seen = new HashSet<>();
+
+ public TypeProjection(List<Type> vars) {
+ this.vars = vars;
+ }
+
+ @Override
+ public Type visitClassType(ClassType t, ProjectionKind pkind) {
+ if (t.isCompound()) {
+ List<Type> components = directSupertypes(t);
+ List<Type> components1 = components.map(c -> c.map(this, pkind));
+ if (components == components1) return t;
+ else return makeIntersectionType(components1);
+ } else {
+ Type outer = t.getEnclosingType();
+ Type outer1 = visit(outer, pkind);
+ List<Type> typarams = t.getTypeArguments();
+ List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, pkind));
+ if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
+ //not defined
+ return syms.botType;
+ }
+ if (outer1 == outer && typarams1 == typarams) return t;
+ else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
+ @Override
+ protected boolean needsStripping() {
+ return true;
+ }
+ };
+ }
+ }
+
+ protected Type makeWildcard(Type upper, Type lower) {
+ BoundKind bk;
+ Type bound;
+ if (upper.hasTag(BOT)) {
+ upper = syms.objectType;
+ }
+ boolean isUpperObject = isSameType(upper, syms.objectType);
+ if (!lower.hasTag(BOT) && isUpperObject) {
+ bound = lower;
+ bk = SUPER;
+ } else {
+ bound = upper;
+ bk = isUpperObject ? UNBOUND : EXTENDS;
+ }
+ return new WildcardType(bound, bk, syms.boundClass);
+ }
+
+ @Override
+ public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
+ if (vars.contains(t)) {
+ try {
+ if (seen.add(t)) {
+ final Type bound;
+ switch (pkind) {
+ case UPWARDS:
+ bound = t.getUpperBound();
+ break;
+ case DOWNWARDS:
+ bound = (t.getLowerBound() == null) ?
+ syms.botType :
+ t.getLowerBound();
+ break;
+ default:
+ Assert.error();
+ return null;
+ }
+ return bound.map(this, pkind);
+ } else {
+ //cycle
+ return syms.objectType;
+ }
+ } finally {
+ seen.remove(t);
+ }
+ } else {
+ return t;
+ }
+ }
+
+ @Override
+ public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
+ switch (pkind) {
+ case UPWARDS:
+ return wt.isExtendsBound() ?
+ wt.type.map(this, pkind) :
+ syms.objectType;
+ case DOWNWARDS:
+ return wt.isSuperBound() ?
+ wt.type.map(this, pkind) :
+ syms.botType;
+ default:
+ Assert.error();
+ return null;
+ }
+ }
+
+ private Type mapTypeArgument(Type t, ProjectionKind pkind) {
+ if (!t.containsAny(vars)) {
+ return t;
+ } else if (!t.hasTag(WILDCARD) && pkind == ProjectionKind.DOWNWARDS) {
+ //not defined
+ return syms.botType;
+ } else {
+ Type upper = t.map(this, pkind);
+ Type lower = t.map(this, pkind.complement());
+ return makeWildcard(upper, lower);
+ }
+ }
+ }
+
+ /**
+ * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
+ *
+ * @param t the type to be projected
+ * @param vars the set of type variables to be mapped
+ * @return the type obtained as result of the projection
+ */
+ public Type upward(Type t, List<Type> vars) {
+ return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
+ }
+
+ /**
+ * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
+ * This routine is typically used to computed the input set of variables to be used during
+ * an upwards projection (see {@link Types#upward(Type, List)}).
+ *
+ * @param t the type where occurrences of captured variables have to be found
+ * @return the set of captured variables found in t
+ */
+ public List<Type> captures(Type t) {
+ CaptureScanner cs = new CaptureScanner();
+ Set<Type> captures = new HashSet<>();
+ cs.visit(t, captures);
+ return List.from(captures);
+ }
+
+ /**
+ * This visitor scans a type recursively looking for occurrences of captured type variables.
+ */
+ class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
+
+ @Override
+ public Void visitType(Type t, Set<Type> types) {
+ return null;
+ }
+
+ @Override
+ public Void visitClassType(ClassType t, Set<Type> seen) {
+ if (t.isCompound()) {
+ directSupertypes(t).forEach(s -> visit(s, seen));
+ } else {
+ t.allparams().forEach(ta -> visit(ta, seen));
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitArrayType(ArrayType t, Set<Type> seen) {
+ return visit(t.elemtype, seen);
+ }
+
+ @Override
+ public Void visitWildcardType(WildcardType t, Set<Type> seen) {
+ visit(t.type, seen);
+ return null;
+ }
+
+ @Override
+ public Void visitTypeVar(TypeVar t, Set<Type> seen) {
+ if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
+ visit(t.getUpperBound(), seen);
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitCapturedType(CapturedType t, Set<Type> seen) {
+ if (seen.add(t)) {
+ visit(t.getUpperBound(), seen);
+ visit(t.getLowerBound(), seen);
+ }
+ return null;
+ }
+ }
+
+ // </editor-fold>
+
// <editor-fold defaultstate="collapsed" desc="isUnbounded">
/**
* Checks that all the arguments to a class are unbounded
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java Wed Oct 04 20:01:19 2017 +0000
@@ -83,6 +83,7 @@
import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
+import static com.sun.tools.javac.tree.JCTree.Tag.FOREACHLOOP;
import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED;
import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
@@ -139,7 +140,8 @@
enum AnalyzerMode {
DIAMOND("diamond", Source::allowDiamond),
LAMBDA("lambda", Source::allowLambda),
- METHOD("method", Source::allowGraphInference);
+ METHOD("method", Source::allowGraphInference),
+ LOCAL("local", Source::allowLocalVariableTypeInference);
final String opt;
final Predicate<Source> sourceFilter;
@@ -341,11 +343,91 @@
}
}
+ /**
+ * Base class for local variable inference analyzers.
+ */
+ abstract class RedundantLocalVarTypeAnalyzerBase<X extends JCStatement> extends StatementAnalyzer<X, X> {
+
+ RedundantLocalVarTypeAnalyzerBase(JCTree.Tag tag) {
+ super(AnalyzerMode.LOCAL, tag);
+ }
+
+ /**
+ * Map a variable tree into a new declaration using implicit type.
+ */
+ JCVariableDecl mapVar(JCVariableDecl oldTree, JCVariableDecl newTree){
+ newTree.vartype = null;
+ return newTree;
+ }
+
+ /**
+ * Analyze results of local variable inference.
+ */
+ void processVar(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
+ if (!hasErrors) {
+ if (types.isSameType(oldTree.type, newTree.type)) {
+ log.warning(oldTree, Warnings.LocalRedundantType);
+ }
+ }
+ }
+ }
+
+ /**
+ * This analyzer checks if a local variable declaration has redundant type.
+ */
+ class RedundantLocalVarTypeAnalyzer extends RedundantLocalVarTypeAnalyzerBase<JCVariableDecl> {
+
+ RedundantLocalVarTypeAnalyzer() {
+ super(VARDEF);
+ }
+
+ boolean match(JCVariableDecl tree){
+ return tree.sym.owner.kind == Kind.MTH &&
+ tree.init != null && !tree.isImplicitlyTyped() &&
+ attr.canInferLocalVarType(tree) == null;
+ }
+ @Override
+ JCVariableDecl map(JCVariableDecl oldTree, JCVariableDecl newTree){
+ return mapVar(oldTree, newTree);
+ }
+ @Override
+ void process(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
+ processVar(oldTree, newTree, hasErrors);
+ }
+ }
+
+ /**
+ * This analyzer checks if a for each variable declaration has redundant type.
+ */
+ class RedundantLocalVarTypeAnalyzerForEach extends RedundantLocalVarTypeAnalyzerBase<JCEnhancedForLoop> {
+
+ RedundantLocalVarTypeAnalyzerForEach() {
+ super(FOREACHLOOP);
+ }
+
+ @Override
+ boolean match(JCEnhancedForLoop tree){
+ return !tree.var.isImplicitlyTyped();
+ }
+ @Override
+ JCEnhancedForLoop map(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree){
+ newTree.var = mapVar(oldTree.var, newTree.var);
+ newTree.body = make.Block(0, List.nil()); //ignore body for analysis purpose
+ return newTree;
+ }
+ @Override
+ void process(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree, boolean hasErrors){
+ processVar(oldTree.var, newTree.var, hasErrors);
+ }
+ }
+
@SuppressWarnings({"unchecked", "rawtypes"})
StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
new DiamondInitializer(),
new LambdaAnalyzer(),
- new RedundantTypeArgAnalyzer()
+ new RedundantTypeArgAnalyzer(),
+ new RedundantLocalVarTypeAnalyzer(),
+ new RedundantLocalVarTypeAnalyzerForEach()
};
/**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Wed Oct 04 20:01:19 2017 +0000
@@ -28,9 +28,11 @@
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Attribute.Compound;
import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Kinds.KindSelector;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
+import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
@@ -602,7 +604,7 @@
}
private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
- Type result = attr.attribExpr(tree, env, expectedElementType);
+ Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
Symbol sym = TreeInfo.symbol(tree);
if (sym == null ||
TreeInfo.nonstaticSelect(tree) ||
@@ -616,7 +618,7 @@
}
private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
- Type result = attr.attribExpr(tree, env, expectedElementType);
+ Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
if (result.isErroneous()) {
// Does it look like an unresolved class literal?
if (TreeInfo.name(tree) == names._class &&
@@ -642,7 +644,7 @@
}
private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
- Type result = attr.attribExpr(tree, env, expectedElementType);
+ Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
if (result.isErroneous())
return new Attribute.Error(result.getOriginalType());
if (result.constValue() == null) {
@@ -653,6 +655,22 @@
return new Attribute.Constant(expectedElementType, result.constValue());
}
+ private Attr.ResultInfo annotationValueInfo(Type pt) {
+ return attr.unknownExprInfo.dup(pt, new AnnotationValueContext(attr.unknownExprInfo.checkContext));
+ }
+
+ class AnnotationValueContext extends Check.NestedCheckContext {
+ AnnotationValueContext(CheckContext enclosingContext) {
+ super(enclosingContext);
+ }
+
+ @Override
+ public boolean compatible(Type found, Type req, Warner warn) {
+ //handle non-final implicitly-typed vars (will be rejected later on)
+ return found.hasTag(TypeTag.NONE) || super.compatible(found, req, warn);
+ }
+ }
+
private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
// Special case, implicit array
if (!tree.hasTag(NEWARRAY)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Wed Oct 04 20:01:19 2017 +0000
@@ -36,7 +36,6 @@
import com.sun.source.tree.TreeVisitor;
import com.sun.source.util.SimpleTreeVisitor;
import com.sun.tools.javac.code.*;
-import com.sun.tools.javac.code.Directive.RequiresFlag;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
@@ -46,7 +45,6 @@
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
-import com.sun.tools.javac.comp.Infer.FreeTypeListener;
import com.sun.tools.javac.jvm.*;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
@@ -830,6 +828,10 @@
final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
try {
Type itype = attribExpr(variable.init, env, type);
+ if (variable.isImplicitlyTyped()) {
+ //fixup local variable type
+ type = variable.type = variable.sym.type = chk.checkLocalVarType(variable, itype.baseType(), variable.name);
+ }
if (itype.constValue() != null) {
return coerce(itype, type).constValue();
} else {
@@ -1108,6 +1110,21 @@
// parameters have already been entered
env.info.scope.enter(tree.sym);
} else {
+ if (tree.isImplicitlyTyped() && (tree.getModifiers().flags & PARAMETER) == 0) {
+ if (tree.init == null) {
+ //cannot use 'var' without initializer
+ log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit));
+ tree.vartype = make.Erroneous();
+ } else {
+ Fragment msg = canInferLocalVarType(tree);
+ if (msg != null) {
+ //cannot use 'var' with initializer which require an explicit target
+ //(e.g. lambda, method reference, array initializer).
+ log.error(tree, Errors.CantInferLocalVarType(tree.name, msg));
+ tree.vartype = make.Erroneous();
+ }
+ }
+ }
try {
annotate.blockAnnotations();
memberEnter.memberEnter(tree, env);
@@ -1131,7 +1148,7 @@
boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) &&
((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
(tree.sym.flags() & PARAMETER) != 0;
- chk.validate(tree.vartype, env, !isImplicitLambdaParameter);
+ chk.validate(tree.vartype, env, !isImplicitLambdaParameter && !tree.isImplicitlyTyped());
try {
v.getConstValue(); // ensure compile-time constant initializer is evaluated
@@ -1152,6 +1169,10 @@
// marking the variable as undefined.
initEnv.info.enclVar = v;
attribExpr(tree.init, initEnv, v.type);
+ if (tree.isImplicitlyTyped()) {
+ //fixup local variable type
+ v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), tree.name);
+ }
}
}
result = tree.type = v.type;
@@ -1161,6 +1182,71 @@
}
}
+ Fragment canInferLocalVarType(JCVariableDecl tree) {
+ LocalInitScanner lis = new LocalInitScanner();
+ lis.scan(tree.init);
+ return lis.badInferenceMsg;
+ }
+
+ static class LocalInitScanner extends TreeScanner {
+ Fragment badInferenceMsg = null;
+ boolean needsTarget = true;
+
+ @Override
+ public void visitNewArray(JCNewArray tree) {
+ if (tree.elemtype == null && needsTarget) {
+ badInferenceMsg = Fragments.LocalArrayMissingTarget;
+ }
+ }
+
+ @Override
+ public void visitLambda(JCLambda tree) {
+ if (needsTarget) {
+ badInferenceMsg = Fragments.LocalLambdaMissingTarget;
+ }
+ }
+
+ @Override
+ public void visitTypeCast(JCTypeCast tree) {
+ boolean prevNeedsTarget = needsTarget;
+ try {
+ needsTarget = false;
+ super.visitTypeCast(tree);
+ } finally {
+ needsTarget = prevNeedsTarget;
+ }
+ }
+
+ @Override
+ public void visitReference(JCMemberReference tree) {
+ if (needsTarget) {
+ badInferenceMsg = Fragments.LocalMrefMissingTarget;
+ }
+ }
+
+ @Override
+ public void visitNewClass(JCNewClass tree) {
+ boolean prevNeedsTarget = needsTarget;
+ try {
+ needsTarget = false;
+ super.visitNewClass(tree);
+ } finally {
+ needsTarget = prevNeedsTarget;
+ }
+ }
+
+ @Override
+ public void visitApply(JCMethodInvocation tree) {
+ boolean prevNeedsTarget = needsTarget;
+ try {
+ needsTarget = false;
+ super.visitApply(tree);
+ } finally {
+ needsTarget = prevNeedsTarget;
+ }
+ }
+ }
+
public void visitSkip(JCSkip tree) {
result = null;
}
@@ -1243,7 +1329,6 @@
//attributing the for-each expression; we mimick this by attributing
//the for-each expression first (against original scope).
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
- attribStat(tree.var, loopEnv);
chk.checkNonVoid(tree.pos(), exprType);
Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
if (elemtype == null) {
@@ -1261,6 +1346,15 @@
: types.wildUpperBound(iterableParams.head);
}
}
+ if (tree.var.isImplicitlyTyped()) {
+ Type inferredType = chk.checkLocalVarType(tree.var, elemtype, tree.var.name);
+ if (inferredType.isErroneous()) {
+ tree.var.vartype = make.at(tree.var.vartype).Erroneous();
+ } else {
+ tree.var.vartype = make.at(tree.var.vartype).Type(inferredType);
+ }
+ }
+ attribStat(tree.var, loopEnv);
chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
loopEnv.tree = tree; // before, we were not in loop!
attribStat(tree.body, loopEnv);
@@ -2379,7 +2473,8 @@
if (pt().hasTag(ARRAY)) {
elemtype = types.elemtype(pt());
} else {
- if (!pt().hasTag(ERROR)) {
+ if (!pt().hasTag(ERROR) &&
+ (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
log.error(tree.pos(),
Errors.IllegalInitializerForType(pt()));
}
@@ -2404,7 +2499,7 @@
@Override
public void visitLambda(final JCLambda that) {
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
- if (pt().hasTag(NONE)) {
+ if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
//lambda only allowed in assignment or method invocation/cast context
log.error(that.pos(), Errors.UnexpectedLambda);
}
@@ -2837,7 +2932,7 @@
@Override
public void visitReference(final JCMemberReference that) {
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
- if (pt().hasTag(NONE)) {
+ if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
//method reference only allowed in assignment or method invocation/cast context
log.error(that.pos(), Errors.UnexpectedMref);
}
@@ -3811,6 +3906,14 @@
break;
case VAR:
VarSymbol v = (VarSymbol)sym;
+
+ if (env.info.enclVar != null
+ && v.type.hasTag(NONE)) {
+ //self reference to implicitly typed variable declaration
+ log.error(TreeInfo.positionFor(v, env.enclClass), Errors.CantInferLocalVarType(v.name, Fragments.LocalSelfRef));
+ return v.type = types.createErrorType(v.type);
+ }
+
// Test (4): if symbol is an instance field of a raw type,
// which is being assigned to, issue an unchecked warning if
// its type changes under erasure.
@@ -4135,6 +4238,9 @@
public void visitTypeArray(JCArrayTypeTree tree) {
Type etype = attribType(tree.elemtype, env);
Type type = new ArrayType(etype, syms.arrayClass);
+ if (etype.isErroneous()) {
+ type = types.createErrorType(type);
+ }
result = check(tree, type, KindSelector.TYP, resultInfo);
}
@@ -4776,7 +4882,7 @@
}
public void visitVarDef(final JCVariableDecl tree) {
//System.err.println("validateTypeAnnotations.visitVarDef " + tree);
- if (tree.sym != null && tree.sym.type != null)
+ if (tree.sym != null && tree.sym.type != null && !tree.isImplicitlyTyped())
validateAnnotatedType(tree.vartype, tree.sym.type);
scan(tree.mods);
scan(tree.vartype);
@@ -4904,17 +5010,16 @@
repeat = false;
} else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) {
JCWildcard wc = (JCWildcard) enclTr;
- if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD) {
- validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getExtendsBound());
- } else if (wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
- validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getSuperBound());
+ if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD ||
+ wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
+ validateAnnotatedType(wc.getBound(), wc.getBound().type);
} else {
// Nothing to do for UNBOUND
}
repeat = false;
} else if (enclTr.hasTag(TYPEARRAY)) {
JCArrayTypeTree art = (JCArrayTypeTree) enclTr;
- validateAnnotatedType(art.getType(), ((ArrayType)enclTy).getComponentType());
+ validateAnnotatedType(art.getType(), art.elemtype.type);
repeat = false;
} else if (enclTr.hasTag(TYPEUNION)) {
JCTypeUnion ut = (JCTypeUnion) enclTr;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Wed Oct 04 20:01:19 2017 +0000
@@ -843,26 +843,30 @@
List<Type> checkDiamondDenotable(ClassType t) {
ListBuffer<Type> buf = new ListBuffer<>();
for (Type arg : t.allparams()) {
- if (!diamondTypeChecker.visit(arg, null)) {
+ if (!checkDenotable(arg)) {
buf.append(arg);
}
}
return buf.toList();
}
+
+ boolean checkDenotable(Type t) {
+ return denotableChecker.visit(t, null);
+ }
// where
/** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
* types. The visit methods return false as soon as a non-denotable type is encountered and true
* otherwise.
*/
- private static final Types.SimpleVisitor<Boolean, Void> diamondTypeChecker = new Types.SimpleVisitor<Boolean, Void>() {
+ private static final Types.SimpleVisitor<Boolean, Void> denotableChecker = new Types.SimpleVisitor<Boolean, Void>() {
@Override
public Boolean visitType(Type t, Void s) {
return true;
}
@Override
public Boolean visitClassType(ClassType t, Void s) {
- if (t.isCompound()) {
+ if (t.isUnion() || t.isIntersection()) {
return false;
}
for (Type targ : t.allparams()) {
@@ -878,7 +882,7 @@
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
(i.e cannot have been produced by inference (18.4))
*/
- return t.tsym.owner.type.getTypeArguments().contains(t);
+ return (t.tsym.flags() & SYNTHETIC) == 0;
}
@Override
@@ -941,6 +945,17 @@
(allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
}
+ Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
+ //upward project the initializer type
+ t = types.upward(t, types.captures(t));
+ //check that resulting type is not the null type
+ if (t.hasTag(BOT)) {
+ log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferNull));
+ return types.createErrorType(t);
+ }
+ return t;
+ }
+
Type checkMethod(final Type mtype,
final Symbol sym,
final Env<AttrContext> env,
@@ -3159,7 +3174,10 @@
if (s.kind == PCK)
return true;
} else if (target == names.TYPE_USE) {
- if (s.kind == TYP || s.kind == VAR ||
+ if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
+ //cannot type annotate implictly typed locals
+ return false;
+ } else if (s.kind == TYP || s.kind == VAR ||
(s.kind == MTH && !s.isConstructor() &&
!s.type.getReturnType().hasTag(VOID)) ||
(s.kind == MTH && s.isConstructor())) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Wed Oct 04 20:01:19 2017 +0000
@@ -529,7 +529,7 @@
List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
if (Type.containsAny(upperBounds, vars)) {
TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
- fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null);
+ fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), syms.botType);
todo.append(uv);
uv.setInst(fresh_tvar.type);
} else if (upperBounds.nonEmpty()) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Wed Oct 04 20:01:19 2017 +0000
@@ -259,7 +259,7 @@
try {
if (TreeInfo.isEnumInit(tree)) {
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
- } else {
+ } else if (!tree.isImplicitlyTyped()) {
attr.attribType(tree.vartype, localEnv);
if (TreeInfo.isReceiverParam(tree))
checkReceiver(tree, localEnv);
@@ -279,8 +279,8 @@
tree.vartype.type = atype.makeVarargs();
}
WriteableScope enclScope = enter.enterScope(env);
- VarSymbol v =
- new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
+ Type vartype = tree.isImplicitlyTyped() ? Type.noType : tree.vartype.type;
+ VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
tree.sym = v;
if (tree.init != null) {
@@ -298,7 +298,9 @@
}
annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
- annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
+ if (!tree.isImplicitlyTyped()) {
+ annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
+ }
v.pos = tree.pos;
}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Oct 04 20:01:19 2017 +0000
@@ -59,6 +59,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
+import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
@@ -105,6 +106,7 @@
public final boolean allowModules;
public final boolean checkVarargsAccessAfterResolution;
private final boolean compactMethodDiags;
+ private final boolean allowLocalVariableTypeInference;
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
WriteableScope polymorphicSignatureScope;
@@ -116,7 +118,7 @@
varNotFound = new SymbolNotFoundError(ABSENT_VAR);
methodNotFound = new SymbolNotFoundError(ABSENT_MTH);
typeNotFound = new SymbolNotFoundError(ABSENT_TYP);
- referenceNotFound = new ReferenceLookupResult(methodNotFound, null);
+ referenceNotFound = ReferenceLookupResult.error(methodNotFound);
names = Names.instance(context);
log = Log.instance(context);
@@ -136,6 +138,7 @@
Target target = Target.instance(context);
allowMethodHandles = target.hasMethodHandles();
allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
+ allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
checkVarargsAccessAfterResolution =
source.allowPostApplicabilityVarargsAccessCheck();
polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
@@ -2325,6 +2328,10 @@
* (a subset of VAL, TYP, PCK).
*/
Symbol findIdent(Env<AttrContext> env, Name name, KindSelector kind) {
+ return checkVarType(findIdentInternal(env, name, kind), name);
+ }
+
+ Symbol findIdentInternal(Env<AttrContext> env, Name name, KindSelector kind) {
Symbol bestSoFar = typeNotFound;
Symbol sym;
@@ -2354,6 +2361,11 @@
*/
Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck,
Name name, KindSelector kind) {
+ return checkVarType(findIdentInPackageInternal(env, pck, name, kind), name);
+ }
+
+ Symbol findIdentInPackageInternal(Env<AttrContext> env, TypeSymbol pck,
+ Name name, KindSelector kind) {
Name fullname = TypeSymbol.formFullName(name, pck);
Symbol bestSoFar = typeNotFound;
if (kind.contains(KindSelector.TYP)) {
@@ -2383,6 +2395,11 @@
*/
Symbol findIdentInType(Env<AttrContext> env, Type site,
Name name, KindSelector kind) {
+ return checkVarType(findIdentInTypeInternal(env, site, name, kind), name);
+ }
+
+ Symbol findIdentInTypeInternal(Env<AttrContext> env, Type site,
+ Name name, KindSelector kind) {
Symbol bestSoFar = typeNotFound;
Symbol sym;
if (kind.contains(KindSelector.VAL)) {
@@ -2399,6 +2416,14 @@
return bestSoFar;
}
+ private Symbol checkVarType(Symbol bestSoFar, Name name) {
+ if (allowLocalVariableTypeInference && name.equals(names.var) &&
+ (bestSoFar.kind == TYP || bestSoFar.kind == ABSENT_TYP)) {
+ bestSoFar = new BadVarTypeError();
+ }
+ return bestSoFar;
+ }
+
/* ***************************************************************************
* Access checking
* The following methods convert ResolveErrors to ErrorSymbols, issuing
@@ -2944,10 +2969,10 @@
//merge results
Pair<Symbol, ReferenceLookupHelper> res;
- Symbol bestSym = referenceChooser.result(boundRes, unboundRes);
- res = new Pair<>(bestSym,
- bestSym == unboundSym ? unboundLookupHelper : boundLookupHelper);
- env.info.pendingResolutionPhase = bestSym == unboundSym ?
+ ReferenceLookupResult bestRes = referenceChooser.result(boundRes, unboundRes);
+ res = new Pair<>(bestRes.sym,
+ bestRes == unboundRes ? unboundLookupHelper : boundLookupHelper);
+ env.info.pendingResolutionPhase = bestRes == unboundRes ?
unboundEnv.info.pendingResolutionPhase :
boundEnv.info.pendingResolutionPhase;
@@ -3003,11 +3028,15 @@
Symbol sym;
ReferenceLookupResult(Symbol sym, MethodResolutionContext resolutionContext) {
- this.staticKind = staticKind(sym, resolutionContext);
+ this(sym, staticKind(sym, resolutionContext));
+ }
+
+ private ReferenceLookupResult(Symbol sym, StaticKind staticKind) {
+ this.staticKind = staticKind;
this.sym = sym;
}
- private StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
+ private static StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
switch (sym.kind) {
case MTH:
case AMBIGUOUS:
@@ -3056,6 +3085,10 @@
return false;
}
}
+
+ static ReferenceLookupResult error(Symbol sym) {
+ return new ReferenceLookupResult(sym, StaticKind.UNDEFINED);
+ }
}
/**
@@ -3068,7 +3101,7 @@
* Generate a result from a pair of lookup result objects. This method delegates to the
* appropriate result generation routine.
*/
- Symbol result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
+ ReferenceLookupResult result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
return unboundRes != referenceNotFound ?
unboundResult(boundRes, unboundRes) :
boundResult(boundRes);
@@ -3077,12 +3110,12 @@
/**
* Generate a symbol from a given bound lookup result.
*/
- abstract Symbol boundResult(ReferenceLookupResult boundRes);
+ abstract ReferenceLookupResult boundResult(ReferenceLookupResult boundRes);
/**
* Generate a symbol from a pair of bound/unbound lookup results.
*/
- abstract Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes);
+ abstract ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes);
}
/**
@@ -3092,37 +3125,38 @@
ReferenceChooser basicReferenceChooser = new ReferenceChooser() {
@Override
- Symbol boundResult(ReferenceLookupResult boundRes) {
+ ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
return !boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC) ?
- boundRes.sym : //the search produces a non-static method
- new BadMethodReferenceError(boundRes.sym, false);
+ boundRes : //the search produces a non-static method
+ ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
}
@Override
- Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
+ ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
if (boundRes.hasKind(StaticKind.STATIC) &&
(!unboundRes.isSuccess() || unboundRes.hasKind(StaticKind.STATIC))) {
//the first search produces a static method and no non-static method is applicable
//during the second search
- return boundRes.sym;
+ return boundRes;
} else if (unboundRes.hasKind(StaticKind.NON_STATIC) &&
(!boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC))) {
//the second search produces a non-static method and no static method is applicable
//during the first search
- return unboundRes.sym;
+ return unboundRes;
} else if (boundRes.isSuccess() && unboundRes.isSuccess()) {
//both searches produce some result; ambiguity (error recovery)
- return ambiguityError(boundRes.sym, unboundRes.sym);
+ return ReferenceLookupResult.error(ambiguityError(boundRes.sym, unboundRes.sym));
} else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
//Both searches failed to produce a result with correct staticness (i.e. first search
//produces an non-static method). Alternatively, a given search produced a result
//with the right staticness, but the other search has applicable methods with wrong
//staticness (error recovery)
- return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true);
+ return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
+ boundRes.sym : unboundRes.sym, true));
} else {
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
- unboundRes.sym : boundRes.sym;
+ unboundRes : boundRes;
}
}
};
@@ -3134,28 +3168,29 @@
ReferenceChooser structuralReferenceChooser = new ReferenceChooser() {
@Override
- Symbol boundResult(ReferenceLookupResult boundRes) {
+ ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
return (!boundRes.isSuccess() || !boundRes.hasKind(StaticKind.STATIC)) ?
- boundRes.sym : //the search has at least one applicable non-static method
- new BadMethodReferenceError(boundRes.sym, false);
+ boundRes : //the search has at least one applicable non-static method
+ ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
}
@Override
- Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
+ ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
if (boundRes.isSuccess() && !boundRes.hasKind(StaticKind.NON_STATIC)) {
//the first serach has at least one applicable static method
- return boundRes.sym;
+ return boundRes;
} else if (unboundRes.isSuccess() && !unboundRes.hasKind(StaticKind.STATIC)) {
//the second search has at least one applicable non-static method
- return unboundRes.sym;
+ return unboundRes;
} else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
//either the first search produces a non-static method, or second search produces
//a non-static method (error recovery)
- return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true);
+ return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
+ boundRes.sym : unboundRes.sym, true));
} else {
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
- unboundRes.sym : boundRes.sym;
+ unboundRes : boundRes;
}
}
};
@@ -3774,6 +3809,17 @@
}
}
+ class BadVarTypeError extends ResolveError {
+ BadVarTypeError() {
+ super(Kind.BAD_VAR, "bad var use");
+ }
+
+ @Override
+ JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
+ return diags.create(dkind, log.currentSource(), pos, "illegal.ref.to.var.type", name);
+ }
+ }
+
/**
* InvalidSymbolError error class indicating that a symbol matching a
* given name does not exists in a given site.
@@ -3995,14 +4041,35 @@
}
//where
private Map<Symbol, JCDiagnostic> mapCandidates() {
- Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<>();
+ MostSpecificMap candidates = new MostSpecificMap();
for (Candidate c : resolveContext.candidates) {
if (c.isApplicable()) continue;
- candidates.put(c.sym, c.details);
+ candidates.put(c);
}
return candidates;
}
+ @SuppressWarnings("serial")
+ private class MostSpecificMap extends LinkedHashMap<Symbol, JCDiagnostic> {
+ private void put(Candidate c) {
+ ListBuffer<Symbol> overridden = new ListBuffer<>();
+ for (Symbol s : keySet()) {
+ if (s == c.sym) {
+ continue;
+ }
+ if (c.sym.overrides(s, (TypeSymbol)s.owner, types, false)) {
+ overridden.add(s);
+ } else if (s.overrides(c.sym, (TypeSymbol)c.sym.owner, types, false)) {
+ return;
+ }
+ }
+ for (Symbol s : overridden) {
+ remove(s);
+ }
+ put(c.sym, c.details);
+ }
+ }
+
Map<Symbol, JCDiagnostic> filterCandidates(Map<Symbol, JCDiagnostic> candidatesMap) {
Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<>();
for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Wed Oct 04 20:01:19 2017 +0000
@@ -179,6 +179,7 @@
this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
+ this.allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
this.keepDocComments = keepDocComments;
this.parseModuleInfo = parseModuleInfo;
docComments = newDocCommentTable(keepDocComments, fac);
@@ -270,11 +271,14 @@
*/
boolean allowThisIdent;
+ /** Switch: is local variable inference allowed?
+ */
+ boolean allowLocalVariableTypeInference;
+
/** The type of the method receiver, as specified by a first "this" parameter.
*/
JCVariableDecl receiverParam;
-
/** When terms are parsed, the mode determines which is expected:
* mode = EXPR : an expression
* mode = TYPE : a type
@@ -808,12 +812,16 @@
* parsing annotations.
*/
public JCExpression parseType() {
- List<JCAnnotation> annotations = typeAnnotationsOpt();
- return parseType(annotations);
+ return parseType(false);
}
- public JCExpression parseType(List<JCAnnotation> annotations) {
- JCExpression result = unannotatedType();
+ public JCExpression parseType(boolean allowVar) {
+ List<JCAnnotation> annotations = typeAnnotationsOpt();
+ return parseType(allowVar, annotations);
+ }
+
+ public JCExpression parseType(boolean allowVar, List<JCAnnotation> annotations) {
+ JCExpression result = unannotatedType(allowVar);
if (annotations.nonEmpty()) {
result = insertAnnotationsToMostInner(result, annotations, false);
@@ -822,10 +830,18 @@
return result;
}
- public JCExpression unannotatedType() {
- return term(TYPE);
+ public JCExpression unannotatedType(boolean allowVar) {
+ JCExpression result = term(TYPE);
+
+ if (!allowVar && isRestrictedLocalVarTypeName(result)) {
+ syntaxError(result.pos, "var.not.allowed.here");
+ }
+
+ return result;
}
+
+
protected JCExpression term(int newmode) {
int prevmode = mode;
mode = newmode;
@@ -1152,11 +1168,11 @@
accept(LPAREN);
mode = TYPE;
int pos1 = pos;
- List<JCExpression> targets = List.of(t = term3());
+ List<JCExpression> targets = List.of(t = parseType());
while (token.kind == AMP) {
checkIntersectionTypesInCast();
accept(AMP);
- targets = targets.prepend(term3());
+ targets = targets.prepend(parseType());
}
if (targets.length() > 1) {
t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
@@ -1912,7 +1928,7 @@
*/
JCExpression typeArgument() {
List<JCAnnotation> annotations = typeAnnotationsOpt();
- if (token.kind != QUES) return parseType(annotations);
+ if (token.kind != QUES) return parseType(false, annotations);
int pos = token.pos;
nextToken();
JCExpression result;
@@ -2425,13 +2441,8 @@
token.kind == ENUM) {
return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
} else {
- JCExpression t = parseType();
- ListBuffer<JCStatement> stats =
- variableDeclarators(mods, t, new ListBuffer<JCStatement>());
- // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
- accept(SEMI);
- storeEnd(stats.last(), S.prevToken().endPos);
- return stats.toList();
+ JCExpression t = parseType(true);
+ return localVariableDeclarations(mods, t);
}
}
case ABSTRACT: case STRICTFP: {
@@ -2458,12 +2469,7 @@
pos = token.pos;
JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
F.at(pos);
- ListBuffer<JCStatement> stats =
- variableDeclarators(mods, t, new ListBuffer<JCStatement>());
- // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
- accept(SEMI);
- storeEnd(stats.last(), S.prevToken().endPos);
- return stats.toList();
+ return localVariableDeclarations(mods, t);
} else {
// This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
t = checkExprStat(t);
@@ -2473,6 +2479,15 @@
}
}
}
+ //where
+ private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) {
+ ListBuffer<JCStatement> stats =
+ variableDeclarators(mods, type, new ListBuffer<>(), true);
+ // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
+ accept(SEMI);
+ storeEnd(stats.last(), S.prevToken().endPos);
+ return stats.toList();
+ }
/** Statement =
* Block
@@ -2766,11 +2781,11 @@
ListBuffer<JCStatement> stats = new ListBuffer<>();
int pos = token.pos;
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
- return variableDeclarators(optFinal(0), parseType(), stats).toList();
+ return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
} else {
JCExpression t = term(EXPR | TYPE);
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
- return variableDeclarators(modifiersOpt(), t, stats).toList();
+ return variableDeclarators(modifiersOpt(), t, stats, true).toList();
} else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
error(pos, "bad.initializer", "for-loop");
return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
@@ -2989,9 +3004,10 @@
*/
public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
JCExpression type,
- T vdefs)
+ T vdefs,
+ boolean localDecl)
{
- return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
+ return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs, localDecl);
}
/** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
@@ -3006,14 +3022,20 @@
Name name,
boolean reqInit,
Comment dc,
- T vdefs)
+ T vdefs,
+ boolean localDecl)
{
- vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
+ JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl);
+ boolean implicit = allowLocalVariableTypeInference && head.vartype == null;
+ vdefs.append(head);
while (token.kind == COMMA) {
+ if (implicit) {
+ reportSyntaxError(pos, "var.not.allowed.compound");
+ }
// All but last of multiple declarators subsume a comma
storeEnd((JCTree)vdefs.last(), token.endPos);
nextToken();
- vdefs.append(variableDeclarator(mods, type, reqInit, dc));
+ vdefs.append(variableDeclarator(mods, type, reqInit, dc, localDecl));
}
return vdefs;
}
@@ -3021,8 +3043,8 @@
/** VariableDeclarator = Ident VariableDeclaratorRest
* ConstantDeclarator = Ident ConstantDeclaratorRest
*/
- JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
- return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
+ JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
+ return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc, localDecl);
}
/** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
@@ -3032,7 +3054,7 @@
* @param dc The documentation comment for the variable declarations, or null.
*/
JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
- boolean reqInit, Comment dc) {
+ boolean reqInit, Comment dc, boolean localDecl) {
type = bracketsOpt(type);
JCExpression init = null;
if (token.kind == EQ) {
@@ -3040,12 +3062,40 @@
init = variableInitializer();
}
else if (reqInit) syntaxError(token.pos, "expected", EQ);
+ JCTree elemType = TreeInfo.innermostType(type, true);
+ if (allowLocalVariableTypeInference && elemType.hasTag(IDENT)) {
+ Name typeName = ((JCIdent)elemType).name;
+ if (isRestrictedLocalVarTypeName(typeName)) {
+ if (type.hasTag(TYPEARRAY)) {
+ //error - 'var' and arrays
+ reportSyntaxError(pos, "var.not.allowed.array");
+ } else {
+ //implicit type
+ type = null;
+ }
+ }
+ }
JCVariableDecl result =
toP(F.at(pos).VarDef(mods, name, type, init));
attach(result, dc);
return result;
}
+ boolean isRestrictedLocalVarTypeName(JCExpression e) {
+ switch (e.getTag()) {
+ case IDENT:
+ return isRestrictedLocalVarTypeName(((JCIdent)e).name);
+ case TYPEARRAY:
+ return isRestrictedLocalVarTypeName(((JCArrayTypeTree)e).elemtype);
+ default:
+ return false;
+ }
+ }
+
+ boolean isRestrictedLocalVarTypeName(Name name) {
+ return allowLocalVariableTypeInference && name == names.var;
+ }
+
/** VariableDeclaratorId = Ident BracketsOpt
*/
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
@@ -3111,13 +3161,13 @@
int startPos = token.pos;
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
JCModifiers mods = optFinal(Flags.FINAL);
- JCExpression t = parseType();
- return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
+ JCExpression t = parseType(true);
+ return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
}
JCExpression t = term(EXPR | TYPE);
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL));
- return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
+ return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
} else {
checkVariableInTryWithResources(startPos);
if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
@@ -3397,7 +3447,7 @@
protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
int pos = token.pos;
accept(CLASS);
- Name name = ident();
+ Name name = typeName();
List<JCTypeParameter> typarams = typeParametersOpt();
@@ -3418,6 +3468,15 @@
return result;
}
+ Name typeName() {
+ int pos = token.pos;
+ Name name = ident();
+ if (isRestrictedLocalVarTypeName(name)) {
+ reportSyntaxError(pos, "var.not.allowed", name);
+ }
+ return name;
+ }
+
/** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
* [EXTENDS TypeList] InterfaceBody
* @param mods The modifiers starting the interface declaration
@@ -3426,7 +3485,8 @@
protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
int pos = token.pos;
accept(INTERFACE);
- Name name = ident();
+
+ Name name = typeName();
List<JCTypeParameter> typarams = typeParametersOpt();
@@ -3449,7 +3509,8 @@
protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
int pos = token.pos;
accept(ENUM);
- Name name = ident();
+
+ Name name = typeName();
List<JCExpression> implementing = List.nil();
if (token.kind == IMPLEMENTS) {
@@ -3647,7 +3708,7 @@
nextToken();
} else {
// method returns types are un-annotated types
- type = unannotatedType();
+ type = unannotatedType(false);
}
if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
if (isInterface || tk.name() != className)
@@ -3667,7 +3728,7 @@
} else if (!isVoid && typarams.isEmpty()) {
List<JCTree> defs =
variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
- new ListBuffer<JCTree>()).toList();
+ new ListBuffer<JCTree>(), false).toList();
accept(SEMI);
storeEnd(defs.last(), S.prevToken().endPos);
return defs;
@@ -3809,7 +3870,7 @@
JCTypeParameter typeParameter() {
int pos = token.pos;
List<JCAnnotation> annos = typeAnnotationsOpt();
- Name name = ident();
+ Name name = typeName();
ListBuffer<JCExpression> bounds = new ListBuffer<>();
if (token.kind == EXTENDS) {
nextToken();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Oct 04 20:01:19 2017 +0000
@@ -1190,6 +1190,47 @@
compiler.err.undef.label=\
undefined label: {0}
+# 0: name (type)
+compiler.err.illegal.ref.to.var.type=\
+ illegal reference to restricted type ''{0}''
+
+# 0: token
+compiler.err.var.not.allowed=\
+ ''{0}'' not allowed here\n\
+ as of release 10, ''{0}'' is a restricted local variable type and cannot be used for type declarations
+
+# 0: name (variable), 1: message segment
+compiler.err.cant.infer.local.var.type=\
+ cannot infer type for local variable {0}\n\
+ ({1})
+
+compiler.err.var.not.allowed.here=\
+ ''var'' is not allowed here
+
+compiler.err.var.not.allowed.array=\
+ ''var'' is not allowed as an element type of an array
+
+compiler.err.var.not.allowed.compound=\
+ ''var'' is not allowed in a compound declaration
+
+compiler.misc.local.cant.infer.null=\
+ variable initializer is ''null''
+
+compiler.misc.local.missing.init=\
+ cannot use ''var'' on variable without initializer
+
+compiler.misc.local.lambda.missing.target=\
+ lambda expression needs an explicit target-type
+
+compiler.misc.local.mref.missing.target=\
+ method reference needs an explicit target-type
+
+compiler.misc.local.array.missing.target=\
+ array initializer needs an explicit target-type
+
+compiler.misc.local.self.ref=\
+ cannot use ''var'' on self-referencing variable
+
# 0: message segment, 1: unused
compiler.err.cant.apply.diamond=\
cannot infer type arguments for {0}
@@ -1873,6 +1914,9 @@
compiler.warn.diamond.redundant.args=\
Redundant type arguments in new expression (use diamond operator instead).
+compiler.warn.local.redundant.type=\
+ Redundant type for local variable (replace explicit type with ''var'').
+
compiler.warn.potential.lambda.found=\
This anonymous inner class creation can be turned into a lambda expression.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Wed Oct 04 20:01:19 2017 +0000
@@ -946,6 +946,10 @@
}
}
+ public boolean isImplicitlyTyped() {
+ return vartype == null;
+ }
+
@Override
public void accept(Visitor v) { v.visitVarDef(this); }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Wed Oct 04 20:01:19 2017 +0000
@@ -1359,7 +1359,7 @@
// Prints the inner element type of a nested array
private void printBaseElementType(JCTree tree) throws IOException {
- printExpr(TreeInfo.innermostType(tree));
+ printExpr(TreeInfo.innermostType(tree, false));
}
// prints the brackets of a nested array in reverse order
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Wed Oct 04 20:01:19 2017 +0000
@@ -1136,7 +1136,7 @@
* For an array that contains an annotated type, return that annotated type.
* TODO: currently only used by Pretty. Describe behavior better.
*/
- public static JCTree innermostType(JCTree type) {
+ public static JCTree innermostType(JCTree type, boolean skipAnnos) {
JCTree lastAnnotatedType = null;
JCTree cur = type;
loop: while (true) {
@@ -1157,7 +1157,7 @@
break loop;
}
}
- if (lastAnnotatedType!=null) {
+ if (!skipAnnos && lastAnnotatedType!=null) {
return lastAnnotatedType;
} else {
return cur;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java Wed Oct 04 20:01:19 2017 +0000
@@ -63,6 +63,7 @@
public final Name _default;
public final Name _super;
public final Name _this;
+ public final Name var;
public final Name exports;
public final Name opens;
public final Name module;
@@ -224,6 +225,7 @@
_default = fromString("default");
_super = fromString("super");
_this = fromString("this");
+ var = fromString("var");
exports = fromString("exports");
opens = fromString("opens");
module = fromString("module");
--- a/src/jdk.compiler/share/classes/module-info.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/module-info.java Wed Oct 04 20:01:19 2017 +0000
@@ -106,7 +106,8 @@
exports com.sun.tools.javac.jvm to
jdk.javadoc;
exports com.sun.tools.javac.main to
- jdk.javadoc;
+ jdk.javadoc,
+ jdk.jshell;
exports com.sun.tools.javac.model to
jdk.javadoc;
exports com.sun.tools.javac.parser to
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java Wed Oct 04 20:01:19 2017 +0000
@@ -39,6 +39,7 @@
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.SimpleTypeVisitor9;
+import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -98,15 +99,19 @@
*/
@Override
protected Content getDeprecatedLink(Element member) {
- StringBuilder sb = new StringBuilder();
- sb.append(utils.getFullyQualifiedName(member));
+ Content deprecatedLinkContent = new ContentBuilder();
+ deprecatedLinkContent.addContent(utils.getFullyQualifiedName(member));
if (!utils.isConstructor(member)) {
- sb.append(".");
- sb.append(member.getSimpleName());
+ deprecatedLinkContent.addContent(".");
+ deprecatedLinkContent.addContent(member.getSimpleName());
}
- sb.append(utils.flatSignature((ExecutableElement) member));
+ String signature = utils.flatSignature((ExecutableElement) member);
+ if (signature.length() > 2) {
+ deprecatedLinkContent.addContent(Contents.ZERO_WIDTH_SPACE);
+ }
+ deprecatedLinkContent.addContent(signature);
- return writer.getDocLink(MEMBER, member, sb);
+ return writer.getDocLink(MEMBER, utils.getEnclosingTypeElement(member), member, deprecatedLinkContent);
}
/**
@@ -199,55 +204,61 @@
*/
protected void addParameters(ExecutableElement member,
boolean includeAnnotations, Content htmltree, int indentSize) {
- htmltree.addContent(Contents.ZERO_WIDTH_SPACE);
- htmltree.addContent("(");
+ Content paramTree = new ContentBuilder();
String sep = "";
List<? extends VariableElement> parameters = member.getParameters();
CharSequence indent = makeSpace(indentSize + 1);
TypeMirror rcvrType = member.getReceiverType();
if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) {
List<? extends AnnotationMirror> annotationMirrors = rcvrType.getAnnotationMirrors();
- addReceiverAnnotations(member, rcvrType, annotationMirrors, htmltree);
+ addReceiverAnnotations(member, rcvrType, annotationMirrors, paramTree);
sep = "," + DocletConstants.NL + indent;
}
int paramstart;
for (paramstart = 0; paramstart < parameters.size(); paramstart++) {
- htmltree.addContent(sep);
+ paramTree.addContent(sep);
VariableElement param = parameters.get(paramstart);
if (param.getKind() != ElementKind.INSTANCE_INIT) {
if (includeAnnotations) {
boolean foundAnnotations =
writer.addAnnotationInfo(indent.length(),
- member, param, htmltree);
+ member, param, paramTree);
if (foundAnnotations) {
- htmltree.addContent(DocletConstants.NL);
- htmltree.addContent(indent);
+ paramTree.addContent(DocletConstants.NL);
+ paramTree.addContent(indent);
}
}
addParam(member, param,
- (paramstart == parameters.size() - 1) && member.isVarArgs(), htmltree);
+ (paramstart == parameters.size() - 1) && member.isVarArgs(), paramTree);
break;
}
}
for (int i = paramstart + 1; i < parameters.size(); i++) {
- htmltree.addContent(",");
- htmltree.addContent(DocletConstants.NL);
- htmltree.addContent(indent);
+ paramTree.addContent(",");
+ paramTree.addContent(DocletConstants.NL);
+ paramTree.addContent(indent);
if (includeAnnotations) {
boolean foundAnnotations =
writer.addAnnotationInfo(indent.length(), member, parameters.get(i),
- htmltree);
+ paramTree);
if (foundAnnotations) {
- htmltree.addContent(DocletConstants.NL);
- htmltree.addContent(indent);
+ paramTree.addContent(DocletConstants.NL);
+ paramTree.addContent(indent);
}
}
addParam(member, parameters.get(i), (i == parameters.size() - 1) && member.isVarArgs(),
- htmltree);
+ paramTree);
}
- htmltree.addContent(")");
+ if (paramTree.isEmpty()) {
+ htmltree.addContent("()");
+ } else {
+ htmltree.addContent(Contents.ZERO_WIDTH_SPACE);
+ htmltree.addContent("(");
+ htmltree.addContent(paramTree);
+ paramTree.addContent(")");
+ }
}
/**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java Wed Oct 04 20:01:19 2017 +0000
@@ -364,7 +364,7 @@
List<? extends DocTree> tags;
Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element));
HtmlTree div = new HtmlTree(HtmlTag.DIV);
- div.addStyle(HtmlStyle.block);
+ div.addStyle(HtmlStyle.deprecationBlock);
if (utils.isDeprecated(element)) {
div.addContent(span);
tags = utils.getBlockTags(element, DocTree.Kind.DEPRECATED);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java Wed Oct 04 20:01:19 2017 +0000
@@ -355,7 +355,7 @@
writer.getTagletWriterInstance(false));
if (!output.isEmpty()) {
Content deprecatedContent = output;
- Content div = HtmlTree.DIV(HtmlStyle.block, deprecatedContent);
+ Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprecatedContent);
contentTree.addContent(div);
}
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java Wed Oct 04 20:01:19 2017 +0000
@@ -278,7 +278,8 @@
*/
@Override
public void addAnnotationTypeSignature(String modifiers, Content annotationInfoTree) {
- annotationInfoTree.addContent(new HtmlTree(HtmlTag.BR));
+ Content hr = new HtmlTree(HtmlTag.HR);
+ annotationInfoTree.addContent(hr);
Content pre = new HtmlTree(HtmlTag.PRE);
addAnnotationInfo(annotationType, pre);
pre.addContent(modifiers);
@@ -324,18 +325,15 @@
*/
@Override
public void addAnnotationTypeDeprecationInfo(Content annotationInfoTree) {
- Content hr = new HtmlTree(HtmlTag.HR);
- annotationInfoTree.addContent(hr);
List<? extends DocTree> deprs = utils.getBlockTags(annotationType, DocTree.Kind.DEPRECATED);
if (utils.isDeprecated(annotationType)) {
CommentHelper ch = utils.getCommentHelper(annotationType);
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(annotationType));
- Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
+ Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
if (!deprs.isEmpty()) {
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
if (!commentTags.isEmpty()) {
- div.addContent(Contents.SPACE);
addInlineDeprecatedComment(annotationType, deprs.get(0), div);
}
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java Wed Oct 04 20:01:19 2017 +0000
@@ -293,7 +293,8 @@
*/
@Override
public void addClassSignature(String modifiers, Content classInfoTree) {
- classInfoTree.addContent(new HtmlTree(HtmlTag.BR));
+ Content hr = new HtmlTree(HtmlTag.HR);
+ classInfoTree.addContent(hr);
Content pre = new HtmlTree(HtmlTag.PRE);
addAnnotationInfo(typeElement, pre);
pre.addContent(modifiers);
@@ -606,18 +607,15 @@
*/
@Override
public void addClassDeprecationInfo(Content classInfoTree) {
- Content hr = new HtmlTree(HtmlTag.HR);
- classInfoTree.addContent(hr);
List<? extends DocTree> deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED);
if (utils.isDeprecated(typeElement)) {
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement));
- Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
+ Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
if (!deprs.isEmpty()) {
CommentHelper ch = utils.getCommentHelper(typeElement);
DocTree dt = deprs.get(0);
List<? extends DocTree> commentTags = ch.getBody(configuration, dt);
if (!commentTags.isEmpty()) {
- div.addContent(Contents.SPACE);
addInlineDeprecatedComment(typeElement, deprs.get(0), div);
}
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java Wed Oct 04 20:01:19 2017 +0000
@@ -100,33 +100,33 @@
private String getHeadingKey(DeprElementKind kind) {
switch (kind) {
case REMOVAL:
- return "doclet.Deprecated_For_Removal";
+ return "doclet.For_Removal";
case MODULE:
- return "doclet.Deprecated_Modules";
+ return "doclet.Modules";
case PACKAGE:
- return "doclet.Deprecated_Packages";
+ return "doclet.Packages";
case INTERFACE:
- return "doclet.Deprecated_Interfaces";
+ return "doclet.Interfaces";
case CLASS:
- return "doclet.Deprecated_Classes";
+ return "doclet.Classes";
case ENUM:
- return "doclet.Deprecated_Enums";
+ return "doclet.Enums";
case EXCEPTION:
- return "doclet.Deprecated_Exceptions";
+ return "doclet.Exceptions";
case ERROR:
- return "doclet.Deprecated_Errors";
+ return "doclet.Errors";
case ANNOTATION_TYPE:
- return "doclet.Deprecated_Annotation_Types";
+ return "doclet.Annotation_Types";
case FIELD:
- return "doclet.Deprecated_Fields";
+ return "doclet.Fields";
case METHOD:
- return "doclet.Deprecated_Methods";
+ return "doclet.Methods";
case CONSTRUCTOR:
- return "doclet.Deprecated_Constructors";
+ return "doclet.Constructors";
case ENUM_CONSTANT:
- return "doclet.Deprecated_Enum_Constants";
+ return "doclet.Enum_Constants";
case ANNOTATION_TYPE_MEMBER:
- return "doclet.Deprecated_Annotation_Type_Members";
+ return "doclet.Annotation_Type_Members";
default:
throw new AssertionError("unknown kind: " + kind);
}
@@ -135,33 +135,33 @@
private String getSummaryKey(DeprElementKind kind) {
switch (kind) {
case REMOVAL:
- return "doclet.deprecated_for_removal";
+ return "doclet.for_removal";
case MODULE:
- return "doclet.deprecated_modules";
+ return "doclet.modules";
case PACKAGE:
- return "doclet.deprecated_packages";
+ return "doclet.packages";
case INTERFACE:
- return "doclet.deprecated_interfaces";
+ return "doclet.interfaces";
case CLASS:
- return "doclet.deprecated_classes";
+ return "doclet.classes";
case ENUM:
- return "doclet.deprecated_enums";
+ return "doclet.enums";
case EXCEPTION:
- return "doclet.deprecated_exceptions";
+ return "doclet.exceptions";
case ERROR:
- return "doclet.deprecated_errors";
+ return "doclet.errors";
case ANNOTATION_TYPE:
- return "doclet.deprecated_annotation_types";
+ return "doclet.annotation_types";
case FIELD:
- return "doclet.deprecated_fields";
+ return "doclet.fields";
case METHOD:
- return "doclet.deprecated_methods";
+ return "doclet.methods";
case CONSTRUCTOR:
- return "doclet.deprecated_constructors";
+ return "doclet.constructors";
case ENUM_CONSTANT:
- return "doclet.deprecated_enum_constants";
+ return "doclet.enum_constants";
case ANNOTATION_TYPE_MEMBER:
- return "doclet.deprecated_annotation_type_members";
+ return "doclet.annotation_type_members";
default:
throw new AssertionError("unknown kind: " + kind);
}
@@ -473,6 +473,6 @@
default:
writer = new AnnotationTypeOptionalMemberWriterImpl(this, null);
}
- return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, writer.getDeprecatedLink(e));
+ return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colDeprecatedItemName, writer.getDeprecatedLink(e));
}
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Wed Oct 04 20:01:19 2017 +0000
@@ -1715,8 +1715,7 @@
Content div;
Content result = commentTagsToContent(null, element, tags, first);
if (depr) {
- Content italic = HtmlTree.SPAN(HtmlStyle.deprecationComment, result);
- div = HtmlTree.DIV(HtmlStyle.block, italic);
+ div = HtmlTree.DIV(HtmlStyle.deprecationComment, result);
htmltree.addContent(div);
}
else {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java Wed Oct 04 20:01:19 2017 +0000
@@ -929,7 +929,7 @@
if (utils.isDeprecated(mdle)) {
CommentHelper ch = utils.getCommentHelper(mdle);
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
- deprDiv.addStyle(HtmlStyle.deprecatedContent);
+ deprDiv.addStyle(HtmlStyle.deprecationBlock);
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle));
deprDiv.addContent(deprPhrase);
if (!deprs.isEmpty()) {
@@ -1064,7 +1064,7 @@
if (utils.isDeprecated(pkg)) {
deprs = utils.getDeprecatedTrees(pkg);
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
- deprDiv.addStyle(HtmlStyle.deprecatedContent);
+ deprDiv.addStyle(HtmlStyle.deprecationBlock);
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg));
deprDiv.addContent(deprPhrase);
if (!deprs.isEmpty()) {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java Wed Oct 04 20:01:19 2017 +0000
@@ -171,7 +171,7 @@
if (utils.isDeprecated(packageElement)) {
CommentHelper ch = utils.getCommentHelper(packageElement);
HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
- deprDiv.addStyle(HtmlStyle.deprecatedContent);
+ deprDiv.addStyle(HtmlStyle.deprecationBlock);
Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(packageElement));
deprDiv.addContent(deprPhrase);
if (!deprs.isEmpty()) {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java Wed Oct 04 20:01:19 2017 +0000
@@ -189,9 +189,8 @@
if (utils.isDeprecated(member)) {
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(member));
div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
- div.addContent(Contents.SPACE);
if (!deprs.isEmpty()) {
- addInlineDeprecatedComment(member, deprs.get(0), div);
+ addSummaryDeprecatedComment(member, deprs.get(0), div);
}
tdSummary.addContent(div);
return;
@@ -200,7 +199,6 @@
if (te != null && utils.isTypeElement(te) && utils.isDeprecated(te)) {
Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(te));
div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
- div.addContent(Contents.SPACE);
tdSummary.addContent(div);
}
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java Wed Oct 04 20:01:19 2017 +0000
@@ -179,7 +179,6 @@
if (utils.isDeprecated(element)) {
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
htmlWriter.getDeprecatedPhrase(element)));
- result.addContent(RawHtml.nbsp);
if (!deprs.isEmpty()) {
List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
if (!commentTags.isEmpty()) {
@@ -191,19 +190,17 @@
if (utils.isDeprecated(element)) {
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
htmlWriter.getDeprecatedPhrase(element)));
- result.addContent(RawHtml.nbsp);
if (!deprs.isEmpty()) {
List<? extends DocTree> bodyTags = ch.getBody(configuration, deprs.get(0));
Content body = commentTagsToOutput(null, element, bodyTags, false);
if (!body.isEmpty())
- result.addContent(HtmlTree.SPAN(HtmlStyle.deprecationComment, body));
+ result.addContent(HtmlTree.DIV(HtmlStyle.deprecationComment, body));
}
} else {
Element ee = utils.getEnclosingTypeElement(element);
if (utils.isDeprecated(ee)) {
result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
htmlWriter.getDeprecatedPhrase(ee)));
- result.addContent(RawHtml.nbsp);
}
}
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java Wed Oct 04 20:01:19 2017 +0000
@@ -47,15 +47,16 @@
circle,
classUseContainer,
colConstructorName,
+ colDeprecatedItemName,
colFirst,
colLast,
colSecond,
constantsSummary,
constantValuesContainer,
contentContainer,
- deprecatedContent,
deprecatedLabel,
deprecatedSummary,
+ deprecationBlock,
deprecationComment,
description,
descfrmTypeLabel,
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties Wed Oct 04 20:01:19 2017 +0000
@@ -74,34 +74,12 @@
doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1}
doclet.tag.invalid_usage=invalid usage of tag {0}
doclet.Deprecated_API=Deprecated API
-doclet.Deprecated_For_Removal=Deprecated For Removal
-doclet.Deprecated_Modules=Deprecated Modules
-doclet.Deprecated_Packages=Deprecated Packages
-doclet.Deprecated_Classes=Deprecated Classes
-doclet.Deprecated_Enums=Deprecated Enums
-doclet.Deprecated_Interfaces=Deprecated Interfaces
-doclet.Deprecated_Exceptions=Deprecated Exceptions
-doclet.Deprecated_Annotation_Types=Deprecated Annotation Types
-doclet.Deprecated_Errors=Deprecated Errors
-doclet.Deprecated_Fields=Deprecated Fields
-doclet.Deprecated_Constructors=Deprecated Constructors
-doclet.Deprecated_Methods=Deprecated Methods
-doclet.Deprecated_Enum_Constants=Deprecated Enum Constants
-doclet.Deprecated_Annotation_Type_Members=Deprecated Annotation Type Elements
-doclet.deprecated_for_removal=deprecated for removal
-doclet.deprecated_modules=deprecated modules
-doclet.deprecated_packages=deprecated packages
-doclet.deprecated_classes=deprecated classes
-doclet.deprecated_enums=deprecated enums
-doclet.deprecated_interfaces=deprecated interfaces
-doclet.deprecated_exceptions=deprecated exceptions
-doclet.deprecated_annotation_types=deprecated annotation types
-doclet.deprecated_errors=deprecated errors
-doclet.deprecated_fields=deprecated fields
-doclet.deprecated_constructors=deprecated constructors
-doclet.deprecated_methods=deprecated methods
-doclet.deprecated_enum_constants=deprecated enum constants
-doclet.deprecated_annotation_type_members=deprecated annotation type elements
+doclet.For_Removal=For Removal
+doclet.Annotation_Types=Annotation Types
+doclet.Annotation_Type_Members=Annotation Type Elements
+doclet.for_removal=for removal
+doclet.annotation_types=annotation types
+doclet.annotation_type_members=annotation type elements
doclet.Generated_Docs_Untitled=Generated Documentation (Untitled)
doclet.Other_Packages=Other Packages
doclet.Description=Description
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeBuilder.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeBuilder.java Wed Oct 04 20:01:19 2017 +0000
@@ -147,8 +147,8 @@
throws DocletException {
Content annotationInfoTree = writer.getAnnotationInfoTreeHeader();
+ buildAnnotationTypeSignature(annotationInfoTree);
buildDeprecationInfo(annotationInfoTree);
- buildAnnotationTypeSignature(annotationInfoTree);
buildAnnotationTypeDescription(annotationInfoTree);
buildAnnotationTypeTagInfo(annotationInfoTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java Wed Oct 04 20:01:19 2017 +0000
@@ -175,8 +175,8 @@
buildInterfaceUsageInfo(classInfoTree);
buildNestedClassInfo(classInfoTree);
buildFunctionalInterfaceInfo(classInfoTree);
+ buildClassSignature(classInfoTree);
buildDeprecationInfo(classInfoTree);
- buildClassSignature(classInfoTree);
buildClassDescription(classInfoTree);
buildClassTagInfo(classInfoTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css Wed Oct 04 20:01:19 2017 +0000
@@ -531,14 +531,16 @@
text-align:left;
padding:0px 0px 12px 10px;
}
-th.colFirst, th.colSecond, th.colLast, th.colConstructorName, .useSummary th, .constantsSummary th, .packagesSummary th,
-td.colFirst, td.colSecond, td.colLast, .useSummary td, .constantsSummary td {
+th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .useSummary th,
+.constantsSummary th, .packagesSummary th, td.colFirst, td.colSecond, td.colLast, .useSummary td,
+.constantsSummary td {
vertical-align:top;
padding-right:0px;
padding-top:8px;
padding-bottom:3px;
}
-th.colFirst, th.colSecond, th.colLast, th.colConstructorName, .constantsSummary th, .packagesSummary th {
+th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .constantsSummary th,
+.packagesSummary th {
background:#dee3e9;
text-align:left;
padding:8px 3px 3px 7px;
@@ -547,7 +549,7 @@
white-space:nowrap;
font-size:13px;
}
-td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colLast {
+td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colDeprecatedItemName, th.colLast {
font-size:13px;
}
.constantsSummary th, .packagesSummary th {
@@ -576,6 +578,7 @@
th.colFirst a:link, th.colFirst a:visited,
th.colSecond a:link, th.colSecond a:visited,
th.colConstructorName a:link, th.colConstructorName a:visited,
+th.colDeprecatedItemName a:link, th.colDeprecatedItemName a:visited,
.constantValuesContainer td a:link, .constantValuesContainer td a:visited {
font-weight:bold;
}
@@ -645,8 +648,19 @@
.deprecationComment, .emphasizedPhrase, .interfaceName {
font-style:italic;
}
+.deprecationBlock {
+ font-size:14px;
+ font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
+ border-style:solid;
+ border-width:thin;
+ border-radius:10px;
+ padding:10px;
+ margin-bottom:10px;
+ margin-right:10px;
+ display:inline-block;
+}
-div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase,
+div.block div.deprecationComment, div.block div.block span.emphasizedPhrase,
div.block div.block span.interfaceName {
font-style:normal;
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DeprecatedAPIListBuilder.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DeprecatedAPIListBuilder.java Wed Oct 04 20:01:19 2017 +0000
@@ -78,7 +78,7 @@
deprecatedMap = new EnumMap<>(DeprElementKind.class);
for (DeprElementKind kind : DeprElementKind.values()) {
deprecatedMap.put(kind,
- new TreeSet<>(utils.makeGeneralPurposeComparator()));
+ new TreeSet<>(utils.makeDeprecatedComparator()));
}
buildDeprecatedAPIInfo();
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java Wed Oct 04 20:01:19 2017 +0000
@@ -1733,6 +1733,25 @@
return packageComparator;
}
+ private Comparator<Element> deprecatedComparator = null;
+ /**
+ * Returns a Comparator for deprecated items listed on deprecated list page, by comparing the
+ * fully qualified names.
+ *
+ * @return a Comparator
+ */
+ public Comparator<Element> makeDeprecatedComparator() {
+ if (deprecatedComparator == null) {
+ deprecatedComparator = new Utils.ElementComparator() {
+ @Override
+ public int compare(Element e1, Element e2) {
+ return compareFullyQualifiedNames(e1, e2);
+ }
+ };
+ }
+ return deprecatedComparator;
+ }
+
private Comparator<SerialFieldTree> serialFieldTreeComparator = null;
/**
* Returns a Comparator for SerialFieldTree.
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Oct 04 20:01:19 2017 +0000
@@ -234,49 +234,6 @@
}
},
- new Option(true, CommandOption.CHECK_MODULES) {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- if (task.command != null) {
- throw new BadArgs("err.command.set", task.command, opt);
- }
- Set<String> mods = Set.of(arg.split(","));
- task.options.addmods.addAll(mods);
- task.command = task.checkModuleDeps(mods);
- }
- },
- new Option(true, CommandOption.GENERATE_MODULE_INFO) {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- if (task.command != null) {
- throw new BadArgs("err.command.set", task.command, opt);
- }
- task.command = task.genModuleInfo(Paths.get(arg), false);
- }
- },
- new Option(true, CommandOption.GENERATE_OPEN_MODULE) {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- if (task.command != null) {
- throw new BadArgs("err.command.set", task.command, opt);
- }
- task.command = task.genModuleInfo(Paths.get(arg), true);
- }
- },
- new Option(false, CommandOption.LIST_DEPS) {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- if (task.command != null) {
- throw new BadArgs("err.command.set", task.command, opt);
- }
- task.command = task.listModuleDeps(false);
- }
- },
- new Option(false, CommandOption.LIST_REDUCED_DEPS) {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- if (task.command != null) {
- throw new BadArgs("err.command.set", task.command, opt);
- }
- task.command = task.listModuleDeps(true);
- }
- },
-
// ---- paths option ----
new Option(true, "-cp", "-classpath", "--class-path") {
void process(JdepsTask task, String opt, String arg) {
@@ -312,15 +269,6 @@
task.options.addmods.addAll(mods);
}
},
- new Option(true, "-m", "--module") {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- if (!task.options.rootModules.isEmpty()) {
- throw new BadArgs("err.option.already.specified", opt);
- }
- task.options.rootModules.add(arg);
- task.options.addmods.add(arg);
- }
- },
new Option(true, "--multi-release") {
void process(JdepsTask task, String opt, String arg) throws BadArgs {
if (arg.equalsIgnoreCase("base")) {
@@ -338,6 +286,70 @@
}
}
},
+ new Option(false, "-q", "-quiet") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.nowarning = true;
+ }
+ },
+ new Option(false, "-version", "--version") {
+ void process(JdepsTask task, String opt, String arg) {
+ task.options.version = true;
+ }
+ },
+
+ // ---- module-specific options ----
+
+ new Option(true, "-m", "--module") {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ if (!task.options.rootModules.isEmpty()) {
+ throw new BadArgs("err.option.already.specified", opt);
+ }
+ task.options.rootModules.add(arg);
+ task.options.addmods.add(arg);
+ }
+ },
+ new Option(true, CommandOption.GENERATE_MODULE_INFO) {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ if (task.command != null) {
+ throw new BadArgs("err.command.set", task.command, opt);
+ }
+ task.command = task.genModuleInfo(Paths.get(arg), false);
+ }
+ },
+ new Option(true, CommandOption.GENERATE_OPEN_MODULE) {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ if (task.command != null) {
+ throw new BadArgs("err.command.set", task.command, opt);
+ }
+ task.command = task.genModuleInfo(Paths.get(arg), true);
+ }
+ },
+ new Option(true, CommandOption.CHECK_MODULES) {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ if (task.command != null) {
+ throw new BadArgs("err.command.set", task.command, opt);
+ }
+ Set<String> mods = Set.of(arg.split(","));
+ task.options.addmods.addAll(mods);
+ task.command = task.checkModuleDeps(mods);
+ }
+ },
+ new Option(false, CommandOption.LIST_DEPS) {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ if (task.command != null) {
+ throw new BadArgs("err.command.set", task.command, opt);
+ }
+ task.command = task.listModuleDeps(false);
+ }
+ },
+ new Option(false, CommandOption.LIST_REDUCED_DEPS) {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ if (task.command != null) {
+ throw new BadArgs("err.command.set", task.command, opt);
+ }
+ task.command = task.listModuleDeps(true);
+ }
+ },
// ---- Target filtering options ----
new Option(true, "-p", "-package", "--package") {
@@ -424,17 +436,6 @@
}
},
- new Option(false, "-q", "-quiet") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.nowarning = true;
- }
- },
-
- new Option(false, "-version", "--version") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.version = true;
- }
- },
new HiddenOption(false, "-fullversion") {
void process(JdepsTask task, String opt, String arg) {
task.options.fullVersion = true;
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Wed Oct 04 20:01:19 2017 +0000
@@ -86,10 +86,6 @@
\ --add-modules <module-name>[,<module-name>...]\n\
\ Adds modules to the root set for analysis
-main.opt.m=\
-\ -m <module-name>\n\
-\ --module <module-name> Specify the root module for analysis
-
main.opt.R=\
\ -R -recursive Recursively traverse all run-time dependences.\n\
\ The -R option implies -filter:none. If -p,\n\
@@ -121,6 +117,11 @@
\ type, method parameter types, returned type,\n\
\ checked exception types etc.
+main.opt.m=\n\
+\Module dependence analysis options:\n\
+\ -m <module-name>\n\
+\ --module <module-name> Specify the root module for analysis
+
main.opt.generate-module-info=\
\ --generate-module-info <dir> Generate module-info.java under the specified\n\
\ directory. The specified JAR files will be\n\
@@ -142,7 +143,6 @@
\ graph after transition reduction. It also\n\
\ identifies any unused qualified exports.
-
main.opt.dotoutput=\
\ -dotoutput <dir>\n\
\ --dot-output <dir> Destination directory for DOT file output
@@ -157,15 +157,15 @@
\ WARNING: JDK internal APIs are inaccessible.
main.opt.list-deps=\
-\ --list-deps Lists the dependences and use of JDK internal\n\
-\ APIs.
+\ --list-deps Lists the module dependences and also the\n\
+\ package names of JDK internal APIs if referenced.
main.opt.list-reduced-deps=\
\ --list-reduced-deps Same as --list-deps with not listing\n\
\ the implied reads edges from the module graph\n\
-\ If module M1 depends on M2 and M3,\n\
-\ M2 requires public on M3, then M1 reading M3 is\n\
-\ implied and removed from the module graph.
+\ If module M1 reads M2, and M2 requires\n\
+\ transitive on M3, then M1 reading M3 is implied\n\
+\ and is not shown in the graph.
main.opt.depth=\
\ -depth=<depth> Specify the depth of the transitive\n\
--- a/src/jdk.jshell/share/classes/jdk/jshell/Eval.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Eval.java Wed Oct 04 20:01:19 2017 +0000
@@ -40,6 +40,7 @@
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ModifiersTree;
+import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.tree.JCTree;
@@ -59,6 +60,7 @@
import jdk.jshell.TaskFactory.BaseTask;
import jdk.jshell.TaskFactory.CompileTask;
import jdk.jshell.TaskFactory.ParseTask;
+import jdk.jshell.Wrap.CompoundWrap;
import jdk.jshell.Wrap.Range;
import jdk.jshell.Snippet.Status;
import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
@@ -274,26 +276,119 @@
for (Tree unitTree : units) {
VariableTree vt = (VariableTree) unitTree;
String name = vt.getName().toString();
- String typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
- Tree baseType = vt.getType();
+ String typeName;
+ String fullTypeName;
TreeDependencyScanner tds = new TreeDependencyScanner();
- tds.scan(baseType); // Not dependent on initializer
+ Wrap typeWrap;
+ Wrap anonDeclareWrap = null;
+ Wrap winit = null;
StringBuilder sbBrackets = new StringBuilder();
- while (baseType instanceof ArrayTypeTree) {
- //TODO handle annotations too
- baseType = ((ArrayTypeTree) baseType).getType();
- sbBrackets.append("[]");
+ Tree baseType = vt.getType();
+ if (baseType != null) {
+ tds.scan(baseType); // Not dependent on initializer
+ fullTypeName = typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
+ while (baseType instanceof ArrayTypeTree) {
+ //TODO handle annotations too
+ baseType = ((ArrayTypeTree) baseType).getType();
+ sbBrackets.append("[]");
+ }
+ Range rtype = dis.treeToRange(baseType);
+ typeWrap = Wrap.rangeWrap(compileSource, rtype);
+ } else {
+ Tree init = vt.getInitializer();
+ if (init != null) {
+ Range rinit = dis.treeToRange(init);
+ String initCode = rinit.part(compileSource);
+ ExpressionInfo ei =
+ ExpressionToTypeInfo.localVariableTypeForInitializer(initCode, state);
+ typeName = ei == null ? "java.lang.Object" : ei.typeName;
+ fullTypeName = ei == null ? "java.lang.Object" : ei.fullTypeName;
+ if (ei != null && init.getKind() == Tree.Kind.NEW_CLASS &&
+ ((NewClassTree) init).getClassBody() != null) {
+ NewClassTree nct = (NewClassTree) init;
+ StringBuilder constructor = new StringBuilder();
+ constructor.append(fullTypeName).append("(");
+ String sep = "";
+ if (ei.enclosingInstanceType != null) {
+ constructor.append(ei.enclosingInstanceType);
+ constructor.append(" encl");
+ sep = ", ";
+ }
+ int idx = 0;
+ for (String type : ei.parameterTypes) {
+ constructor.append(sep);
+ constructor.append(type);
+ constructor.append(" ");
+ constructor.append("arg" + idx++);
+ sep = ", ";
+ }
+ if (ei.enclosingInstanceType != null) {
+ constructor.append(") { encl.super (");
+ } else {
+ constructor.append(") { super (");
+ }
+ sep = "";
+ for (int i = 0; i < idx; i++) {
+ constructor.append(sep);
+ constructor.append("arg" + i++);
+ sep = ", ";
+ }
+ constructor.append("); }");
+ List<? extends Tree> members = nct.getClassBody().getMembers();
+ Range bodyRange = dis.treeListToRange(members);
+ Wrap bodyWrap;
+
+ if (bodyRange != null) {
+ bodyWrap = Wrap.rangeWrap(compileSource, bodyRange);
+ } else {
+ bodyWrap = Wrap.simpleWrap(" ");
+ }
+
+ Range argRange = dis.treeListToRange(nct.getArguments());
+ Wrap argWrap;
+
+ if (argRange != null) {
+ argWrap = Wrap.rangeWrap(compileSource, argRange);
+ } else {
+ argWrap = Wrap.simpleWrap(" ");
+ }
+
+ if (ei.enclosingInstanceType != null) {
+ Range enclosingRanges =
+ dis.treeToRange(nct.getEnclosingExpression());
+ Wrap enclosingWrap = Wrap.rangeWrap(compileSource, enclosingRanges);
+ argWrap = argRange != null ? new CompoundWrap(enclosingWrap,
+ Wrap.simpleWrap(","),
+ argWrap)
+ : enclosingWrap;
+ }
+ Wrap hwrap = Wrap.simpleWrap("public static class " + fullTypeName +
+ (ei.isClass ? " extends " : " implements ") +
+ typeName + " { " + constructor);
+ anonDeclareWrap = new CompoundWrap(hwrap, bodyWrap, Wrap.simpleWrap("}"));
+ winit = new CompoundWrap("new " + fullTypeName + "(", argWrap, ")");
+
+ String superType = typeName;
+
+ typeName = fullTypeName;
+ fullTypeName = ei.isClass ? "<anonymous class extending " + superType + ">"
+ : "<anonymous class implementing " + superType + ">";
+ }
+ tds.scan(init);
+ } else {
+ fullTypeName = typeName = "java.lang.Object";
+ }
+ typeWrap = Wrap.identityWrap(typeName);
}
- Range rtype = dis.treeToRange(baseType);
Range runit = dis.treeToRange(vt);
runit = new Range(runit.begin, runit.end - 1);
ExpressionTree it = vt.getInitializer();
- Range rinit = null;
int nameMax = runit.end - 1;
SubKind subkind;
if (it != null) {
subkind = SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND;
- rinit = dis.treeToRange(it);
+ Range rinit = dis.treeToRange(it);
+ winit = winit == null ? Wrap.rangeWrap(compileSource, rinit) : winit;
nameMax = rinit.begin - 1;
} else {
subkind = SubKind.VAR_DECLARATION_SUBKIND;
@@ -304,10 +399,11 @@
}
int nameEnd = nameStart + name.length();
Range rname = new Range(nameStart, nameEnd);
- Wrap guts = Wrap.varWrap(compileSource, rtype, sbBrackets.toString(), rname, rinit);
- DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
+ Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), rname,
+ winit, anonDeclareWrap);
+ DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
- name, subkind, typeName,
+ name, subkind, fullTypeName,
tds.declareReferences(), modDiag);
snippets.add(snip);
}
--- a/src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java Wed Oct 04 20:01:19 2017 +0000
@@ -29,14 +29,20 @@
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ConditionalExpressionTree;
+import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.util.List;
import jdk.jshell.TaskFactory.AnalyzeTask;
/**
@@ -63,6 +69,10 @@
public static class ExpressionInfo {
ExpressionTree tree;
String typeName;
+ String fullTypeName;
+ List<String> parameterTypes;
+ String enclosingInstanceType;
+ boolean isClass;
boolean isNonVoid;
}
@@ -111,6 +121,16 @@
return null;
}
}
+
+ @Override
+ public TreePath visitVariable(VariableTree node, Boolean isTargetContext) {
+ if (isTargetContext) {
+ throw new Result(getCurrentPath());
+ } else {
+ return null;
+ }
+ }
+
}
private Type pathToType(TreePath tp) {
@@ -156,6 +176,30 @@
}
}
+ /**
+ * Entry method: get expression info corresponding to a local variable declaration if its type
+ * has been inferred automatically from the given initializer.
+ * @param code the initializer as a string
+ * @param state a JShell instance
+ * @return type information
+ */
+ public static ExpressionInfo localVariableTypeForInitializer(String code, JShell state) {
+ if (code == null || code.isEmpty()) {
+ return null;
+ }
+ try {
+ OuterWrap codeWrap = state.outerMap.wrapInTrialClass(Wrap.methodWrap("var $$$ = " + code));
+ AnalyzeTask at = state.taskFactory.new AnalyzeTask(codeWrap);
+ CompilationUnitTree cu = at.firstCuTree();
+ if (at.hasErrors() || cu == null) {
+ return null;
+ }
+ return new ExpressionToTypeInfo(at, cu, state).typeOfExpression();
+ } catch (Exception ex) {
+ return null;
+ }
+ }
+
private ExpressionInfo typeOfExpression() {
return treeToInfo(findExpressionPath());
}
@@ -172,9 +216,11 @@
private ExpressionInfo treeToInfo(TreePath tp) {
if (tp != null) {
Tree tree = tp.getLeaf();
- if (tree instanceof ExpressionTree) {
+ boolean isExpression = tree instanceof ExpressionTree;
+ if (isExpression || tree.getKind() == Kind.VARIABLE) {
ExpressionInfo ei = new ExpressionInfo();
- ei.tree = (ExpressionTree) tree;
+ if (isExpression)
+ ei.tree = (ExpressionTree) tree;
Type type = pathToType(tp, tree);
if (type != null) {
switch (type.getKind()) {
@@ -189,27 +235,56 @@
break;
default: {
ei.isNonVoid = true;
- ei.typeName = varTypeName(type);
- if (ei.typeName == null) {
- ei.typeName = OBJECT_TYPE_NAME;
- }
+ ei.typeName = varTypeName(type, false);
+ ei.fullTypeName = varTypeName(type, true);
break;
}
}
}
+ if (tree.getKind() == Tree.Kind.VARIABLE) {
+ Tree init = ((VariableTree) tree).getInitializer();
+ if (init.getKind() == Tree.Kind.NEW_CLASS &&
+ ((NewClassTree) init).getClassBody() != null) {
+ NewClassTree nct = (NewClassTree) init;
+ ClassTree clazz = nct.getClassBody();
+ MethodTree constructor = (MethodTree) clazz.getMembers().get(0);
+ ExpressionStatementTree superCallStatement =
+ (ExpressionStatementTree) constructor.getBody().getStatements().get(0);
+ MethodInvocationTree superCall =
+ (MethodInvocationTree) superCallStatement.getExpression();
+ TreePath superCallPath =
+ at.trees().getPath(tp.getCompilationUnit(), superCall.getMethodSelect());
+ Type constrType = pathToType(superCallPath);
+ ei.parameterTypes = constrType.getParameterTypes()
+ .stream()
+ .map(t -> varTypeName(t, false))
+ .collect(List.collector());
+ if (nct.getEnclosingExpression() != null) {
+ TreePath enclPath = new TreePath(tp, nct.getEnclosingExpression());
+ ei.enclosingInstanceType = varTypeName(pathToType(enclPath), false);
+ }
+ ei.isClass = at.task.getTypes().directSupertypes(type).size() == 1;
+ }
+ }
return ei;
}
}
return null;
}
- private String varTypeName(Type type) {
+ private String varTypeName(Type type, boolean printIntersectionTypes) {
try {
- TypePrinter tp = new VarTypePrinter(at.messages(),
- state.maps::fullClassNameAndPackageToClass, syms, types);
- return tp.toString(type);
+ TypePrinter tp = new TypePrinter(at.messages(),
+ state.maps::fullClassNameAndPackageToClass, printIntersectionTypes);
+ List<Type> captures = types.captures(type);
+ String res = tp.toString(types.upward(type, captures));
+
+ if (res == null)
+ res = OBJECT_TYPE_NAME;
+
+ return res;
} catch (Exception ex) {
- return null;
+ return OBJECT_TYPE_NAME;
}
}
--- a/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java Wed Oct 04 20:01:19 2017 +0000
@@ -232,7 +232,7 @@
//mods.flags |= Flags.STATIC;
List<JCTree> defs
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
- new ListBuffer<JCTree>()).toList();
+ new ListBuffer<JCTree>(), true).toList();
accept(SEMI);
storeEnd(defs.last(), S.prevToken().endPos);
return defs;
--- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Wed Oct 04 20:01:19 2017 +0000
@@ -134,6 +134,8 @@
import static java.util.stream.Collectors.joining;
+import javax.lang.model.type.IntersectionType;
+
/**
* The concrete implementation of SourceCodeAnalysis.
* @author Robert Field
@@ -715,6 +717,13 @@
return Collections.emptyList();
switch (site.getKind()) {
+ case INTERSECTION: {
+ List<Element> result = new ArrayList<>();
+ for (TypeMirror bound : ((IntersectionType) site).getBounds()) {
+ result.addAll(membersOf(at, bound, shouldGenerateDotClassItem));
+ }
+ return result;
+ }
case DECLARED: {
TypeElement element = (TypeElement) at.getTypes().asElement(site);
List<Element> result = new ArrayList<>();
--- a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java Wed Oct 04 20:01:19 2017 +0000
@@ -61,7 +61,20 @@
import javax.tools.FileObject;
import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
import java.lang.Runtime.Version;
+import java.nio.CharBuffer;
import com.sun.source.tree.Tree.Kind;
+import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.parser.Parser;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCTypeCast;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.util.Context.Factory;
+import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
+import jdk.jshell.Snippet.Status;
/**
* The primary interface to the compiler API. Parsing, analysis, and
@@ -355,6 +368,7 @@
Iterable<? extends JavaFileObject> compilationUnits = inputs
.map(in -> sh.sourceToFileObject(fileManager, in))
.collect(Collectors.toList());
+ JShellJavaCompiler.preRegister(context, state);
this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null,
fileManager, diagnostics, options, null,
compilationUnits, context);
@@ -464,4 +478,57 @@
}
}
+ private static final class JShellJavaCompiler extends com.sun.tools.javac.main.JavaCompiler {
+
+ public static void preRegister(Context c, JShell state) {
+ c.put(compilerKey, (Factory<com.sun.tools.javac.main.JavaCompiler>) i -> new JShellJavaCompiler(i, state));
+ }
+
+ private final JShell state;
+
+ public JShellJavaCompiler(Context context, JShell state) {
+ super(context);
+ this.state = state;
+ }
+
+ @Override
+ public void processAnnotations(com.sun.tools.javac.util.List<JCCompilationUnit> roots, Collection<String> classnames) {
+ super.processAnnotations(roots, classnames);
+ state.maps
+ .snippetList()
+ .stream()
+ .filter(s -> s.status() == Status.VALID)
+ .filter(s -> s.kind() == Snippet.Kind.VAR)
+ .filter(s -> s.subKind() == Snippet.SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)
+ .forEach(s -> setVariableType(roots, (VarSnippet) s));
+ }
+
+ private void setVariableType(com.sun.tools.javac.util.List<JCCompilationUnit> roots, VarSnippet s) {
+ ClassSymbol clazz = syms.getClass(syms.unnamedModule, names.fromString(s.classFullName()));
+ if (clazz == null || !clazz.isCompleted())
+ return;
+ VarSymbol field = (VarSymbol) clazz.members().findFirst(names.fromString(s.name()), sym -> sym.kind == Kinds.Kind.VAR);
+ if (field != null) {
+ JavaFileObject prev = log.useSource(null);
+ DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log);
+ try {
+ String typeName = s.typeName();
+ CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3);
+ Parser parser = parserFactory.newParser(buf, false, false, false);
+ JCExpression expr = parser.parseExpression();
+ if (expr.hasTag(Tag.TYPECAST)) {
+ JCTypeCast tree = (JCTypeCast) expr;
+ if (tree.clazz.hasTag(Tag.TYPEINTERSECTION)) {
+ field.type = attr.attribType(tree.clazz,
+ ((JCClassDecl) roots.head.getTypeDecls().head).sym);
+ }
+ }
+ } finally {
+ log.popDiagnosticHandler(h);
+ log.useSource(prev);
+ }
+ }
+ }
+ }
+
}
--- a/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java Wed Oct 04 20:01:19 2017 +0000
@@ -227,7 +227,7 @@
Type typeImpl = (Type) type;
try {
TypePrinter tp = new TypePrinter(at.messages(),
- state.maps::fullClassNameAndPackageToClass);
+ state.maps::fullClassNameAndPackageToClass, true);
return tp.toString(typeImpl);
} catch (Exception ex) {
return null;
--- a/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java Wed Oct 04 20:01:19 2017 +0000
@@ -32,9 +32,11 @@
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Type.IntersectionClassType;
import com.sun.tools.javac.util.JavacMessages;
import java.util.Locale;
import java.util.function.BinaryOperator;
+import java.util.stream.Collectors;
/**
* Print types in source form.
@@ -45,10 +47,14 @@
private final JavacMessages messages;
private final BinaryOperator<String> fullClassNameAndPackageToClass;
+ private final boolean printEnhancedTypes;
- TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
+ TypePrinter(JavacMessages messages,
+ BinaryOperator<String> fullClassNameAndPackageToClass,
+ boolean printEnhancedTypes) {
this.messages = messages;
this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
+ this.printEnhancedTypes = printEnhancedTypes;
}
String toString(Type t) {
@@ -92,8 +98,18 @@
protected String className(ClassType t, boolean longform, Locale locale) {
Symbol sym = t.tsym;
if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
- return OBJECT;
+ if (printEnhancedTypes) {
+ return ((IntersectionClassType) t).getExplicitComponents()
+ .stream()
+ .map(i -> visit(i, locale))
+ .collect(Collectors.joining("&"));
+ } else {
+ return OBJECT;
+ }
} else if (sym.name.length() == 0) {
+ if (printEnhancedTypes) {
+ return t.tsym.flatName().toString().substring(t.tsym.outermostClass().flatName().length());
+ }
// Anonymous
String s;
ClassType norm = (ClassType) t.tsym.type;
--- a/src/jdk.jshell/share/classes/jdk/jshell/VarTypePrinter.java Wed Oct 04 11:52:07 2017 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,265 +0,0 @@
-/*
- * 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.jshell;
-
-import java.util.HashSet;
-import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.code.Type.ClassType;
-import com.sun.tools.javac.util.JavacMessages;
-import java.util.Locale;
-import java.util.Set;
-import java.util.function.BinaryOperator;
-import com.sun.tools.javac.code.BoundKind;
-import com.sun.tools.javac.code.Flags;
-import com.sun.tools.javac.code.Symtab;
-import com.sun.tools.javac.code.Type.CapturedType;
-import com.sun.tools.javac.code.Type.StructuralTypeMapping;
-import com.sun.tools.javac.code.Type.TypeVar;
-import com.sun.tools.javac.code.Type.WildcardType;
-import com.sun.tools.javac.code.Types;
-import com.sun.tools.javac.code.Types.SimpleVisitor;
-import com.sun.tools.javac.util.List;
-import static com.sun.tools.javac.code.BoundKind.EXTENDS;
-import static com.sun.tools.javac.code.BoundKind.SUPER;
-import static com.sun.tools.javac.code.BoundKind.UNBOUND;
-import static com.sun.tools.javac.code.Type.ArrayType;
-import static com.sun.tools.javac.code.TypeTag.BOT;
-import static com.sun.tools.javac.code.TypeTag.WILDCARD;
-
-/**
- * Print variable types in source form.
- * TypeProjection and CaptureScanner are copied from Types in the JEP-286
- * Sandbox by Maurizio. The checks for Non-Denotable in TypePrinter are
- * cribbed from denotableChecker of the same source.
- *
- * @author Maurizio Cimadamore
- * @author Robert Field
- */
-class VarTypePrinter extends TypePrinter {
- private static final String WILD = "?";
-
- private final Symtab syms;
- private final Types types;
-
- VarTypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass,
- Symtab syms, Types types) {
- super(messages, fullClassNameAndPackageToClass);
- this.syms = syms;
- this.types = types;
- }
-
- @Override
- String toString(Type t) {
- return super.toString(upward(t));
- }
-
- @Override
- public String visitTypeVar(TypeVar t, Locale locale) {
- /* Any type variable mentioned in the inferred type must have been declared as a type parameter
- (i.e cannot have been produced by inference (18.4))
- */
- // and beyond that, there are no global type vars, so if there are any
- // type variables left, they need to be eliminated
- return WILD; // Non-denotable
- }
-
- @Override
- public String visitCapturedType(CapturedType t, Locale locale) {
- /* Any type variable mentioned in the inferred type must have been declared as a type parameter
- (i.e cannot have been produced by capture conversion (5.1.10))
- */
- return WILD; // Non-denotable
- }
-
- public Type upward(Type t) {
- List<Type> captures = captures(t);
- return upward(t, captures);
- }
-
- /************* Following from JEP-286 Types.java ***********/
-
- public Type upward(Type t, List<Type> vars) {
- return t.map(new TypeProjection(vars), true);
- }
-
- public List<Type> captures(Type t) {
- CaptureScanner cs = new CaptureScanner();
- Set<Type> captures = new HashSet<>();
- cs.visit(t, captures);
- return List.from(captures);
- }
-
- class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
-
- @Override
- public Void visitType(Type t, Set<Type> types) {
- return null;
- }
-
- @Override
- public Void visitClassType(ClassType t, Set<Type> seen) {
- if (t.isCompound()) {
- types.directSupertypes(t).forEach(s -> visit(s, seen));
- } else {
- t.allparams().forEach(ta -> visit(ta, seen));
- }
- return null;
- }
-
- @Override
- public Void visitArrayType(ArrayType t, Set<Type> seen) {
- return visit(t.elemtype, seen);
- }
-
- @Override
- public Void visitWildcardType(WildcardType t, Set<Type> seen) {
- visit(t.type, seen);
- return null;
- }
-
- @Override
- public Void visitTypeVar(TypeVar t, Set<Type> seen) {
- if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
- visit(t.getUpperBound(), seen);
- }
- return null;
- }
-
- @Override
- public Void visitCapturedType(CapturedType t, Set<Type> seen) {
- if (seen.add(t)) {
- visit(t.getUpperBound(), seen);
- visit(t.getLowerBound(), seen);
- }
- return null;
- }
- }
-
- class TypeProjection extends StructuralTypeMapping<Boolean> {
-
- List<Type> vars;
- Set<Type> seen = new HashSet<>();
-
- public TypeProjection(List<Type> vars) {
- this.vars = vars;
- }
-
- @Override
- public Type visitClassType(ClassType t, Boolean upward) {
- if (upward && !t.isCompound() && t.tsym.name.isEmpty()) {
- //lift anonymous class type to first supertype (class or interface)
- return types.directSupertypes(t).last();
- } else if (t.isCompound()) {
- List<Type> components = types.directSupertypes(t);
- List<Type> components1 = components.map(c -> c.map(this, upward));
- if (components == components1) return t;
- else return types.makeIntersectionType(components1);
- } else {
- Type outer = t.getEnclosingType();
- Type outer1 = visit(outer, upward);
- List<Type> typarams = t.getTypeArguments();
- List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, upward));
- if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
- //not defined
- return syms.botType;
- }
- if (outer1 == outer && typarams1 == typarams) return t;
- else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
- @Override
- protected boolean needsStripping() {
- return true;
- }
- };
- }
- }
-
- protected Type makeWildcard(Type upper, Type lower) {
- BoundKind bk;
- Type bound;
- if (upper.hasTag(BOT)) {
- upper = syms.objectType;
- }
- boolean isUpperObject = types.isSameType(upper, syms.objectType);
- if (!lower.hasTag(BOT) && isUpperObject) {
- bound = lower;
- bk = SUPER;
- } else {
- bound = upper;
- bk = isUpperObject ? UNBOUND : EXTENDS;
- }
- return new WildcardType(bound, bk, syms.boundClass);
- }
-
- @Override
- public Type visitTypeVar(TypeVar t, Boolean upward) {
- if (vars.contains(t)) {
- try {
- if (seen.add(t)) {
- return (upward ?
- t.getUpperBound() :
- (t.getLowerBound() == null) ?
- syms.botType :
- t.getLowerBound())
- .map(this, upward);
- } else {
- //cycle
- return syms.objectType;
- }
- } finally {
- seen.remove(t);
- }
- } else {
- return t;
- }
- }
-
- @Override
- public Type visitWildcardType(WildcardType wt, Boolean upward) {
- if (upward) {
- return wt.isExtendsBound() ?
- wt.type.map(this, upward) :
- syms.objectType;
- } else {
- return wt.isSuperBound() ?
- wt.type.map(this, upward) :
- syms.botType;
- }
- }
-
- private Type mapTypeArgument(Type t, boolean upward) {
- if (!t.containsAny(vars)) {
- return t;
- } else if (!t.hasTag(WILDCARD) && !upward) {
- //not defined
- return syms.botType;
- } else {
- Type upper = t.map(this, upward);
- Type lower = t.map(this, !upward);
- return makeWildcard(upper, lower);
- }
- }
- }
-}
--- a/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java Wed Oct 04 20:01:19 2017 +0000
@@ -74,16 +74,15 @@
* @param rdecl Type name and name
* @return
*/
- public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) {
+ public static Wrap varWrap(String source, Wrap wtype, String brackets,
+ Range rname, Wrap winit, Wrap anonDeclareWrap) {
RangeWrap wname = new RangeWrap(source, rname);
- RangeWrap wtype = new RangeWrap(source, rtype);
Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
Wrap wmeth;
- if (rinit == null) {
+ if (winit == null) {
wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n");
} else {
- RangeWrap winit = new RangeWrap(source, rinit);
// int x = y
// int x_ = y; return x = x_;
// decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
@@ -93,7 +92,8 @@
);
}
Wrap wInitMeth = new DoitMethodWrap(wmeth);
- return new CompoundWrap(wVarDecl, wInitMeth);
+ return anonDeclareWrap != null ? new CompoundWrap(wVarDecl, wInitMeth, anonDeclareWrap)
+ : new CompoundWrap(wVarDecl, wInitMeth);
}
public static Wrap tempVarWrap(String source, String typename, String name) {
@@ -112,6 +112,14 @@
return new NoWrap(source);
}
+ public static Wrap identityWrap(String source) {
+ return new NoWrap(source);
+ }
+
+ public static Wrap rangeWrap(String source, Range range) {
+ return new RangeWrap(source, range);
+ }
+
public static Wrap classMemberWrap(String source) {
Wrap w = new NoWrap(source);
return new CompoundWrap(" public static\n ", w);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java Wed Oct 04 20:01:19 2017 +0000
@@ -273,7 +273,8 @@
private static final class LocalVariableTypeCalculationPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
- final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler));
+ final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler,
+ compiler.getReturnType()));
final ScriptEnvironment senv = compiler.getScriptEnvironment();
final PrintWriter err = senv.getErr();
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Wed Oct 04 20:01:19 2017 +0000
@@ -619,6 +619,10 @@
return types == null ? null : types.get(fn, pos);
}
+ Type getReturnType() {
+ return types == null || !isOnDemandCompilation() ? Type.UNKNOWN : types.getReturnType();
+ }
+
/**
* Do a compilation job
*
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Wed Oct 04 20:01:19 2017 +0000
@@ -405,10 +405,15 @@
// variables).
private final Deque<Label> catchLabels = new ArrayDeque<>();
- LocalVariableTypesCalculator(final Compiler compiler) {
+ private LocalVariableTypesCalculator(final Compiler compiler) {
this.compiler = compiler;
}
+ LocalVariableTypesCalculator(final Compiler compiler, final Type returnType) {
+ this(compiler);
+ this.returnType = returnType;
+ }
+
private JumpTarget createJumpTarget(final Label label) {
assert !jumpTargets.containsKey(label);
final JumpTarget jumpTarget = new JumpTarget();
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeMap.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeMap.java Wed Oct 04 20:01:19 2017 +0000
@@ -117,6 +117,15 @@
return null;
}
+ /**
+ * Get the return type required for the call site we're compiling for. This only determines
+ * whether object return type is required or not.
+ * @return Type.OBJECT for call sites with object return types, Type.UNKNOWN for everything else
+ */
+ Type getReturnType() {
+ return returnType.isObject() ? Type.OBJECT : Type.UNKNOWN;
+ }
+
@Override
public String toString() {
return toString("");
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java Wed Oct 04 20:01:19 2017 +0000
@@ -43,6 +43,7 @@
import jdk.dynalink.linker.support.TypeUtilities;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -430,9 +431,9 @@
if (objArray == null) {
return null;
} else if (objArray instanceof Collection) {
- return new NativeArray(((Collection<?>)objArray).toArray());
+ return new NativeArray(ScriptUtils.unwrapArray(((Collection<?>)objArray).toArray()));
} else if (objArray instanceof Object[]) {
- return new NativeArray(((Object[])objArray).clone());
+ return new NativeArray(ScriptUtils.unwrapArray(((Object[])objArray).clone()));
} else if (objArray instanceof int[]) {
return new NativeArray(((int[])objArray).clone());
} else if (objArray instanceof double[]) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Wed Oct 04 20:01:19 2017 +0000
@@ -2053,10 +2053,18 @@
if (outer != null) {
restoreBlock(outer);
if (body != null) {
+ List<Statement> statements = new ArrayList<>();
+ for (final Statement var : outer.getStatements()) {
+ if(var instanceof VarNode && !((VarNode)var).isBlockScoped()) {
+ appendStatement(var);
+ }else {
+ statements.add(var);
+ }
+ }
appendStatement(new BlockStatement(forLine, new Block(
outer.getToken(),
body.getFinish(),
- outer.getStatements())));
+ statements)));
}
}
}
@@ -5101,8 +5109,13 @@
final LiteralNode<Expression[]> rawStringArray = LiteralNode.newInstance(templateToken, finish, rawStrings);
final LiteralNode<Expression[]> cookedStringArray = LiteralNode.newInstance(templateToken, finish, cookedStrings);
- final RuntimeNode templateObject = new RuntimeNode(templateToken, finish, RuntimeNode.Request.GET_TEMPLATE_OBJECT, rawStringArray, cookedStringArray);
- argumentList.set(0, templateObject);
+
+ if (!env._parse_only) {
+ final RuntimeNode templateObject = new RuntimeNode(templateToken, finish, RuntimeNode.Request.GET_TEMPLATE_OBJECT, rawStringArray, cookedStringArray);
+ argumentList.set(0, templateObject);
+ } else {
+ argumentList.set(0, rawStringArray);
+ }
return optimizeList(argumentList);
}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Source.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Source.java Wed Oct 04 20:01:19 2017 +0000
@@ -336,6 +336,7 @@
}
}
+ @SuppressWarnings("try")
protected void loadMeta() throws IOException {
if (length == 0 && lastModified == 0) {
final URLConnection c = url.openConnection();
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, 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
@@ -59,7 +59,7 @@
*/
public class LinkerCallSite extends ChainedCallSite {
/** Maximum number of arguments passed directly. */
- public static final int ARGLIMIT = 250;
+ public static final int ARGLIMIT = 125;
private static final String PROFILEFILE = Options.getStringProperty("nashorn.profilefile", "NashornProfile.txt");
--- a/src/jdk.scripting.nashorn/share/classes/module-info.java Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/module-info.java Wed Oct 04 20:01:19 2017 +0000
@@ -44,8 +44,7 @@
</pre>
*
* and then use it just as you would any other JSR-223 script engine. See
- * <a href="jdk/nashorn/api/scripting/package-summary.html">
- * {@code jdk.nashorn.api.scripting}</a> package for details.
+ * {@link jdk.nashorn.api.scripting} package for details.
* <h1>Compatibility</h1>
* Nashorn is 100% compliant with the
* <a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm"
--- a/src/sample/nashorn/autoimports.js Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/autoimports.js Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
# autoimports script requires -scripting mode
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -43,6 +43,12 @@
* script, you can call autoimports to get the exact Java imports you need and replace
* the autoimports load with the generated import statements (to avoid costly init of
* the autoimports script).
+ *
+ * Example usage of autoimports.js in interactive mode:
+ *
+ * jjs -scripting autoimports.js -
+ * jjs> Vector
+ * jjs> [JavaClass java.util.Vector]
*/
(function() {
@@ -99,8 +105,8 @@
Files.walk(root).forEach(function(p) {
if (Files.isRegularFile(p)) {
var str = p.toString();
- if (str.endsWith(".class")) {
- str = str.substring(1);
+ if (str.endsWith(".class") && !str.endsWith("module-info.class")) {
+ str = str.substring("/modules/".length);
var idx = str.indexOf('/');
if (idx != -1) {
str = str.substring(idx + 1);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sample/nashorn/base64.js Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Usage: jjs --language=es6 base64.js
+
+const Base64 = Java.type("java.util.Base64");
+const ByteArray = Java.type("byte[]");
+const JString = Java.type("java.lang.String");
+
+function toBase64(s) {
+ const ba = s instanceof ByteArray? s : String(s).bytes;
+ return Base64.encoder.encodeToString(ba);
+}
+
+function fromBase64(s) {
+ const ba = s instanceof ByteArray? s : String(s).bytes;
+ return new JString(Base64.decoder.decode(ba));
+}
+
+print(toBase64`hello world`);
+print(fromBase64(toBase64`hello world`));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sample/nashorn/dom_tagged_literal.js Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This sample demonstrates the use of es6 tagged template literal to
+ * create a java object. A XML DOM Document object is created from
+ * String using es6 tagged template literal.
+ *
+ * Usage:
+ * jjs --language=es6 dom_tagged_literal.js
+ */
+
+// Java types used
+const BAIS = Java.type("java.io.ByteArrayInputStream")
+const DocBuilderFac = Java.type("javax.xml.parsers.DocumentBuilderFactory")
+const DOMSource = Java.type("javax.xml.transform.dom.DOMSource")
+const StreamResult = Java.type("javax.xml.transform.stream.StreamResult")
+const StringWriter = Java.type("java.io.StringWriter")
+const TransformerFactory = Java.type("javax.xml.transform.TransformerFactory")
+
+function DOM(str) {
+ var docBuilder = DocBuilderFac.newInstance().newDocumentBuilder()
+ docBuilder.validating = false
+ return docBuilder["parse(java.io.InputStream)"](new BAIS(String(str).bytes))
+}
+
+// es6 tagged template literal to create DOM from
+// multi-line XML string
+
+const dom = DOM`
+<foo>
+ <bar title="hello">world</bar>
+</foo>`
+
+// access DOM elements
+const foo = dom.documentElement
+print(foo.tagName)
+const bar = foo.getElementsByTagName("bar").item(0)
+print(bar.tagName)
+print(bar.getAttribute("title"))
+
+// modify DOM
+foo.setAttribute("name", "nashorn")
+foo.appendChild(dom.createElement("test"))
+
+// serialize DOM to XML string
+function domToXML(d) {
+ const transformer = TransformerFactory.newInstance().newTransformer()
+ const res = new StreamResult(new StringWriter())
+ transformer.transform(new DOMSource(d), res)
+ return res.writer.toString()
+}
+
+// serialize DOM to a String & print
+print(domToXML(dom))
--- a/src/sample/nashorn/dynalink/README Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/README Wed Oct 04 20:01:19 2017 +0000
@@ -4,12 +4,6 @@
"xyz_linker.js". These scripts build dynalink linker jar from java code and exec
another jjs process with appropriate classpath set.
-Note: you need to build jdk9 forest and put "images/jdk/bin" in your PATH to use
-these scripts. This is because these scripts use javac to build dynalink jar and
-exec another jjs with classpath set! Alternatively, you can also manually build
-dynalink linker jars and invoke sample scripts by putting linker jar in jjs tool's
-classpath as well.
-
Dynalink samples:
* array_stream_linker.js
--- a/src/sample/nashorn/dynalink/array_stream_linker.js Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/array_stream_linker.js Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
#! array stream linker example
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,10 +37,12 @@
$EXEC.throwOnError=true
// compile ArrayStreamLinkerExporter
-`javac -cp ../../dist/nashorn.jar ArrayStreamLinkerExporter.java`
+`javac ArrayStreamLinkerExporter.java`
+
+load("jarutil.js");
// make a jar file out of pluggable linker
-`jar cvf array_stream_linker.jar ArrayStreamLinkerExporter*.class META-INF/`
+makeJar("array_stream_linker.jar");
// run a sample script that uses pluggable linker
// but make sure classpath points to the pluggable linker jar!
--- a/src/sample/nashorn/dynalink/buffer_indexing_linker.js Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/buffer_indexing_linker.js Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
# buffer indexing linker example
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,10 +37,12 @@
$EXEC.throwOnError=true
// compile BufferIndexingLinkerExporter
-`javac -cp ../../dist/nashorn.jar BufferIndexingLinkerExporter.java`
+`javac BufferIndexingLinkerExporter.java`
+
+load("jarutil.js");
// make a jar file out of pluggable linker
-`jar cvf buffer_indexing_linker.jar BufferIndexingLinkerExporter*.class META-INF/`
+makeJar("buffer_indexing_linker.jar");
// run a sample script that uses pluggable linker
// but make sure classpath points to the pluggable linker jar!
--- a/src/sample/nashorn/dynalink/dom_linker.js Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/dom_linker.js Wed Oct 04 20:01:19 2017 +0000
@@ -37,10 +37,12 @@
$EXEC.throwOnError=true
// compile DOMLinkerExporter
-`javac -cp ../../dist/nashorn.jar DOMLinkerExporter.java`
+`javac DOMLinkerExporter.java`
+
+load("jarutil.js");
// make a jar file out of pluggable linker
-`jar cvf dom_linker.jar DOMLinkerExporter*.class META-INF/`
+makeJar("dom_linker.jar");
// run a sample script that uses pluggable linker
// but make sure classpath points to the pluggable linker jar!
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sample/nashorn/dynalink/jarutil.js Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+function classFiles() {
+ var arr = new java.io.File(".").listFiles(
+ new java.io.FilenameFilter() {
+ accept: function(dir, str) str.endsWith(".class")
+ });
+ var str = "";
+ for (var i in arr) str += " " + arr[i];
+ return str;
+}
+
+function makeJar(name) {
+ $EXEC("jar cvf " + name + " META-INF/ " + classFiles());
+ print($ERR);
+}
--- a/src/sample/nashorn/dynalink/missing_method_linker.js Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/missing_method_linker.js Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
#! missing method linker example
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,10 +37,12 @@
$EXEC.throwOnError=true
// compile MissingMethodLinkerExporter
-`javac -cp ../../dist/nashorn.jar MissingMethodLinkerExporter.java MissingMethodHandler.java MissingMethodExample.java`
+`javac MissingMethodLinkerExporter.java MissingMethodHandler.java MissingMethodExample.java`
+
+load("jarutil.js");
// make a jar file out of pluggable linker
-`jar cvf missing_method_linker.jar MissingMethod*.class META-INF/`
+makeJar("missing_method_linker.jar");
// run a sample script that uses pluggable linker
// but make sure classpath points to the pluggable linker jar!
--- a/src/sample/nashorn/dynalink/underscore_linker.js Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/underscore_linker.js Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
# underscore name translator dynalink linker example
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,10 +37,12 @@
$EXEC.throwOnError=true
// compile UnderscoreNameLinkerExporter
-`javac -cp ../../dist/nashorn.jar UnderscoreNameLinkerExporter.java`
+`javac UnderscoreNameLinkerExporter.java`
+
+load('jarutil.js');
// make a jar file out of pluggable linker
-`jar cvf underscore_linker.jar UnderscoreNameLinkerExporter*.class META-INF/`
+makeJar("underscore_linker.jar");
// run a sample script that uses pluggable linker
// but make sure classpath points to the pluggable linker jar!
--- a/test/TestCommon.gmk Wed Oct 04 11:52:07 2017 -0700
+++ b/test/TestCommon.gmk Wed Oct 04 20:01:19 2017 +0000
@@ -273,7 +273,7 @@
prep:
@$(MKDIR) -p $(ABS_TEST_OUTPUT_DIR)
@$(MKDIR) -p `$(DIRNAME) $(ARCHIVE_BUNDLE)`
- @if [ ! -d $(TEST_ROOT)/../.hg ] ; then \
+ @if [ ! -d $(TEST_ROOT)/../../.hg ] && [ ! -d $(TEST_ROOT)/../../../.hg ]; then \
$(FIND) $(TEST_ROOT) \( -name \*.dll -o -name \*.DLL -o -name \*.so \) \
-exec $(CHMOD) a+rx {} \; ; \
fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/execstack/TestCheckJDK.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, 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 Testexecstack.java
+ * @summary Searches for all libraries in test VM and checks that they
+ * have the noexecstack bit set.
+ * @requires (os.family == "linux")
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * TestCheckJDK
+ */
+
+import jdk.test.lib.Asserts;
+import sun.hotspot.WhiteBox;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class TestCheckJDK {
+ static boolean testPassed = true;
+ private static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+ static void checkExecStack(Path file) {
+ String filename = file.toString();
+ if (filename.endsWith(".so")) {
+ if (!WB.checkLibSpecifiesNoexecstack(filename)) {
+ System.out.println("Library does not have the noexecstack bit set: " + filename);
+ testPassed = false;
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Throwable {
+ String vmInstallDir = System.getProperty("java.home");
+
+ Files.walk(Paths.get(vmInstallDir)).filter(Files::isRegularFile).forEach(TestCheckJDK::checkExecStack);
+
+ Asserts.assertTrue(testPassed,
+ "The tested VM contains libs that don't have the noexecstack " +
+ "bit set. They must be linked with -z,noexecstack.");
+ }
+}
--- a/test/jdk/java/lang/StackWalker/Basic.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/lang/StackWalker/Basic.java Wed Oct 04 20:01:19 2017 +0000
@@ -29,8 +29,9 @@
*/
import java.lang.StackWalker.StackFrame;
+import java.lang.invoke.MethodType;
import java.util.List;
-import java.util.Objects;
+import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.lang.StackWalker.Option.*;
@@ -74,6 +75,37 @@
found);
}
+ @Test
+ public static void testMethodSignature() throws Exception {
+ List<StackFrame> frames = new StackBuilder(16, 16).build();
+ Map<String, MethodType> methodTypes = StackBuilder.methodTypes();
+ for (StackFrame f : frames) {
+ MethodType type = methodTypes.get(f.getMethodName());
+ if (type != null) {
+ System.out.format("%s.%s %s%n", f.getClassName(), f.getMethodName(),
+ f.getDescriptor());
+
+ String descriptor = f.getDescriptor();
+ if (!descriptor.equals(type.toMethodDescriptorString())) {
+ throw new RuntimeException("Expected: " + type.toMethodDescriptorString()
+ + " got: " + f.getDescriptor());
+ }
+
+ if (!f.getMethodType().equals(type)) {
+ throw new RuntimeException("Expected: " + type
+ + " got: " + f.getMethodType());
+ }
+
+ // verify descriptor returned by getDescriptor() before and after
+ // getMethodType() is called
+ if (!descriptor.equals(f.getDescriptor())) {
+ throw new RuntimeException("Mismatched: " + descriptor
+ + " got: " + f.getDescriptor());
+ }
+ }
+ }
+ }
+
private final int depth;
Basic(int depth) {
this.depth = depth;
@@ -132,7 +164,7 @@
}
}
- class StackBuilder {
+ static class StackBuilder {
private final int stackDepth;
private final int limit;
private int depth = 0;
@@ -150,15 +182,17 @@
trace("m1");
m2();
}
- void m2() {
+ List m2() {
trace("m2");
m3();
+ return null;
}
- void m3() {
+ int m3() {
trace("m3");
- m4();
+ m4(null);
+ return 0;
}
- void m4() {
+ void m4(Object o) {
trace("m4");
int remaining = stackDepth-depth-1;
if (remaining >= 4) {
@@ -184,6 +218,13 @@
if (verbose)
System.out.format("%2d: %s%n", depth, methodname);
}
+
+ static Map<String, MethodType> methodTypes() throws Exception {
+ return Map.of("m1", MethodType.methodType(void.class),
+ "m2", MethodType.methodType(List.class),
+ "m3", MethodType.methodType(int.class),
+ "m4", MethodType.methodType(void.class, Object.class));
+ }
}
}
--- a/test/jdk/java/lang/StackWalker/SanityTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/lang/StackWalker/SanityTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -79,4 +79,24 @@
throw new RuntimeException("NPE expected");
} catch (NullPointerException e) {}
}
+
+
+ @Test
+ public static void testUOEFromGetDeclaringClass() {
+ try {
+ StackWalker sw = StackWalker.getInstance();
+ sw.forEach(StackWalker.StackFrame::getDeclaringClass);
+ throw new RuntimeException("UOE expected");
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ @Test
+ public static void testUOEFromGetMethodType() {
+ try {
+ StackWalker sw = StackWalker.getInstance();
+ sw.forEach(StackWalker.StackFrame::getMethodType);
+ throw new RuntimeException("UOE expected");
+ } catch (UnsupportedOperationException expected) {}
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/InvokeWithArgumentsTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017, 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
+ * @summary basic tests for MethodHandle.invokeWithArguments
+ * @run testng test.java.lang.invoke.InvokeWithArgumentsTest
+ */
+
+package test.java.lang.invoke;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.WrongMethodTypeException;
+
+import static java.lang.invoke.MethodType.methodType;
+
+public class InvokeWithArgumentsTest {
+ static final MethodHandles.Lookup L = MethodHandles.lookup();
+
+ static Object[] arity(Object o1, Object o2, Object... a) {
+ return a;
+ }
+
+ @Test
+ public void testArity() throws Throwable {
+ MethodHandle mh = L.findStatic(L.lookupClass(), "arity",
+ methodType(Object[].class, Object.class, Object.class, Object[].class));
+
+ try {
+ mh.invokeWithArguments("");
+ Assert.fail("WrongMethodTypeException expected");
+ } catch (WrongMethodTypeException e) {}
+ }
+
+ static Object[] passThrough(String... a) {
+ return a;
+ }
+
+ static Object[] pack(Object o, Object... a) {
+ return a;
+ }
+
+ @Test
+ public void testArrayNoPassThrough() throws Throwable {
+ String[] actual = {"A", "B"};
+
+ MethodHandle mh = L.findStatic(L.lookupClass(), "passThrough",
+ methodType(Object[].class, String[].class));
+
+ // Note: the actual array is not preserved, the elements will be
+ // unpacked and then packed into a new array before invoking the method
+ String[] expected = (String[]) mh.invokeWithArguments(actual);
+
+ Assert.assertTrue(actual != expected, "Array should not pass through");
+ Assert.assertEquals(actual, expected, "Array contents should be equal");
+ }
+
+ @Test
+ public void testArrayPack() throws Throwable {
+ String[] actual = new String[]{"A", "B"};
+
+ MethodHandle mh = L.findStatic(L.lookupClass(), "pack",
+ methodType(Object[].class, Object.class, Object[].class));
+
+ // Note: since String[] can be cast to Object, the actual String[] array
+ // will cast to Object become the single element of a new Object[] array
+ Object[] expected = (Object[]) mh.invokeWithArguments("", actual);
+
+ Assert.assertEquals(1, expected.length, "Array should contain just one element");
+ Assert.assertTrue(actual == expected[0], "Array should pass through");
+ }
+
+ static void intArray(int... a) {
+ }
+
+ @Test
+ public void testPrimitiveArrayWithNull() throws Throwable {
+ MethodHandle mh = L.findStatic(L.lookupClass(), "intArray",
+ methodType(void.class, int[].class));
+ try {
+ mh.invokeWithArguments(null, null);
+ Assert.fail("NullPointerException expected");
+ } catch (NullPointerException e) {}
+ }
+
+ @Test
+ public void testPrimitiveArrayWithRef() throws Throwable {
+ MethodHandle mh = L.findStatic(L.lookupClass(), "intArray",
+ methodType(void.class, int[].class));
+ try {
+ mh.invokeWithArguments("A", "B");
+ Assert.fail("ClassCastException expected");
+ } catch (ClassCastException e) {}
+ }
+
+
+ static void numberArray(Number... a) {
+ }
+
+ @Test
+ public void testRefArrayWithCast() throws Throwable {
+ MethodHandle mh = L.findStatic(L.lookupClass(), "numberArray",
+ methodType(void.class, Number[].class));
+ // All numbers, should not throw
+ mh.invokeWithArguments(1, 1.0, 1.0F, 1L);
+
+ try {
+ mh.invokeWithArguments("A");
+ Assert.fail("ClassCastException expected");
+ } catch (ClassCastException e) {}
+ }
+}
--- a/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -203,10 +203,8 @@
static List<TestAccessMode> testAccessModesOfType(TestAccessType... ats) {
Stream<TestAccessMode> s = Stream.of(TestAccessMode.values());
- for (TestAccessType at : ats) {
- s = s.filter(e -> e.isOfType(at));
- }
- return s.collect(toList());
+ return s.filter(e -> Stream.of(ats).anyMatch(e::isOfType))
+ .collect(toList());
}
static List<VarHandle.AccessMode> accessModes() {
@@ -215,10 +213,9 @@
static List<VarHandle.AccessMode> accessModesOfType(TestAccessType... ats) {
Stream<TestAccessMode> s = Stream.of(TestAccessMode.values());
- for (TestAccessType at : ats) {
- s = s.filter(e -> e.isOfType(at));
- }
- return s.map(TestAccessMode::toAccessMode).collect(toList());
+ return s.filter(e -> Stream.of(ats).anyMatch(e::isOfType))
+ .map(TestAccessMode::toAccessMode)
+ .collect(toList());
}
static MethodHandle toMethodHandle(VarHandle vh, TestAccessMode tam, MethodType mt) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/HugeDataTransferTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,881 @@
+/*
+ * Copyright (c) 2017, 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 8185072
+ * @summary network006 times out in many configs in JDK10-hs nightly
+ * @run main/othervm/manual HugeDataTransferTest 1
+ */
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Random;
+
+/**
+ * This test makes huge number of data transfers between 2 Java virtual machines
+ * using the TCP/IP protocol, and checks if those data are transfered correctly.
+ * Both client and server VMs run on the same local computer and attach TCP/IP
+ * sockets to the local host, or to the loopback domain
+ * ``<code>localhost</code>'' (having IP address <code>127.0.0.1</code>).
+ *
+ * <p>
+ * In this test, 128 client/server connections are established. Once a
+ * connection is established, client passes a data parcel to server, and server
+ * reads that parcel and checks if it is same as expected (byte-to-byte equality
+ * is desired). Then server passes (some other) parcel to the client, and client
+ * reads and verifies those bytes. This ping-pong game is repeated 128 times;
+ * and after that each pair of sockets checks if there are no extra bytes
+ * accedentally passed through their connection.
+ *
+ * <p>
+ * Parcels lengths and contents are chosen randomly, and average parcel length
+ * is 128 bytes. So totally, each pair of sockets passes ~16Kb of data to each
+ * other, and thus ~32Kb of data are transfered by each sockets pair. Totally,
+ * ~4Mb of data are transfered by all client/server pairs.
+ *
+ * @author vtewari
+ */
+public class HugeDataTransferTest {
+
+ /**
+ * Timeout for TCP/IP sockets (currently set to 1 min).
+ */
+ private static int SO_TIMEOUT;// = 2*60*1000;
+
+ /**
+ * Maximal number of connections this test should open simultaneously.
+ */
+ private final static int MAX_CONNECTIONS = 128;
+
+ /**
+ * Check few more connections to make sure that MAX_CONNECTIONS are safe.
+ */
+ private final static int CONNECTIONS_RESERVE = 10;
+
+ /**
+ * The test used to fail with connection reset by peer set to 50. (and once
+ * in a three if it was set to 10). So now we set it to MAX_CONNECTIONS
+ * (128).
+ */
+ private final static int BACKLOG_QUEUE_LENGTH = MAX_CONNECTIONS;
+
+ /**
+ * Number of parcels to be sent/recieved.
+ */
+ private final static int DATA_PARCELS = 128;
+
+ /**
+ * Maximal length of data parcel to be sent/recieved (it equals to 256 bytes
+ * now).
+ */
+ private final static int MAX_PARCEL = 1 << 8;
+
+ /**
+ * Either actually display optional reports or not.
+ */
+ static private final boolean DEBUG_MODE = false;
+
+ /**
+ * How many IP sockets can we open simultaneously? Check if
+ * <code>MAX_CONNECTIONS</code> connections can be open simultaneously.
+ */
+ private static int detectOSLimitation() {
+ final int CONNECTIONS_TO_TRY = MAX_CONNECTIONS + CONNECTIONS_RESERVE;
+ display("--- Trying to open " + CONNECTIONS_TO_TRY + " connections:");
+
+ InetAddress address;
+ ServerSocket serverSocket;
+ try {
+ address = InetAddress.getLocalHost();
+ int anyPort = 0;
+ int defaultBacklog = BACKLOG_QUEUE_LENGTH;
+ serverSocket = new ServerSocket(anyPort, defaultBacklog, address);
+ } catch (IOException ioe) {
+ throw new Error("FATAL error while loading the test: " + ioe);
+ }
+ display(serverSocket.toString());
+
+ Socket server[] = new Socket[CONNECTIONS_TO_TRY];
+ Socket client[] = new Socket[CONNECTIONS_TO_TRY];
+
+ int i, port = serverSocket.getLocalPort();
+ for (i = 0; i < CONNECTIONS_TO_TRY; i++) {
+ try {
+ client[i] = new Socket(address, port);
+ display(">Open: client[" + i + "] = " + client[i]);
+ server[i] = serverSocket.accept();
+ display(">Open: server[" + i + "] = " + server[i]);
+ } catch (IOException ioe) {
+ display(">OOPS! -- failed to open connection #" + i);
+ break;
+ }
+ }
+ display("> Could open "
+ + (i < CONNECTIONS_TO_TRY ? "only " : "") + i + " connections.");
+ display(">Closing them:");
+ for (int j = 0; j < i; j++) {
+ try {
+ server[j].close();
+ client[j].close();
+ } catch (IOException ioe) {
+ throw new Error("FATAL error while loading the test: " + ioe);
+ }
+ }
+ display(">OK.");
+ int safeConnections = i - CONNECTIONS_RESERVE;
+ if (safeConnections < 1) {
+ safeConnections = 1;
+ }
+ if (safeConnections < MAX_CONNECTIONS) {
+ complain("------------------------- CAUTION: -------------------");
+ complain("While checking the OS limitations, the test found that");
+ complain("only " + i + " TCP/IP socket connections could be safely open");
+ complain("simultaneously. However, possibility to open at least");
+ complain("" + MAX_CONNECTIONS + "+" + CONNECTIONS_RESERVE
+ + " connections were expected.");
+ complain("");
+ complain("So, the test will check only " + safeConnections + " connection"
+ + (safeConnections == 1 ? "" : "s") + " which seem");
+ complain("safe to be open simultaneously.");
+ complain("------------------------------------------------------");
+ }
+ return safeConnections;
+ }
+
+ //----------------------------------------------------------------//
+ /**
+ * Re-calls to the method <code>run(args[],out)</code> actually performing
+ * the test. After <code>run(args[],out)</code> stops, follow JDK-like
+ * convention for exit codes. I.e.: stop with exit status 95 if the test has
+ * passed, or with status 97 if the test has failed.
+ *
+ * @see #run(String[],PrintStream)
+ */
+ public static void main(String args[]) {
+ int exitCode = run(args, System.out);
+ System.exit(exitCode + 95);
+ // JCK-like exit status.
+ }
+
+ public static int run(String args[], PrintStream out) {
+ HugeDataTransferTest.out = out;
+
+ //
+ // Get the Internet address of the local machine.
+ //
+ InetAddress address = null;
+ try {
+ address = InetAddress.getLocalHost();
+ } catch (UnknownHostException exception) {
+ complain(exception.toString());
+ return 2; // FAILED
+ }
+ display("Host: " + address);
+
+ //
+ // Detect if it is safe to open MAX_CONNETIONS simultaneously:
+ //
+ final int CONNECTIONS = detectOSLimitation();
+
+ //
+ // Assign ServerSocket, and start client VM which should open
+ // the prescribed number of CONNECTIONS to that ServerSocket.
+ //
+ ServerSocket serverSocket;
+ try {
+ final int anyPort = 0;
+ final int defaultBacklog = BACKLOG_QUEUE_LENGTH;
+ serverSocket = new ServerSocket(anyPort, defaultBacklog, address);
+ } catch (IOException exception) {
+ complain("Cannot assign a ServerSocket on: " + address);
+ return 2;
+ }
+
+ //
+ // Start the client process on different VM.
+ //
+ String jdkPath = System.getProperty("test.jdk");
+ Path toolName = Paths.get("bin", "java" + (isWindows() ? ".exe" : ""));
+ Path jdkTool = Paths.get(jdkPath, toolName.toString());
+
+ String IPAddress = address.getHostAddress();
+ int localPort = serverSocket.getLocalPort();
+ String arguments = " " + CONNECTIONS + " " + IPAddress + " " + localPort;
+ //String command = args[0] + " " + network006.class.getName() + "$Client " + arguments;
+ String command = jdkTool.toAbsolutePath().toString() + " " + Client.class.getName() + " " + arguments;
+ try {
+ SO_TIMEOUT = Integer.parseInt(args[0]) * 60 * 1000;
+ } catch (NumberFormatException e) {
+ complain("Wrong timeout argument: " + e);
+ return 2;
+ }
+
+ Runtime runtime = Runtime.getRuntime();
+
+ Process client = null;
+ IORedirector redirectOut = null;
+ IORedirector redirectErr = null;
+
+ try {
+ // Start clients on different JVM:
+ client = runtime.exec(command);
+
+ // Provide clients with access to stderr and stdout:
+ InputStream clientOut = client.getInputStream();
+ InputStream clientErr = client.getErrorStream();
+ redirectOut = new IORedirector(clientOut, DEBUG_MODE ? out : null);
+ redirectErr = new IORedirector(clientErr, out);
+ redirectOut.start();
+ redirectErr.start();
+
+ } catch (IOException exception) {
+ complain("Failed to start client: " + exception);
+ return 2;
+ }
+ //
+ // Start the server threads (and let them establish connections):
+ //
+
+ Server server[] = new Server[CONNECTIONS];
+ for (int i = 0; i < CONNECTIONS; i++) {
+ server[i] = new Server(serverSocket);
+ display("Server #" + i + ": " + server[i]);
+ server[i].start();
+ }
+
+ //
+ // Wait for the servers and the clients:
+ //
+ boolean testFailed = false;
+
+ try {
+ client.waitFor();
+ int clientStatus = client.exitValue();
+ display("Client VM exitCode=" + clientStatus);
+
+ // Let I/O redirectors to flush:
+ if (redirectOut.isAlive()) {
+ redirectOut.join();
+ }
+ if (redirectErr.isAlive()) {
+ redirectErr.join();
+ }
+
+ // If client has crashed, also terminate the server (to avoid hangup).
+ if (clientStatus != 95) {
+ complain("Client VM has crashed: exit status=" + clientStatus);
+ testFailed = true;
+ }
+
+ // Client has finished OK; wait for the server.
+ for (int i = 0; i < CONNECTIONS; i++) {
+ display("Server: waiting for #" + i);
+ if (server[i].isAlive()) {
+ display("Server #" + i + ": (joining...)" + server[i]);
+ server[i].join();
+ }
+ if (server[i].exception != null) {
+ if (server[i].message != null) {
+ complain("Server #" + i + "(finished): with message:" + server[i].message);
+ }
+
+ complain("Server #" + i + "(finished): " + server[i].exception);
+ server[i].exception.printStackTrace(out);
+ out.flush();
+// complain("Server #"+i+": "+server[i].exception.getStackTrace());
+ testFailed = true;
+ }
+ }
+
+ } catch (InterruptedException exception) {
+ complain("Test interrupted: " + exception);
+ testFailed = true;
+ }
+
+ if (testFailed) {
+ complain("Test failed.");
+ } else {
+ display("Test passed.");
+ }
+ return testFailed ? 2 : 0;
+ }
+
+ private static boolean isWindows() {
+ return System.getProperty("os.name").toLowerCase().startsWith("win");
+ }
+ //----------------------------------------------------------------//
+ /**
+ * Log stream for error messages and/or (optional) execution trace.
+ */
+ private static PrintStream out;
+
+ /**
+ * Print error message.
+ */
+ private static synchronized void complain(Object message) {
+ out.println("# " + message);
+ out.flush();
+ }
+
+ ;
+
+ /**
+ * Display optional report: comment ca va?
+ */
+ private static synchronized void display(Object report) {
+ if (DEBUG_MODE) {
+ out.println(report.toString());
+ }
+ out.flush(); //todo shouldn't this be inside if??
+ }
+
+ ;
+
+ //----------------------------------------------------------------//
+
+ /**
+ * Server thread should reply to data parcels sent by Client VM.
+ */
+ private static class Server extends Thread {
+
+ /**
+ * The socket is assigned at the Server instantiation.
+ */
+ private ServerSocket serverSocket;
+
+ /**
+ * The socket is assigned at the Server runtime.
+ */
+ private Socket socket;
+
+ /**
+ * Display the server socket.
+ */
+ @Override
+ public String toString() {
+
+ return "ServerSocket: " + serverSocket.toString();
+// + " socket: " + socket.toString();
+ }
+
+ /**
+ * Which port is this socket listening?
+ */
+ int getPort() {
+ return serverSocket.getLocalPort();
+ }
+
+ /**
+ * Find some free port at the given <code>address</code> and attach new
+ * server to hear that port. // lidsten to??
+ */
+ public Server(ServerSocket serverSocket) {
+ this.serverSocket = serverSocket;
+ }
+
+ /**
+ * Exception just arisen while the server was working, or
+ * <code>null</code> if it was OK with the server.
+ */
+ Exception exception = null;
+ String message = null;
+
+ /**
+ * Accept connection, then reply to client's parcels.
+ */
+ @Override
+ public void run() {
+ try {
+ socket = serverSocket.accept();
+ socket.setSoTimeout(SO_TIMEOUT);
+
+ InputStream istream = socket.getInputStream();
+ OutputStream ostream = socket.getOutputStream();
+
+ Random random = new Random(getPort());
+
+ for (int i = 0; i < DATA_PARCELS; i++) {
+ Parcel etalon = new Parcel(random);
+ message = "reading parcel number " + i;
+ Parcel sample = new Parcel(istream); // read
+ if (!sample.equals(etalon)) {
+ complain("Server thread for port #"
+ + getPort() + " got unexpected parcel:\n"
+ + "sample=" + sample + "\n"
+ + "etalon=" + etalon);
+ throw new TestFailure( //received??
+ "server has read unexpected parcel");
+ }
+ message = "sending parcel number " + i;
+ etalon.send(ostream);
+ ostream.flush();
+ }
+
+ int datum = istream.read(); // wait for client close()
+ if (datum >= 0) {
+ throw new TestFailure(
+ "server has read ambigous byte: " + datum);
+ }
+
+ ostream.close(); // implies: socket.close();
+
+ } catch (Exception oops) {
+ exception = oops;
+ }
+ }
+ }
+
+ //----------------------------------------------------------------//
+ /**
+ * Client VM should send data parcels to Server VM and recieve and verify
+ * the server's replies.
+ */
+ private static class Client extends Thread {
+
+ /**
+ * This thread uses the single client socket.
+ */
+ private Socket socket;
+
+ /**
+ * Address and port of this socket.
+ */
+ @Override
+ public String toString() {
+ return socket.toString();
+ }
+
+ /**
+ * Did the thread failed? If yes, what is the failure's reason.
+ */
+ Exception exception = null;
+ String message = null;
+
+ public static java.io.PrintStream complainStream = System.out;
+ public static java.io.PrintStream displayStream = System.err;
+
+ /**
+ * Connect client socket on the given <code>address</code> and
+ * <code>port</code>.
+ */
+ Client(InetAddress address, int port) throws IOException {
+ socket = new Socket(address, port);
+ socket.setSoTimeout(SO_TIMEOUT);
+ }
+
+ /**
+ * What is the port number this socket is listening for?
+ */
+ int getPort() {
+ return socket.getPort();
+ }
+
+ /**
+ * Establish connection, then read/respond <code>DATA_PARCELS</code>
+ * parcels of random data. Set initial seed for pseudo-random numbers
+ * generator to the value of the local port number.
+ *
+ * @see #DATA_PARCELS
+ * @see #getPort()
+ */
+ @Override
+ public void run() {
+ try {
+ InputStream istream = socket.getInputStream();
+ OutputStream ostream = socket.getOutputStream();
+
+ Random random = new Random(getPort());
+ // suggested by Oleg -- to avoid race conditions
+ /* try{
+ Thread.sleep(500);
+ }
+ catch (java.lang.InterruptedException e)
+ {
+ }*/
+
+ for (int i = 0; i < DATA_PARCELS; i++) {
+ Parcel etalon = new Parcel(random);
+ message = "sending parcel number: " + i;
+ etalon.send(ostream);
+ ostream.flush();
+
+ message = "reading parcel number: " + i;
+ Parcel sample = new Parcel(istream); // read
+ if (!sample.equals(etalon)) {
+ complain("Client thread for port #"
+ + getPort() + " got unexpected parcel:\n"
+ + "sample=" + sample + "\n"
+ + "etalon=" + etalon);
+ throw new TestFailure(
+ "parcel context is unexpected to client");
+ }
+ }
+
+ if (istream.available() > 0) {
+ int datum = istream.read();
+ throw new TestFailure(
+ "client has read ambigous byte: " + datum);
+ }
+ ostream.close(); // implies: socket.close()
+
+ } catch (Exception oops) {
+ exception = oops;
+ }
+ }
+
+ /**
+ * Establish lots of connections to server socket, attack servers with
+ * huge data parcels, and check if they reply correctly. The number of
+ * connections to try, the address and port number for the server socket
+ * are passed through <code>args[]</code>, like:
+ * <pre>
+ * java network006$Client connections_to_try address port
+ * </pre>
+ */
+ public static void main(String args[]) {
+ if (DEBUG_MODE) {
+ try {
+ String filename = "Client" + ((args.length == 3) ? args[2] : "new");
+ displayStream = new PrintStream(filename + ".out");
+ complainStream = new PrintStream(filename + ".err");
+ } catch (FileNotFoundException exception) {
+ complain(exception);
+ }
+
+ }
+
+ if (args.length != 3) {
+ complain("Client expects 3 paramenets:");
+ complain(" java " + Client.class.getName() + " connections_to_try address port");
+ exit(1); // FAILED
+ }
+
+ int CONNECTIONS = Integer.parseInt(args[0]);
+ display("Client VM: will try " + CONNECTIONS + " connections.");
+ InetAddress address;
+ try {
+ address = InetAddress.getByName(args[1]);
+ } catch (UnknownHostException exception) {
+ address = null;
+ complain("Client: cannot find host: \"" + args[1] + "\"");
+ exit(4);
+ }
+ display("Client: host to contact: " + address);
+ int port = Integer.parseInt(args[2]);
+ display("Client: port to contact: " + port);
+
+ //
+ // Establish connections, and start client processes:
+ //
+ Client client[] = new Client[CONNECTIONS];
+ for (int i = 0; i < CONNECTIONS; i++) {
+ try {
+ client[i] = new Client(address, port);
+ display("Client #" + i + ": " + client[i]);
+
+ } catch (IOException ioe) {
+ complain("Client #" + i + "(creation): " + ioe);
+ ioe.printStackTrace(complainStream);
+ complainStream.flush();
+// complain("Client #" + i + "(creation): " + ioe.getStackTrace());
+ exit(3);
+ }
+ }
+
+ for (int i = 0; i < CONNECTIONS; i++) {
+ client[i].start();
+ }
+
+ //
+ // Wait until testing is not finished:
+ //
+ int status = 0;
+ for (int i = 0; i < CONNECTIONS; i++) {
+ display("Client: waiting for #" + i);
+ if (client[i].isAlive()) {
+ display("Client #" + i + ": (joining...)" + client[i]);
+
+ try {
+ client[i].join();
+ } catch (InterruptedException ie) {
+ complain("Client #" + i + ": " + ie);
+ status = 3;
+ }
+ }
+ if (client[i].exception != null) {
+ if (client[i].message != null) {
+ complain("Client #" + i + "(finished) with message: " + client[i].message);
+ }
+ complain("Client #" + i + "(finished): " + client[i].exception);
+ client[i].exception.printStackTrace(complainStream);
+ complainStream.flush();
+ if (status == 0) {
+ status = 2;
+ }
+ }
+ }
+
+ exit(status);
+ }
+
+ /**
+ * Print error message.
+ */
+ private static synchronized void complain(Object message) {
+ complainStream.println("# " + message);
+ complainStream.flush();
+ }
+
+ /**
+ * Display execution trace.
+ */
+ private static synchronized void display(Object message) {
+ if (!DEBUG_MODE) {
+ return;
+ }
+ displayStream.println(message.toString());
+ displayStream.flush();
+ }
+
+ /**
+ * Exit with JCK-like status.
+ */
+ private static void exit(int exitCode) {
+ int status = exitCode + 95;
+// display("Client: exiting with code=" + status);
+ System.exit(status);
+ }
+ }
+
+ /**
+ * Two of such threads should redirect <code>out</code> and <code>err</code>
+ * streams of client VM.
+ */
+ private static class IORedirector extends Thread {
+
+ /**
+ * Source stream.
+ */
+ InputStream in;
+ /**
+ * Destination stream.
+ */
+ OutputStream out;
+
+ /**
+ * Redirect <code>in</code> to <code>out</code>.
+ */
+ public IORedirector(InputStream in, OutputStream out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ /**
+ * Read input stream until the EOF, and write everithing to output
+ * stream. If output stream is assigned to <code>null</code>, do not
+ * print anything, but read the input stream anywhere.
+ */
+ @Override
+ public void run() {
+ try {
+ for (;;) {
+ int symbol = in.read();
+ if (symbol < 0) {
+ break; // EOF
+ }
+ if (out != null) {
+ out.write(symbol);
+ }
+ }
+
+ if (out != null) {
+ out.flush();
+ }
+
+ } catch (IOException exception) {
+ throw new TestFailure("IORedirector exception: " + exception);
+ }
+ }
+ }
+
+ //----------------------------------------------------------------//
+ /**
+ * A data parcel to be sent/recieved between Client VM and Server thread.
+ * When data parcel is sent, first 4 bytes are transfered which encode the
+ * <code>int</code> number equal to size of the parcel minus 1. I.e.: if
+ * number of data bytes in the parcel's contents is <code>N</code>, then the
+ * first 4 bytes encode the number <code>N-1</code>. After that, the
+ * parcel's contents bytes are transered.
+ */
+ static class Parcel {
+
+ private final byte[] parcel;
+
+ /**
+ * Display all bytes as integer values from 0 to 255; or return
+ * ``<tt>null</tt>'' if this Parcel is not yet initialized.
+ */
+ @Override
+ public String toString() {
+ if (parcel == null) {
+ return "null";
+ }
+ String s = "{";
+ for (int i = 0; i < parcel.length; i++) {
+ s += (i > 0 ? ", " : "") + ((int) parcel[i] & 0xFF);
+ }
+ return s + "}";
+ }
+
+ /**
+ * Generate new <code>parcel[]</code> array using the given
+ * <code>random</code> numbers generator. Client and Server threads
+ * should use identical <code>random</code> generators, so that those
+ * threads could generate equal data parcels and check the parcel just
+ * transfered.
+ */
+ public Parcel(Random random) {
+ int size = random.nextInt(MAX_PARCEL) + 1;
+ parcel = new byte[size];
+ for (int i = 0; i < size; i++) {
+ parcel[i] = (byte) random.nextInt(256);
+ }
+ }
+
+ ;
+
+ /**
+ * Read exactly <code>size</code> bytes from the <code>istream</code>
+ * if possible, or throw <code>TestFailure</code> if unexpected end of
+ * <code>istream</code> occurs.
+ */
+ private static byte[] readBytes(int size, InputStream istream)
+ throws IOException {
+
+ byte data[] = new byte[size];
+ for (int i = 0; i < size; i++) {
+ int datum = istream.read();
+ if (datum < 0) {
+ throw new TestFailure(
+ "unexpected EOF: have read: " + i + " bytes of " + size);
+ }
+ data[i] = (byte) datum;
+ }
+ return data;
+ }
+
+ /**
+ * Read 4 bytes from <code>istream</code> and threat them to encode size
+ * of data parcel following these 4 bytes.
+ */
+ private static int getSize(InputStream istream) throws IOException {
+ byte data[] = readBytes(4, istream);
+ int data0 = (int) data[0] & 0xFF;
+ int data1 = (int) data[1] & 0xFF;
+ int data2 = (int) data[2] & 0xFF;
+ int data3 = (int) data[3] & 0xFF;
+ int sizeWord = data0 + (data1 << 8) + (data2 << 16) + (data3 << 24);
+ int size = sizeWord + 1;
+ if (size <= 0) {
+ throw new TestFailure("illegal size: " + size);
+ }
+ return size;
+ }
+
+ /**
+ * Send 4 bytes encoding actual size of the parcel just to be
+ * transfered.
+ */
+ private static void putSize(OutputStream ostream, int size)
+ throws IOException {
+
+ if (size <= 0) {
+ throw new TestFailure("illegal size: " + size);
+ }
+
+ int sizeWord = size - 1;
+ byte data[] = new byte[4];
+ data[0] = (byte) sizeWord;
+ data[1] = (byte) (sizeWord >> 8);
+ data[2] = (byte) (sizeWord >> 16);
+ data[3] = (byte) (sizeWord >> 24);
+ ostream.write(data);
+ }
+
+ /**
+ * Recieve data parcel.
+ */
+ public Parcel(InputStream istream) throws IOException {
+ int size = getSize(istream);
+ parcel = readBytes(size, istream);
+ }
+
+ /**
+ * Send <code>this</code> data parcel.
+ */
+ public void send(OutputStream ostream) throws IOException {
+ int size = parcel.length;
+ putSize(ostream, size);
+ ostream.write(parcel);
+ }
+
+ /**
+ * Check byte-to-byte equality between <code>this</code> and the
+ * <code>other</code> parcels.
+ */
+ public boolean equals(Parcel other) {
+ if (this.parcel.length != other.parcel.length) {
+ return false;
+ }
+ int size = parcel.length;
+ for (int i = 0; i < size; i++) {
+ if (this.parcel[i] != other.parcel[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Server or Client may throw this exception to report the test failure.
+ */
+ static class TestFailure extends RuntimeException {
+
+ /**
+ * Report particular <code>purpose</code> of the test failure.
+ */
+ public TestFailure(String purpose) {
+ super(purpose);
+ }
+ }
+}
--- a/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java Wed Oct 04 20:01:19 2017 +0000
@@ -105,7 +105,7 @@
channel.configureBlocking(true);
StringBuilder request = new StringBuilder();
if (!readRequest(channel, request)) {
- throw new IOException("Bad request");
+ throw new IOException("Bad request:" + request);
}
List<String> strings = asList(request.toString().split("\r\n"));
List<String> response = mapping.apply(strings);
@@ -156,6 +156,7 @@
public void close() {
log.log(INFO, "Stopping: " + getURI());
thread.interrupt();
+ close(ssc);
}
URI getURI() {
@@ -169,19 +170,21 @@
throws IOException
{
ByteBuffer buffer = ByteBuffer.allocate(512);
- int num = channel.read(buffer);
- if (num == -1) {
- return false;
+ while (channel.read(buffer) != -1) {
+ // read the complete HTTP request headers, there should be no body
+ CharBuffer decoded;
+ buffer.flip();
+ try {
+ decoded = ISO_8859_1.newDecoder().decode(buffer);
+ } catch (CharacterCodingException e) {
+ throw new UncheckedIOException(e);
+ }
+ request.append(decoded);
+ if (Pattern.compile("\r\n\r\n").matcher(request).find())
+ return true;
+ buffer.clear();
}
- CharBuffer decoded;
- buffer.flip();
- try {
- decoded = ISO_8859_1.newDecoder().decode(buffer);
- } catch (CharacterCodingException e) {
- throw new UncheckedIOException(e);
- }
- request.append(decoded);
- return Pattern.compile("\r\n\r\n").matcher(request).find();
+ return false;
}
private void writeResponse(SocketChannel channel, List<String> response)
--- a/test/jdk/java/net/httpclient/websocket/LoggingHelper.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/net/httpclient/websocket/LoggingHelper.java Wed Oct 04 20:01:19 2017 +0000
@@ -32,7 +32,7 @@
* @run main/othervm/jul=logging.properties ClassUnderTest
*/
public static void setupLogging() {
- String path = System.getProperty("test.src") + File.separator + "logging.properties";
+ String path = System.getProperty("test.src", ".") + File.separator + "logging.properties";
System.setProperty("java.util.logging.config.file", path);
}
}
--- a/test/jdk/java/util/Collection/IteratorMicroBenchmark.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/Collection/IteratorMicroBenchmark.java Wed Oct 04 20:01:19 2017 +0000
@@ -36,12 +36,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
-import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
-import java.util.Map;
import java.util.PriorityQueue;
import java.util.Spliterator;
import java.util.Vector;
@@ -52,7 +50,6 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.PriorityBlockingQueue;
-import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
--- a/test/jdk/java/util/Collection/RemoveMicroBenchmark.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/Collection/RemoveMicroBenchmark.java Wed Oct 04 20:01:19 2017 +0000
@@ -29,20 +29,16 @@
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
-import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
-import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
-import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
-import java.util.Spliterator;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
--- a/test/jdk/java/util/Collection/testlibrary/CollectionAsserts.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/Collection/testlibrary/CollectionAsserts.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
--- a/test/jdk/java/util/Collection/testlibrary/ExtendsAbstractCollection.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/Collection/testlibrary/ExtendsAbstractCollection.java Wed Oct 04 20:01:19 2017 +0000
@@ -21,8 +21,6 @@
* questions.
*/
import java.util.AbstractCollection;
-import java.util.HashSet;
-import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
--- a/test/jdk/java/util/List/ListDefaults.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/List/ListDefaults.java Wed Oct 04 20:01:19 2017 +0000
@@ -42,12 +42,10 @@
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
-import java.lang.reflect.Constructor;
import java.util.ConcurrentModificationException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
-import java.util.function.Supplier;
/**
* @test
--- a/test/jdk/java/util/concurrent/CompletableFuture/Basic.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/CompletableFuture/Basic.java Wed Oct 04 20:01:19 2017 +0000
@@ -74,7 +74,7 @@
check(!cf.isCompletedExceptionally(), "Expected isCompletedExceptionally to return false");
check(!cf.isCancelled(), "Expected isCancelled to be false");
check(!cf.cancel(true), "Expected cancel to return false");
- check(cf.toString().contains("[Completed normally]"));
+ check(cf.toString().matches(".*\\[.*Completed normally.*\\]"));
check(cf.complete(null) == false, "Expected complete() to fail");
check(cf.completeExceptionally(new Throwable()) == false,
"Expected completeExceptionally() to fail");
@@ -106,7 +106,7 @@
check(cf.isCompletedExceptionally(), "Expected isCompletedExceptionally");
check(cf.isCancelled() == cancelled, "Expected isCancelled: " + cancelled + ", got:" + cf.isCancelled());
check(cf.cancel(true) == cancelled, "Expected cancel: " + cancelled + ", got:" + cf.cancel(true));
- check(cf.toString().contains("[Completed exceptionally]")); // ## TODO: 'E'xceptionally
+ check(cf.toString().matches(".*\\[.*Completed exceptionally.*\\]")); // ## TODO: 'E'xceptionally
check(cf.complete((T)new Object()) == false, "Expected complete() to fail");
check(cf.completeExceptionally(new Throwable()) == false,
"Expected completeExceptionally() to fail, already completed");
--- a/test/jdk/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java Wed Oct 04 20:01:19 2017 +0000
@@ -43,7 +43,6 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
@@ -55,26 +54,18 @@
extends ConcurrentHashMap<Class<?>, Integer> {
void inc(Class<?> key) {
- for (;;) {
- Integer i = get(key);
- if (i == null) {
- if (putIfAbsent(key, 1) == null)
- return;
- } else {
- if (replace(key, i, i + 1))
- return;
- }
- }
+ compute(key, (k, v) -> (v == null) ? 1 : v + 1);
}
}
+ /** Double-check that HashTable and ConcurrentHashMap are work-alikes. */
@SuppressWarnings("serial")
static class UncaughtExceptionsTable
extends Hashtable<Class<?>, Integer> {
synchronized void inc(Class<?> key) {
- Integer i = get(key);
- put(key, (i == null) ? 1 : i + 1);
+ Integer v = get(key);
+ put(key, (v == null) ? 1 : v + 1);
}
}
@@ -82,37 +73,20 @@
= new UncaughtExceptions();
static final UncaughtExceptionsTable uncaughtExceptionsTable
= new UncaughtExceptionsTable();
- static final AtomicLong totalUncaughtExceptions
- = new AtomicLong(0);
+ static final AtomicInteger totalUncaughtExceptions
+ = new AtomicInteger(0);
static final CountDownLatch uncaughtExceptionsLatch
= new CountDownLatch(24);
- static final Thread.UncaughtExceptionHandler handler
- = new Thread.UncaughtExceptionHandler() {
- public void uncaughtException(Thread t, Throwable e) {
- check(! Thread.currentThread().isInterrupted());
- totalUncaughtExceptions.getAndIncrement();
- uncaughtExceptions.inc(e.getClass());
- uncaughtExceptionsTable.inc(e.getClass());
- uncaughtExceptionsLatch.countDown();
- }};
-
static final ThreadGroup tg = new ThreadGroup("Flaky");
- static final ThreadFactory tf = new ThreadFactory() {
- public Thread newThread(Runnable r) {
- Thread t = new Thread(tg, r);
- t.setUncaughtExceptionHandler(handler);
- return t;
- }};
-
static final RuntimeException rte = new RuntimeException();
static final Error error = new Error();
static final Throwable weird = new Throwable();
static final Exception checkedException = new Exception();
static class Thrower implements Runnable {
- Throwable t;
+ final Throwable t;
Thrower(Throwable t) { this.t = t; }
public void run() {
if (t != null)
@@ -120,14 +94,12 @@
}
}
- static final Thrower noThrower = new Thrower(null);
- static final Thrower rteThrower = new Thrower(rte);
- static final Thrower errorThrower = new Thrower(error);
- static final Thrower weirdThrower = new Thrower(weird);
- static final Thrower checkedThrower = new Thrower(checkedException);
-
static final List<Thrower> throwers = Arrays.asList(
- noThrower, rteThrower, errorThrower, weirdThrower, checkedThrower);
+ new Thrower(null),
+ new Thrower(rte),
+ new Thrower(error),
+ new Thrower(weird),
+ new Thrower(checkedException));
static class Flaky implements Runnable {
final Runnable beforeExecute;
@@ -190,7 +162,18 @@
super(10, 10,
1L, TimeUnit.HOURS,
new LinkedBlockingQueue<Runnable>(),
- tf);
+ (ThreadFactory) (runnable) -> {
+ Thread thread = new Thread(tg, runnable);
+ Thread.UncaughtExceptionHandler handler = (t, e) -> {
+ check(! t.isInterrupted());
+ totalUncaughtExceptions.getAndIncrement();
+ uncaughtExceptions.inc(e.getClass());
+ uncaughtExceptionsTable.inc(e.getClass());
+ uncaughtExceptionsLatch.countDown();
+ };
+ thread.setUncaughtExceptionHandler(handler);
+ return thread;
+ });
}
@Override protected void beforeExecute(Thread t, Runnable r) {
final boolean lessThanCorePoolSize;
@@ -262,19 +245,17 @@
check(tpe.awaitTermination(10L, TimeUnit.MINUTES));
checkTerminated(tpe);
- //while (tg.activeCount() > 0) Thread.sleep(10);
- //System.out.println(uncaughtExceptions);
List<Map<Class<?>, Integer>> maps = new ArrayList<>();
maps.add(uncaughtExceptions);
maps.add(uncaughtExceptionsTable);
for (Map<Class<?>, Integer> map : maps) {
- equal(map.get(Exception.class), throwers.size());
- equal(map.get(weird.getClass()), throwers.size());
- equal(map.get(Error.class), throwers.size() + 1 + 2);
+ equal(map.get(Exception.class), throwers.size() + 1);
+ equal(map.get(weird.getClass()), throwers.size() + 1);
+ equal(map.get(Error.class), throwers.size() + 1);
equal(map.get(RuntimeException.class), throwers.size() + 1);
equal(map.size(), 4);
}
- equal(totalUncaughtExceptions.get(), 4L*throwers.size() + 4L);
+ equal(totalUncaughtExceptions.get(), 4*throwers.size() + 4);
equal(beforeExecuteCount.get(), flakes.size());
equal(afterExecuteCount.get(), throwers.size());
--- a/test/jdk/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -58,6 +58,9 @@
/**
* A simple mutex class, adapted from the class javadoc. Exclusive
* acquire tests exercise this as a sample user extension.
+ *
+ * Unlike the javadoc sample, we don't track owner thread via
+ * AbstractOwnableSynchronizer methods.
*/
static class Mutex extends AbstractQueuedLongSynchronizer {
/** An eccentric value > 32 bits for locked synchronizer state. */
@@ -65,18 +68,19 @@
static final long UNLOCKED = 0;
- public boolean isHeldExclusively() {
+ /** Owner thread is untracked, so this is really just isLocked(). */
+ @Override public boolean isHeldExclusively() {
long state = getState();
assertTrue(state == UNLOCKED || state == LOCKED);
return state == LOCKED;
}
- public boolean tryAcquire(long acquires) {
+ @Override protected boolean tryAcquire(long acquires) {
assertEquals(LOCKED, acquires);
return compareAndSetState(UNLOCKED, LOCKED);
}
- public boolean tryRelease(long releases) {
+ @Override protected boolean tryRelease(long releases) {
if (getState() != LOCKED) throw new IllegalMonitorStateException();
setState(UNLOCKED);
return true;
@@ -106,13 +110,14 @@
release(LOCKED);
}
+ /** Faux-Implements Lock.newCondition(). */
public ConditionObject newCondition() {
return new ConditionObject();
}
}
/**
- * A simple latch class, to test shared mode.
+ * A minimal latch class, to test shared mode.
*/
static class BooleanLatch extends AbstractQueuedLongSynchronizer {
public boolean isSignalled() { return getState() != 0; }
--- a/test/jdk/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -61,6 +61,9 @@
* methods/features of AbstractQueuedSynchronizer are tested via
* other test classes, including those for ReentrantLock,
* ReentrantReadWriteLock, and Semaphore.
+ *
+ * Unlike the javadoc sample, we don't track owner thread via
+ * AbstractOwnableSynchronizer methods.
*/
static class Mutex extends AbstractQueuedSynchronizer {
/** An eccentric value for locked synchronizer state. */
@@ -68,18 +71,19 @@
static final int UNLOCKED = 0;
+ /** Owner thread is untracked, so this is really just isLocked(). */
@Override public boolean isHeldExclusively() {
int state = getState();
assertTrue(state == UNLOCKED || state == LOCKED);
return state == LOCKED;
}
- @Override public boolean tryAcquire(int acquires) {
+ @Override protected boolean tryAcquire(int acquires) {
assertEquals(LOCKED, acquires);
return compareAndSetState(UNLOCKED, LOCKED);
}
- @Override public boolean tryRelease(int releases) {
+ @Override protected boolean tryRelease(int releases) {
if (getState() != LOCKED) throw new IllegalMonitorStateException();
assertEquals(LOCKED, releases);
setState(UNLOCKED);
@@ -110,13 +114,14 @@
release(LOCKED);
}
+ /** Faux-Implements Lock.newCondition(). */
public ConditionObject newCondition() {
return new ConditionObject();
}
}
/**
- * A simple latch class, to test shared mode.
+ * A minimal latch class, to test shared mode.
*/
static class BooleanLatch extends AbstractQueuedSynchronizer {
public boolean isSignalled() { return getState() != 0; }
--- a/test/jdk/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -51,57 +51,6 @@
return new TestSuite(AtomicIntegerFieldUpdaterTest.class);
}
- // for testing subclass access
- static class AtomicIntegerFieldUpdaterTestSubclass extends AtomicIntegerFieldUpdaterTest {
- public void checkPrivateAccess() {
- try {
- AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
- AtomicIntegerFieldUpdater.newUpdater
- (AtomicIntegerFieldUpdaterTest.class, "privateField");
- shouldThrow();
- } catch (RuntimeException success) {
- assertNotNull(success.getCause());
- }
- }
-
- public void checkCompareAndSetProtectedSub() {
- AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
- AtomicIntegerFieldUpdater.newUpdater
- (AtomicIntegerFieldUpdaterTest.class, "protectedField");
- this.protectedField = 1;
- assertTrue(a.compareAndSet(this, 1, 2));
- assertTrue(a.compareAndSet(this, 2, -4));
- assertEquals(-4, a.get(this));
- assertFalse(a.compareAndSet(this, -5, 7));
- assertEquals(-4, a.get(this));
- assertTrue(a.compareAndSet(this, -4, 7));
- assertEquals(7, a.get(this));
- }
- }
-
- static class UnrelatedClass {
- public void checkPackageAccess(AtomicIntegerFieldUpdaterTest obj) {
- obj.x = 72;
- AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
- AtomicIntegerFieldUpdater.newUpdater
- (AtomicIntegerFieldUpdaterTest.class, "x");
- assertEquals(72, a.get(obj));
- assertTrue(a.compareAndSet(obj, 72, 73));
- assertEquals(73, a.get(obj));
- }
-
- public void checkPrivateAccess(AtomicIntegerFieldUpdaterTest obj) {
- try {
- AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
- AtomicIntegerFieldUpdater.newUpdater
- (AtomicIntegerFieldUpdaterTest.class, "privateField");
- throw new AssertionError("should throw");
- } catch (RuntimeException success) {
- assertNotNull(success.getCause());
- }
- }
- }
-
AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> updaterFor(String fieldName) {
return AtomicIntegerFieldUpdater.newUpdater
(AtomicIntegerFieldUpdaterTest.class, fieldName);
@@ -143,9 +92,8 @@
* construction using private field from subclass throws RuntimeException
*/
public void testPrivateFieldInSubclass() {
- AtomicIntegerFieldUpdaterTestSubclass s =
- new AtomicIntegerFieldUpdaterTestSubclass();
- s.checkPrivateAccess();
+ new NonNestmates.AtomicIntegerFieldUpdaterTestSubclass()
+ .checkPrivateAccess();
}
/**
@@ -153,8 +101,8 @@
* private access is not
*/
public void testUnrelatedClassAccess() {
- new UnrelatedClass().checkPackageAccess(this);
- new UnrelatedClass().checkPrivateAccess(this);
+ new NonNestmates().checkPackageAccess(this);
+ new NonNestmates().checkPrivateAccess(this);
}
/**
@@ -223,9 +171,8 @@
* equal to expected else fails
*/
public void testCompareAndSetProtectedInSubclass() {
- AtomicIntegerFieldUpdaterTestSubclass s =
- new AtomicIntegerFieldUpdaterTestSubclass();
- s.checkCompareAndSetProtectedSub();
+ new NonNestmates.AtomicIntegerFieldUpdaterTestSubclass()
+ .checkCompareAndSetProtectedSub();
}
/**
--- a/test/jdk/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -51,57 +51,6 @@
return new TestSuite(AtomicLongFieldUpdaterTest.class);
}
- // for testing subclass access
- static class AtomicLongFieldUpdaterTestSubclass extends AtomicLongFieldUpdaterTest {
- public void checkPrivateAccess() {
- try {
- AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
- AtomicLongFieldUpdater.newUpdater
- (AtomicLongFieldUpdaterTest.class, "privateField");
- shouldThrow();
- } catch (RuntimeException success) {
- assertNotNull(success.getCause());
- }
- }
-
- public void checkCompareAndSetProtectedSub() {
- AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
- AtomicLongFieldUpdater.newUpdater
- (AtomicLongFieldUpdaterTest.class, "protectedField");
- this.protectedField = 1;
- assertTrue(a.compareAndSet(this, 1, 2));
- assertTrue(a.compareAndSet(this, 2, -4));
- assertEquals(-4, a.get(this));
- assertFalse(a.compareAndSet(this, -5, 7));
- assertEquals(-4, a.get(this));
- assertTrue(a.compareAndSet(this, -4, 7));
- assertEquals(7, a.get(this));
- }
- }
-
- static class UnrelatedClass {
- public void checkPackageAccess(AtomicLongFieldUpdaterTest obj) {
- obj.x = 72L;
- AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
- AtomicLongFieldUpdater.newUpdater
- (AtomicLongFieldUpdaterTest.class, "x");
- assertEquals(72L, a.get(obj));
- assertTrue(a.compareAndSet(obj, 72L, 73L));
- assertEquals(73L, a.get(obj));
- }
-
- public void checkPrivateAccess(AtomicLongFieldUpdaterTest obj) {
- try {
- AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
- AtomicLongFieldUpdater.newUpdater
- (AtomicLongFieldUpdaterTest.class, "privateField");
- throw new AssertionError("should throw");
- } catch (RuntimeException success) {
- assertNotNull(success.getCause());
- }
- }
- }
-
AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> updaterFor(String fieldName) {
return AtomicLongFieldUpdater.newUpdater
(AtomicLongFieldUpdaterTest.class, fieldName);
@@ -143,9 +92,8 @@
* construction using private field from subclass throws RuntimeException
*/
public void testPrivateFieldInSubclass() {
- AtomicLongFieldUpdaterTestSubclass s =
- new AtomicLongFieldUpdaterTestSubclass();
- s.checkPrivateAccess();
+ new NonNestmates.AtomicLongFieldUpdaterTestSubclass()
+ .checkPrivateAccess();
}
/**
@@ -153,8 +101,8 @@
* private access is not
*/
public void testUnrelatedClassAccess() {
- new UnrelatedClass().checkPackageAccess(this);
- new UnrelatedClass().checkPrivateAccess(this);
+ new NonNestmates().checkPackageAccess(this);
+ new NonNestmates().checkPrivateAccess(this);
}
/**
@@ -223,9 +171,8 @@
* equal to expected else fails
*/
public void testCompareAndSetProtectedInSubclass() {
- AtomicLongFieldUpdaterTestSubclass s =
- new AtomicLongFieldUpdaterTestSubclass();
- s.checkCompareAndSetProtectedSub();
+ new NonNestmates.AtomicLongFieldUpdaterTestSubclass()
+ .checkCompareAndSetProtectedSub();
}
/**
--- a/test/jdk/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -53,57 +53,6 @@
return new TestSuite(AtomicReferenceFieldUpdaterTest.class);
}
- // for testing subclass access
- static class AtomicReferenceFieldUpdaterTestSubclass extends AtomicReferenceFieldUpdaterTest {
- public void checkPrivateAccess() {
- try {
- AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
- AtomicReferenceFieldUpdater.newUpdater
- (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField");
- shouldThrow();
- } catch (RuntimeException success) {
- assertNotNull(success.getCause());
- }
- }
-
- public void checkCompareAndSetProtectedSub() {
- AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
- AtomicReferenceFieldUpdater.newUpdater
- (AtomicReferenceFieldUpdaterTest.class, Integer.class, "protectedField");
- this.protectedField = one;
- assertTrue(a.compareAndSet(this, one, two));
- assertTrue(a.compareAndSet(this, two, m4));
- assertSame(m4, a.get(this));
- assertFalse(a.compareAndSet(this, m5, seven));
- assertNotSame(seven, a.get(this));
- assertTrue(a.compareAndSet(this, m4, seven));
- assertSame(seven, a.get(this));
- }
- }
-
- static class UnrelatedClass {
- public void checkPackageAccess(AtomicReferenceFieldUpdaterTest obj) {
- obj.x = one;
- AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
- AtomicReferenceFieldUpdater.newUpdater
- (AtomicReferenceFieldUpdaterTest.class, Integer.class, "x");
- assertSame(one, a.get(obj));
- assertTrue(a.compareAndSet(obj, one, two));
- assertSame(two, a.get(obj));
- }
-
- public void checkPrivateAccess(AtomicReferenceFieldUpdaterTest obj) {
- try {
- AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
- AtomicReferenceFieldUpdater.newUpdater
- (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField");
- throw new AssertionError("should throw");
- } catch (RuntimeException success) {
- assertNotNull(success.getCause());
- }
- }
- }
-
static AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> updaterFor(String fieldName) {
return AtomicReferenceFieldUpdater.newUpdater
(AtomicReferenceFieldUpdaterTest.class, Integer.class, fieldName);
@@ -155,9 +104,8 @@
* construction using private field from subclass throws RuntimeException
*/
public void testPrivateFieldInSubclass() {
- AtomicReferenceFieldUpdaterTestSubclass s =
- new AtomicReferenceFieldUpdaterTestSubclass();
- s.checkPrivateAccess();
+ new NonNestmates.AtomicReferenceFieldUpdaterTestSubclass()
+ .checkPrivateAccess();
}
/**
@@ -165,8 +113,8 @@
* private access is not
*/
public void testUnrelatedClassAccess() {
- new UnrelatedClass().checkPackageAccess(this);
- new UnrelatedClass().checkPrivateAccess(this);
+ new NonNestmates().checkPackageAccess(this);
+ new NonNestmates().checkPrivateAccess(this);
}
/**
@@ -198,7 +146,7 @@
}
/**
- * compareAndSet succeeds in changing value if equal to expected else fails
+ * compareAndSet succeeds in changing value if same as expected else fails
*/
public void testCompareAndSet() {
AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
@@ -214,6 +162,15 @@
}
/**
+ * compareAndSet succeeds in changing protected field value if
+ * same as expected else fails
+ */
+ public void testCompareAndSetProtectedInSubclass() {
+ new NonNestmates.AtomicReferenceFieldUpdaterTestSubclass()
+ .checkCompareAndSetProtectedSub();
+ }
+
+ /**
* compareAndSet in one thread enables another waiting for value
* to succeed
*/
@@ -236,8 +193,7 @@
}
/**
- * repeated weakCompareAndSet succeeds in changing value when equal
- * to expected
+ * repeated weakCompareAndSet succeeds in changing value when same as expected
*/
public void testWeakCompareAndSet() {
AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
--- a/test/jdk/java/util/concurrent/tck/Collection8Test.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/Collection8Test.java Wed Oct 04 20:01:19 2017 +0000
@@ -86,9 +86,9 @@
Object bomb() {
return new Object() {
- public boolean equals(Object x) { throw new AssertionError(); }
- public int hashCode() { throw new AssertionError(); }
- };
+ public boolean equals(Object x) { throw new AssertionError(); }
+ public int hashCode() { throw new AssertionError(); }
+ };
}
/** Checks properties of empty collections. */
--- a/test/jdk/java/util/concurrent/tck/CompletableFutureTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/CompletableFutureTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -86,7 +86,7 @@
void checkIncomplete(CompletableFuture<?> f) {
assertFalse(f.isDone());
assertFalse(f.isCancelled());
- assertTrue(f.toString().contains("Not completed"));
+ assertTrue(f.toString().matches(".*\\[.*Not completed.*\\]"));
try {
assertNull(f.getNow(null));
} catch (Throwable fail) { threadUnexpectedException(fail); }
@@ -109,7 +109,7 @@
assertTrue(f.isDone());
assertFalse(f.isCancelled());
assertFalse(f.isCompletedExceptionally());
- assertTrue(f.toString().contains("[Completed normally]"));
+ assertTrue(f.toString().matches(".*\\[.*Completed normally.*\\]"));
}
/**
@@ -165,7 +165,7 @@
assertFalse(f.isCancelled());
assertTrue(f.isDone());
assertTrue(f.isCompletedExceptionally());
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
}
void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
@@ -220,7 +220,7 @@
assertTrue(f.isDone());
assertTrue(f.isCompletedExceptionally());
assertTrue(f.isCancelled());
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
}
/**
@@ -356,23 +356,40 @@
/**
* toString indicates current completion state
*/
- public void testToString() {
- CompletableFuture<String> f;
-
- f = new CompletableFuture<String>();
- assertTrue(f.toString().contains("[Not completed]"));
-
+ public void testToString_incomplete() {
+ CompletableFuture<String> f = new CompletableFuture<String>();
+ assertTrue(f.toString().matches(".*\\[.*Not completed.*\\]"));
+ if (testImplementationDetails)
+ assertEquals(identityString(f) + "[Not completed]",
+ f.toString());
+ }
+
+ public void testToString_normal() {
+ CompletableFuture<String> f = new CompletableFuture<String>();
assertTrue(f.complete("foo"));
- assertTrue(f.toString().contains("[Completed normally]"));
-
- f = new CompletableFuture<String>();
+ assertTrue(f.toString().matches(".*\\[.*Completed normally.*\\]"));
+ if (testImplementationDetails)
+ assertEquals(identityString(f) + "[Completed normally]",
+ f.toString());
+ }
+
+ public void testToString_exception() {
+ CompletableFuture<String> f = new CompletableFuture<String>();
assertTrue(f.completeExceptionally(new IndexOutOfBoundsException()));
- assertTrue(f.toString().contains("[Completed exceptionally]"));
-
+ assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
+ if (testImplementationDetails)
+ assertTrue(f.toString().startsWith(
+ identityString(f) + "[Completed exceptionally: "));
+ }
+
+ public void testToString_cancelled() {
for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
- f = new CompletableFuture<String>();
+ CompletableFuture<String> f = new CompletableFuture<String>();
assertTrue(f.cancel(mayInterruptIfRunning));
- assertTrue(f.toString().contains("[Completed exceptionally]"));
+ assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
+ if (testImplementationDetails)
+ assertTrue(f.toString().startsWith(
+ identityString(f) + "[Completed exceptionally: "));
}
}
--- a/test/jdk/java/util/concurrent/tck/ConcurrentHashMapTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/ConcurrentHashMapTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -26,8 +26,9 @@
* However, the following notice accompanied the original version of this
* file:
*
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
* Other contributors include Andrew Wright, Jeffrey Hayes,
* Pat Fisher, Mike Judd.
@@ -45,14 +46,25 @@
import java.util.concurrent.ConcurrentHashMap;
import junit.framework.Test;
-import junit.framework.TestSuite;
public class ConcurrentHashMapTest extends JSR166TestCase {
public static void main(String[] args) {
main(suite(), args);
}
public static Test suite() {
- return new TestSuite(ConcurrentHashMapTest.class);
+ class Implementation implements MapImplementation {
+ public Class<?> klazz() { return ConcurrentHashMap.class; }
+ public Map emptyMap() { return new ConcurrentHashMap(); }
+ public Object makeKey(int i) { return i; }
+ public Object makeValue(int i) { return i; }
+ public boolean isConcurrent() { return true; }
+ public boolean permitsNullKeys() { return false; }
+ public boolean permitsNullValues() { return false; }
+ public boolean supportsSetValue() { return true; }
+ }
+ return newTestSuite(
+ ConcurrentHashMapTest.class,
+ MapTest.testSuite(new Implementation()));
}
/**
--- a/test/jdk/java/util/concurrent/tck/ConcurrentSkipListMapTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/ConcurrentSkipListMapTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -45,14 +45,25 @@
import java.util.concurrent.ConcurrentSkipListMap;
import junit.framework.Test;
-import junit.framework.TestSuite;
public class ConcurrentSkipListMapTest extends JSR166TestCase {
public static void main(String[] args) {
main(suite(), args);
}
public static Test suite() {
- return new TestSuite(ConcurrentSkipListMapTest.class);
+ class Implementation implements MapImplementation {
+ public Class<?> klazz() { return ConcurrentSkipListMap.class; }
+ public Map emptyMap() { return new ConcurrentSkipListMap(); }
+ public Object makeKey(int i) { return i; }
+ public Object makeValue(int i) { return i; }
+ public boolean isConcurrent() { return true; }
+ public boolean permitsNullKeys() { return false; }
+ public boolean permitsNullValues() { return false; }
+ public boolean supportsSetValue() { return false; }
+ }
+ return newTestSuite(
+ ConcurrentSkipListMapTest.class,
+ MapTest.testSuite(new Implementation()));
}
/**
--- a/test/jdk/java/util/concurrent/tck/ExecutorsTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/ExecutorsTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -613,4 +613,56 @@
} catch (NullPointerException success) {}
}
+ /**
+ * callable(runnable, x).toString() contains toString of wrapped task
+ */
+ public void testCallable_withResult_toString() {
+ if (testImplementationDetails) {
+ Runnable r = () -> {};
+ Callable<String> c = Executors.callable(r, "");
+ assertEquals(
+ identityString(c) + "[Wrapped task = " + r.toString() + "]",
+ c.toString());
+ }
+ }
+
+ /**
+ * callable(runnable).toString() contains toString of wrapped task
+ */
+ public void testCallable_toString() {
+ if (testImplementationDetails) {
+ Runnable r = () -> {};
+ Callable<Object> c = Executors.callable(r);
+ assertEquals(
+ identityString(c) + "[Wrapped task = " + r.toString() + "]",
+ c.toString());
+ }
+ }
+
+ /**
+ * privilegedCallable(callable).toString() contains toString of wrapped task
+ */
+ public void testPrivilegedCallable_toString() {
+ if (testImplementationDetails) {
+ Callable<String> c = () -> "";
+ Callable<String> priv = Executors.privilegedCallable(c);
+ assertEquals(
+ identityString(priv) + "[Wrapped task = " + c.toString() + "]",
+ priv.toString());
+ }
+ }
+
+ /**
+ * privilegedCallableUsingCurrentClassLoader(callable).toString()
+ * contains toString of wrapped task
+ */
+ public void testPrivilegedCallableUsingCurrentClassLoader_toString() {
+ if (testImplementationDetails) {
+ Callable<String> c = () -> "";
+ Callable<String> priv = Executors.privilegedCallableUsingCurrentClassLoader(c);
+ assertEquals(
+ identityString(priv) + "[Wrapped task = " + c.toString() + "]",
+ priv.toString());
+ }
+ }
}
--- a/test/jdk/java/util/concurrent/tck/ForkJoinTaskTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/ForkJoinTaskTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -35,6 +35,7 @@
import java.util.Arrays;
import java.util.HashSet;
+import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
@@ -1675,4 +1676,42 @@
testInvokeOnPool(mainPool(), a);
}
+ /**
+ * adapt(runnable).toString() contains toString of wrapped task
+ */
+ public void testAdapt_Runnable_toString() {
+ if (testImplementationDetails) {
+ Runnable r = () -> {};
+ ForkJoinTask<?> task = ForkJoinTask.adapt(r);
+ assertEquals(
+ identityString(task) + "[Wrapped task = " + r.toString() + "]",
+ task.toString());
+ }
+ }
+
+ /**
+ * adapt(runnable, x).toString() contains toString of wrapped task
+ */
+ public void testAdapt_Runnable_withResult_toString() {
+ if (testImplementationDetails) {
+ Runnable r = () -> {};
+ ForkJoinTask<String> task = ForkJoinTask.adapt(r, "");
+ assertEquals(
+ identityString(task) + "[Wrapped task = " + r.toString() + "]",
+ task.toString());
+ }
+ }
+
+ /**
+ * adapt(callable).toString() contains toString of wrapped task
+ */
+ public void testAdapt_Callable_toString() {
+ if (testImplementationDetails) {
+ Callable<String> c = () -> "";
+ ForkJoinTask<String> task = ForkJoinTask.adapt(c);
+ assertEquals(
+ identityString(task) + "[Wrapped task = " + c.toString() + "]",
+ task.toString());
+ }
+ }
}
--- a/test/jdk/java/util/concurrent/tck/FutureTaskTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/FutureTaskTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -861,4 +861,45 @@
}
}
+ /**
+ * toString indicates current completion state
+ */
+ public void testToString_incomplete() {
+ FutureTask<String> f = new FutureTask<String>(() -> "");
+ assertTrue(f.toString().matches(".*\\[.*Not completed.*\\]"));
+ if (testImplementationDetails)
+ assertTrue(f.toString().startsWith(
+ identityString(f) + "[Not completed, task ="));
+ }
+
+ public void testToString_normal() {
+ FutureTask<String> f = new FutureTask<String>(() -> "");
+ f.run();
+ assertTrue(f.toString().matches(".*\\[.*Completed normally.*\\]"));
+ if (testImplementationDetails)
+ assertEquals(identityString(f) + "[Completed normally]",
+ f.toString());
+ }
+
+ public void testToString_exception() {
+ FutureTask<String> f = new FutureTask<String>(
+ () -> { throw new ArithmeticException(); });
+ f.run();
+ assertTrue(f.toString().matches(".*\\[.*Completed exceptionally.*\\]"));
+ if (testImplementationDetails)
+ assertTrue(f.toString().startsWith(
+ identityString(f) + "[Completed exceptionally: "));
+ }
+
+ public void testToString_cancelled() {
+ for (boolean mayInterruptIfRunning : new boolean[] { true, false }) {
+ FutureTask<String> f = new FutureTask<String>(() -> "");
+ assertTrue(f.cancel(mayInterruptIfRunning));
+ assertTrue(f.toString().matches(".*\\[.*Cancelled.*\\]"));
+ if (testImplementationDetails)
+ assertEquals(identityString(f) + "[Cancelled]",
+ f.toString());
+ }
+ }
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/concurrent/tck/HashMapTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Test;
+
+public class HashMapTest extends JSR166TestCase {
+ public static void main(String[] args) {
+ main(suite(), args);
+ }
+
+ public static Test suite() {
+ class Implementation implements MapImplementation {
+ public Class<?> klazz() { return HashMap.class; }
+ public Map emptyMap() { return new HashMap(); }
+ public Object makeKey(int i) { return i; }
+ public Object makeValue(int i) { return i; }
+ public boolean isConcurrent() { return false; }
+ public boolean permitsNullKeys() { return true; }
+ public boolean permitsNullValues() { return true; }
+ public boolean supportsSetValue() { return true; }
+ }
+ return newTestSuite(
+ // HashMapTest.class,
+ MapTest.testSuite(new Implementation()));
+ }
+}
--- a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java Wed Oct 04 20:01:19 2017 +0000
@@ -571,6 +571,7 @@
"DoubleAdderTest",
"ForkJoinPool8Test",
"ForkJoinTask8Test",
+ "HashMapTest",
"LinkedBlockingDeque8Test",
"LinkedBlockingQueue8Test",
"LongAccumulatorTest",
@@ -1940,6 +1941,18 @@
Collections.shuffle(Arrays.asList(array), ThreadLocalRandom.current());
}
+ /**
+ * Returns the same String as would be returned by {@link
+ * Object#toString}, whether or not the given object's class
+ * overrides toString().
+ *
+ * @see System#identityHashCode
+ */
+ static String identityString(Object x) {
+ return x.getClass().getName()
+ + "@" + Integer.toHexString(System.identityHashCode(x));
+ }
+
// --- Shared assertions for Executor tests ---
/**
--- a/test/jdk/java/util/concurrent/tck/LinkedTransferQueueTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/LinkedTransferQueueTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -801,7 +801,7 @@
}
/**
- * transfer waits until a poll occurs. The transfered element
+ * transfer waits until a poll occurs. The transferred element
* is returned by the associated poll.
*/
public void testTransfer2() throws InterruptedException {
@@ -882,7 +882,7 @@
}
/**
- * transfer waits until a take occurs. The transfered element
+ * transfer waits until a take occurs. The transferred element
* is returned by the associated take.
*/
public void testTransfer5() throws InterruptedException {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/concurrent/tck/MapImplementation.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.Map;
+
+/** Allows tests to work with different Map implementations. */
+public interface MapImplementation {
+ /** Returns the Map implementation class. */
+ public Class<?> klazz();
+ /** Returns an empty map. */
+ public Map emptyMap();
+ public Object makeKey(int i);
+ public Object makeValue(int i);
+ public boolean isConcurrent();
+ public boolean permitsNullKeys();
+ public boolean permitsNullValues();
+ public boolean supportsSetValue();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/concurrent/tck/MapTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import junit.framework.Test;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * Contains tests applicable to all Map implementations.
+ */
+public class MapTest extends JSR166TestCase {
+ final MapImplementation impl;
+
+ /** Tests are parameterized by a Map implementation. */
+ MapTest(MapImplementation impl, String methodName) {
+ super(methodName);
+ this.impl = impl;
+ }
+
+ public static Test testSuite(MapImplementation impl) {
+ return newTestSuite(
+ parameterizedTestSuite(MapTest.class,
+ MapImplementation.class,
+ impl));
+ }
+
+ public void testImplSanity() {
+ final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ {
+ Map m = impl.emptyMap();
+ assertTrue(m.isEmpty());
+ assertEquals(0, m.size());
+ Object k = impl.makeKey(rnd.nextInt());
+ Object v = impl.makeValue(rnd.nextInt());
+ m.put(k, v);
+ assertFalse(m.isEmpty());
+ assertEquals(1, m.size());
+ assertTrue(m.containsKey(k));
+ assertTrue(m.containsValue(v));
+ }
+ {
+ Map m = impl.emptyMap();
+ Object v = impl.makeValue(rnd.nextInt());
+ if (impl.permitsNullKeys()) {
+ m.put(null, v);
+ assertTrue(m.containsKey(null));
+ assertTrue(m.containsValue(v));
+ } else {
+ assertThrows(NullPointerException.class, () -> m.put(null, v));
+ }
+ }
+ {
+ Map m = impl.emptyMap();
+ Object k = impl.makeKey(rnd.nextInt());
+ if (impl.permitsNullValues()) {
+ m.put(k, null);
+ assertTrue(m.containsKey(k));
+ assertTrue(m.containsValue(null));
+ } else {
+ assertThrows(NullPointerException.class, () -> m.put(k, null));
+ }
+ }
+ {
+ Map m = impl.emptyMap();
+ Object k = impl.makeKey(rnd.nextInt());
+ Object v1 = impl.makeValue(rnd.nextInt());
+ Object v2 = impl.makeValue(rnd.nextInt());
+ m.put(k, v1);
+ if (impl.supportsSetValue()) {
+ ((Map.Entry)(m.entrySet().iterator().next())).setValue(v2);
+ assertSame(v2, m.get(k));
+ assertTrue(m.containsKey(k));
+ assertTrue(m.containsValue(v2));
+ assertFalse(m.containsValue(v1));
+ } else {
+ assertThrows(UnsupportedOperationException.class,
+ () -> ((Map.Entry)(m.entrySet().iterator().next())).setValue(v2));
+ }
+ }
+ }
+
+ /**
+ * Tests and extends the scenario reported in
+ * https://bugs.openjdk.java.net/browse/JDK-8186171
+ * HashMap: Entry.setValue may not work after Iterator.remove() called for previous entries
+ * ant -Djsr166.tckTestClass=HashMapTest -Djsr166.methodFilter=testBug8186171 -Djsr166.runsPerTest=1000 tck
+ */
+ public void testBug8186171() {
+ if (!impl.supportsSetValue()) return;
+ final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ final boolean permitsNullValues = impl.permitsNullValues();
+ final Object v1 = (permitsNullValues && rnd.nextBoolean())
+ ? null : impl.makeValue(1);
+ final Object v2 = (permitsNullValues && rnd.nextBoolean() && v1 != null)
+ ? null : impl.makeValue(2);
+
+ /** If true, always lands in first bucket in hash tables. */
+ final boolean poorHash = rnd.nextBoolean();
+ class Key implements Comparable<Key> {
+ final int i;
+ Key(int i) { this.i = i; }
+ public int hashCode() { return poorHash ? 0 : super.hashCode(); }
+ public int compareTo(Key x) {
+ return Integer.compare(this.i, x.i);
+ }
+ }
+
+ // Both HashMap and ConcurrentHashMap have:
+ // TREEIFY_THRESHOLD = 8; UNTREEIFY_THRESHOLD = 6;
+ final int size = rnd.nextInt(1, 25);
+
+ List<Key> keys = new ArrayList<>();
+ for (int i = size; i-->0; ) keys.add(new Key(i));
+ Key keyToFrob = keys.get(rnd.nextInt(keys.size()));
+
+ Map<Key, Object> m = impl.emptyMap();
+ for (Key key : keys) m.put(key, v1);
+
+ for (Iterator<Map.Entry<Key, Object>> it = m.entrySet().iterator();
+ it.hasNext(); ) {
+ Map.Entry<Key, Object> entry = it.next();
+ if (entry.getKey() == keyToFrob)
+ entry.setValue(v2); // does this have the expected effect?
+ else
+ it.remove();
+ }
+
+ assertFalse(m.containsValue(v1));
+ assertTrue(m.containsValue(v2));
+ assertTrue(m.containsKey(keyToFrob));
+ assertEquals(1, m.size());
+ }
+
+// public void testFailsIntentionallyForDebugging() {
+// fail(impl.klazz().getSimpleName());
+// }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/concurrent/tck/NonNestmates.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * Other contributors include Andrew Wright, Jeffrey Hayes,
+ * Pat Fisher, Mike Judd.
+ */
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+/**
+ * This source file contains test code deliberately not contained in
+ * the same source file as the tests that use them, to avoid making
+ * them nestmates, which affects accessibility rules (see JEP 181).
+ */
+class NonNestmates {
+
+ public void checkPackageAccess(AtomicIntegerFieldUpdaterTest obj) {
+ obj.x = 72;
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
+ AtomicIntegerFieldUpdater.newUpdater(
+ AtomicIntegerFieldUpdaterTest.class, "x");
+ assertEquals(72, a.get(obj));
+ assertTrue(a.compareAndSet(obj, 72, 73));
+ assertEquals(73, a.get(obj));
+ }
+
+ public void checkPackageAccess(AtomicLongFieldUpdaterTest obj) {
+ obj.x = 72L;
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
+ AtomicLongFieldUpdater.newUpdater(
+ AtomicLongFieldUpdaterTest.class, "x");
+ assertEquals(72L, a.get(obj));
+ assertTrue(a.compareAndSet(obj, 72L, 73L));
+ assertEquals(73L, a.get(obj));
+ }
+
+ public void checkPackageAccess(AtomicReferenceFieldUpdaterTest obj) {
+ Integer one = new Integer(1);
+ Integer two = new Integer(2);
+ obj.x = one;
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
+ AtomicReferenceFieldUpdater.newUpdater(
+ AtomicReferenceFieldUpdaterTest.class, Integer.class, "x");
+ assertSame(one, a.get(obj));
+ assertTrue(a.compareAndSet(obj, one, two));
+ assertSame(two, a.get(obj));
+ }
+
+ public void checkPrivateAccess(AtomicIntegerFieldUpdaterTest obj) {
+ try {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
+ AtomicIntegerFieldUpdater.newUpdater(
+ AtomicIntegerFieldUpdaterTest.class, "privateField");
+ throw new AssertionError("should throw");
+ } catch (RuntimeException success) {
+ assertNotNull(success.getCause());
+ }
+ }
+
+ public void checkPrivateAccess(AtomicLongFieldUpdaterTest obj) {
+ try {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
+ AtomicLongFieldUpdater.newUpdater(
+ AtomicLongFieldUpdaterTest.class, "privateField");
+ throw new AssertionError("should throw");
+ } catch (RuntimeException success) {
+ assertNotNull(success.getCause());
+ }
+ }
+
+ public void checkPrivateAccess(AtomicReferenceFieldUpdaterTest obj) {
+ try {
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
+ AtomicReferenceFieldUpdater.newUpdater(
+ AtomicReferenceFieldUpdaterTest.class,
+ Integer.class, "privateField");
+ throw new AssertionError("should throw");
+ } catch (RuntimeException success) {
+ assertNotNull(success.getCause());
+ }
+ }
+
+ static class AtomicIntegerFieldUpdaterTestSubclass
+ extends AtomicIntegerFieldUpdaterTest {
+
+ public void checkPrivateAccess() {
+ try {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
+ AtomicIntegerFieldUpdater.newUpdater(
+ AtomicIntegerFieldUpdaterTest.class, "privateField");
+ shouldThrow();
+ } catch (RuntimeException success) {
+ assertNotNull(success.getCause());
+ }
+ }
+
+ public void checkCompareAndSetProtectedSub() {
+ AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> a =
+ AtomicIntegerFieldUpdater.newUpdater(
+ AtomicIntegerFieldUpdaterTest.class, "protectedField");
+ this.protectedField = 1;
+ assertTrue(a.compareAndSet(this, 1, 2));
+ assertTrue(a.compareAndSet(this, 2, -4));
+ assertEquals(-4, a.get(this));
+ assertFalse(a.compareAndSet(this, -5, 7));
+ assertEquals(-4, a.get(this));
+ assertTrue(a.compareAndSet(this, -4, 7));
+ assertEquals(7, a.get(this));
+ }
+ }
+
+ static class AtomicLongFieldUpdaterTestSubclass
+ extends AtomicLongFieldUpdaterTest {
+
+ public void checkPrivateAccess() {
+ try {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
+ AtomicLongFieldUpdater.newUpdater(
+ AtomicLongFieldUpdaterTest.class, "privateField");
+ shouldThrow();
+ } catch (RuntimeException success) {
+ assertNotNull(success.getCause());
+ }
+ }
+
+ public void checkCompareAndSetProtectedSub() {
+ AtomicLongFieldUpdater<AtomicLongFieldUpdaterTest> a =
+ AtomicLongFieldUpdater.newUpdater(
+ AtomicLongFieldUpdaterTest.class, "protectedField");
+ this.protectedField = 1;
+ assertTrue(a.compareAndSet(this, 1, 2));
+ assertTrue(a.compareAndSet(this, 2, -4));
+ assertEquals(-4, a.get(this));
+ assertFalse(a.compareAndSet(this, -5, 7));
+ assertEquals(-4, a.get(this));
+ assertTrue(a.compareAndSet(this, -4, 7));
+ assertEquals(7, a.get(this));
+ }
+ }
+
+ static class AtomicReferenceFieldUpdaterTestSubclass
+ extends AtomicReferenceFieldUpdaterTest {
+
+ public void checkPrivateAccess() {
+ try {
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
+ AtomicReferenceFieldUpdater.newUpdater(
+ AtomicReferenceFieldUpdaterTest.class,
+ Integer.class, "privateField");
+ shouldThrow();
+ } catch (RuntimeException success) {
+ assertNotNull(success.getCause());
+ }
+ }
+
+ public void checkCompareAndSetProtectedSub() {
+ AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
+ AtomicReferenceFieldUpdater.newUpdater(
+ AtomicReferenceFieldUpdaterTest.class,
+ Integer.class, "protectedField");
+ this.protectedField = one;
+ assertTrue(a.compareAndSet(this, one, two));
+ assertTrue(a.compareAndSet(this, two, m4));
+ assertSame(m4, a.get(this));
+ assertFalse(a.compareAndSet(this, m5, seven));
+ assertNotSame(seven, a.get(this));
+ assertTrue(a.compareAndSet(this, m4, seven));
+ assertSame(seven, a.get(this));
+ }
+ }
+}
--- a/test/jdk/java/util/concurrent/tck/ReentrantLockTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/ReentrantLockTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -35,11 +35,13 @@
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -173,6 +175,11 @@
enum AwaitMethod { await, awaitTimed, awaitNanos, awaitUntil }
+ static AwaitMethod randomAwaitMethod() {
+ AwaitMethod[] awaitMethods = AwaitMethod.values();
+ return awaitMethods[ThreadLocalRandom.current().nextInt(awaitMethods.length)];
+ }
+
/**
* Awaits condition "indefinitely" using the specified AwaitMethod.
*/
@@ -1160,4 +1167,60 @@
lock.unlock();
assertTrue(lock.toString().contains("Unlocked"));
}
+
+ /**
+ * Tests scenario for JDK-8187408
+ * AbstractQueuedSynchronizer wait queue corrupted when thread awaits without holding the lock
+ */
+ public void testBug8187408() throws InterruptedException {
+ final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ final AwaitMethod awaitMethod = randomAwaitMethod();
+ final int nThreads = rnd.nextInt(2, 10);
+ final ReentrantLock lock = new ReentrantLock();
+ final Condition cond = lock.newCondition();
+ final CountDownLatch done = new CountDownLatch(nThreads);
+ final ArrayList<Thread> threads = new ArrayList<>();
+
+ Runnable rogue = () -> {
+ while (done.getCount() > 0) {
+ try {
+ // call await without holding lock?!
+ await(cond, awaitMethod);
+ throw new AssertionError("should throw");
+ }
+ catch (IllegalMonitorStateException expected) {}
+ catch (Throwable fail) { threadUnexpectedException(fail); }}};
+ Thread rogueThread = new Thread(rogue, "rogue");
+ threads.add(rogueThread);
+ rogueThread.start();
+
+ Runnable waiter = () -> {
+ lock.lock();
+ try {
+ done.countDown();
+ cond.await();
+ } catch (Throwable fail) {
+ threadUnexpectedException(fail);
+ } finally {
+ lock.unlock();
+ }};
+ for (int i = 0; i < nThreads; i++) {
+ Thread thread = new Thread(waiter, "waiter");
+ threads.add(thread);
+ thread.start();
+ }
+
+ assertTrue(done.await(LONG_DELAY_MS, MILLISECONDS));
+ lock.lock();
+ try {
+ assertEquals(nThreads, lock.getWaitQueueLength(cond));
+ } finally {
+ cond.signalAll();
+ lock.unlock();
+ }
+ for (Thread thread : threads) {
+ thread.join(LONG_DELAY_MS);
+ assertFalse(thread.isAlive());
+ }
+ }
}
--- a/test/jdk/java/util/concurrent/tck/StampedLockTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/StampedLockTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -1207,4 +1207,90 @@
}
assertUnlocked(lock);
}
+
+ /**
+ * Stamped locks are not reentrant.
+ */
+ public void testNonReentrant() throws InterruptedException {
+ final StampedLock lock = new StampedLock();
+ long stamp;
+
+ stamp = lock.writeLock();
+ assertValid(lock, stamp);
+ assertEquals(0L, lock.tryWriteLock(0L, DAYS));
+ assertEquals(0L, lock.tryReadLock(0L, DAYS));
+ assertValid(lock, stamp);
+ lock.unlockWrite(stamp);
+
+ stamp = lock.tryWriteLock(1L, DAYS);
+ assertEquals(0L, lock.tryWriteLock(0L, DAYS));
+ assertValid(lock, stamp);
+ lock.unlockWrite(stamp);
+
+ stamp = lock.readLock();
+ assertEquals(0L, lock.tryWriteLock(0L, DAYS));
+ assertValid(lock, stamp);
+ lock.unlockRead(stamp);
+ }
+
+ /**
+ * """StampedLocks have no notion of ownership. Locks acquired in
+ * one thread can be released or converted in another."""
+ */
+ public void testNoOwnership() throws Throwable {
+ ArrayList<Future<?>> futures = new ArrayList<>();
+ for (Function<StampedLock, Long> writeLocker : writeLockers())
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers()) {
+ StampedLock lock = new StampedLock();
+ long stamp = writeLocker.apply(lock);
+ futures.add(cachedThreadPool.submit(new CheckedRunnable() {
+ public void realRun() {
+ writeUnlocker.accept(lock, stamp);
+ assertUnlocked(lock);
+ assertFalse(lock.validate(stamp));
+ }}));
+ }
+ for (Future<?> future : futures)
+ assertNull(future.get());
+ }
+
+ /** Tries out sample usage code from StampedLock javadoc. */
+ public void testSampleUsage() throws Throwable {
+ class Point {
+ private double x, y;
+ private final StampedLock sl = new StampedLock();
+
+ void move(double deltaX, double deltaY) { // an exclusively locked method
+ long stamp = sl.writeLock();
+ try {
+ x += deltaX;
+ y += deltaY;
+ } finally {
+ sl.unlockWrite(stamp);
+ }
+ }
+
+ double distanceFromOrigin() { // A read-only method
+ double currentX, currentY;
+ long stamp = sl.tryOptimisticRead();
+ do {
+ if (stamp == 0L)
+ stamp = sl.readLock();
+ try {
+ // possibly racy reads
+ currentX = x;
+ currentY = y;
+ } finally {
+ stamp = sl.tryConvertToOptimisticRead(stamp);
+ }
+ } while (stamp == 0);
+ return Math.hypot(currentX, currentY);
+ }
+ }
+
+ Point p = new Point();
+ p.move(3.0, 4.0);
+ assertEquals(5.0, p.distanceFromOrigin());
+ }
+
}
--- a/test/jdk/java/util/concurrent/tck/ThreadLocalRandomTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/ThreadLocalRandomTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -84,6 +84,9 @@
* possible values.
*/
public void testNext() throws ReflectiveOperationException {
+ // Inhibit "An illegal reflective access operation has occurred"
+ if (!testImplementationDetails) return;
+
ThreadLocalRandom rnd = ThreadLocalRandom.current();
final java.lang.reflect.Method m;
try {
--- a/test/jdk/java/util/concurrent/tck/TreeMapTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/util/concurrent/tck/TreeMapTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -44,14 +44,25 @@
import java.util.TreeMap;
import junit.framework.Test;
-import junit.framework.TestSuite;
public class TreeMapTest extends JSR166TestCase {
public static void main(String[] args) {
main(suite(), args);
}
public static Test suite() {
- return new TestSuite(TreeMapTest.class);
+ class Implementation implements MapImplementation {
+ public Class<?> klazz() { return TreeMap.class; }
+ public Map emptyMap() { return new TreeMap(); }
+ public Object makeKey(int i) { return i; }
+ public Object makeValue(int i) { return i; }
+ public boolean isConcurrent() { return false; }
+ public boolean permitsNullKeys() { return false; }
+ public boolean permitsNullValues() { return true; }
+ public boolean supportsSetValue() { return true; }
+ }
+ return newTestSuite(
+ TreeMapTest.class,
+ MapTest.testSuite(new Implementation()));
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2017, 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 8184328
+ * @summary JDK8u131-b34-socketRead0 hang at SSL read
+ * @run main/othervm SSLSocketCloseHang
+ */
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.security.*;
+import javax.net.ssl.*;
+
+public class SSLSocketCloseHang {
+
+ /*
+ * =============================================================
+ * Set the various variables needed for the tests, then
+ * specify what tests to run on each side.
+ */
+
+ /*
+ * Should we run the client or server in a separate thread?
+ * Both sides can throw exceptions, but do you have a preference
+ * as to which side should be the main thread.
+ */
+ static boolean separateServerThread = true;
+
+ /*
+ * Where do we find the keystores?
+ */
+ static String pathToStores = "../../../../javax/net/ssl/etc";
+ static String keyStoreFile = "keystore";
+ static String trustStoreFile = "truststore";
+ static String passwd = "passphrase";
+
+ /*
+ * Is the server ready to serve?
+ */
+ volatile static boolean serverReady = false;
+
+ /*
+ * Was the client responsible for closing the socket
+ */
+ volatile static boolean clientClosed = false;
+
+ /*
+ * Turn on SSL debugging?
+ */
+ static boolean debug = false;
+
+ /*
+ * If the client or server is doing some kind of object creation
+ * that the other side depends on, and that thread prematurely
+ * exits, you may experience a hang. The test harness will
+ * terminate all hung threads after its timeout has expired,
+ * currently 3 minutes by default, but you might try to be
+ * smart about it....
+ */
+
+ /*
+ * Define the server side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doServerSide() throws Exception {
+ SSLServerSocketFactory sslssf =
+ (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+ serverPort = sslServerSocket.getLocalPort();
+
+ /*
+ * Signal Client, we're ready for his connect.
+ */
+ serverReady = true;
+
+ SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+ sslSocket.startHandshake();
+ while (!clientClosed) {
+ Thread.sleep(500);
+ }
+ }
+
+ /*
+ * Define the client side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doClientSide() throws Exception {
+ boolean caught = false;
+
+ /*
+ * Wait for server to get started.
+ */
+ System.out.println("waiting on server");
+ while (!serverReady) {
+ Thread.sleep(50);
+ }
+ System.out.println("server ready");
+
+ Socket baseSocket = new Socket("localhost", serverPort);
+ baseSocket.setSoTimeout(100);
+
+ SSLSocketFactory sslsf =
+ (SSLSocketFactory) SSLSocketFactory.getDefault();
+ SSLSocket sslSocket = (SSLSocket)
+ sslsf.createSocket(baseSocket, "localhost", serverPort, false);
+
+ // handshaking
+ sslSocket.startHandshake();
+ System.out.println("handshake done");
+
+ Thread.sleep(500);
+ System.out.println("client closing");
+
+ sslSocket.close();
+ clientClosed = true;
+ System.out.println("client closed");
+ }
+
+ /*
+ * =============================================================
+ * The remainder is just support stuff
+ */
+
+ // use any free port by default
+ volatile int serverPort = 0;
+
+ volatile Exception serverException = null;
+ volatile Exception clientException = null;
+
+ volatile byte[] serverDigest = null;
+
+ public static void main(String[] args) throws Exception {
+ String keyFilename =
+ System.getProperty("test.src", "./") + "/" + pathToStores +
+ "/" + keyStoreFile;
+ String trustFilename =
+ System.getProperty("test.src", "./") + "/" + pathToStores +
+ "/" + trustStoreFile;
+
+ System.setProperty("javax.net.ssl.keyStore", keyFilename);
+ System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+ System.setProperty("javax.net.ssl.trustStore", trustFilename);
+ System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+ if (debug)
+ System.setProperty("javax.net.debug", "all");
+
+ /*
+ * Start the tests.
+ */
+ new SSLSocketCloseHang();
+ }
+
+ Thread clientThread = null;
+ Thread serverThread = null;
+
+ /*
+ * Primary constructor, used to drive remainder of the test.
+ *
+ * Fork off the other side, then do your work.
+ */
+ SSLSocketCloseHang() throws Exception {
+ if (separateServerThread) {
+ startServer(true);
+ startClient(false);
+ } else {
+ startClient(true);
+ startServer(false);
+ }
+
+ /*
+ * Wait for other side to close down.
+ */
+ if (separateServerThread) {
+ serverThread.join();
+ } else {
+ clientThread.join();
+ }
+
+ /*
+ * When we get here, the test is pretty much over.
+ *
+ * If the main thread excepted, that propagates back
+ * immediately. If the other thread threw an exception, we
+ * should report back.
+ */
+ if (serverException != null) {
+ System.out.print("Server Exception:");
+ throw serverException;
+ }
+ if (clientException != null) {
+ System.out.print("Client Exception:");
+ throw clientException;
+ }
+ }
+
+ void startServer(boolean newThread) throws Exception {
+ if (newThread) {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ /*
+ * Our server thread just died.
+ *
+ * Release the client, if not active already...
+ */
+ System.err.println("Server died...");
+ System.err.println(e);
+ serverReady = true;
+ serverException = e;
+ }
+ }
+ };
+ serverThread.start();
+ } else {
+ doServerSide();
+ }
+ }
+
+ void startClient(boolean newThread) throws Exception {
+ if (newThread) {
+ clientThread = new Thread() {
+ public void run() {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ /*
+ * Our client thread just died.
+ */
+ System.err.println("Client died...");
+ clientException = e;
+ }
+ }
+ };
+ clientThread.start();
+ } else {
+ doClientSide();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/tools/jarsigner/LineBrokenMultiByteCharacter.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2017, 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 6695402
+ * @summary verify signatures of jars containing classes with names
+ * with multi-byte unicode characters broken across lines
+ * @library /test/lib
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.jar.JarFile;
+import java.util.jar.Attributes.Name;
+import java.util.jar.JarEntry;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import jdk.test.lib.SecurityTools;
+import jdk.test.lib.util.JarUtils;
+
+public class LineBrokenMultiByteCharacter {
+
+ /**
+ * this name will break across lines in MANIFEST.MF at the
+ * middle of a two-byte utf-8 encoded character due to its e acute letter
+ * at its exact position.
+ *
+ * because no file with such a name exists {@link JarUtils} will add the
+ * name itself as contents to the jar entry which would have contained a
+ * compiled class in the original bug. For this test, the contents of the
+ * files contained in the jar file is not important as long as they get
+ * signed.
+ *
+ * @see #verifyClassNameLineBroken(JarFile, String)
+ */
+ static final String testClassName =
+ "LineBrokenMultiByteCharacterA1234567890B1234567890C123456789D12\u00E9xyz.class";
+
+ static final String anotherName =
+ "LineBrokenMultiByteCharacterA1234567890B1234567890C123456789D1234567890.class";
+
+ static final String alias = "a";
+ static final String keystoreFileName = "test.jks";
+ static final String manifestFileName = "MANIFEST.MF";
+
+ public static void main(String[] args) throws Exception {
+ prepare();
+
+ testSignJar("test.jar");
+ testSignJarNoManifest("test-no-manifest.jar");
+ testSignJarUpdate("test-update.jar", "test-updated.jar");
+ }
+
+ static void prepare() throws Exception {
+ SecurityTools.keytool("-keystore", keystoreFileName, "-genkeypair",
+ "-storepass", "changeit", "-keypass", "changeit", "-storetype",
+ "JKS", "-alias", alias, "-dname", "CN=X", "-validity", "366")
+ .shouldHaveExitValue(0);
+
+ Files.write(Paths.get(manifestFileName), (Name.
+ MANIFEST_VERSION.toString() + ": 1.0\r\n").getBytes(UTF_8));
+ }
+
+ static void testSignJar(String jarFileName) throws Exception {
+ JarUtils.createJar(jarFileName, manifestFileName, testClassName);
+ verifyJarSignature(jarFileName);
+ }
+
+ static void testSignJarNoManifest(String jarFileName) throws Exception {
+ JarUtils.createJar(jarFileName, testClassName);
+ verifyJarSignature(jarFileName);
+ }
+
+ static void testSignJarUpdate(
+ String initialFileName, String updatedFileName) throws Exception {
+ JarUtils.createJar(initialFileName, manifestFileName, anotherName);
+ SecurityTools.jarsigner("-keystore", keystoreFileName, "-storetype",
+ "JKS", "-storepass", "changeit", "-debug", initialFileName,
+ alias).shouldHaveExitValue(0);
+ JarUtils.updateJar(initialFileName, updatedFileName, testClassName);
+ verifyJarSignature(updatedFileName);
+ }
+
+ static void verifyJarSignature(String jarFileName) throws Exception {
+ // actually sign the jar
+ SecurityTools.jarsigner("-keystore", keystoreFileName, "-storetype",
+ "JKS", "-storepass", "changeit", "-debug", jarFileName, alias)
+ .shouldHaveExitValue(0);
+
+ try (
+ JarFile jar = new JarFile(jarFileName);
+ ) {
+ verifyClassNameLineBroken(jar, testClassName);
+ verifyCodeSigners(jar, jar.getJarEntry(testClassName));
+ }
+ }
+
+ /**
+ * it would be too easy to miss the actual test case by just renaming an
+ * identifier so that the multi-byte encoded character would not any longer
+ * be broken across a line break.
+ *
+ * this check here verifies that the actual test case is tested based on
+ * the manifest and not based on the signature file because at the moment,
+ * the signature file does not even contain the desired entry at all.
+ *
+ * this relies on {@link java.util.jar.Manifest} breaking lines unaware
+ * of bytes that belong to the same multi-byte utf characters.
+ */
+ static void verifyClassNameLineBroken(JarFile jar, String className)
+ throws IOException {
+ byte[] eAcute = "\u00E9".getBytes(UTF_8);
+ byte[] eAcuteBroken =
+ new byte[] {eAcute[0], '\r', '\n', ' ', eAcute[1]};
+
+ if (jar.getManifest().getAttributes(className) == null) {
+ throw new AssertionError(className + " not found in manifest");
+ }
+
+ JarEntry manifestEntry = jar.getJarEntry(JarFile.MANIFEST_NAME);
+ try (
+ InputStream manifestIs = jar.getInputStream(manifestEntry);
+ ) {
+ int bytesMatched = 0;
+ for (int b = manifestIs.read(); b > -1; b = manifestIs.read()) {
+ if ((byte) b == eAcuteBroken[bytesMatched]) {
+ bytesMatched++;
+ if (bytesMatched == eAcuteBroken.length) {
+ break;
+ }
+ } else {
+ bytesMatched = 0;
+ }
+ }
+ if (bytesMatched < eAcuteBroken.length) {
+ throw new AssertionError("self-test failed: multi-byte "
+ + "utf-8 character not broken across lines");
+ }
+ }
+ }
+
+ static void verifyCodeSigners(JarFile jar, JarEntry jarEntry)
+ throws IOException {
+ // codeSigners is initialized only after the entry has been read
+ try (
+ InputStream inputStream = jar.getInputStream(jarEntry);
+ ) {
+ inputStream.readAllBytes();
+ }
+
+ // a check for the presence of code signers is sufficient to check
+ // bug JDK-6695402. no need to also verify the actual code signers
+ // attributes here.
+ if (jarEntry.getCodeSigners() == null
+ || jarEntry.getCodeSigners().length == 0) {
+ throw new AssertionError(
+ "no signing certificate found for " + jarEntry.getName());
+ }
+ }
+
+}
--- a/test/langtools/jdk/javadoc/doclet/testClassLinks/TestClassLinks.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testClassLinks/TestClassLinks.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8163800 8175200
+ * @bug 8163800 8175200 8186332
* @summary The fix for JDK-8072052 shows up other minor incorrect use of styles
* @library ../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@@ -51,11 +51,11 @@
checkOutput("p/C1.html", true,
"<code><a href=\"../p/C2.html\" title=\"class in p\">C2</a></code>",
- "<code><span class=\"memberNameLink\"><a href=\"../p/C1.html#C1--\">C1</a></span>​()</code>");
+ "<code><span class=\"memberNameLink\"><a href=\"../p/C1.html#C1--\">C1</a></span>()</code>");
checkOutput("p/C2.html", true,
"<code><a href=\"../p/C3.html\" title=\"class in p\">C3</a></code>",
- "<code><span class=\"memberNameLink\"><a href=\"../p/C2.html#C2--\">C2</a></span>​()</code>");
+ "<code><span class=\"memberNameLink\"><a href=\"../p/C2.html#C2--\">C2</a></span>()</code>");
checkOutput("p/C3.html", true,
"<code><a href=\"../p/I1.html\" title=\"interface in p\">I1</a></code>, "
@@ -63,7 +63,7 @@
+ "<code><a href=\"../p/I2.html\" title=\"interface in p\">I2</a></code>, "
+ "<code><a href=\"../p/IT1.html\" title=\"interface in p\">IT1</a><T></code>, "
+ "<code><a href=\"../p/IT2.html\" title=\"interface in p\">IT2</a><java.lang.String></code>",
- "<code><span class=\"memberNameLink\"><a href=\"../p/C3.html#C3--\">C3</a></span>​()</code>");
+ "<code><span class=\"memberNameLink\"><a href=\"../p/C3.html#C3--\">C3</a></span>()</code>");
checkOutput("p/I1.html", true,
"<code><a href=\"../p/C3.html\" title=\"class in p\">C3</a></code>",
--- a/test/langtools/jdk/javadoc/doclet/testConstructors/TestConstructors.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testConstructors/TestConstructors.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8025524 8031625 8081854 8175200
+ * @bug 8025524 8031625 8081854 8175200 8186332
* @summary Test for constructor name which should be a non-qualified name.
* @author Bhavesh Patel
* @library ../lib
@@ -58,19 +58,19 @@
+ "<a href=\"../pkg1/Outer.html#Outer-int-\"><code>Outer(int)</code></a>, "
+ "<a href=\"../pkg1/Outer.Inner.NestedInner.html#NestedInner-int-\"><code>"
+ "NestedInner(int)</code></a>",
- "<a href=\"../pkg1/Outer.html#Outer--\">Outer</a></span>​()",
+ "<a href=\"../pkg1/Outer.html#Outer--\">Outer</a></span>()",
"<a name=\"Outer--\">",
"<a href=\"../pkg1/Outer.html#Outer-int-\">Outer</a></span>​(int i)",
"<a name=\"Outer-int-\">");
checkOutput("pkg1/Outer.Inner.html", true,
- "<a href=\"../pkg1/Outer.Inner.html#Inner--\">Inner</a></span>​()",
+ "<a href=\"../pkg1/Outer.Inner.html#Inner--\">Inner</a></span>()",
"<a name=\"Inner--\">",
"<a href=\"../pkg1/Outer.Inner.html#Inner-int-\">Inner</a></span>​(int i)",
"<a name=\"Inner-int-\">");
checkOutput("pkg1/Outer.Inner.NestedInner.html", true,
- "<a href=\"../pkg1/Outer.Inner.NestedInner.html#NestedInner--\">NestedInner</a></span>​()",
+ "<a href=\"../pkg1/Outer.Inner.NestedInner.html#NestedInner--\">NestedInner</a></span>()",
"<a name=\"NestedInner--\">",
"<a href=\"../pkg1/Outer.Inner.NestedInner.html#NestedInner-int-\">NestedInner</a></span>​(int i)",
"<a name=\"NestedInner-int-\">");
--- a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4927552 8026567 8071982 8162674 8175200 8175218
+ * @bug 4927552 8026567 8071982 8162674 8175200 8175218 8183511 8186332 8169819 8074407
* @summary <DESC>
* @author jamieh
* @library ../lib
@@ -81,133 +81,202 @@
+ "extends java.lang.Object</pre>",
"<pre>@Deprecated(forRemoval=true)\n"
+ "public int field</pre>\n"
- + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> </div>",
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span></div>",
"<pre>@Deprecated(forRemoval=true)\n"
- + "public DeprecatedClassByAnnotation​()</pre>\n"
- + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> </div>",
+ + "public DeprecatedClassByAnnotation()</pre>\n"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span></div>",
"<pre>@Deprecated\n"
- + "public void method​()</pre>\n"
- + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span> </div>");
+ + "public void method()</pre>\n"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated.</span></div>");
checkOutput("pkg/TestAnnotationType.html", true,
- "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> \n"
- + "<div class=\"block\"><span class=\"deprecationComment\">annotation_test1 passes.</span></div>\n"
- + "</div>\n"
- + "<br>\n"
+ "<hr>\n"
+ "<pre>@Deprecated(forRemoval=true)\n"
+ "@Documented\n"
- + "public @interface <span class=\"memberNameLabel\">TestAnnotationType</span></pre>",
+ + "public @interface <span class=\"memberNameLabel\">TestAnnotationType</span></pre>\n"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">annotation_test1 passes.</div>\n"
+ + "</div>",
"<pre>@Deprecated(forRemoval=true)\n"
+ "static final int field</pre>\n"
- + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This "
- + "API element is subject to removal in a future version.</span> <span class=\"deprecationComment\">annotation_test4 passes.</span></div>",
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This "
+ + "API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">annotation_test4 passes.</div>\n"
+ + "</div>",
"<pre>@Deprecated(forRemoval=true)\n"
+ "int required</pre>\n"
- + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> "
- + "<span class=\"deprecationComment\">annotation_test3 passes.</span></div>",
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">annotation_test3 passes.</div>\n"
+ + "</div>",
"<pre>java.lang.String optional</pre>\n"
- + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span> <span class=\"deprecationComment\">annotation_test2 passes.</span></div>");
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">annotation_test2 passes.</div>\n"
+ + "</div>");
checkOutput("pkg/TestClass.html", true,
- "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> \n"
- + "<div class=\"block\"><span class=\"deprecationComment\">class_test1 passes.</span></div>\n"
- + "</div>\n"
- + "<br>\n"
+ "<hr>\n"
+ "<pre>@Deprecated(forRemoval=true)\n"
+ "public class <span class=\"typeNameLabel\">TestClass</span>\n"
- + "extends java.lang.Object</pre>",
+ + "extends java.lang.Object</pre>\n"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">class_test1 passes.</div>\n"
+ + "</div>",
"<pre>@Deprecated(forRemoval=true)\n"
- + "public TestClass​()</pre>\n"
- + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> "
- + "<span class=\"deprecationComment\">class_test3 passes.</span></div>");
+ + "public TestClass()</pre>\n"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">class_test3 passes. This is the second sentence of deprecated description for a constructor.</div>\n"
+ + "</div>",
+ "<td class=\"colLast\">\n"
+ + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">class_test2 passes.</div>\n"
+ + "</div>\n"
+ + "</td>",
+ "<td class=\"colLast\">\n"
+ + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">class_test3 passes.</div>\n"
+ + "</div>\n"
+ + "</td>",
+ "<td class=\"colLast\">\n"
+ + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">class_test4 passes.</div>\n"
+ + "</div>\n"
+ + "</td>");
+
+ checkOutput("pkg/TestClass.html", false,
+ "<div class=\"deprecationComment\">class_test2 passes. This is the second sentence of deprecated description for a field.</div>\n"
+ + "</div>\n"
+ + "</td>",
+ "<div class=\"deprecationComment\">class_test3 passes. This is the second sentence of deprecated description for a constructor.</div>\n"
+ + "</div>\n"
+ + "</td>",
+ "<div class=\"deprecationComment\">class_test4 passes. This is the second sentence of deprecated description for a method.</div>\n"
+ + "</div>\n"
+ + "</td>");
checkOutput("pkg/TestEnum.html", true,
- "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> \n"
- + "<div class=\"block\"><span class=\"deprecationComment\">enum_test1 passes.</span></div>\n"
- + "</div>\n"
- + "<br>\n"
+ "<hr>\n"
+ "<pre>@Deprecated(forRemoval=true)\n"
+ "public enum <span class=\"typeNameLabel\">TestEnum</span>\n"
- + "extends java.lang.Enum<<a href=\"../pkg/TestEnum.html\" title=\"enum in pkg\">TestEnum</a>></pre>",
+ + "extends java.lang.Enum<<a href=\"../pkg/TestEnum.html\" title=\"enum in pkg\">TestEnum</a>></pre>\n"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">enum_test1 passes.</div>\n"
+ + "</div>",
"<pre>@Deprecated(forRemoval=true)\n"
+ "public static final <a href=\"../pkg/TestEnum.html\" title=\"enum in pkg\">TestEnum</a> FOR_REMOVAL</pre>\n"
- + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> "
- + "<span class=\"deprecationComment\">enum_test3 passes.</span></div>");
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">enum_test3 passes.</div>\n"
+ + "</div>");
checkOutput("pkg/TestError.html", true,
- "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> \n"
- + "<div class=\"block\"><span class=\"deprecationComment\">error_test1 passes.</span></div>\n"
- + "</div>\n"
- + "<br>\n"
+ "<hr>\n"
+ "<pre>@Deprecated(forRemoval=true)\n"
+ "public class <span class=\"typeNameLabel\">TestError</span>\n"
- + "extends java.lang.Error</pre>");
+ + "extends java.lang.Error</pre>\n"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">error_test1 passes.</div>\n"
+ + "</div>");
checkOutput("pkg/TestException.html", true,
- "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> \n"
- + "<div class=\"block\"><span class=\"deprecationComment\">exception_test1 passes.</span></div>\n"
- + "</div>\n"
- + "<br>\n"
+ "<hr>\n"
+ "<pre>@Deprecated(forRemoval=true)\n"
+ "public class <span class=\"typeNameLabel\">TestException</span>\n"
- + "extends java.lang.Exception</pre>");
+ + "extends java.lang.Exception</pre>\n"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">exception_test1 passes.</div>\n"
+ + "</div>");
checkOutput("pkg/TestInterface.html", true,
- "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span> \n"
- + "<div class=\"block\"><span class=\"deprecationComment\">interface_test1 passes.</span></div>\n"
- + "</div>\n"
- + "<br>\n"
+ "<hr>\n"
+ "<pre>@Deprecated(forRemoval=true)\n"
+ "public class <span class=\"typeNameLabel\">TestInterface</span>\n"
- + "extends java.lang.Object</pre>");
+ + "extends java.lang.Object</pre>\n"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal: This API element is subject to removal in a future version.</span>\n"
+ + "<div class=\"deprecationComment\">interface_test1 passes.</div>\n"
+ + "</div>");
checkOutput("deprecated-list.html", true,
"<ul>\n"
- + "<li><a href=\"#forRemoval\">Deprecated For Removal</a></li>\n"
- + "<li><a href=\"#class\">Deprecated Classes</a></li>\n"
- + "<li><a href=\"#enum\">Deprecated Enums</a></li>\n"
- + "<li><a href=\"#exception\">Deprecated Exceptions</a></li>\n"
- + "<li><a href=\"#error\">Deprecated Errors</a></li>\n"
- + "<li><a href=\"#annotation.type\">Deprecated Annotation Types</a></li>\n"
- + "<li><a href=\"#field\">Deprecated Fields</a></li>\n"
- + "<li><a href=\"#method\">Deprecated Methods</a></li>\n"
- + "<li><a href=\"#constructor\">Deprecated Constructors</a></li>\n"
- + "<li><a href=\"#enum.constant\">Deprecated Enum Constants</a></li>\n"
- + "<li><a href=\"#annotation.type.member\">Deprecated Annotation Type Elements</a></li>\n"
+ + "<li><a href=\"#forRemoval\">For Removal</a></li>\n"
+ + "<li><a href=\"#class\">Classes</a></li>\n"
+ + "<li><a href=\"#enum\">Enums</a></li>\n"
+ + "<li><a href=\"#exception\">Exceptions</a></li>\n"
+ + "<li><a href=\"#error\">Errors</a></li>\n"
+ + "<li><a href=\"#annotation.type\">Annotation Types</a></li>\n"
+ + "<li><a href=\"#field\">Fields</a></li>\n"
+ + "<li><a href=\"#method\">Methods</a></li>\n"
+ + "<li><a href=\"#constructor\">Constructors</a></li>\n"
+ + "<li><a href=\"#enum.constant\">Enum Constants</a></li>\n"
+ + "<li><a href=\"#annotation.type.member\">Annotation Type Elements</a></li>\n"
+ "</ul>",
"<a name=\"forRemoval\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated For Removal table, listing deprecated for removal, and an explanation\">\n"
- + "<caption><span>Deprecated For Removal</span><span class=\"tabEnd\"> </span></caption>\n"
+ "<table class=\"deprecatedSummary\" summary=\"For Removal table, listing for removal, and an explanation\">\n"
+ + "<caption><span>For Removal</span><span class=\"tabEnd\"> </span></caption>\n"
+ "<tr>\n"
+ "<th class=\"colFirst\" scope=\"col\">Element</th>\n"
+ "<th class=\"colLast\" scope=\"col\">Description</th>\n"
+ "</tr>",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Enums table, listing deprecated enums, and an explanation\">\n"
- + "<caption><span>Deprecated Enums</span><span class=\"tabEnd\"> </span></caption>\n"
+ "<table class=\"deprecatedSummary\" summary=\"Enums table, listing enums, and an explanation\">\n"
+ + "<caption><span>Enums</span><span class=\"tabEnd\"> </span></caption>\n"
+ "<tr>\n"
+ "<th class=\"colFirst\" scope=\"col\">Enum</th>\n"
+ "<th class=\"colLast\" scope=\"col\">Description</th>\n"
+ "</tr>\n"
+ "<tbody>\n"
+ "<tr class=\"altColor\">\n"
- + "<th class=\"colFirst\" scope=\"row\"><a href=\"pkg/TestEnum.html\" title=\"enum in pkg\">pkg.TestEnum</a></th>\n"
+ + "<th class=\"colDeprecatedItemName\" scope=\"row\"><a href=\"pkg/TestEnum.html\" title=\"enum in pkg\">pkg.TestEnum</a></th>\n"
+ "<td class=\"colLast\">\n"
- + "<div class=\"block\"><span class=\"deprecationComment\">enum_test1 passes.</span></div>\n"
+ + "<div class=\"deprecationComment\">enum_test1 passes.</div>\n"
+ "</td>\n"
+ "</tr>\n"
+ "</tbody>\n"
+ "</table>",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Exceptions table, listing deprecated exceptions, and an explanation\">\n"
- + "<caption><span>Deprecated Exceptions</span><span class=\"tabEnd\"> </span></caption>\n"
+ "<table class=\"deprecatedSummary\" summary=\"Exceptions table, listing exceptions, and an explanation\">\n"
+ + "<caption><span>Exceptions</span><span class=\"tabEnd\"> </span></caption>\n"
+ "<tr>\n"
+ "<th class=\"colFirst\" scope=\"col\">Exceptions</th>\n"
+ "<th class=\"colLast\" scope=\"col\">Description</th>\n"
+ "</tr>\n"
+ "<tbody>\n"
+ "<tr class=\"altColor\">\n"
- + "<th class=\"colFirst\" scope=\"row\"><a href=\"pkg/TestException.html\" title=\"class in pkg\">pkg.TestException</a></th>\n"
+ + "<th class=\"colDeprecatedItemName\" scope=\"row\"><a href=\"pkg/TestException.html\" title=\"class in pkg\">pkg.TestException</a></th>\n"
+ + "<td class=\"colLast\">\n"
+ + "<div class=\"deprecationComment\">exception_test1 passes.</div>\n"
+ + "</td>\n"
+ + "</tr>\n"
+ + "</tbody>\n"
+ + "</table>",
+ "<table class=\"deprecatedSummary\" summary=\"Fields table, listing fields, and an explanation\">\n"
+ + "<caption><span>Fields</span><span class=\"tabEnd\"> </span></caption>\n"
+ + "<tr>\n"
+ + "<th class=\"colFirst\" scope=\"col\">Field</th>\n"
+ + "<th class=\"colLast\" scope=\"col\">Description</th>\n"
+ + "</tr>\n"
+ + "<tbody>\n"
+ + "<tr class=\"altColor\">\n"
+ + "<th class=\"colDeprecatedItemName\" scope=\"row\"><a href=\"pkg/DeprecatedClassByAnnotation.html#field\">pkg.DeprecatedClassByAnnotation.field</a></th>\n"
+ + "</tr>\n"
+ + "<tr class=\"rowColor\">\n"
+ + "<th class=\"colDeprecatedItemName\" scope=\"row\"><a href=\"pkg/TestClass.html#field\">pkg.TestClass.field</a></th>\n"
+ "<td class=\"colLast\">\n"
- + "<div class=\"block\"><span class=\"deprecationComment\">exception_test1 passes.</span></div>\n"
+ + "<div class=\"deprecationComment\">class_test2 passes. This is the second sentence of deprecated description for a field.</div>\n"
+ + "</td>\n"
+ + "</tr>\n"
+ + "<tr class=\"altColor\">\n"
+ + "<th class=\"colDeprecatedItemName\" scope=\"row\"><a href=\"pkg/TestError.html#field\">pkg.TestError.field</a></th>\n"
+ + "<td class=\"colLast\">\n"
+ + "<div class=\"deprecationComment\">error_test2 passes.</div>\n"
+ + "</td>\n"
+ + "</tr>\n"
+ + "<tr class=\"rowColor\">\n"
+ + "<th class=\"colDeprecatedItemName\" scope=\"row\"><a href=\"pkg/TestException.html#field\">pkg.TestException.field</a></th>\n"
+ + "<td class=\"colLast\">\n"
+ + "<div class=\"deprecationComment\">exception_test2 passes.</div>\n"
+ + "</td>\n"
+ + "</tr>\n"
+ + "<tr class=\"altColor\">\n"
+ + "<th class=\"colDeprecatedItemName\" scope=\"row\"><a href=\"pkg/TestInterface.html#field\">pkg.TestInterface.field</a></th>\n"
+ + "<td class=\"colLast\">\n"
+ + "<div class=\"deprecationComment\">interface_test2 passes.</div>\n"
+ "</td>\n"
+ "</tr>\n"
+ "</tbody>\n"
--- a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/pkg/TestClass.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/pkg/TestClass.java Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -30,18 +30,18 @@
public class TestClass {
/**
- * @deprecated class_test2 passes.
+ * @deprecated class_test2 passes. This is the second sentence of deprecated description for a field.
*/
public int field;
/**
- * @deprecated class_test3 passes.
+ * @deprecated class_test3 passes. This is the second sentence of deprecated description for a constructor.
*/
@Deprecated(forRemoval=true)
public TestClass() {}
/**
- * @deprecated class_test4 passes.
+ * @deprecated class_test4 passes. This is the second sentence of deprecated description for a method.
*/
public void method() {}
}
--- a/test/langtools/jdk/javadoc/doclet/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6786690 6820360 8025633 8026567 8175200
+ * @bug 6786690 6820360 8025633 8026567 8175200 8183511 8186332 8074407
* @summary This test verifies the nesting of definition list tags.
* @author Bhavesh Patel
* @library ../lib
@@ -226,10 +226,11 @@
+ "<dd><a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
+ "<code>C1.setUndecorated(boolean)</code></a></dd>\n"
+ "</dl>",
- "<span class=\"deprecatedLabel\">Deprecated.</span>"
- + " <span class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ "<span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ " <a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
- + "<code>setUndecorated(boolean)</code></a>.</span></div>\n"
+ + "<code>setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ "<div class=\"block\">This field indicates whether the C1 is "
+ "undecorated.</div>\n"
+ " \n"
@@ -241,10 +242,11 @@
+ "<dd><a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
+ "<code>C1.setUndecorated(boolean)</code></a></dd>\n"
+ "</dl>",
- "<span class=\"deprecatedLabel\">Deprecated.</span>"
- + " <span class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ "<span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ " <a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
- + "<code>setUndecorated(boolean)</code></a>.</span></div>\n"
+ + "<code>setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ "<div class=\"block\">Reads the object stream.</div>\n"
+ "<dl>\n"
+ "<dt><span class=\"throwsLabel\">Throws:"
@@ -252,7 +254,7 @@
+ "<dd><code>java.io.IOException</code></dd>\n"
+ "</dl>",
"<span class=\"deprecatedLabel\">Deprecated.</span>"
- + " </div>\n"
+ + "</div>\n"
+ "<div class=\"block\">The name for this class.</div>");
}
@@ -332,10 +334,11 @@
+ "<dd><a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
+ "<code>C1.setUndecorated(boolean)</code></a></dd>\n"
+ "</dl>",
- "<span class=\"deprecatedLabel\">Deprecated.</span>"
- + " <span class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ "<span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ " <a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
- + "<code>setUndecorated(boolean)</code></a>.</span></div>\n"
+ + "<code>setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ "<div class=\"block\">This field indicates whether the C1 is "
+ "undecorated.</div>\n"
+ " \n"
@@ -347,10 +350,11 @@
+ "<dd><a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
+ "<code>C1.setUndecorated(boolean)</code></a></dd>\n"
+ "</dl>",
- "<span class=\"deprecatedLabel\">Deprecated.</span>"
- + " <span class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ "<span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ " <a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
- + "<code>setUndecorated(boolean)</code></a>.</span></div>\n"
+ + "<code>setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ "<div class=\"block\">Reads the object stream.</div>\n"
+ "<dl>\n"
+ "<dt><span class=\"throwsLabel\">Throws:"
@@ -358,7 +362,7 @@
+ "<dd><code>java.io.IOException</code></dd>\n"
+ "</dl>",
"<span class=\"deprecatedLabel\">Deprecated.</span>"
- + " </div>\n"
+ + "</div>\n"
+ "<div class=\"block\">"
+ "The name for this class.</div>");
}
@@ -367,12 +371,12 @@
// Test with -nocomment and -nodeprecated options. The ClassDocs whould
// not display definition lists for any member details.
checkOutput("pkg1/C1.html", expectFound,
- "<pre>public void readObject​()\n" +
+ "<pre>public void readObject()\n" +
" throws java.io.IOException</pre>\n" +
"</li>");
checkOutput("pkg1/C2.html", expectFound,
- "<pre>public C2​()</pre>\n" +
+ "<pre>public C2()</pre>\n" +
"</li>");
checkOutput("pkg1/C1.ModalExclusionType.html", expectFound,
@@ -385,16 +389,21 @@
checkOutput("serialized-form.html", expectFound,
"<pre>boolean " +
"undecorated</pre>\n" +
- "<div class=\"block\"><span class=\"deprecatedLabel\">" +
- "Deprecated.</span> <span class=\"deprecationComment\">As of JDK version 1.5, replaced by\n" +
- " <a href=\"pkg1/C1.html#setUndecorated-boolean-\"><code>" +
- "setUndecorated(boolean)</code></a>.</span></div>\n" +
+ "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">" +
+ "Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ + " <a href=\"pkg1/C1.html#setUndecorated-boolean-\"><code>"
+ + "setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ +
"</li>",
- "<span class=\"deprecatedLabel\">" +
- "Deprecated.</span> <span class=\"deprecationComment\">As of JDK version" +
- " 1.5, replaced by\n" +
- " <a href=\"pkg1/C1.html#setUndecorated-boolean-\">" +
- "<code>setUndecorated(boolean)</code></a>.</span></div>\n" +
- "</li>");
+ "<span class=\"deprecatedLabel\">"
+ + "Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">As of JDK version"
+ + " 1.5, replaced by\n"
+ + " <a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
+ + "<code>setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ + "</li>");
}
}
--- a/test/langtools/jdk/javadoc/doclet/testHtmlTableStyles/TestHtmlTableStyles.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlTableStyles/TestHtmlTableStyles.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8008164
+ * @bug 8008164 8169819
* @summary Test styles on HTML tables generated by javadoc.
* @author Bhavesh Patel
* @library ../lib
@@ -68,8 +68,8 @@
+ "summary=\"Packages table, listing packages, and an explanation\">");
checkOutput("deprecated-list.html", true,
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Methods table, listing " +
- "deprecated methods, and an explanation\">");
+ "<table class=\"deprecatedSummary\" summary=\"Methods table, listing " +
+ "methods, and an explanation\">");
checkOutput("constant-values.html", true,
"<table class=\"constantsSummary\" summary=\"Constant Field Values table, listing " +
--- a/test/langtools/jdk/javadoc/doclet/testHtmlTableTags/TestHtmlTableTags.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlTableTags/TestHtmlTableTags.java Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6786688 8008164 8162363
+ * @bug 6786688 8008164 8162363 8169819
* @summary HTML tables should have table summary, caption and table headers.
* @author Bhavesh Patel
* @library ../lib
@@ -129,9 +129,9 @@
// Deprecated
checkOutput("deprecated-list.html", true,
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Fields table, listing deprecated fields, "
+ "<table class=\"deprecatedSummary\" summary=\"Fields table, listing fields, "
+ "and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Methods table, listing deprecated methods, "
+ "<table class=\"deprecatedSummary\" summary=\"Methods table, listing methods, "
+ "and an explanation\">");
// Constant values
@@ -239,9 +239,9 @@
// Deprecated
checkOutput("deprecated-list.html", true,
- "<caption><span>Deprecated Fields</span><span class=\"tabEnd\">"
+ "<caption><span>Fields</span><span class=\"tabEnd\">"
+ " </span></caption>",
- "<caption><span>Deprecated Methods</span><span class=\"tabEnd\">"
+ "<caption><span>Methods</span><span class=\"tabEnd\">"
+ " </span></caption>");
// Constant values
--- a/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8072945 8081854 8141492 8148985 8150188 4649116 8173707 8151743
+ * @bug 8072945 8081854 8141492 8148985 8150188 4649116 8173707 8151743 8169819
* @summary Test the version of HTML generated by the javadoc tool.
* @author bpatel
* @library ../lib
@@ -736,16 +736,16 @@
+ "<div class=\"header\">\n"
+ "<h1 title=\"Deprecated API\" class=\"title\">Deprecated API</h1>\n"
+ "<h2 title=\"Contents\">Contents</h2>",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Classes table, listing deprecated classes, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Enums table, listing deprecated enums, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Exceptions table, listing deprecated exceptions, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Errors table, listing deprecated errors, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Annotation Types table, listing deprecated annotation types, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Fields table, listing deprecated fields, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Methods table, listing deprecated methods, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Constructors table, listing deprecated constructors, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Enum Constants table, listing deprecated enum constants, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Annotation Type Elements table, listing deprecated annotation type elements, and an explanation\">");
+ "<table class=\"deprecatedSummary\" summary=\"Classes table, listing classes, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Enums table, listing enums, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Exceptions table, listing exceptions, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Errors table, listing errors, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Annotation Types table, listing annotation types, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Fields table, listing fields, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Methods table, listing methods, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Constructors table, listing constructors, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Enum Constants table, listing enum constants, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Annotation Type Elements table, listing annotation type elements, and an explanation\">");
// Negated test for serialized-form page
checkOutput("serialized-form.html", false,
@@ -1179,16 +1179,16 @@
+ "<div class=\"header\">\n"
+ "<h1 title=\"Deprecated API\" class=\"title\">Deprecated API</h1>\n"
+ "<h2 title=\"Contents\">Contents</h2>",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Classes table, listing deprecated classes, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Enums table, listing deprecated enums, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Exceptions table, listing deprecated exceptions, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Errors table, listing deprecated errors, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Annotation Types table, listing deprecated annotation types, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Fields table, listing deprecated fields, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Methods table, listing deprecated methods, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Constructors table, listing deprecated constructors, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Enum Constants table, listing deprecated enum constants, and an explanation\">",
- "<table class=\"deprecatedSummary\" summary=\"Deprecated Annotation Type Elements table, listing deprecated annotation type elements, and an explanation\">");
+ "<table class=\"deprecatedSummary\" summary=\"Classes table, listing classes, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Enums table, listing enums, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Exceptions table, listing exceptions, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Errors table, listing errors, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Annotation Types table, listing annotation types, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Fields table, listing fields, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Methods table, listing methods, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Constructors table, listing constructors, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Enum Constants table, listing enum constants, and an explanation\">",
+ "<table class=\"deprecatedSummary\" summary=\"Annotation Type Elements table, listing annotation type elements, and an explanation\">");
// Test for serialized-form page
checkOutput("serialized-form.html", true,
--- a/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4682448 4947464 5029946 8025633 8026567 8035473 8139101 8175200
+ * @bug 4682448 4947464 5029946 8025633 8026567 8035473 8139101 8175200 8186332
* @summary Verify that the public modifier does not show up in the
* documentation for public methods, as recommended by the JLS.
* If A implements I and B extends A, B should be in the list of
@@ -64,7 +64,7 @@
checkExit(Exit.OK);
checkOutput("pkg/Interface.html", true,
- "<pre>int method​()</pre>",
+ "<pre>int method()</pre>",
"<pre>static final int field</pre>",
// Make sure known implementing class list is correct and omits type parameters.
"<dl>\n"
@@ -119,7 +119,7 @@
+ "</dl>");
checkOutput("pkg/Interface.html", false,
- "public int method​()",
+ "public int method()",
"public static final int field");
checkOutput("pkg/ClassWithStaticMethod.html", false,
--- a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java Wed Oct 04 20:01:19 2017 +0000
@@ -24,7 +24,7 @@
/*
* @test
* @bug 7112427 8012295 8025633 8026567 8061305 8081854 8150130 8162363
- * 8167967 8172528 8175200 8178830 8182257
+ * 8167967 8172528 8175200 8178830 8182257 8186332
* @summary Test of the JavaFX doclet features.
* @author jvalenta
* @library ../lib
@@ -58,7 +58,7 @@
+ "<div class=\"block\">Sets the value of the property rate.</div>\n"
+ "<dl>\n"
+ "<dt><span class=\"simpleTagLabel\">Property description:</span></dt>",
- "<pre>public final double getRate​()</pre>\n"
+ "<pre>public final double getRate()</pre>\n"
+ "<div class=\"block\">Gets the value of the property rate.</div>\n"
+ "<dl>\n"
+ "<dt><span class=\"simpleTagLabel\">Property description:</span></dt>",
@@ -78,7 +78,7 @@
"<span class=\"simpleTagLabel\">Property description:</span>",
"<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
+ "<a href=\"../pkg1/C.html#setTestMethodProperty--\">"
- + "setTestMethodProperty</a></span>​()</code></th>",
+ + "setTestMethodProperty</a></span>()</code></th>",
"<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
+ "<a href=\"../pkg1/C.html#pausedProperty\">paused</a></span></code></th>\n"
+ "<td class=\"colLast\">\n"
@@ -88,7 +88,7 @@
+ "title=\"class in pkg1\">C.BooleanProperty</a> pausedProperty</pre>\n"
+ "<div class=\"block\">Defines if paused. The second line.</div>",
"<h4>isPaused</h4>\n"
- + "<pre>public final double isPaused​()</pre>\n"
+ + "<pre>public final double isPaused()</pre>\n"
+ "<div class=\"block\">Gets the value of the property paused.</div>",
"<h4>setPaused</h4>\n"
+ "<pre>public final void setPaused​(boolean value)</pre>\n"
@@ -99,7 +99,7 @@
+ "<dt><span class=\"simpleTagLabel\">Default value:</span></dt>\n"
+ "<dd>false</dd>",
"<h4>isPaused</h4>\n"
- + "<pre>public final double isPaused​()</pre>\n"
+ + "<pre>public final double isPaused()</pre>\n"
+ "<div class=\"block\">Gets the value of the property paused.</div>\n"
+ "<dl>\n"
+ "<dt><span class=\"simpleTagLabel\">Property description:</span></dt>\n"
@@ -124,7 +124,7 @@
+ "<dt><span class=\"simpleTagLabel\">Since:</span></dt>\n"
+ "<dd>JavaFX 8.0</dd>",
"<h4>getRate</h4>\n"
- + "<pre>public final double getRate​()</pre>\n"
+ + "<pre>public final double getRate()</pre>\n"
+ "<div class=\"block\">Gets the value of the property rate.</div>\n"
+ "<dl>\n"
+ "<dt><span class=\"simpleTagLabel\">Property description:</span></dt>\n"
@@ -253,20 +253,20 @@
+ "<tr id=\"i1\" class=\"rowColor\">\n"
+ "<td class=\"colFirst\"><code>java.lang.Object</code></td>\n"
+ "<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
- + "<a href=\"../pkg2/Test.html#betaProperty--\">betaProperty</a></span>​()</code></th>\n"
+ + "<a href=\"../pkg2/Test.html#betaProperty--\">betaProperty</a></span>()</code></th>\n"
+ "<td class=\"colLast\"> </td>\n"
+ "</tr>\n"
+ "<tr id=\"i2\" class=\"altColor\">\n"
+ "<td class=\"colFirst\"><code>java.util.List<java.util.Set<? super java.lang.Object>>"
+ "</code></td>\n"
+ "<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
- + "<a href=\"../pkg2/Test.html#deltaProperty--\">deltaProperty</a></span>​()</code></th>\n"
+ + "<a href=\"../pkg2/Test.html#deltaProperty--\">deltaProperty</a></span>()</code></th>\n"
+ "<td class=\"colLast\"> </td>\n"
+ "</tr>\n"
+ "<tr id=\"i3\" class=\"rowColor\">\n"
+ "<td class=\"colFirst\"><code>java.util.List<java.lang.String></code></td>\n"
+ "<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
- + "<a href=\"../pkg2/Test.html#gammaProperty--\">gammaProperty</a></span>​()</code></th>\n"
+ + "<a href=\"../pkg2/Test.html#gammaProperty--\">gammaProperty</a></span>()</code></th>\n"
+ "<td class=\"colLast\"> </td>"
);
}
--- a/test/langtools/jdk/javadoc/doclet/testLambdaFeature/TestLambdaFeature.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testLambdaFeature/TestLambdaFeature.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8004893 8022738 8029143 8175200
+ * @bug 8004893 8022738 8029143 8175200 8186332
* @summary Make sure that the lambda feature changes work fine in
* javadoc.
* @author bpatel
@@ -55,7 +55,7 @@
checkOutput("pkg/A.html", true,
"<td class=\"colFirst\"><code>default void</code></td>",
- "<pre>default void defaultMethod​()</pre>",
+ "<pre>default void defaultMethod()</pre>",
"<caption><span id=\"t0\" class=\"activeTableTab\"><span>"
+ "All Methods</span><span class=\"tabEnd\"> </span></span>"
+ "<span id=\"t2\" class=\"tableTab\"><span>"
@@ -83,7 +83,7 @@
checkOutput("pkg/A.html", false,
"<td class=\"colFirst\"><code>default default void</code></td>",
- "<pre>default default void defaultMethod​()</pre>");
+ "<pre>default default void defaultMethod()</pre>");
checkOutput("pkg/B.html", false,
"<td class=\"colFirst\"><code>default void</code></td>",
--- a/test/langtools/jdk/javadoc/doclet/testLiteralCodeInPre/TestLiteralCodeInPre.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testLiteralCodeInPre/TestLiteralCodeInPre.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8002387 8014636 8078320 8175200
+ * @bug 8002387 8014636 8078320 8175200 8186332
* @summary Improve rendered HTML formatting for {@code}
* @library ../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@@ -47,19 +47,19 @@
checkExit(Exit.OK);
checkOutput("pkg/Test.html", true,
- "no_pre​()</pre>\n"
+ "no_pre()</pre>\n"
+ "<div class=\"block\">abc<code>def</code>ghi</div>",
- "no_pre_extra_whitespace​()</pre>\n"
+ "no_pre_extra_whitespace()</pre>\n"
+ "<div class=\"block\">abc<code> def </code>ghi</div>",
- "in_pre​()</pre>\n"
+ "in_pre()</pre>\n"
+ "<div class=\"block\"><pre> abc<code> def </code>ghi</pre></div>",
- "pre_after_text​()</pre>\n"
+ "pre_after_text()</pre>\n"
+ "<div class=\"block\">xyz <pre> abc<code> def </code>ghi</pre></div>",
- "after_pre​()</pre>\n"
+ "after_pre()</pre>\n"
+ "<div class=\"block\">xyz <pre> pqr </pre> abc<code> def </code>ghi</div>",
- "back_in_pre​()</pre>\n"
+ "back_in_pre()</pre>\n"
+ "<div class=\"block\">xyz <pre> pqr </pre> mno <pre> abc<code> def </code>ghi</pre></div>",
- "typical_usage_code​()</pre>\n"
+ "typical_usage_code()</pre>\n"
+ "<div class=\"block\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
+ " Example: <pre><code>\n"
+ " line 0 @Override\n"
@@ -68,7 +68,7 @@
+ " line 3 }\n"
+ " </code></pre>\n"
+ " and so it goes.</div>",
- "typical_usage_literal​()</pre>\n"
+ "typical_usage_literal()</pre>\n"
+ "<div class=\"block\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
+ " Example: <pre>\n"
+ " line 0 @Override\n"
@@ -77,7 +77,7 @@
+ " line 3 }\n"
+ " </pre>\n"
+ " and so it goes.</div>",
- "recommended_usage_literal​()</pre>\n"
+ "recommended_usage_literal()</pre>\n"
+ "<div class=\"block\">Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
+ " Example: <pre>\n"
+ " line 0 @Override\n"
@@ -89,7 +89,7 @@
+ " <PRE>\n"
+ " <b>id </b>\n"
+ " </PRE></div>",
- "<pre>public void htmlAttrInPre1​()</pre>\n"
+ "<pre>public void htmlAttrInPre1()</pre>\n"
+ "<div class=\"block\">More html tag outliers.\n"
+ " <pre>\n"
+ " @Override\n"
--- a/test/langtools/jdk/javadoc/doclet/testMemberSummary/TestMemberSummary.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testMemberSummary/TestMemberSummary.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4951228 6290760 8025633 8026567 8081854 8162363 8175200 8177417
+ * @bug 4951228 6290760 8025633 8026567 8081854 8162363 8175200 8177417 8186332
* @summary Test the case where the overriden method returns a different
* type than the method in the child class. Make sure the
* documentation is inherited but the return type isn't.
@@ -52,12 +52,12 @@
// Check return type in member summary.
"<code><a href=\"../pkg/PublicChild.html\" title=\"class in pkg\">PublicChild</a></code></td>\n"
+ "<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\"><a href=\"../pkg/PublicChild.html#returnTypeTest--\">"
- + "returnTypeTest</a></span>​()</code>",
+ + "returnTypeTest</a></span>()</code>",
// Check return type in member detail.
"<pre>public <a href=\"../pkg/PublicChild.html\" title=\"class in pkg\">"
- + "PublicChild</a> returnTypeTest​()</pre>",
+ + "PublicChild</a> returnTypeTest()</pre>",
"<th class=\"colConstructorName\" scope=\"row\"><code><span class=\"memberNameLink\">"
- + "<a href=\"../pkg/PublicChild.html#PublicChild--\">PublicChild</a></span>​()</code></th>");
+ + "<a href=\"../pkg/PublicChild.html#PublicChild--\">PublicChild</a></span>()</code></th>");
checkOutput("pkg/PrivateParent.html", true,
"<td class=\"colFirst\"><code>private </code></td>\n"
--- a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java Wed Oct 04 20:01:19 2017 +0000
@@ -25,7 +25,7 @@
* @test
* @bug 8154119 8154262 8156077 8157987 8154261 8154817 8135291 8155995 8162363
* 8168766 8168688 8162674 8160196 8175799 8174974 8176778 8177562 8175218 8175823 8166306
- * 8178043 8181622
+ * 8178043 8181622 8183511 8169819 8074407
* @summary Test modules support in javadoc.
* @author bpatel
* @library ../lib
@@ -446,9 +446,9 @@
void checkHtml5Description(boolean found) {
checkOutput("moduleA-summary.html", found,
"<section role=\"region\">\n"
- + "<div class=\"deprecatedContent\"><span class=\"deprecatedLabel\">Deprecated, for removal:"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal:"
+ " This API element is subject to removal in a future version.</span>\n"
- + "<div class=\"block\"><span class=\"deprecationComment\">This module is deprecated.</span></div>\n"
+ + "<div class=\"deprecationComment\">This module is deprecated.</div>\n"
+ "</div>\n"
+ "<!-- ============ MODULE DESCRIPTION =========== -->\n"
+ "<a id=\"module.description\">\n"
@@ -1015,28 +1015,28 @@
void checkModuleDeprecation(boolean found) {
checkOutput("moduleA-summary.html", found,
- "<div class=\"deprecatedContent\"><span class=\"deprecatedLabel\">Deprecated, for removal:"
+ "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated, for removal:"
+ " This API element is subject to removal in a future version.</span>\n"
- + "<div class=\"block\"><span class=\"deprecationComment\">This module is deprecated.</span></div>\n"
+ + "<div class=\"deprecationComment\">This module is deprecated.</div>\n"
+ "</div>");
checkOutput("deprecated-list.html", found,
"<ul>\n"
- + "<li><a href=\"#forRemoval\">Deprecated For Removal</a></li>\n"
- + "<li><a href=\"#module\">Deprecated Modules</a></li>\n"
+ + "<li><a href=\"#forRemoval\">For Removal</a></li>\n"
+ + "<li><a href=\"#module\">Modules</a></li>\n"
+ "</ul>",
"<tr class=\"altColor\">\n"
+ "<th class=\"colFirst\" scope=\"row\"><a href=\"moduleA-summary.html\">moduleA</a></th>\n"
+ "<td class=\"colLast\">\n"
- + "<div class=\"block\"><span class=\"deprecationComment\">This module is deprecated.</span></div>\n"
+ + "<div class=\"deprecationComment\">This module is deprecated.</div>\n"
+ "</td>\n"
+ "</tr>");
checkOutput("moduleB-summary.html", !found,
- "<div class=\"deprecatedContent\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
- + "<div class=\"block\"><span class=\"deprecationComment\">This module is deprecated using just the javadoc tag.</span></div>");
+ "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">This module is deprecated using just the javadoc tag.</div>\n");
checkOutput("moduletags-summary.html", found,
"<p>@Deprecated\n"
+ "</p>",
- "<div class=\"deprecatedContent\"><span class=\"deprecatedLabel\">Deprecated.</span></div>");
+ "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated.</span></div>");
}
void checkModuleAnnotation() {
@@ -1143,5 +1143,5 @@
+ "<div class=\"block\">This is a test description for the test.moduleFullName.</div>\n"
+ "</dd>\n"
+ "</dl>");
+ }
}
-}
--- a/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java Wed Oct 04 20:01:19 2017 +0000
@@ -24,7 +24,7 @@
/*
* @test
* @bug 4789689 4905985 4927164 4827184 4993906 5004549 7025314 7010344 8025633 8026567 8162363
- * 8175200
+ * 8175200 8186332
* @summary Run Javadoc on a set of source files that demonstrate new
* language features. Check the output to ensure that the new
* language features are properly documented.
@@ -549,7 +549,7 @@
+ "=\"Constructor Annotation\",\n"
+ " <a href=\"../pkg/AnnotationType.html#required--\">"
+ "required</a>=1994)\n"
- + "public AnnotationTypeUsage​()</pre>",
+ + "public AnnotationTypeUsage()</pre>",
// METHOD
"<pre><a href=\"../pkg/AnnotationType.html\" "
+ "title=\"annotation in pkg\">@AnnotationType</a>("
@@ -557,7 +557,7 @@
+ "=\"Method Annotation\",\n"
+ " <a href=\"../pkg/AnnotationType.html#required--\">"
+ "required</a>=1994)\n"
- + "public void method​()</pre>",
+ + "public void method()</pre>",
// METHOD PARAMS
"<pre>public void methodWithParams​("
+ "<a href=\"../pkg/AnnotationType.html\" title=\"annotation in pkg\">"
@@ -630,11 +630,11 @@
// CONSTRUCTOR
"<a href=\"../pkg/AnnotationTypeUndocumented.html\" title=\"annotation in pkg\">@AnnotationTypeUndocumented</a>(<a href=\"../pkg/AnnotationType.html#optional\">optional</a>=\"Constructor Annotation\",\n"
+ " <a href=\"../pkg/AnnotationType.html#required\">required</a>=1994)\n"
- + "public <span class=\"typeNameLabel\">AnnotationTypeUsage</span>​()",
+ + "public <span class=\"typeNameLabel\">AnnotationTypeUsage</span>()",
// METHOD
"<a href=\"../pkg/AnnotationTypeUndocumented.html\" title=\"annotation in pkg\">@AnnotationTypeUndocumented</a>(<a href=\"../pkg/AnnotationType.html#optional\">optional</a>=\"Method Annotation\",\n"
+ " <a href=\"../pkg/AnnotationType.html#required\">required</a>=1994)\n"
- + "public void <span class=\"memberNameLabel\">method</span>​()");
+ + "public void <span class=\"memberNameLabel\">method</span>()");
//=================================
// Make sure annotation types do not
--- a/test/langtools/jdk/javadoc/doclet/testOptions/TestOptions.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testOptions/TestOptions.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4749567 8071982 8175200
+ * @bug 4749567 8071982 8175200 8186332
* @summary Test the output for -header, -footer, -nooverview, -nodeprecatedlist, -nonavbar, -notree, -stylesheetfile options.
* @author Bhavesh Patel
* @library ../lib
@@ -148,7 +148,7 @@
"<pre>public java.lang.Object <a href="
+ "\"../src-html/linksource/Properties.html#line.31\">someProperty</a></pre>",
"<pre>public java.lang.Object <a href="
- + "\"../src-html/linksource/Properties.html#line.31\">someProperty</a>​()</pre>");
+ + "\"../src-html/linksource/Properties.html#line.31\">someProperty</a>()</pre>");
checkOutput("src-html/linksource/Properties.html", true,
"<title>Source code</title>",
@@ -161,9 +161,9 @@
"<pre>public int <a href=\"../src-html/linksource/SomeClass.html#line.31\">"
+ "field</a></pre>",
"<pre>public <a href=\"../src-html/linksource/SomeClass.html#line.33\">"
- + "SomeClass</a>​()</pre>",
+ + "SomeClass</a>()</pre>",
"<pre>public int <a href=\"../src-html/linksource/SomeClass.html#line.36\">"
- + "method</a>​()</pre>");
+ + "method</a>()</pre>");
checkOutput("src-html/linksource/SomeClass.html", true,
"<title>Source code</title>",
--- a/test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestBadOverride.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestBadOverride.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8174839 8175200
+ * @bug 8174839 8175200 8186332
* @summary Bad overriding method should not crash
* @library ../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@@ -52,7 +52,7 @@
checkOutput("pkg4/Foo.html", true,
"<li class=\"blockList\">\n"
+ "<h4>toString</h4>\n"
- + "<pre>public void toString​()</pre>\n"
+ + "<pre>public void toString()</pre>\n"
+ "<div class=\"block\">Why can't I do this ?</div>\n"
+ "</li>");
}
--- a/test/langtools/jdk/javadoc/doclet/testPackageDeprecation/TestPackageDeprecation.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testPackageDeprecation/TestPackageDeprecation.java Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6492694 8026567 8048351 8162363
+ * @bug 6492694 8026567 8048351 8162363 8183511 8169819 8074407
* @summary Test package deprecation.
* @author bpatel
* @library ../lib/
@@ -48,13 +48,12 @@
checkExit(Exit.OK);
checkOutput("pkg1/package-summary.html", true,
- "<div class=\"deprecatedContent\"><span class=\"deprecatedLabel\">Deprecated.</span>\n" +
- "<div class=\"block\"><span class=\"deprecationComment\">This package is Deprecated." +
- "</span></div>"
+ "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">This package is Deprecated.</div>"
);
checkOutput("deprecated-list.html", true,
- "<li><a href=\"#package\">Deprecated Packages</a></li>"
+ "<li><a href=\"#package\">Packages</a></li>"
);
}
--- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8141492 8071982 8141636 8147890 8166175 8168965 8176794 8175218 8147881 8181622 8182263
+ * @bug 8141492 8071982 8141636 8147890 8166175 8168965 8176794 8175218 8147881 8181622 8182263 8074407
* @summary Test the search feature of javadoc.
* @author bpatel
* @library ../lib
@@ -324,10 +324,10 @@
"<dt><span class=\"memberNameLink\"><a href=\"pkg2/TestEnum.html#TWO\">TWO</a></span> - "
+ "pkg2.<a href=\"pkg2/TestEnum.html\" title=\"enum in pkg2\">TestEnum</a></dt>");
checkOutput("index-all.html", true,
- "<div class=\"block\"><span class=\"deprecationComment\">class_test1 passes. Search tag"
- + " <a id=\"SearchTagDeprecatedClass\" class=\"searchTagResult\">SearchTagDeprecatedClass</a></span></div>",
- "<div class=\"block\"><span class=\"deprecationComment\">error_test3 passes. Search tag for\n"
- + " method <a id=\"SearchTagDeprecatedMethod\" class=\"searchTagResult\">SearchTagDeprecatedMethod</a></span></div>");
+ "<div class=\"deprecationComment\">class_test1 passes. Search tag"
+ + " <a id=\"SearchTagDeprecatedClass\" class=\"searchTagResult\">SearchTagDeprecatedClass</a></div>",
+ "<div class=\"deprecationComment\">error_test3 passes. Search tag for\n"
+ + " method <a id=\"SearchTagDeprecatedMethod\" class=\"searchTagResult\">SearchTagDeprecatedMethod</a></div>");
}
void checkSplitIndex() {
@@ -403,10 +403,10 @@
+ "SearchTagDeprecatedClass</a></span> - Search tag in pkg2.TestClass</dt>",
"<dt><span class=\"searchTagLink\"><a href=\"pkg/package-summary.html#SingleWord\">"
+ "SingleWord</a></span> - Search tag in pkg</dt>",
- "<div class=\"block\"><span class=\"deprecationComment\">class_test1 passes. Search tag"
- + " <a id=\"SearchTagDeprecatedClass\">SearchTagDeprecatedClass</a></span></div>",
- "<div class=\"block\"><span class=\"deprecationComment\">error_test3 passes. Search tag for\n"
- + " method <a id=\"SearchTagDeprecatedMethod\">SearchTagDeprecatedMethod</a></span></div>");
+ "<div class=\"deprecationComment\">class_test1 passes. Search tag"
+ + " <a id=\"SearchTagDeprecatedClass\">SearchTagDeprecatedClass</a></div>",
+ "<div class=\"deprecationComment\">error_test3 passes. Search tag for\n"
+ + " method <a id=\"SearchTagDeprecatedMethod\">SearchTagDeprecatedMethod</a></div>");
checkOutput("index-all.html", true,
"<dt><span class=\"searchTagLink\"><a href=\"pkg2/TestEnum.html#searchphrasedeprecated\">"
+ "search phrase deprecated</a></span> - Search tag in pkg2.TestEnum.ONE</dt>",
@@ -434,10 +434,10 @@
+ "search phrase deprecated</a></span> - Search tag in pkg2.TestEnum.ONE</dt>",
"<dt><span class=\"searchTagLink\"><a href=\"pkg2/TestError.html#SearchTagDeprecatedMethod\">"
+ "SearchTagDeprecatedMethod</a></span> - Search tag in pkg2.TestError</dt>",
- "<div class=\"block\"><span class=\"deprecationComment\">class_test1 passes. Search tag"
- + " <a id=\"SearchTagDeprecatedClass\">SearchTagDeprecatedClass</a></span></div>",
- "<div class=\"block\"><span class=\"deprecationComment\">error_test3 passes. Search tag for\n"
- + " method <a id=\"SearchTagDeprecatedMethod\">SearchTagDeprecatedMethod</a></span></div>");
+ "<div class=\"deprecationComment\">class_test1 passes. Search tag"
+ + " <a id=\"SearchTagDeprecatedClass\">SearchTagDeprecatedClass</a></div>",
+ "<div class=\"deprecationComment\">error_test3 passes. Search tag for\n"
+ + " method <a id=\"SearchTagDeprecatedMethod\">SearchTagDeprecatedMethod</a></div>");
}
void checkJavaFXOutput() {
--- a/test/langtools/jdk/javadoc/doclet/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6802694 8025633 8026567
+ * @bug 6802694 8025633 8026567 8183511 8074407
* @summary This test verifies deprecation info in serialized-form.html.
* @author Bhavesh Patel
* @library ../lib
@@ -99,10 +99,11 @@
+ "<dd><a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
+ "<code>C1.setUndecorated(boolean)</code></a></dd>\n"
+ "</dl>",
- "<span class=\"deprecatedLabel\">Deprecated.</span>"
- + " <span class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ "<span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ " <a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
- + "<code>setUndecorated(boolean)</code></a>.</span></div>\n"
+ + "<code>setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ "<div class=\"block\">This field indicates whether the C1 "
+ "is undecorated.</div>\n"
+ " \n"
@@ -114,17 +115,18 @@
+ "<dd><a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
+ "<code>C1.setUndecorated(boolean)</code></a></dd>\n"
+ "</dl>",
- "<span class=\"deprecatedLabel\">Deprecated.</span>"
- + " <span class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ "<span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">As of JDK version 1.5, replaced by\n"
+ " <a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
- + "<code>setUndecorated(boolean)</code></a>.</span></div>\n"
+ + "<code>setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ "<div class=\"block\">Reads the object stream.</div>\n"
+ "<dl>\n"
+ "<dt><span class=\"throwsLabel\">Throws:</span></dt>\n"
+ "<dd><code>java.io.IOException</code> - on error</dd>\n"
+ "</dl>",
"<span class=\"deprecatedLabel\">Deprecated.</span>"
- + " </div>\n"
+ + "</div>\n"
+ "<div class=\"block\">"
+ "The name for this class.</div>");
}
@@ -135,16 +137,20 @@
void checkNoComment(boolean expectFound) {
checkOutput("serialized-form.html", expectFound,
"<pre>boolean undecorated</pre>\n"
- + "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span> <span class=\"deprecationComment\">"
+ + "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">"
+ "As of JDK version 1.5, replaced by\n"
+ " <a href=\"pkg1/C1.html#setUndecorated-boolean-\"><code>"
- + "setUndecorated(boolean)</code></a>.</span></div>\n"
+ + "setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ "</li>",
"<span class=\"deprecatedLabel\">"
- + "Deprecated.</span> <span class=\"deprecationComment\">As of JDK version"
+ + "Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">As of JDK version"
+ " 1.5, replaced by\n"
+ " <a href=\"pkg1/C1.html#setUndecorated-boolean-\">"
- + "<code>setUndecorated(boolean)</code></a>.</span></div>\n"
+ + "<code>setUndecorated(boolean)</code></a>.</div>\n"
+ + "</div>\n"
+ "</li>");
}
--- a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java Wed Oct 04 20:01:19 2017 +0000
@@ -24,7 +24,7 @@
/*
* @test
* @bug 4494033 7028815 7052425 8007338 8023608 8008164 8016549 8072461 8154261 8162363 8160196 8151743 8177417
- * 8175218 8176452 8181215 8182263
+ * 8175218 8176452 8181215 8182263 8183511 8169819
* @summary Run tests on doclet stylesheet.
* @author jamieh
* @library ../lib
@@ -183,9 +183,21 @@
+ "th.colFirst a:link, th.colFirst a:visited,\n"
+ "th.colSecond a:link, th.colSecond a:visited,\n"
+ "th.colConstructorName a:link, th.colConstructorName a:visited,\n"
+ + "th.colDeprecatedItemName a:link, th.colDeprecatedItemName a:visited, \n"
+ ".constantValuesContainer td a:link, .constantValuesContainer td a:visited {\n"
+ " font-weight:bold;\n"
+ "}",
+ ".deprecationBlock {\n"
+ + " font-size:14px;\n"
+ + " font-family:'DejaVu Serif', Georgia, \"Times New Roman\", Times, serif;\n"
+ + " border-style:solid;\n"
+ + " border-width:thin;\n"
+ + " border-radius:10px;\n"
+ + " padding:10px;\n"
+ + " margin-bottom:10px;\n"
+ + " margin-right:10px;\n"
+ + " display:inline-block;\n"
+ + "}",
"#reset {\n"
+ " background-color: rgb(255,255,255);\n"
+ " background-image:url('resources/x.png');\n"
--- a/test/langtools/jdk/javadoc/doclet/testSummaryTag/TestSummaryTag.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testSummaryTag/TestSummaryTag.java Wed Oct 04 20:01:19 2017 +0000
@@ -25,7 +25,7 @@
/*
* @test
- * @bug 8173425
+ * @bug 8173425 8186332
* @summary tests for the summary tag behavior
* @library ../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
@@ -87,7 +87,7 @@
checkOutput("p1/A.html", true,
"<li class=\"blockList\">\n"
+ "<h4>m3</h4>\n"
- + "<pre>public void m3​()</pre>\n"
+ + "<pre>public void m3()</pre>\n"
+ "<div class=\"block\">First sentence some text maybe second sentence.</div>\n"
+ "</li>\n"
);
--- a/test/langtools/jdk/javadoc/doclet/testTagOutput/TestTagOutput.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testTagOutput/TestTagOutput.java Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8026370 8026567
+ * @bug 8026370 8026567 8183511 8074407
* @summary This test checks the generated tag output.
* @author Bhavesh Patel
* @library ../lib
@@ -47,12 +47,14 @@
checkExit(Exit.OK);
checkOutput("pkg1/DeprecatedTag.html", true,
- "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span> </div>",
- "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated.</span> " +
- "<span class=\"deprecationComment\">Do not use this.</span></div>");
+ "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated.</span></div>",
+ "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\">Do not use this.</div>\n"
+ + "</div>");
checkOutput("pkg1/DeprecatedTag.html", false,
- "<div class=\"block\"><span class=\"deprecatedLabel\">Deprecated." +
- "</span> <span class=\"deprecationComment\"></span></div>");
+ "<div class=\"deprecationBlock\"><span class=\"deprecatedLabel\">Deprecated.</span>\n"
+ + "<div class=\"deprecationComment\"></div>\n"
+ + "</div>");
}
}
--- a/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8005091 8009686 8025633 8026567 6469562 8071982 8071984 8162363 8175200
+ * @bug 8005091 8009686 8025633 8026567 6469562 8071982 8071984 8162363 8175200 8186332
* @summary Make sure that type annotations are displayed correctly
* @author Bhavesh Patel
* @library ../lib
@@ -155,17 +155,17 @@
checkOutput("typeannos/MtdDefaultScope.html", true,
"<pre>public <T> <a href=\"../typeannos/MRtnA.html\" "
+ "title=\"annotation in typeannos\">@MRtnA</a> java.lang.String"
- + " method​()</pre>",
+ + " method()</pre>",
// When JDK-8068737 is fixed, we should change the order
"<pre><a href=\"../typeannos/MRtnA.html\" title=\"annotation in typeannos\">"
+ "@MRtnA</a> java.lang.String "
+ "<a href=\"../typeannos/MRtnB.html\" title=\"annotation in typeannos\">@MRtnB</a> [] "
+ "<a href=\"../typeannos/MRtnA.html\" title=\"annotation in typeannos\">@MRtnA</a> []"
- + " array2Deep​()</pre>",
+ + " array2Deep()</pre>",
"<pre><a href=\"../typeannos/MRtnA.html\" title=\"annotation in "
- + "typeannos\">@MRtnA</a> java.lang.String[][] array2​()</pre>");
+ + "typeannos\">@MRtnA</a> java.lang.String[][] array2()</pre>");
checkOutput("typeannos/MtdModifiedScoped.html", true,
"<pre>public final <a href=\"../typeannos/MtdParameterized.html\" "
@@ -177,25 +177,25 @@
+ "String,<a href=\"../typeannos/MRtnB.html\" title=\"annotation in "
+ "typeannos\">@MRtnB</a> java.lang.String>,<a href=\"../typeannos/"
+ "MRtnB.html\" title=\"annotation in typeannos\">@MRtnB</a> java."
- + "lang.String> nestedMtdParameterized​()</pre>");
+ + "lang.String> nestedMtdParameterized()</pre>");
// Test for type annotations on method type parameters (MethodTypeParameters.java).
checkOutput("typeannos/UnscopedUnmodified.html", true,
"<pre><K extends <a href=\"../typeannos/MTyParamA.html\" title=\""
+ "annotation in typeannos\">@MTyParamA</a> java.lang.String>"
- + " void methodExtends​()</pre>",
+ + " void methodExtends()</pre>",
"<pre><K extends <a href=\"../typeannos/MTyParamA.html\" title=\""
+ "annotation in typeannos\">@MTyParamA</a> <a href=\"../typeannos/"
+ "MtdTyParameterized.html\" title=\"class in typeannos\">"
+ "MtdTyParameterized</a><<a href=\"../typeannos/MTyParamB.html\" "
+ "title=\"annotation in typeannos\">@MTyParamB</a> java.lang.String"
- + ">> void nestedExtends​()</pre>");
+ + ">> void nestedExtends()</pre>");
checkOutput("typeannos/PublicModifiedMethods.html", true,
"<pre>public final <K extends <a href=\"../typeannos/"
+ "MTyParamA.html\" title=\"annotation in typeannos\">@MTyParamA</a> "
- + "java.lang.String> void methodExtends​()</pre>",
+ + "java.lang.String> void methodExtends()</pre>",
"<pre>public final <K extends <a href=\"../typeannos/"
+ "MTyParamA.html\" title=\"annotation in typeannos\">@MTyParamA</a> "
@@ -204,7 +204,7 @@
+ "typeannos/MtdTyParameterized.html\" title=\"class in typeannos\">"
+ "MtdTyParameterized</a><<a href=\"../typeannos/MTyParamB.html\" "
+ "title=\"annotation in typeannos\">@MTyParamB</a> java.lang.String"
- + ">> void dual​()</pre>");
+ + ">> void dual()</pre>");
// Test for type annotations on parameters (Parameters.java).
checkOutput("typeannos/Parameters.html", true,
@@ -236,11 +236,11 @@
// Test for type annotations on throws (Throws.java).
checkOutput("typeannos/ThrDefaultUnmodified.html", true,
- "<pre>void oneException​()\n"
+ "<pre>void oneException()\n"
+ " throws <a href=\"../typeannos/ThrA.html\" title=\""
+ "annotation in typeannos\">@ThrA</a> java.lang.Exception</pre>",
- "<pre>void twoExceptions​()\n"
+ "<pre>void twoExceptions()\n"
+ " throws <a href=\"../typeannos/ThrA.html\" title=\""
+ "annotation in typeannos\">@ThrA</a> java.lang.RuntimeException,\n"
+ " <a href=\"../typeannos/ThrA.html\" title=\""
@@ -258,12 +258,12 @@
+ "title=\"annotation in typeannos\">@ThrA</a> java.lang.Exception</pre>");
checkOutput("typeannos/ThrWithValue.html", true,
- "<pre>void oneException​()\n"
+ "<pre>void oneException()\n"
+ " throws <a href=\"../typeannos/ThrB.html\" title=\""
+ "annotation in typeannos\">@ThrB</a>("
+ "\"m\") java.lang.Exception</pre>",
- "<pre>void twoExceptions​()\n"
+ "<pre>void twoExceptions()\n"
+ " throws <a href=\"../typeannos/ThrB.html\" title=\""
+ "annotation in typeannos\">@ThrB</a>("
+ "\"m\") java.lang.RuntimeException,\n"
@@ -275,7 +275,7 @@
"<pre><K,<a href=\"../typeannos/TyParaA.html\" title=\"annotation in typeannos\">"
+ "@TyParaA</a> V extends <a href=\"../typeannos/TyParaA.html\" "
+ "title=\"annotation in typeannos\">@TyParaA</a> "
- + "java.lang.String> void secondAnnotated​()</pre>"
+ + "java.lang.String> void secondAnnotated()</pre>"
);
// Test for type annotations on wildcard type (Wildcards.java).
@@ -288,7 +288,7 @@
"<pre><a href=\"../typeannos/MyList.html\" title=\"class in "
+ "typeannos\">MyList</a><? super <a href=\"../typeannos/WldA.html\" "
+ "title=\"annotation in typeannos\">@WldA</a> java.lang.String>"
- + " returnWcSuper​()</pre>");
+ + " returnWcSuper()</pre>");
checkOutput("typeannos/BoundWithValue.html", true,
"<pre>void wcSuper​(<a href=\"../typeannos/MyList.html\" title=\""
@@ -301,7 +301,7 @@
+ "typeannos\">MyList</a><? extends <a href=\"../typeannos/WldB."
+ "html\" title=\"annotation in typeannos\">@WldB</a>("
+ "\"m\") java.lang.String"
- + "> returnWcExtends​()</pre>");
+ + "> returnWcExtends()</pre>");
// Test for receiver annotations (Receivers.java).
checkOutput("typeannos/DefaultUnmodified.html", true,
@@ -396,7 +396,7 @@
+ "\"../typeannos/RepConstructorB.html\" title=\"annotation in typeannos"
+ "\">@RepConstructorB</a> <a href=\"../typeannos/RepConstructorB.html"
+ "\" title=\"annotation in typeannos\">@RepConstructorB</a>\n"
- + "RepeatingOnConstructor​()</pre>",
+ + "RepeatingOnConstructor()</pre>",
"<pre><a href=\"../typeannos/RepConstructorA.html\" title=\"annotation in typeannos"
+ "\">@RepConstructorA</a> <a href=\"../typeannos/RepConstructorA.html"
@@ -574,7 +574,7 @@
checkOutput("typeannos/RepeatingOnMethod.html", true,
"<code>(package private) java.lang.String</code></td>\n<th class=\"colSecond\" scope=\"row\">"
+ "<code><span class=\"memberNameLink\"><a href="
- + "\"../typeannos/RepeatingOnMethod.html#test1--\">test1</a></span>​()</code>",
+ + "\"../typeannos/RepeatingOnMethod.html#test1--\">test1</a></span>()</code>",
"<code>(package private) <a href=\"../typeannos/RepTypeUseA.html\" "
+ "title=\"annotation in typeannos\">@RepTypeUseA</a> <a href="
@@ -584,7 +584,7 @@
+ "\" title=\"annotation in typeannos\">@RepTypeUseB</a> java.lang.String</code>"
+ "</td>\n<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
+ "<a href=\"../typeannos/RepeatingOnMethod.html#test2--\">test2</a>"
- + "</span>​()</code>",
+ + "</span>()</code>",
"<code>(package private) <a href=\"../typeannos/RepTypeUseA.html\" "
+ "title=\"annotation in typeannos\">@RepTypeUseA</a> <a href="
@@ -594,7 +594,7 @@
+ "title=\"annotation in typeannos\">@RepTypeUseB</a> java.lang.String</code>"
+ "</td>\n<th class=\"colSecond\" scope=\"row\"><code><span class=\"memberNameLink\">"
+ "<a href=\"../typeannos/RepeatingOnMethod.html#test3--\">test3</a>"
- + "</span>​()</code>",
+ + "</span>()</code>",
"<code>(package private) <a href=\"../typeannos/RepAllContextsA.html\" "
+ "title=\"annotation in typeannos\">@RepAllContextsA</a> <a href="
@@ -604,7 +604,7 @@
+ "\"../typeannos/RepAllContextsB.html\" title=\"annotation in typeannos\">"
+ "@RepAllContextsB</a> java.lang.String</code></td>\n<th class=\"colSecond\" scope=\"row\">"
+ "<code><span class=\"memberNameLink\"><a href=\"../typeannos/RepeatingOnMethod.html"
- + "#test4--\">test4</a></span>​()</code>",
+ + "#test4--\">test4</a></span>()</code>",
"<code><span class=\"memberNameLink\"><a href=\"../typeannos/RepeatingOnMethod.html"
+ "#test5-java.lang.String-java.lang.String...-\">test5</a></span>"
@@ -621,13 +621,13 @@
+ "\"annotation in typeannos\">@RepMethodA</a>\n<a href=\"../typeannos/RepMethodB.html\""
+ " title=\"annotation in typeannos\">@RepMethodB</a> <a href="
+ "\"../typeannos/RepMethodB.html\" title=\"annotation in typeannos\">"
- + "@RepMethodB</a>\njava.lang.String test1​()",
+ + "@RepMethodB</a>\njava.lang.String test1()",
"<a href=\"../typeannos/RepTypeUseA.html\" title=\"annotation in typeannos\">"
+ "@RepTypeUseA</a> <a href=\"../typeannos/RepTypeUseA.html\" title="
+ "\"annotation in typeannos\">@RepTypeUseA</a> <a href=\"../typeannos/RepTypeUseB.html\" "
+ "title=\"annotation in typeannos\">@RepTypeUseB</a> <a href=\"../typeannos/RepTypeUseB.html\" "
- + "title=\"annotation in typeannos\">@RepTypeUseB</a> java.lang.String test2​()",
+ + "title=\"annotation in typeannos\">@RepTypeUseB</a> java.lang.String test2()",
"<a href=\"../typeannos/RepMethodA.html\" title=\"annotation in typeannos\">"
+ "@RepMethodA</a> <a href=\"../typeannos/RepMethodA.html\" title="
@@ -639,7 +639,7 @@
+ "title=\"annotation in typeannos\">@RepTypeUseA</a> <a href="
+ "\"../typeannos/RepTypeUseB.html\" title=\"annotation in typeannos\">"
+ "@RepTypeUseB</a> <a href=\"../typeannos/RepTypeUseB.html\" title="
- + "\"annotation in typeannos\">@RepTypeUseB</a> java.lang.String test3​()",
+ + "\"annotation in typeannos\">@RepTypeUseB</a> java.lang.String test3()",
"<a href=\"../typeannos/RepAllContextsA.html\" title=\"annotation in typeannos\">"
+ "@RepAllContextsA</a> <a href=\"../typeannos/RepAllContextsA.html\" "
@@ -652,7 +652,7 @@
+ "title=\"annotation in typeannos\">@RepAllContextsA</a> <a href="
+ "\"../typeannos/RepAllContextsB.html\" title=\"annotation in typeannos\">"
+ "@RepAllContextsB</a> <a href=\"../typeannos/RepAllContextsB.html\" "
- + "title=\"annotation in typeannos\">@RepAllContextsB</a> java.lang.String test4​()",
+ + "title=\"annotation in typeannos\">@RepAllContextsB</a> java.lang.String test4()",
"java.lang.String test5​(<a href=\"../typeannos/RepTypeUseA.html\" "
+ "title=\"annotation in typeannos\">@RepTypeUseA</a> <a href="
@@ -697,7 +697,7 @@
"<code>(package private) java.lang.String</code></td>\n<th class=\"colSecond\" scope=\"row\"><code>"
+ "<span class=\"memberNameLink\"><a href=\"../typeannos/RepeatingOnTypeParametersBoundsTypeArgumentsOnMethod.html#"
- + "test--\">test</a></span>​()</code>",
+ + "test--\">test</a></span>()</code>",
"java.lang.String test​(<a href=\"../typeannos/RepTypeUseA.html\" "
+ "title=\"annotation in typeannos\">@RepTypeUseA</a> <a href="
@@ -718,6 +718,6 @@
+ "\"annotation in typeannos\">@RepMethodA</a>\n<a href=\"../typeannos/RepMethodB.html"
+ "\" title=\"annotation in typeannos\">@RepMethodB</a> <a href="
+ "\"../typeannos/RepMethodB.html\" title=\"annotation in typeannos\">"
- + "@RepMethodB</a>\nvoid test​()");
+ + "@RepMethodB</a>\nvoid test()");
}
}
--- a/test/langtools/jdk/javadoc/doclet/testUseOption/TestUseOption.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testUseOption/TestUseOption.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4496290 4985072 7006178 7068595 8016328 8050031 8048351 8081854 8071982 8162363 8175200
+ * @bug 4496290 4985072 7006178 7068595 8016328 8050031 8048351 8081854 8071982 8162363 8175200 8186332
* @summary A simple test to ensure class-use files are correct.
* @author jamieh
* @library ../lib
@@ -134,7 +134,7 @@
"<td class=\"colFirst\"><code>void</code></td>\n<th class=\"colSecond\" scope=\"row\"><span class="
+ "\"typeNameLabel\">C1.</span><code><span class=\"memberNameLink\">"
+ "<a href=\"../../pkg1/C1.html#methodInC1ThrowsThrowable--\">methodInC1ThrowsThrowable"
- + "</a></span>​()</code></th>"
+ + "</a></span>()</code></th>"
);
}
--- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110
+ * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466
* @summary Test Completion and Documentation
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
@@ -645,6 +645,22 @@
assertCompletion("Foo.m(new Baz<>(|", true, "str");
}
+ public void testIntersection() {
+ assertEval("<Z extends Runnable & CharSequence> Z get() { return null; }");
+ assertEval("var v = get();");
+ assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of());
+ assertCompletion("Runnable r = |", true, "get()", "v");
+ assertCompletion("CharSequence r = |", true, "get()", "v");
+ assertCompletion("Number r = |", true);
+ }
+
+ public void testAnonymous() {
+ assertEval("var v = new Runnable() { public void run() { } public int length() { return 0; } };");
+ assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of());
+ assertCompletion("Runnable r = |", true, "v");
+ assertCompletion("CharSequence r = |", true);
+ }
+
@BeforeMethod
public void setUp() {
super.setUp();
--- a/test/langtools/jdk/jshell/ToolSimpleTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/jshell/ToolSimpleTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508
+ * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466
* @summary Simple jshell tool tests
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
@@ -740,4 +740,26 @@
(a) -> assertCommandOutputContains(a, "1234", "==> 1234")
);
}
+
+ @Test
+ public void testIntersection() {
+ test(
+ (a) -> assertCommandOutputContains(a, "<Z extends Runnable&CharSequence> Z get1() { return null; }", "get1()"),
+ (a) -> assertCommandOutputContains(a, "var g1 = get1()", "g1"),
+ (a) -> assertCommand(a, "/vars g1", "| CharSequence&Runnable g1 = null"),
+ (a) -> assertCommandOutputContains(a, "<Z extends Number&CharSequence> Z get2() { return null; }", "get2()"),
+ (a) -> assertCommandOutputContains(a, "var g2 = get2()", "g2"),
+ (a) -> assertCommand(a, "/vars g2", "| Number&CharSequence g2 = null")
+ );
+ }
+
+ @Test
+ public void testAnonymous() {
+ test(
+ (a) -> assertCommandOutputContains(a, "var r1 = new Object() {}", "r1"),
+ (a) -> assertCommandOutputContains(a, "/vars r1", "| <anonymous class extending Object> r1 = "),
+ (a) -> assertCommandOutputContains(a, "var r2 = new Runnable() { public void run() { } }", "r2"),
+ (a) -> assertCommandOutputContains(a, "/vars r2", "| <anonymous class implementing Runnable> r2 = ")
+ );
+ }
}
--- a/test/langtools/jdk/jshell/VariablesTest.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/jdk/jshell/VariablesTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8144903
+ * @bug 8144903 8177466
* @summary Tests for EvaluationState.variables
* @build KullaTesting TestingInputStream ExpectedDiagnostic
* @run testng VariablesTest
@@ -337,4 +337,30 @@
assertEquals(unr.get(0), "class undefined");
assertVariables(variable("undefined", "d"));
}
+
+ public void lvti() {
+ assertEval("var d = 234;", "234");
+ assertEval("class Test<T> { T[][] get() { return null; } }", added(VALID));
+ assertEval("Test<? extends String> test() { return new Test<>(); }", added(VALID));
+ assertEval("var t = test().get();", added(VALID));
+ assertEval("<Z extends Runnable & CharSequence> Z get1() { return null; }", added(VALID));
+ assertEval("var i1 = get1();", added(VALID));
+ assertEval("void t1() { i1.run(); i1.length(); }", added(VALID));
+ assertEval("i1 = 1;", DiagCheck.DIAG_ERROR, DiagCheck.DIAG_OK, ste(MAIN_SNIPPET, NONEXISTENT, REJECTED, false, null));
+ assertEval("<Z extends Number & CharSequence> Z get2() { return null; }", added(VALID));
+ assertEval("var i2 = get2();", added(VALID));
+ assertEval("void t2() { i2.length(); }", added(VALID));
+ assertEval("var r1 = new Runnable() { public void run() { } public String get() { return \"good\"; } };", added(VALID));
+ assertEval("Runnable r2 = r1;");
+ assertEval("r1.get()", "\"good\"");
+ assertEval("var v = r1.get();", "\"good\"");
+ assertEval("var r3 = new java.util.ArrayList<String>(42) { public String get() { return \"good\"; } };", added(VALID));
+ assertEval("r3.get()", "\"good\"");
+ assertEval("class O { public class Inner { public String test() { return \"good\"; } } }");
+ assertEval("var r4 = new O().new Inner() { public String get() { return \"good\"; } };");
+ assertEval("r4.get()", "\"good\"");
+ assertEval("class O2 { public class Inner { public Inner(int i) { } public String test() { return \"good\"; } } }");
+ assertEval("var r5 = new O2().new Inner(1) { public String get() { return \"good\"; } };");
+ assertEval("r5.get()", "\"good\"");
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/T8187978/FilterOutCandidatesForDiagnosticsTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8187978
+ * @summary javac can show overload error messages that include non-valid candidates
+ * @compile/fail/ref=FilterOutCandidatesForDiagnosticsTest.out -XDrawDiagnostics FilterOutCandidatesForDiagnosticsTest.java
+ */
+
+import java.util.*;
+
+class FilterOutCandidatesForDiagnosticsTest {
+ void test() {
+ make(new ArrayList<String>(), new ArrayList<Integer>()).add("");
+ }
+
+ <Z> Z make(Z z1, Z z2) {
+ return null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/T8187978/FilterOutCandidatesForDiagnosticsTest.out Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,2 @@
+FilterOutCandidatesForDiagnosticsTest.java:12:64: compiler.err.cant.apply.symbols: kindname.method, add, java.lang.String,{(compiler.misc.inapplicable.method: kindname.method, java.util.ArrayList, add(compiler.misc.type.captureof: 1, ? extends java.lang.Object&java.io.Serializable&java.lang.Comparable<? extends java.lang.Object&java.io.Serializable&java.lang.Comparable<?>>,java.lang.Object[],int), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, java.util.ArrayList, add(compiler.misc.type.captureof: 1, ? extends java.lang.Object&java.io.Serializable&java.lang.Comparable<? extends java.lang.Object&java.io.Serializable&java.lang.Comparable<?>>), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.String, compiler.misc.type.captureof: 1, ? extends java.lang.Object&java.io.Serializable&java.lang.Comparable<? extends java.lang.Object&java.io.Serializable&java.lang.Comparable<?>>))),(compiler.misc.inapplicable.method: kindname.method, java.util.ArrayList, add(int,compiler.misc.type.captureof: 1, ? extends java.lang.Object&java.io.Serializable&java.lang.Comparable<? extends java.lang.Object&java.io.Serializable&java.lang.Comparable<?>>), (compiler.misc.arg.length.mismatch))}
+1 error
--- a/test/langtools/tools/javac/capture/Martin.out Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/tools/javac/capture/Martin.out Wed Oct 04 20:01:19 2017 +0000
@@ -1,2 +1,2 @@
-Martin.java:15:11: compiler.err.cant.apply.symbols: kindname.method, addAll, java.util.List<compiler.misc.type.captureof: 1, ?>,{(compiler.misc.inapplicable.method: kindname.method, java.util.Collection, addAll(java.util.Collection<? extends compiler.misc.type.captureof: 2, ?>), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.util.List<compiler.misc.type.captureof: 1, ?>, java.util.Collection<? extends compiler.misc.type.captureof: 2, ?>))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, addAll(java.util.Collection<? extends compiler.misc.type.captureof: 2, ?>), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.util.List<compiler.misc.type.captureof: 1, ?>, java.util.Collection<? extends compiler.misc.type.captureof: 2, ?>))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, addAll(int,java.util.Collection<? extends compiler.misc.type.captureof: 2, ?>), (compiler.misc.arg.length.mismatch))}
+Martin.java:15:11: compiler.err.cant.apply.symbols: kindname.method, addAll, java.util.List<compiler.misc.type.captureof: 1, ?>,{(compiler.misc.inapplicable.method: kindname.method, java.util.List, addAll(java.util.Collection<? extends compiler.misc.type.captureof: 2, ?>), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.util.List<compiler.misc.type.captureof: 1, ?>, java.util.Collection<? extends compiler.misc.type.captureof: 2, ?>))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, addAll(int,java.util.Collection<? extends compiler.misc.type.captureof: 2, ?>), (compiler.misc.arg.length.mismatch))}
1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/IllegalRefToVarType.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,32 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.illegal.ref.to.var.type
+
+import java.util.List;
+
+class IllegalRefToVarType {
+ var<String> list() { return null; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalArrayMissingTarget.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.array.missing.target
+
+class LocalArrayMissingTarget {
+ void test() {
+ var x = { 1, 2, 3 };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalCantInferNull.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.cant.infer.null
+
+class LocalCantInferNull {
+ void test() {
+ var s = null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalLambdaMissingTarget.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.lambda.missing.target
+
+class LocalLambdaMissingTarget {
+ void test() {
+ var x = () -> { };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalMissingInit.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.missing.init
+
+class LocalMissingInit {
+ void test() {
+ var s;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalMrefMissingTarget.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.mref.missing.target
+
+class LocalMrefMissingTarget {
+ void test() {
+ var x = this::test;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalRedundantType.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// options: -XDfind=local
+// key: compiler.warn.local.redundant.type
+
+class LocalRedundantType {
+ void test() {
+ String s = "";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/LocalSelfRef.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.cant.infer.local.var.type
+// key: compiler.misc.local.self.ref
+
+class LocalSelfRef {
+ void test() {
+ var x = m(x);
+ }
+
+ String m(String s) { return s; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/VarNotAllowed.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,28 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.var.not.allowed
+
+class var { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/VarNotAllowedArray.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,32 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.var.not.allowed.array
+
+class VarNotAllowedArray {
+ void test(String[] s) {
+ var[] x = s;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/VarNotAllowedCompound.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.var.not.allowed.compound
+
+class VarNotAllowedCompound {
+ void test() {
+ var x = 1, y = 2;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/VarNotAllowedHere.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,30 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.var.not.allowed.here
+
+class VarNotAllowedField {
+ var s = "";
+}
--- a/test/langtools/tools/javac/lambda/8019480/T8019480.out Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/tools/javac/lambda/8019480/T8019480.out Wed Oct 04 20:01:19 2017 +0000
@@ -1,3 +1,3 @@
-T8019480.java:21:34: compiler.err.cant.apply.symbols: kindname.method, add, java.lang.Object,{(compiler.misc.inapplicable.method: kindname.method, java.util.Collection, add(U), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, U))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, add(U), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, U))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, add(int,U), (compiler.misc.arg.length.mismatch))}
+T8019480.java:21:34: compiler.err.cant.apply.symbols: kindname.method, add, java.lang.Object,{(compiler.misc.inapplicable.method: kindname.method, java.util.List, add(U), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.Object, U))),(compiler.misc.inapplicable.method: kindname.method, java.util.List, add(int,U), (compiler.misc.arg.length.mismatch))}
T8019480.java:21:46: compiler.err.report.access: clone(), protected, java.lang.Object
2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lambda/8188144/T8188144.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8188144
+ * @summary regression in method reference type-checking
+ */
+
+import java.util.function.BiFunction;
+
+public class T8188144 {
+ public static void main(String[] args) {
+ BiFunction<String, String, String> format = String::format;
+ if (!format.apply("foo %s", "bar").endsWith("foo bar")) {
+ throw new AssertionError("Unexpected output!");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/BadLocalVarInferenceTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,33 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile/fail/ref=BadLocalVarInferenceTest.out -XDrawDiagnostics BadLocalVarInferenceTest.java
+ */
+
+class BadLocalVarInferenceTest {
+
+ interface Foo<X> {
+ void m(X x);
+ }
+
+ interface Supplier<X> {
+ void m(X x);
+ }
+
+ void test() {
+ var x;
+ var f = () -> { };
+ var m = this::l;
+ var g = null;
+ var d = d = 1;
+ var k = { 1 , 2 };
+ var l = new Foo<>() { //LHS was Foo<String>
+ @Override
+ void m(String s) { }
+ };
+ var s = f(x -> { x.charAt(0); }); //LHS was String
+ }
+
+ <Z> Z f(Supplier<Z> sz) { return null; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/BadLocalVarInferenceTest.out Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,10 @@
+BadLocalVarInferenceTest.java:19:13: compiler.err.cant.infer.local.var.type: x, (compiler.misc.local.missing.init)
+BadLocalVarInferenceTest.java:20:13: compiler.err.cant.infer.local.var.type: f, (compiler.misc.local.lambda.missing.target)
+BadLocalVarInferenceTest.java:21:13: compiler.err.cant.infer.local.var.type: m, (compiler.misc.local.mref.missing.target)
+BadLocalVarInferenceTest.java:22:13: compiler.err.cant.infer.local.var.type: g, (compiler.misc.local.cant.infer.null)
+BadLocalVarInferenceTest.java:23:13: compiler.err.cant.infer.local.var.type: d, (compiler.misc.local.self.ref)
+BadLocalVarInferenceTest.java:24:13: compiler.err.cant.infer.local.var.type: k, (compiler.misc.local.array.missing.target)
+BadLocalVarInferenceTest.java:25:29: compiler.err.does.not.override.abstract: compiler.misc.anonymous.class: BadLocalVarInferenceTest$1, m(java.lang.Object), BadLocalVarInferenceTest.Foo
+BadLocalVarInferenceTest.java:26:13: compiler.err.method.does.not.override.superclass
+BadLocalVarInferenceTest.java:29:27: compiler.err.cant.resolve.location.args: kindname.method, charAt, , int, (compiler.misc.location.1: kindname.variable, x, java.lang.Object)
+9 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/FoldingTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,47 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile/fail/ref=FoldingTest.out -XDrawDiagnostics FoldingTest.java
+ */
+class FoldingTest {
+
+ void testReachability() {
+ for(var i = 0; i < 3; i++) {
+ // ok
+ }
+ System.out.println("foo"); //this should be reachable
+ }
+
+ void testCase(String s) {
+ var c = "";
+ final String c2 = "" + c;
+ switch (s) {
+ case c: break; //error!
+ case c2: break; //error!
+ }
+ }
+
+ void testAnno() {
+ @Anno1(s1) //error
+ var s1 = "";
+ @Anno2(s2) //error
+ var s2 = "";
+ @Anno3(s3) //error
+ var s3 = "";
+ }
+
+ @interface Anno1 {
+ String value();
+ }
+ @interface Anno2 {
+ Class<?> value();
+ }
+ @interface Anno3 {
+ Foo value();
+ }
+
+ enum Foo {
+ A, B;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/FoldingTest.out Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,6 @@
+FoldingTest.java:20:18: compiler.err.string.const.req
+FoldingTest.java:21:18: compiler.err.string.const.req
+FoldingTest.java:26:16: compiler.err.attribute.value.must.be.constant
+FoldingTest.java:28:16: compiler.err.annotation.value.must.be.class.literal
+FoldingTest.java:30:16: compiler.err.enum.annotation.must.be.enum.constant
+5 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/ParserTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,71 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile -source 9 ParserTest.java
+ * @compile/fail/ref=ParserTest.out -XDrawDiagnostics ParserTest.java
+ */
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.function.Function;
+import java.util.List;
+
+class ParserTest<var> {
+ static class TestClass {
+ static class var { } //illegal
+ }
+
+ static class TestInterface {
+ interface var { } //illegal
+ }
+
+ static class TestEnum {
+ enum var { } //illegal
+ }
+
+ static class TestAnno {
+ @interface var { } //illegal
+ }
+
+ @Target(ElementType.TYPE_USE)
+ @interface TA { }
+
+ @interface DA { }
+
+ static class var extends RuntimeException { } //illegal
+
+ var x = null; //illegal
+
+ void test() {
+ var[] x1 = null; //illegal
+ var x2[] = null; //illegal
+ var[][] x3 = null; //illegal
+ var x4[][] = null; //illegal
+ var[] x5 = null; //illegal
+ var x6[] = null; //illegal
+ var@TA[]@TA[] x7 = null; //illegal
+ var x8@TA[]@TA[] = null; //illegal
+ var x9 = null, y = null; //illegal
+ final @DA var x10 = m(); //ok
+ @DA final var x11 = m(); //ok
+ }
+
+ var m() { //illegal
+ return null;
+ }
+
+ void test2(var x) { //error
+ List<var> l1; //error
+ List<? extends var> l2; //error
+ List<? super var> l3; //error
+ try {
+ Function<var, String> f = (var x2) -> ""; //error
+ } catch (var ex) { } //error
+ }
+
+ void test3(Object o) {
+ boolean b1 = o instanceof var; //error
+ Object o2 = (var)o; //error
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/ParserTest.out Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,25 @@
+ParserTest.java:14:18: compiler.err.var.not.allowed: var
+ParserTest.java:16:22: compiler.err.var.not.allowed: var
+ParserTest.java:20:19: compiler.err.var.not.allowed: var
+ParserTest.java:24:14: compiler.err.var.not.allowed: var
+ParserTest.java:28:20: compiler.err.var.not.allowed: var
+ParserTest.java:36:18: compiler.err.var.not.allowed: var
+ParserTest.java:38:5: compiler.err.var.not.allowed.here
+ParserTest.java:41:15: compiler.err.var.not.allowed.array
+ParserTest.java:42:13: compiler.err.var.not.allowed.array
+ParserTest.java:43:17: compiler.err.var.not.allowed.array
+ParserTest.java:44:13: compiler.err.var.not.allowed.array
+ParserTest.java:45:15: compiler.err.var.not.allowed.array
+ParserTest.java:46:13: compiler.err.var.not.allowed.array
+ParserTest.java:49:13: compiler.err.var.not.allowed.compound
+ParserTest.java:54:5: compiler.err.var.not.allowed.here
+ParserTest.java:58:16: compiler.err.var.not.allowed.here
+ParserTest.java:59:14: compiler.err.var.not.allowed.here
+ParserTest.java:60:24: compiler.err.var.not.allowed.here
+ParserTest.java:61:22: compiler.err.var.not.allowed.here
+ParserTest.java:63:22: compiler.err.var.not.allowed.here
+ParserTest.java:63:40: compiler.err.var.not.allowed.here
+ParserTest.java:64:18: compiler.err.var.not.allowed.here
+ParserTest.java:68:35: compiler.err.var.not.allowed.here
+ParserTest.java:69:22: compiler.err.var.not.allowed.here
+24 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/SelfRefTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,23 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile/fail/ref=SelfRefTest.out -XDrawDiagnostics SelfRefTest.java
+ */
+
+import java.util.function.Function;
+
+class SelfRefTest {
+
+ int q() { return 42; }
+ int m(int t) { return t; }
+
+ void test(boolean cond) {
+ var x = cond ? x : x; //error - self reference
+ var y = (Function<Integer, Integer>)(Integer y) -> y; //error - bad shadowing
+ var z = (Runnable)() -> { int z2 = m(z); }; //error - self reference
+ var w = new Object() { int w = 42; void test() { int w2 = w; } }; //ok
+ int u = u; //ok
+ int q = q(); //ok
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/SelfRefTest.out Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,4 @@
+SelfRefTest.java:16:12: compiler.err.cant.infer.local.var.type: x, (compiler.misc.local.self.ref)
+SelfRefTest.java:17:53: compiler.err.already.defined: kindname.variable, y, kindname.method, test(boolean)
+SelfRefTest.java:18:12: compiler.err.cant.infer.local.var.type: z, (compiler.misc.local.self.ref)
+3 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test /nodynamioccopyright/
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @compile -source 8 pkg/var.java
+ * @compile pkg/nested/var/A.java
+ * @compile/fail/ref=BadTypeReference.out -XDrawDiagnostics BadTypeReference.java
+ */
+
+import pkg.*;
+
+public class BadTypeReference {
+ void test(Object o) {
+ var<String> vs = null; //error
+ Object o2 = var.x; //error
+ pkg.nested.var.A a = new pkg.nested.var.A(); //ok
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/badTypeReference/BadTypeReference.out Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,3 @@
+BadTypeReference.java:39:9: compiler.err.illegal.ref.to.var.type: var
+BadTypeReference.java:40:21: compiler.err.illegal.ref.to.var.type: var
+2 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/badTypeReference/pkg/nested/var/A.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package pkg.nested.var;
+
+public class A {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/badTypeReference/pkg/var.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package pkg;
+
+public class var {
+ public static Object x = "";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/InferredType.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,28 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public @interface InferredType {
+ String value();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/LocalVariableInferenceTester.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreePathScanner;
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTrees;
+import com.sun.tools.javac.code.Printer;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.CapturedType;
+import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.util.Log;
+
+import static javax.tools.StandardLocation.SOURCE_PATH;
+
+public class LocalVariableInferenceTester {
+
+ static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+ static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+ public static void main(String[] args) throws IOException {
+ try {
+ if (args.length != 1) {
+ System.err.println("Usage: LocalVariableInferenceTester <sourcefile>");
+ System.exit(1);
+ }
+ File path = new File(System.getProperty("test.src"));
+ fm.setLocation(SOURCE_PATH, Arrays.asList(path));
+ File input = new File(path, args[0]);
+ JavaFileObject jfo = fm.getJavaFileObjects(input).iterator().next();
+ new LocalVariableInferenceTester().compileAndCheck(jfo);
+ } finally {
+ fm.close();
+ }
+ }
+
+ int errors = 0;
+ int checks = 0;
+
+ void compileAndCheck(JavaFileObject input) throws IOException {
+ JavaCompiler c = ToolProvider.getSystemJavaCompiler();
+ JavacTask task = (JavacTask) c.getTask(null, fm, null, null, null, Arrays.asList(input));
+ JavacTrees trees = JavacTrees.instance(task);
+ Types types = Types.instance(((JavacTaskImpl)task).getContext());
+ Iterable<? extends CompilationUnitTree> roots = task.parse();
+ task.analyze(); //force attribution
+ Log log = Log.instance(((JavacTaskImpl)task).getContext());
+ errors += log.nerrors;
+ new LocalVarTypeChecker(trees, types).scan(roots, null);
+ System.err.println("Checks executed: " + checks);
+ if (errors != 0) {
+ throw new AssertionError("Errors were found");
+ }
+ }
+
+ void error(Tree node, String msg) {
+ System.err.println(node);
+ System.err.println("ERROR: " + msg);
+ errors++;
+ }
+
+ class LocalVarTypeChecker extends TreePathScanner<Void, Void> {
+
+ JavacTrees trees;
+ Types types;
+
+ LocalVarTypeChecker(JavacTrees trees, Types types) {
+ this.trees = trees;
+ this.types = types;
+ }
+
+ @Override
+ public Void visitVariable(VariableTree node, Void aVoid) {
+ Element e = trees.getElement(getCurrentPath());
+ if (e.getKind() == ElementKind.LOCAL_VARIABLE) {
+ TypeMirror type = e.asType();
+ InferredType inferredAnno = e.getAnnotation(InferredType.class);
+ if (inferredAnno != null) {
+ checks++;
+ String req = inferredAnno.value();
+ String found = new TypePrinter().visit((Type)type, null);
+ if (!req.equals(found)) {
+ error(node, "Inferred type mismatch; expected: " + req + " - found: " + found);
+ }
+ }
+ }
+ return super.visitVariable(node, null);
+ }
+
+ class TypePrinter extends Printer {
+
+ Map<Type, Integer> capturedIdMap = new HashMap<>();
+
+ @Override
+ protected String localize(Locale locale, String key, Object... args) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String visitCapturedType(CapturedType t, Locale locale) {
+ return "CAP#" + capturedVarId(t, locale);
+ }
+
+ @Override
+ protected String capturedVarId(CapturedType t, Locale locale) {
+ return String.valueOf(capturedIdMap.getOrDefault(t, capturedIdMap.size()));
+ }
+
+ @Override
+ public String visitClassType(ClassType t, Locale locale) {
+ if (!t.isCompound() && t.tsym.name.isEmpty()) {
+ return "#ANON(" + types.directSupertypes(t) + ")";
+ } else if (t.isCompound()) {
+ return "#INT(" + types.directSupertypes(t) + ")";
+ } else {
+ return super.visitClassType(t, locale);
+ }
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/NonDenotableTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,148 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @modules jdk.compiler/com.sun.source.tree
+ * jdk.compiler/com.sun.source.util
+ * jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build LocalVariableInferenceTester
+ * @run main LocalVariableInferenceTester NonDenotableTest.java
+ */
+import java.util.List;
+
+class NonDenotableTest {
+
+ static final String OBJECT = "java.lang.Object";
+ static final String STRING = "java.lang.String";
+ static final String ANON_OBJECT = "#ANON(java.lang.Object)";
+ static final String ANON_RUNNABLE = "#ANON(java.lang.Object,java.lang.Runnable)";
+ static final String LIST_EXT = "java.util.List<? extends java.lang.String>";
+ static final String LIST_SUP = "java.util.List<? super java.lang.String>";
+ static final String LIST_UNB = "java.util.List<?>";
+ static final String COMP_UNB = "java.lang.Comparable<?>";
+ static final String LIST_EXT_COMP_UNB = "java.util.List<? extends java.lang.Comparable<?>>";
+ static final String LIST_SUP_COMP_UNB = "java.util.List<? super java.lang.Comparable<?>>";
+ static final String INT_INTEGER_DOUBLE = "#INT(java.lang.Number,java.lang.Comparable<? extends java.lang.Number&java.lang.Comparable<?>>)";
+
+ void testExtends() {
+ @InferredType(LIST_EXT)
+ var s = extString();
+ for (@InferredType(LIST_EXT) var s2 = extString() ; ; ) { break; }
+ for (@InferredType(LIST_EXT) var s2 : extStringArr()) { break; }
+ for (@InferredType(LIST_EXT) var s2 : extStringIter()) { break; }
+ for (@InferredType(STRING) var s2 : extString()) { break; }
+ }
+
+ void testExtendsFbound() {
+ @InferredType(LIST_EXT_COMP_UNB)
+ var s = extFbound();
+ for (@InferredType(LIST_EXT_COMP_UNB) var s2 = extFbound() ; ; ) { break; }
+ for (@InferredType(LIST_EXT_COMP_UNB) var s2 : extFboundArr()) { break; }
+ for (@InferredType(LIST_EXT_COMP_UNB) var s2 : extFboundIter()) { break; }
+ for (@InferredType(COMP_UNB) var s2 : extFbound()) { break; }
+ }
+
+ void testSuperFbound() {
+ @InferredType(LIST_UNB)
+ var s = supFbound();
+ for (@InferredType(LIST_UNB) var s2 = supFbound() ; ; ) { break; }
+ for (@InferredType(LIST_UNB) var s2 : supFboundArr()) { break; }
+ for (@InferredType(LIST_UNB) var s2 : supFboundIter()) { break; }
+ for (@InferredType(OBJECT) var s2 : supFbound()) { break; }
+ }
+
+ void testSuper() {
+ @InferredType(LIST_SUP)
+ var s = supString();
+ for (@InferredType(LIST_SUP) var s2 = supString() ; ; ) { break; }
+ for (@InferredType(LIST_SUP) var s2 : supStringArr()) { break; }
+ for (@InferredType(LIST_SUP) var s2 : supStringIter()) { break; }
+ for (@InferredType(OBJECT) var s2 : supString()) { break; }
+ }
+
+ void testUnbound() {
+ @InferredType(LIST_UNB)
+ var s = unbString();
+ for (@InferredType(LIST_UNB) var s2 = unbString() ; ; ) { break; }
+ for (@InferredType(LIST_UNB) var s2 : unbStringArr()) { break; }
+ for (@InferredType(LIST_UNB) var s2 : unbStringIter()) { break; }
+ for (@InferredType(OBJECT) var s2 : unbString()) { break; }
+ }
+
+ void testAnonymousClass() {
+ @InferredType(ANON_OBJECT)
+ var o = new Object() { };
+ for (@InferredType(ANON_OBJECT) var s2 = new Object() { } ; ; ) { break; }
+ for (@InferredType(ANON_OBJECT) var s2 : arrayOf(new Object() { })) { break; }
+ for (@InferredType(ANON_OBJECT) var s2 : listOf(new Object() { })) { break; }
+ }
+
+ void testAnonymousInterface() {
+ @InferredType(ANON_RUNNABLE)
+ var r = new Runnable() { public void run() { } };
+ for (@InferredType(ANON_RUNNABLE) var s2 = new Runnable() { public void run() { } } ; ; ) { break; }
+ for (@InferredType(ANON_RUNNABLE) var s2 : arrayOf(new Runnable() { public void run() { } })) { break; }
+ for (@InferredType(ANON_RUNNABLE) var s2 : listOf(new Runnable() { public void run() { } })) { break; }
+ }
+
+ void testIntersection() {
+ @InferredType(INT_INTEGER_DOUBLE)
+ var c = choose(1, 1L);
+ for (@InferredType(INT_INTEGER_DOUBLE) var s2 = choose(1, 1L) ; ;) { break; }
+ for (@InferredType(INT_INTEGER_DOUBLE) var s2 : arrayOf(choose(1, 1L))) { break; }
+ for (@InferredType(INT_INTEGER_DOUBLE) var s2 : listOf(choose(1, 1L))) { break; }
+ }
+
+ List<? extends String> extString() { return null; }
+ List<? super String> supString() { return null; }
+ List<?> unbString() { return null; }
+
+ List<? extends String>[] extStringArr() { return null; }
+ List<? super String>[] supStringArr() { return null; }
+ List<?>[] unbStringArr() { return null; }
+
+ Iterable<? extends List<? extends String>> extStringIter() { return null; }
+ Iterable<? extends List<? super String>> supStringIter() { return null; }
+ Iterable<? extends List<?>> unbStringIter() { return null; }
+
+ <Z extends Comparable<Z>> List<? extends Z> extFbound() { return null; }
+ <Z extends Comparable<Z>> List<? super Z> supFbound() { return null; }
+
+ <Z extends Comparable<Z>> List<? extends Z>[] extFboundArr() { return null; }
+ <Z extends Comparable<Z>> List<? super Z>[] supFboundArr() { return null; }
+
+ <Z extends Comparable<Z>> Iterable<? extends List<? extends Z>> extFboundIter() { return null; }
+ <Z extends Comparable<Z>> Iterable<? extends List<? super Z>> supFboundIter() { return null; }
+
+ <Z> List<Z> listOf(Z z) { return null; }
+ <Z> Z[] arrayOf(Z z) { return null; }
+
+ <Z> Z choose(Z z1, Z z2) { return z1; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/PrimitiveTypeTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,97 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @modules jdk.compiler/com.sun.source.tree
+ * jdk.compiler/com.sun.source.util
+ * jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build LocalVariableInferenceTester
+ * @run main LocalVariableInferenceTester PrimitiveTypeTest.java
+ */
+class PrimitiveTypeTest {
+
+ byte[] b_arr = { 0 };
+ short[] s_arr = { 0 };
+ int[] i_arr = { 0 };
+ long[] l_arr = { 0 };
+ float[] f_arr = { 0 };
+ double[] d_arr = { 0 };
+ char[] c_arr = { 0 };
+ boolean[] z_arr = { false };
+
+ void testPrimitive() {
+ @InferredType("byte")
+ var b = (byte)0;
+ @InferredType("short")
+ var s = (short)0;
+ @InferredType("int")
+ var i = 0;
+ @InferredType("long")
+ var l = 0L;
+ @InferredType("float")
+ var f = 0f;
+ @InferredType("double")
+ var d = 0d;
+ @InferredType("char")
+ var c = 'c';
+ @InferredType("boolean")
+ var z = false;
+ }
+
+ void testPrimitiveArray() {
+ @InferredType("byte[]")
+ var b = b_arr;
+ @InferredType("short[]")
+ var s = s_arr;
+ @InferredType("int[]")
+ var i = i_arr;
+ @InferredType("long[]")
+ var l = l_arr;
+ @InferredType("float[]")
+ var f = f_arr;
+ @InferredType("double[]")
+ var d = d_arr;
+ @InferredType("char[]")
+ var c = c_arr;
+ @InferredType("boolean[]")
+ var z = z_arr;
+ }
+
+ void testForEachPrimitive() {
+ for (@InferredType("byte") var b : b_arr) { break; }
+ for (@InferredType("short") var s : s_arr) { break; }
+ for (@InferredType("int") var i : i_arr) { break; }
+ for (@InferredType("long") var l : l_arr) { break; }
+ for (@InferredType("float") var f : f_arr) { break; }
+ for (@InferredType("double") var d : d_arr) { break; }
+ for (@InferredType("char") var c : c_arr) { break; }
+ for (@InferredType("boolean") var z : z_arr) { break; }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lvti/harness/ReferenceTypeTest.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,60 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8177466
+ * @summary Add compiler support for local variable type-inference
+ * @modules jdk.compiler/com.sun.source.tree
+ * jdk.compiler/com.sun.source.util
+ * jdk.compiler/com.sun.tools.javac.api
+ * jdk.compiler/com.sun.tools.javac.code
+ * jdk.compiler/com.sun.tools.javac.util
+ * @build LocalVariableInferenceTester
+ * @run main LocalVariableInferenceTester ReferenceTypeTest.java
+ */
+class ReferenceTypeTest {
+
+ static final String STRING = "java.lang.String";
+ static final String FOO = "ReferenceTypeTest.Foo";
+
+ void test() {
+ @InferredType(STRING)
+ var s = "";
+ for (@InferredType(STRING) var s2 = "" ; ; ) { break; }
+ for (@InferredType(STRING) var s2 : stringArray()) { break; }
+ for (@InferredType(STRING) var s2 : stringIterable()) { break; }
+ try (@InferredType(FOO) var s2 = new Foo()) { } finally { }
+ try (@InferredType(FOO) var s2 = new Foo(); @InferredType(FOO) var s3 = new Foo()) { } finally { }
+ }
+
+ String[] stringArray() { return null; }
+ Iterable<String> stringIterable() { return null; }
+
+ static class Foo implements AutoCloseable {
+ @Override
+ public void close() { }
+ }
+}
--- a/test/langtools/tools/javac/parser/extend/TrialParser.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/tools/javac/parser/extend/TrialParser.java Wed Oct 04 20:01:19 2017 +0000
@@ -224,7 +224,7 @@
//mods.flags |= Flags.STATIC;
List<JCTree> defs
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
- new ListBuffer<JCTree>()).toList();
+ new ListBuffer<JCTree>(), true).toList();
accept(SEMI);
storeEnd(defs.last(), S.prevToken().endPos);
return defs;
--- a/test/langtools/tools/javac/processing/model/TestSourceVersion.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/tools/javac/processing/model/TestSourceVersion.java Wed Oct 04 20:01:19 2017 +0000
@@ -41,6 +41,7 @@
public static void main(String... args) {
testLatestSupported();
testVersionVaryingKeywords();
+ testRestrictedKeywords();
}
private static void testLatestSupported() {
@@ -74,6 +75,27 @@
}
}
+ private static void testRestrictedKeywords() {
+ // Restricted keywords are not full keywords
+
+ /*
+ * JLS 3.9
+ * " A further ten character sequences are restricted
+ * keywords: open, module, requires, transitive, exports,
+ * opens, to, uses, provides, and with"
+ */
+ Set<String> restrictedKeywords =
+ Set.of("open", "module", "requires", "transitive", "exports",
+ "opens", "to", "uses", "provides", "with");
+
+ for(String key : restrictedKeywords) {
+ for(SourceVersion version : SourceVersion.values()) {
+ check(false, isKeyword(key, version), "keyword", version);
+ check(true, isName(key, version), "name", version);
+ }
+ }
+ }
+
private static void check(boolean result, boolean expected,
String message, SourceVersion version) {
if (result != expected) {
--- a/test/langtools/tools/lib/types/TypeHarness.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/langtools/tools/lib/types/TypeHarness.java Wed Oct 04 20:01:19 2017 +0000
@@ -354,7 +354,7 @@
public TypeVar TypeVariable(Type bound) {
TypeSymbol tvsym = new TypeVariableSymbol(0, syntheticName(), null, predef.noSymbol);
- tvsym.type = new TypeVar(tvsym, bound, null);
+ tvsym.type = new TypeVar(tvsym, bound, Type.noType);
return (TypeVar)tvsym.type;
}
--- a/test/lib/sun/hotspot/WhiteBox.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/lib/sun/hotspot/WhiteBox.java Wed Oct 04 20:01:19 2017 +0000
@@ -529,4 +529,7 @@
// Compiler Directive
public native int addCompilerDirective(String compDirect);
public native void removeCompilerDirective(int count);
+
+ // Returns true on linux if library has the noexecstack flag set.
+ public native boolean checkLibSpecifiesNoexecstack(String libfilename);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/script/basic/JDK-8147076.js Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8147076: LinkerCallSite.ARGLIMIT is used incorrectly
+ *
+ * @test
+ * @run
+ */
+
+function nonvarargs(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
+ p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
+ p21, p22, p23, p24, p25, p26, p27, p28, p29, p30,
+ p31, p32, p33, p34, p35, p36, p37, p38, p39, p40,
+ p41, p42, p43, p44, p45, p46, p47, p48, p49, p50,
+ p51, p52, p53, p54, p55, p56, p57, p58, p59, p60,
+ p61, p62, p63, p64, p65, p66, p67, p68, p69, p70,
+ p71, p72, p73, p74, p75, p76, p77, p78, p79, p80,
+ p81, p82, p83, p84, p85, p86, p87, p88, p89, p90,
+ p91, p92, p93, p94, p95, p96, p97, p98, p99, p100,
+ p101, p102, p103, p104, p105, p106, p107, p108, p109, p110,
+ p111, p112, p113, p114, p115, p116, p117, p118, p119, p120,
+ p121, p122, p123, p124, p125) {
+ //eval() is just to make sure this-object and callee are passed as parameters
+ eval();
+ print("non-vararg invocation if arguments <= 125");
+}
+
+nonvarargs(1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.10,11.11,12.12,13.13,14.14,15.15,16.16,17.17,18.18,19.19,20.20,
+ 21.21,22.22,23.23,24.24,25.25,26.26,27.27,28.28,29.29,30.30,31.31,32.32,33.33,34.34,35.35,36.36,37.37,38.38,39.39,40.40,
+ 41.41,42.42,43.43,44.44,45.45,46.46,47.47,48.48,49.49,50.50,51.51,52.52,53.53,54.54,55.55,56.56,57.57,58.58,59.59,60.60,
+ 61.61,62.62,63.63,64.64,65.65,66.66,67.67,68.68,69.69,70.70,71.71,72.72,73.73,74.74,75.75,76.76,77.77,78.78,79.79,80.80,
+ 81.81,82.82,83.83,84.84,85.85,86.86,87.87,88.88,89.89,90.90,91.91,92.92,93.93,94.94,95.95,96.96,97.97,98.98,99.99,100.100,
+ 101.101,102.102,103.103,104.104,105.105,106.106,107.107,108.108,109.109,110.110,111.111,112.112,113.113,114.114,115.115,
+ 116.116,117.117,118.118,119.119,120.120,121.121,122.122,123.123,124.124,125.125);
+
+
+
+function varargs(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
+ p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
+ p21, p22, p23, p24, p25, p26, p27, p28, p29, p30,
+ p31, p32, p33, p34, p35, p36, p37, p38, p39, p40,
+ p41, p42, p43, p44, p45, p46, p47, p48, p49, p50,
+ p51, p52, p53, p54, p55, p56, p57, p58, p59, p60,
+ p61, p62, p63, p64, p65, p66, p67, p68, p69, p70,
+ p71, p72, p73, p74, p75, p76, p77, p78, p79, p80,
+ p81, p82, p83, p84, p85, p86, p87, p88, p89, p90,
+ p91, p92, p93, p94, p95, p96, p97, p98, p99, p100,
+ p101, p102, p103, p104, p105, p106, p107, p108, p109, p110,
+ p111, p112, p113, p114, p115, p116, p117, p118, p119, p120,
+ p121, p122, p123, p124, p125, p126) {
+ //eval() is just to make sure this-object and callee are passed as parameters
+ eval();
+ print("vararg invocation if arguments > 125");
+}
+
+varargs(1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.10,11.11,12.12,13.13,14.14,15.15,16.16,17.17,18.18,19.19,20.20,
+ 21.21,22.22,23.23,24.24,25.25,26.26,27.27,28.28,29.29,30.30,31.31,32.32,33.33,34.34,35.35,36.36,37.37,38.38,39.39,40.40,
+ 41.41,42.42,43.43,44.44,45.45,46.46,47.47,48.48,49.49,50.50,51.51,52.52,53.53,54.54,55.55,56.56,57.57,58.58,59.59,60.60,
+ 61.61,62.62,63.63,64.64,65.65,66.66,67.67,68.68,69.69,70.70,71.71,72.72,73.73,74.74,75.75,76.76,77.77,78.78,79.79,80.80,
+ 81.81,82.82,83.83,84.84,85.85,86.86,87.87,88.88,89.89,90.90,91.91,92.92,93.93,94.94,95.95,96.96,97.97,98.98,99.99,100.100,
+ 101.101,102.102,103.103,104.104,105.105,106.106,107.107,108.108,109.109,110.110,111.111,112.112,113.113,114.114,115.115,
+ 116.116,117.117,118.118,119.119,120.120,121.121,122.122,123.123,124.124,125.125,126.126);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/script/basic/JDK-8147076.js.EXPECTED Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,2 @@
+non-vararg invocation if arguments <= 125
+vararg invocation if arguments > 125
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/script/basic/JDK-8186815.js Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8186815: Java.from has a bug, when element is ScriptObject
+ *
+ * @test
+ * @run
+ */
+
+var list = new java.util.ArrayList();
+var obj = { x: 1 };
+list.add(obj);
+
+Assert.assertTrue(list.get(0) === obj);
+Assert.assertTrue(list.get(0) instanceof Object);
+
+var fromList = Java.from(list);
+Assert.assertTrue(fromList[0] === obj);
+Assert.assertTrue(fromList[0] instanceof Object);
+
+var fromArray = Java.from(list.toArray());
+Assert.assertTrue(fromArray[0] === obj);
+Assert.assertTrue(fromArray[0] instanceof Object);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/script/basic/JDK-8187962.js Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8187962: Optimistic types ignore JavaAdapter return types
+ *
+ * @test
+ * @run
+ */
+
+function iterator() {
+ return null;
+}
+
+var list = new java.util.List() { iterator: function() { return iterator(); }};
+var result = list.iterator();
+Assert.assertEquals(result, null);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/script/basic/JDK-8188098.js Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8188098:NPE in SimpleTreeVisitorES6 visitor when parsing a tagged template literal
+ *
+ * @test
+ * @run
+ */
+
+var Parser = Java.type("jdk.nashorn.api.tree.Parser");
+var MemberSelectTree = Java.type("jdk.nashorn.api.tree.MemberSelectTree");
+var SimpleTreeVisitor = Java.type("jdk.nashorn.api.tree.SimpleTreeVisitorES6");
+var parser = Parser.create("--language=es6");
+
+var ast = parser.parse("hello.js", "foo`PI (${Math.PI}) is transcendental`", print);
+
+var reachedCall = false;
+ast.accept(new (Java.extend(SimpleTreeVisitor)) {
+ visitFunctionCall: function(node, extra) {
+ reachedCall = true;
+ Assert.assertTrue(node.functionSelect.name == "foo");
+ var args = node.arguments;
+ Assert.assertTrue(args.size() == 2);
+ var strs = args.get(0).elements;
+ Assert.assertTrue(String(strs.get(0).value) == "PI (");
+ Assert.assertTrue(String(strs.get(1).value) == ") is transcendental");
+ var expr = args.get(1);
+ Assert.assertTrue(expr instanceof MemberSelectTree);
+ Assert.assertTrue(expr.expression.name == "Math");
+ Assert.assertTrue(expr.identifier == "PI");
+ }
+}, null);
+
+Assert.assertTrue(reachedCall);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/script/basic/es6/JDK-8185257.js Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8185257: Nashorn AST is missing nodes when a for-loop contains a VariableDeclarationList
+ *
+ * @test
+ * @run
+ * @fork
+ */
+
+var ASTVisitor = Java.type("jdk.nashorn.test.models.ES6ASTVisitor");
+var testcode = "for (var i = 0; i < 100; i++) {\n print(i);\n}\n";
+ASTVisitor.visit(testcode);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/script/basic/es6/JDK-8185257.js.EXPECTED Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,2 @@
+5-14 VARIABLE
+0-44 FOR_LOOP
--- a/test/nashorn/script/currently-failing/JDK-8055034.js Wed Oct 04 11:52:07 2017 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * JDK-8055034: jjs exits interactive mode if exception was thrown when trying to print value of last evaluated expression
- *
- * @test
- * @option -scripting
- * @run
- */
-
-// assume that this script is run with "nashorn.jar" System
-// property set to relative or absolute path of nashorn.jar
-
-if (typeof fail != 'function') {
- fail = print;
-}
-
-var System = java.lang.System;
-var File = java.io.File;
-var javahome = System.getProperty("java.home");
-var nashornJar = new File(System.getProperty("nashorn.jar"));
-if (! nashornJar.isAbsolute()) {
- nashornJar = new File(".", nashornJar);
-}
-
-// we want to use nashorn.jar passed and not the one that comes with JRE
-var jjsCmd = javahome + "/../bin/jjs";
-jjsCmd = jjsCmd.toString().replace(/\//g, File.separator);
-if (! new File(jjsCmd).isFile()) {
- jjsCmd = javahome + "/bin/jjs";
- jjsCmd = jjsCmd.toString().replace(/\//g, File.separator);
-}
-jjsCmd += " -J--patch-module=jdk.scripting.nashorn=" + nashornJar;
-
-$ENV.PWD=System.getProperty("user.dir") // to avoid RE on Cygwin
-$EXEC(jjsCmd, "var x = Object.create(null);\nx;\nprint('PASSED');\nexit(0)");
-
-// $ERR has all interactions including prompts! Just check for error substring.
-var err = $ERR.trim();
-if (! err.contains("TypeError: Cannot get default string value")) {
- fail("Error stream does not contain expected error message");
-}
-
-// should print "PASSED"
-print($OUT.trim());
-// exit code should be 0
-print("exit code = " + $EXIT);
--- a/test/nashorn/script/currently-failing/JDK-8055034.js.EXPECTED Wed Oct 04 11:52:07 2017 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-PASSED
-exit code = 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/script/nosecurity/JDK-8055034.js Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8055034: jjs exits interactive mode if exception was thrown when trying to print value of last evaluated expression
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+// assume that this script is run with "nashorn.jar" System
+// property set to relative or absolute path of nashorn.jar
+
+if (typeof fail != 'function') {
+ fail = print;
+}
+
+var System = java.lang.System;
+var File = java.io.File;
+var javahome = System.getProperty("java.home");
+var nashornJar = new File(System.getProperty("nashorn.jar"));
+if (! nashornJar.isAbsolute()) {
+ nashornJar = new File(".", nashornJar);
+}
+
+// we want to use nashorn.jar passed and not the one that comes with JRE
+var jjsCmd = javahome + "/../bin/jjs";
+jjsCmd = jjsCmd.toString().replace(/\//g, File.separator);
+if (! new File(jjsCmd).isFile()) {
+ jjsCmd = javahome + "/bin/jjs";
+ jjsCmd = jjsCmd.toString().replace(/\//g, File.separator);
+}
+jjsCmd += " -J--patch-module=jdk.scripting.nashorn=" + nashornJar;
+
+$ENV.PWD=System.getProperty("user.dir") // to avoid RE on Cygwin
+$EXEC(jjsCmd, "var x = Object.create(null);\nx;\nprint('PASSED');\nexit(0)");
+
+// $ERR has all interactions including prompts! Just check for error substring.
+var err = $ERR.trim();
+if (! err.contains("TypeError: Cannot get default string value")) {
+ fail("Error stream does not contain expected error message");
+}
+
+// should print "PASSED"
+print($OUT.trim());
+// exit code should be 0
+print("exit code = " + $EXIT);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/script/nosecurity/JDK-8055034.js.EXPECTED Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,6 @@
+jjs> var x = Object.create(null);
+jjs> x;
+jjs> print('PASSED');
+PASSED
+jjs> exit(0)
+exit code = 0
--- a/test/nashorn/script/trusted/JDK-8006529.js Wed Oct 04 11:52:07 2017 -0700
+++ b/test/nashorn/script/trusted/JDK-8006529.js Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, 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
@@ -256,9 +256,9 @@
// eval, but at least the parent doesn't have to be vararg.
testFirstFn("(function f() { function g() { eval() } })", 'usesSelfSymbol', 'needsParentScope', 'needsCallee', 'hasScopeBlock', 'allVarsInScope')
-// Function with 250 named parameters is ordinary
-testFirstFn("function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45, p46, p47, p48, p49, p50, p51, p52, p53, p54, p55, p56, p57, p58, p59, p60, p61, p62, p63, p64, p65, p66, p67, p68, p69, p70, p71, p72, p73, p74, p75, p76, p77, p78, p79, p80, p81, p82, p83, p84, p85, p86, p87, p88, p89, p90, p91, p92, p93, p94, p95, p96, p97, p98, p99, p100, p101, p102, p103, p104, p105, p106, p107, p108, p109, p110, p111, p112, p113, p114, p115, p116, p117, p118, p119, p120, p121, p122, p123, p124, p125, p126, p127, p128, p129, p130, p131, p132, p133, p134, p135, p136, p137, p138, p139, p140, p141, p142, p143, p144, p145, p146, p147, p148, p149, p150, p151, p152, p153, p154, p155, p156, p157, p158, p159, p160, p161, p162, p163, p164, p165, p166, p167, p168, p169, p170, p171, p172, p173, p174, p175, p176, p177, p178, p179, p180, p181, p182, p183, p184, p185, p186, p187, p188, p189, p190, p191, p192, p193, p194, p195, p196, p197, p198, p199, p200, p201, p202, p203, p204, p205, p206, p207, p208, p209, p210, p211, p212, p213, p214, p215, p216, p217, p218, p219, p220, p221, p222, p223, p224, p225, p226, p227, p228, p229, p230, p231, p232, p233, p234, p235, p236, p237, p238, p239, p240, p241, p242, p243, p244, p245, p246, p247, p248, p249, p250) { p250 = p249 }")
+// Function with 125 named parameters is ordinary
+testFirstFn("function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45, p46, p47, p48, p49, p50, p51, p52, p53, p54, p55, p56, p57, p58, p59, p60, p61, p62, p63, p64, p65, p66, p67, p68, p69, p70, p71, p72, p73, p74, p75, p76, p77, p78, p79, p80, p81, p82, p83, p84, p85, p86, p87, p88, p89, p90, p91, p92, p93, p94, p95, p96, p97, p98, p99, p100, p101, p102, p103, p104, p105, p106, p107, p108, p109, p110, p111, p112, p113, p114, p115, p116, p117, p118, p119, p120, p121, p122, p123, p124, p125) { p125 = p124 }")
-// Function with 251 named parameters is variable arguments
+// Function with 126 named parameters is variable arguments
// NOTE: hasScopeBlock should be optimized away. Implementation of JDK-8038942 should take care of it.
-testFirstFn("function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45, p46, p47, p48, p49, p50, p51, p52, p53, p54, p55, p56, p57, p58, p59, p60, p61, p62, p63, p64, p65, p66, p67, p68, p69, p70, p71, p72, p73, p74, p75, p76, p77, p78, p79, p80, p81, p82, p83, p84, p85, p86, p87, p88, p89, p90, p91, p92, p93, p94, p95, p96, p97, p98, p99, p100, p101, p102, p103, p104, p105, p106, p107, p108, p109, p110, p111, p112, p113, p114, p115, p116, p117, p118, p119, p120, p121, p122, p123, p124, p125, p126, p127, p128, p129, p130, p131, p132, p133, p134, p135, p136, p137, p138, p139, p140, p141, p142, p143, p144, p145, p146, p147, p148, p149, p150, p151, p152, p153, p154, p155, p156, p157, p158, p159, p160, p161, p162, p163, p164, p165, p166, p167, p168, p169, p170, p171, p172, p173, p174, p175, p176, p177, p178, p179, p180, p181, p182, p183, p184, p185, p186, p187, p188, p189, p190, p191, p192, p193, p194, p195, p196, p197, p198, p199, p200, p201, p202, p203, p204, p205, p206, p207, p208, p209, p210, p211, p212, p213, p214, p215, p216, p217, p218, p219, p220, p221, p222, p223, p224, p225, p226, p227, p228, p229, p230, p231, p232, p233, p234, p235, p236, p237, p238, p239, p240, p241, p242, p243, p244, p245, p246, p247, p248, p249, p250, p251) { p250 = p251 }", 'isVarArg', 'hasScopeBlock')
+testFirstFn("function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45, p46, p47, p48, p49, p50, p51, p52, p53, p54, p55, p56, p57, p58, p59, p60, p61, p62, p63, p64, p65, p66, p67, p68, p69, p70, p71, p72, p73, p74, p75, p76, p77, p78, p79, p80, p81, p82, p83, p84, p85, p86, p87, p88, p89, p90, p91, p92, p93, p94, p95, p96, p97, p98, p99, p100, p101, p102, p103, p104, p105, p106, p107, p108, p109, p110, p111, p112, p113, p114, p115, p116, p117, p118, p119, p120, p121, p122, p123, p124, p125, p126) { p125 = p126 }", 'isVarArg', 'hasScopeBlock')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/src/jdk/nashorn/api/tree/test/JDK_8188098_Test.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.api.tree.test;
+
+import jdk.nashorn.api.tree.Parser;
+import jdk.nashorn.api.tree.SimpleTreeVisitorES6;
+import org.testng.annotations.Test;
+
+/**
+ * 8188098: NPE in SimpleTreeVisitorES6 visitor when parsing a tagged template literal
+ *
+ * @test
+ * @run testng jdk.nashorn.api.tree.test.JDK_8188098_Test
+ */
+public class JDK_8188098_Test {
+ @Test
+ public void test() {
+ Parser p = Parser.create("--language=es6");
+ p.parse("test", "foo`hello world`", System.out::println).
+ accept(new SimpleTreeVisitorES6<Void, Void>(), null);
+ }
+}
--- a/test/nashorn/src/jdk/nashorn/test/models/ClassWithFinalFinalizer.java Wed Oct 04 11:52:07 2017 -0700
+++ b/test/nashorn/src/jdk/nashorn/test/models/ClassWithFinalFinalizer.java Wed Oct 04 20:01:19 2017 +0000
@@ -28,6 +28,7 @@
@SuppressWarnings("javadoc")
public class ClassWithFinalFinalizer {
@Override
+ @SuppressWarnings("deprecation")
protected final void finalize() {
//empty
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nashorn/src/jdk/nashorn/test/nashorn/models/ES6ASTVisitor.java Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.test.models;
+
+import jdk.nashorn.api.tree.SimpleTreeVisitorES6;
+import jdk.nashorn.api.tree.*;
+
+public class ES6ASTVisitor{
+
+ public static void visit(String script) {
+ DiagnosticListener listener = (Diagnostic diag) -> { System.err.println(diag.toString()); };
+ Parser parser = Parser.create("--language=es6","--empty-statements");
+ Tree astRoot = parser.parse("unknown", script, listener);
+ astRoot.accept(new SimpleTreeVisitorES6<Boolean, Void>() {
+ @Override
+ public Boolean visitCompilationUnit(CompilationUnitTree stmt, Void none) {
+ for (Tree item : stmt.getSourceElements()) {
+ System.out.println(item.getStartPosition() + "-" + item.getEndPosition() + " " + item.getKind());
+ }
+ return super.visitCompilationUnit(stmt, none);
+ }
+
+ }, null);
+
+ }
+
+}
+