--- a/.hgtags Sat Oct 07 22:45:12 2017 +0900
+++ b/.hgtags Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/bin/jib.sh Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/doc/nashorn/JavaScriptingProgrammersGuide.html Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/BuildNashorn.gmk Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/InitSupport.gmk Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/autoconf/flags.m4 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/autoconf/generated-configure.sh Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/autoconf/spec.gmk.in Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/common/Modules.gmk Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/conf/jib-profiles.js Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/hotspot/lib/CompileLibjsig.gmk Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/langtools/src/classes/build/tools/symbolgenerator/TransitiveDependencies.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/nashorn/build.xml Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/nashorn/buildtools/nasgen/project.properties Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/nashorn/buildtools/nashorntask/project.properties Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/nashorn/project.properties Mon Oct 09 07:08:53 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/make/test/JtregNativeHotspot.gmk Sat Oct 07 22:45:12 2017 +0900
+++ b/make/test/JtregNativeHotspot.gmk Mon Oct 09 07:08:53 2017 +0000
@@ -59,6 +59,7 @@
$(TOPDIR)/test/hotspot/jtreg/runtime/SameObject \
$(TOPDIR)/test/hotspot/jtreg/runtime/BoolReturn \
$(TOPDIR)/test/hotspot/jtreg/runtime/noClassDefFoundMsg \
+ $(TOPDIR)/test/hotspot/jtreg/runtime/RedefineTests \
$(TOPDIR)/test/hotspot/jtreg/compiler/floatingpoint/ \
$(TOPDIR)/test/hotspot/jtreg/compiler/calls \
$(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/GetOwnedMonitorInfo \
@@ -103,6 +104,7 @@
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAClassLoadPrepare := -lc
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAThreadStart := -lc
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libAllowedFunctions := -lc
+ BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libRedefineDoubleDelete := -lc
endif
ifeq ($(OPENJDK_TARGET_OS), linux)
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2840,6 +2840,44 @@
bind(L_done);
}
+// Code for BigInteger::mulAdd instrinsic
+// out = r0
+// in = r1
+// offset = r2 (already out.length-offset)
+// len = r3
+// k = r4
+//
+// pseudo code from java implementation:
+// carry = 0;
+// offset = out.length-offset - 1;
+// for (int j=len-1; j >= 0; j--) {
+// product = (in[j] & LONG_MASK) * kLong + (out[offset] & LONG_MASK) + carry;
+// out[offset--] = (int)product;
+// carry = product >>> 32;
+// }
+// return (int)carry;
+void MacroAssembler::mul_add(Register out, Register in, Register offset,
+ Register len, Register k) {
+ Label LOOP, END;
+ // pre-loop
+ cmp(len, zr); // cmp, not cbz/cbnz: to use condition twice => less branches
+ csel(out, zr, out, Assembler::EQ);
+ br(Assembler::EQ, END);
+ add(in, in, len, LSL, 2); // in[j+1] address
+ add(offset, out, offset, LSL, 2); // out[offset + 1] address
+ mov(out, zr); // used to keep carry now
+ BIND(LOOP);
+ ldrw(rscratch1, Address(pre(in, -4)));
+ madd(rscratch1, rscratch1, k, out);
+ ldrw(rscratch2, Address(pre(offset, -4)));
+ add(rscratch1, rscratch1, rscratch2);
+ strw(rscratch1, Address(offset));
+ lsr(out, rscratch1, 32);
+ subs(len, len, 1);
+ br(Assembler::NE, LOOP);
+ BIND(END);
+}
+
/**
* Emits code to update CRC-32 with a byte value according to constants in table
*
@@ -3291,6 +3329,7 @@
ldr(dst, Address(dst, ConstMethod::constants_offset()));
ldr(dst, Address(dst, ConstantPool::pool_holder_offset_in_bytes()));
ldr(dst, Address(dst, mirror_offset));
+ resolve_oop_handle(dst);
}
void MacroAssembler::cmp_klass(Register oop, Register trial_klass, Register tmp) {
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1265,6 +1265,7 @@
void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z,
Register zlen, Register tmp1, Register tmp2, Register tmp3,
Register tmp4, Register tmp5, Register tmp6, Register tmp7);
+ void mul_add(Register out, Register in, Register offs, Register len, Register k);
// ISB may be needed because of a safepoint
void maybe_isb() { isb(); }
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3607,6 +3607,63 @@
return start;
}
+ address generate_squareToLen() {
+ // squareToLen algorithm for sizes 1..127 described in java code works
+ // faster than multiply_to_len on some CPUs and slower on others, but
+ // multiply_to_len shows a bit better overall results
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "squareToLen");
+ address start = __ pc();
+
+ const Register x = r0;
+ const Register xlen = r1;
+ const Register z = r2;
+ const Register zlen = r3;
+ const Register y = r4; // == x
+ const Register ylen = r5; // == xlen
+
+ const Register tmp1 = r10;
+ const Register tmp2 = r11;
+ const Register tmp3 = r12;
+ const Register tmp4 = r13;
+ const Register tmp5 = r14;
+ const Register tmp6 = r15;
+ const Register tmp7 = r16;
+
+ RegSet spilled_regs = RegSet::of(y, ylen);
+ BLOCK_COMMENT("Entry:");
+ __ enter();
+ __ push(spilled_regs, sp);
+ __ mov(y, x);
+ __ mov(ylen, xlen);
+ __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7);
+ __ pop(spilled_regs, sp);
+ __ leave();
+ __ ret(lr);
+ return start;
+ }
+
+ address generate_mulAdd() {
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "mulAdd");
+
+ address start = __ pc();
+
+ const Register out = r0;
+ const Register in = r1;
+ const Register offset = r2;
+ const Register len = r3;
+ const Register k = r4;
+
+ BLOCK_COMMENT("Entry:");
+ __ enter();
+ __ mul_add(out, in, offset, len, k);
+ __ leave();
+ __ ret(lr);
+
+ return start;
+ }
+
void ghash_multiply(FloatRegister result_lo, FloatRegister result_hi,
FloatRegister a, FloatRegister b, FloatRegister a1_xor_a0,
FloatRegister tmp1, FloatRegister tmp2, FloatRegister tmp3, FloatRegister tmp4) {
@@ -4913,6 +4970,14 @@
StubRoutines::_multiplyToLen = generate_multiplyToLen();
}
+ if (UseSquareToLenIntrinsic) {
+ StubRoutines::_squareToLen = generate_squareToLen();
+ }
+
+ if (UseMulAddIntrinsic) {
+ StubRoutines::_mulAdd = generate_mulAdd();
+ }
+
if (UseMontgomeryMultiplyIntrinsic) {
StubCodeMark mark(this, "StubRoutines", "montgomeryMultiply");
MontgomeryMultiplyGenerator g(_masm, /*squaring*/false);
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2297,6 +2297,7 @@
ConstantPoolCacheEntry::f1_offset())));
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ ldr(obj, Address(obj, mirror_offset));
+ __ resolve_oop_handle(obj);
}
}
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -340,6 +340,14 @@
UseMultiplyToLenIntrinsic = true;
}
+ if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
+ UseSquareToLenIntrinsic = true;
+ }
+
+ if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
+ UseMulAddIntrinsic = true;
+ }
+
if (FLAG_IS_DEFAULT(UseBarriersForVolatile)) {
UseBarriersForVolatile = (_features & CPU_DMB_ATOMICS) != 0;
}
--- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2899,6 +2899,7 @@
ldr(tmp, Address(tmp, ConstMethod::constants_offset()));
ldr(tmp, Address(tmp, ConstantPool::pool_holder_offset_in_bytes()));
ldr(mirror, Address(tmp, mirror_offset));
+ resolve_oop_handle(mirror);
}
--- a/src/hotspot/cpu/arm/templateTable_arm.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/arm/templateTable_arm.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2963,6 +2963,7 @@
cp_base_offset + ConstantPoolCacheEntry::f1_offset()));
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ ldr(Robj, Address(Robj, mirror_offset));
+ __ resolve_oop_handle(Robj);
}
}
--- a/src/hotspot/cpu/ppc/assembler_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -517,6 +517,9 @@
XXPERMDI_OPCODE= (60u << OPCODE_SHIFT | 10u << 3),
XXMRGHW_OPCODE = (60u << OPCODE_SHIFT | 18u << 3),
XXMRGLW_OPCODE = (60u << OPCODE_SHIFT | 50u << 3),
+ XXSPLTW_OPCODE = (60u << OPCODE_SHIFT | 164u << 2),
+ XXLXOR_OPCODE = (60u << OPCODE_SHIFT | 154u << 3),
+ XXLEQV_OPCODE = (60u << OPCODE_SHIFT | 186u << 3),
// Vector Permute and Formatting
VPKPX_OPCODE = (4u << OPCODE_SHIFT | 782u ),
@@ -1125,6 +1128,7 @@
static int vsplti_sim(int x) { return opp_u_field(x, 15, 11); } // for vsplti* instructions
static int vsldoi_shb(int x) { return opp_u_field(x, 25, 22); } // for vsldoi instruction
static int vcmp_rc( int x) { return opp_u_field(x, 21, 21); } // for vcmp* instructions
+ static int xxsplt_uim(int x) { return opp_u_field(x, 15, 14); } // for xxsplt* instructions
//static int xo1( int x) { return opp_u_field(x, 29, 21); }// is contained in our opcodes
//static int xo2( int x) { return opp_u_field(x, 30, 21); }// is contained in our opcodes
@@ -2155,6 +2159,11 @@
inline void xxpermdi( VectorSRegister d, VectorSRegister a, VectorSRegister b, int dm);
inline void xxmrghw( VectorSRegister d, VectorSRegister a, VectorSRegister b);
inline void xxmrglw( VectorSRegister d, VectorSRegister a, VectorSRegister b);
+ inline void mtvsrd( VectorSRegister d, Register a);
+ inline void mtvsrwz( VectorSRegister d, Register a);
+ inline void xxspltw( VectorSRegister d, VectorSRegister b, int ui2);
+ inline void xxlxor( VectorSRegister d, VectorSRegister a, VectorSRegister b);
+ inline void xxleqv( VectorSRegister d, VectorSRegister a, VectorSRegister b);
// VSX Extended Mnemonics
inline void xxspltd( VectorSRegister d, VectorSRegister a, int x);
--- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -761,9 +761,14 @@
// Vector-Scalar (VSX) instructions.
inline void Assembler::lxvd2x( VectorSRegister d, Register s1) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra(0) | rb(s1)); }
inline void Assembler::lxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); }
-inline void Assembler::stxvd2x( VectorSRegister d, Register s1) { emit_int32( STXVD2X_OPCODE | vsrt(d) | ra(0) | rb(s1)); }
-inline void Assembler::stxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( STXVD2X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); }
-inline void Assembler::mtvrd( VectorRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
+inline void Assembler::stxvd2x( VectorSRegister d, Register s1) { emit_int32( STXVD2X_OPCODE | vsrs(d) | ra(0) | rb(s1)); }
+inline void Assembler::stxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( STXVD2X_OPCODE | vsrs(d) | ra0mem(s1) | rb(s2)); }
+inline void Assembler::mtvsrd( VectorSRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d) | ra(a)); }
+inline void Assembler::mtvsrwz( VectorSRegister d, Register a) { emit_int32( MTVSRWZ_OPCODE | vsrt(d) | ra(a)); }
+inline void Assembler::xxspltw( VectorSRegister d, VectorSRegister b, int ui2) { emit_int32( XXSPLTW_OPCODE | vsrt(d) | vsrb(b) | xxsplt_uim(uimm(ui2,2))); }
+inline void Assembler::xxlxor( VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XXLXOR_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); }
+inline void Assembler::xxleqv( VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XXLEQV_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); }
+inline void Assembler::mtvrd( VectorRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
inline void Assembler::mfvrd( Register a, VectorRegister d) { emit_int32( MFVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
inline void Assembler::mtvrwz( VectorRegister d, Register a) { emit_int32( MTVSRWZ_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
inline void Assembler::mfvrwz( Register a, VectorRegister d) { emit_int32( MFVSRWZ_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
--- a/src/hotspot/cpu/ppc/globals_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/globals_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -32,7 +32,7 @@
// Sets the default values for platform dependent flags used by the runtime system.
// (see globals.hpp)
-define_pd_global(bool, ShareVtableStubs, false); // Improves performance markedly for mtrt and compress.
+define_pd_global(bool, ShareVtableStubs, true);
define_pd_global(bool, NeedsDeoptSuspend, false); // Only register window machines need this.
@@ -103,6 +103,9 @@
"CPU Version: x for PowerX. Currently recognizes Power5 to " \
"Power8. Default is 0. Newer CPUs will be recognized as Power8.") \
\
+ product(bool, SuperwordUseVSX, false, \
+ "Use Power8 VSX instructions for superword optimization.") \
+ \
/* Reoptimize code-sequences of calls at runtime, e.g. replace an */ \
/* indirect call by a direct call. */ \
product(bool, ReoptimizeCallSequences, true, \
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3382,6 +3382,7 @@
ld(mirror, in_bytes(ConstMethod::constants_offset()), const_method);
ld(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror);
ld(mirror, in_bytes(Klass::java_mirror_offset()), mirror);
+ resolve_oop_handle(mirror);
}
// Clear Array
--- a/src/hotspot/cpu/ppc/ppc.ad Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/ppc.ad Mon Oct 09 07:08:53 2017 +0000
@@ -254,6 +254,73 @@
reg_def SR_SPEFSCR(SOC, SOC, Op_RegP, 4, SR_SPEFSCR->as_VMReg()); // v
reg_def SR_PPR( SOC, SOC, Op_RegP, 5, SR_PPR->as_VMReg()); // v
+// ----------------------------
+// Vector-Scalar Registers
+// ----------------------------
+ reg_def VSR0 ( SOC, SOC, Op_VecX, 0, NULL);
+ reg_def VSR1 ( SOC, SOC, Op_VecX, 1, NULL);
+ reg_def VSR2 ( SOC, SOC, Op_VecX, 2, NULL);
+ reg_def VSR3 ( SOC, SOC, Op_VecX, 3, NULL);
+ reg_def VSR4 ( SOC, SOC, Op_VecX, 4, NULL);
+ reg_def VSR5 ( SOC, SOC, Op_VecX, 5, NULL);
+ reg_def VSR6 ( SOC, SOC, Op_VecX, 6, NULL);
+ reg_def VSR7 ( SOC, SOC, Op_VecX, 7, NULL);
+ reg_def VSR8 ( SOC, SOC, Op_VecX, 8, NULL);
+ reg_def VSR9 ( SOC, SOC, Op_VecX, 9, NULL);
+ reg_def VSR10 ( SOC, SOC, Op_VecX, 10, NULL);
+ reg_def VSR11 ( SOC, SOC, Op_VecX, 11, NULL);
+ reg_def VSR12 ( SOC, SOC, Op_VecX, 12, NULL);
+ reg_def VSR13 ( SOC, SOC, Op_VecX, 13, NULL);
+ reg_def VSR14 ( SOC, SOC, Op_VecX, 14, NULL);
+ reg_def VSR15 ( SOC, SOC, Op_VecX, 15, NULL);
+ reg_def VSR16 ( SOC, SOC, Op_VecX, 16, NULL);
+ reg_def VSR17 ( SOC, SOC, Op_VecX, 17, NULL);
+ reg_def VSR18 ( SOC, SOC, Op_VecX, 18, NULL);
+ reg_def VSR19 ( SOC, SOC, Op_VecX, 19, NULL);
+ reg_def VSR20 ( SOC, SOC, Op_VecX, 20, NULL);
+ reg_def VSR21 ( SOC, SOC, Op_VecX, 21, NULL);
+ reg_def VSR22 ( SOC, SOC, Op_VecX, 22, NULL);
+ reg_def VSR23 ( SOC, SOC, Op_VecX, 23, NULL);
+ reg_def VSR24 ( SOC, SOC, Op_VecX, 24, NULL);
+ reg_def VSR25 ( SOC, SOC, Op_VecX, 25, NULL);
+ reg_def VSR26 ( SOC, SOC, Op_VecX, 26, NULL);
+ reg_def VSR27 ( SOC, SOC, Op_VecX, 27, NULL);
+ reg_def VSR28 ( SOC, SOC, Op_VecX, 28, NULL);
+ reg_def VSR29 ( SOC, SOC, Op_VecX, 29, NULL);
+ reg_def VSR30 ( SOC, SOC, Op_VecX, 30, NULL);
+ reg_def VSR31 ( SOC, SOC, Op_VecX, 31, NULL);
+ reg_def VSR32 ( SOC, SOC, Op_VecX, 32, NULL);
+ reg_def VSR33 ( SOC, SOC, Op_VecX, 33, NULL);
+ reg_def VSR34 ( SOC, SOC, Op_VecX, 34, NULL);
+ reg_def VSR35 ( SOC, SOC, Op_VecX, 35, NULL);
+ reg_def VSR36 ( SOC, SOC, Op_VecX, 36, NULL);
+ reg_def VSR37 ( SOC, SOC, Op_VecX, 37, NULL);
+ reg_def VSR38 ( SOC, SOC, Op_VecX, 38, NULL);
+ reg_def VSR39 ( SOC, SOC, Op_VecX, 39, NULL);
+ reg_def VSR40 ( SOC, SOC, Op_VecX, 40, NULL);
+ reg_def VSR41 ( SOC, SOC, Op_VecX, 41, NULL);
+ reg_def VSR42 ( SOC, SOC, Op_VecX, 42, NULL);
+ reg_def VSR43 ( SOC, SOC, Op_VecX, 43, NULL);
+ reg_def VSR44 ( SOC, SOC, Op_VecX, 44, NULL);
+ reg_def VSR45 ( SOC, SOC, Op_VecX, 45, NULL);
+ reg_def VSR46 ( SOC, SOC, Op_VecX, 46, NULL);
+ reg_def VSR47 ( SOC, SOC, Op_VecX, 47, NULL);
+ reg_def VSR48 ( SOC, SOC, Op_VecX, 48, NULL);
+ reg_def VSR49 ( SOC, SOC, Op_VecX, 49, NULL);
+ reg_def VSR50 ( SOC, SOC, Op_VecX, 50, NULL);
+ reg_def VSR51 ( SOC, SOC, Op_VecX, 51, NULL);
+ reg_def VSR52 ( SOC, SOC, Op_VecX, 52, NULL);
+ reg_def VSR53 ( SOC, SOC, Op_VecX, 53, NULL);
+ reg_def VSR54 ( SOC, SOC, Op_VecX, 54, NULL);
+ reg_def VSR55 ( SOC, SOC, Op_VecX, 55, NULL);
+ reg_def VSR56 ( SOC, SOC, Op_VecX, 56, NULL);
+ reg_def VSR57 ( SOC, SOC, Op_VecX, 57, NULL);
+ reg_def VSR58 ( SOC, SOC, Op_VecX, 58, NULL);
+ reg_def VSR59 ( SOC, SOC, Op_VecX, 59, NULL);
+ reg_def VSR60 ( SOC, SOC, Op_VecX, 60, NULL);
+ reg_def VSR61 ( SOC, SOC, Op_VecX, 61, NULL);
+ reg_def VSR62 ( SOC, SOC, Op_VecX, 62, NULL);
+ reg_def VSR63 ( SOC, SOC, Op_VecX, 63, NULL);
// ----------------------------
// Specify priority of register selection within phases of register
@@ -385,6 +452,73 @@
);
alloc_class chunk3 (
+ VSR0,
+ VSR1,
+ VSR2,
+ VSR3,
+ VSR4,
+ VSR5,
+ VSR6,
+ VSR7,
+ VSR8,
+ VSR9,
+ VSR10,
+ VSR11,
+ VSR12,
+ VSR13,
+ VSR14,
+ VSR15,
+ VSR16,
+ VSR17,
+ VSR18,
+ VSR19,
+ VSR20,
+ VSR21,
+ VSR22,
+ VSR23,
+ VSR24,
+ VSR25,
+ VSR26,
+ VSR27,
+ VSR28,
+ VSR29,
+ VSR30,
+ VSR31,
+ VSR32,
+ VSR33,
+ VSR34,
+ VSR35,
+ VSR36,
+ VSR37,
+ VSR38,
+ VSR39,
+ VSR40,
+ VSR41,
+ VSR42,
+ VSR43,
+ VSR44,
+ VSR45,
+ VSR46,
+ VSR47,
+ VSR48,
+ VSR49,
+ VSR50,
+ VSR51,
+ VSR52,
+ VSR53,
+ VSR54,
+ VSR55,
+ VSR56,
+ VSR57,
+ VSR58,
+ VSR59,
+ VSR60,
+ VSR61,
+ VSR62,
+ VSR63
+);
+
+alloc_class chunk4 (
// special registers
// These registers are not allocated, but used for nodes generated by postalloc expand.
SR_XER,
@@ -769,6 +903,45 @@
F31, F31_H // nv!
);
+// ----------------------------
+// Vector-Scalar Register Class
+// ----------------------------
+
+reg_class vs_reg(
+ VSR32,
+ VSR33,
+ VSR34,
+ VSR35,
+ VSR36,
+ VSR37,
+ VSR38,
+ VSR39,
+ VSR40,
+ VSR41,
+ VSR42,
+ VSR43,
+ VSR44,
+ VSR45,
+ VSR46,
+ VSR47,
+ VSR48,
+ VSR49,
+ VSR50,
+ VSR51
+// VSR52, // nv!
+// VSR53, // nv!
+// VSR54, // nv!
+// VSR55, // nv!
+// VSR56, // nv!
+// VSR57, // nv!
+// VSR58, // nv!
+// VSR59, // nv!
+// VSR60, // nv!
+// VSR61, // nv!
+// VSR62, // nv!
+// VSR63 // nv!
+);
+
%}
//----------DEFINITION BLOCK---------------------------------------------------
@@ -1502,7 +1675,7 @@
if (reg < 64+64) return rc_float;
// Between float regs & stack are the flags regs.
- assert(OptoReg::is_stack(reg), "blow up if spilling flags");
+ assert(OptoReg::is_stack(reg) || reg < 64+64+64, "blow up if spilling flags");
return rc_stack;
}
@@ -2048,14 +2221,24 @@
// Vector width in bytes.
const int Matcher::vector_width_in_bytes(BasicType bt) {
- assert(MaxVectorSize == 8, "");
- return 8;
+ if (SuperwordUseVSX) {
+ assert(MaxVectorSize == 16, "");
+ return 16;
+ } else {
+ assert(MaxVectorSize == 8, "");
+ return 8;
+ }
}
// Vector ideal reg.
const uint Matcher::vector_ideal_reg(int size) {
- assert(MaxVectorSize == 8 && size == 8, "");
- return Op_RegL;
+ if (SuperwordUseVSX) {
+ assert(MaxVectorSize == 16 && size == 16, "");
+ return Op_VecX;
+ } else {
+ assert(MaxVectorSize == 8 && size == 8, "");
+ return Op_RegL;
+ }
}
const uint Matcher::vector_shift_count_ideal_reg(int size) {
@@ -2075,7 +2258,7 @@
// PPC doesn't support misaligned vectors store/load.
const bool Matcher::misaligned_vectors_ok() {
- return false;
+ return !AlignVector; // can be changed by flag
}
// PPC AES support not yet implemented
@@ -2217,10 +2400,31 @@
F13_num
};
+const MachRegisterNumbers vsarg_reg[64] = {
+ VSR0_num, VSR1_num, VSR2_num, VSR3_num,
+ VSR4_num, VSR5_num, VSR6_num, VSR7_num,
+ VSR8_num, VSR9_num, VSR10_num, VSR11_num,
+ VSR12_num, VSR13_num, VSR14_num, VSR15_num,
+ VSR16_num, VSR17_num, VSR18_num, VSR19_num,
+ VSR20_num, VSR21_num, VSR22_num, VSR23_num,
+ VSR24_num, VSR23_num, VSR24_num, VSR25_num,
+ VSR28_num, VSR29_num, VSR30_num, VSR31_num,
+ VSR32_num, VSR33_num, VSR34_num, VSR35_num,
+ VSR36_num, VSR37_num, VSR38_num, VSR39_num,
+ VSR40_num, VSR41_num, VSR42_num, VSR43_num,
+ VSR44_num, VSR45_num, VSR46_num, VSR47_num,
+ VSR48_num, VSR49_num, VSR50_num, VSR51_num,
+ VSR52_num, VSR53_num, VSR54_num, VSR55_num,
+ VSR56_num, VSR57_num, VSR58_num, VSR59_num,
+ VSR60_num, VSR61_num, VSR62_num, VSR63_num
+};
+
const int num_iarg_registers = sizeof(iarg_reg) / sizeof(iarg_reg[0]);
const int num_farg_registers = sizeof(farg_reg) / sizeof(farg_reg[0]);
+const int num_vsarg_registers = sizeof(vsarg_reg) / sizeof(vsarg_reg[0]);
+
// Return whether or not this register is ever used as an argument. This
// function is used on startup to build the trampoline stubs in generateOptoStub.
// Registers not mentioned will be killed by the VM call in the trampoline, and
@@ -2552,6 +2756,115 @@
return nodes;
}
+typedef struct {
+ loadConL_hiNode *_large_hi;
+ loadConL_loNode *_large_lo;
+ mtvsrdNode *_moved;
+ xxspltdNode *_replicated;
+ loadConLNode *_small;
+ MachNode *_last;
+} loadConLReplicatedNodesTuple;
+
+loadConLReplicatedNodesTuple loadConLReplicatedNodesTuple_create(Compile *C, PhaseRegAlloc *ra_, Node *toc, immLOper *immSrc,
+ vecXOper *dst, immI_0Oper *zero,
+ OptoReg::Name reg_second, OptoReg::Name reg_first,
+ OptoReg::Name reg_vec_second, OptoReg::Name reg_vec_first) {
+ loadConLReplicatedNodesTuple nodes;
+
+ const bool large_constant_pool = true; // TODO: PPC port C->cfg()->_consts_size > 4000;
+ if (large_constant_pool) {
+ // Create new nodes.
+ loadConL_hiNode *m1 = new loadConL_hiNode();
+ loadConL_loNode *m2 = new loadConL_loNode();
+ mtvsrdNode *m3 = new mtvsrdNode();
+ xxspltdNode *m4 = new xxspltdNode();
+
+ // inputs for new nodes
+ m1->add_req(NULL, toc);
+ m2->add_req(NULL, m1);
+ m3->add_req(NULL, m2);
+ m4->add_req(NULL, m3);
+
+ // operands for new nodes
+ m1->_opnds[0] = new iRegLdstOper(); // dst
+ m1->_opnds[1] = immSrc; // src
+ m1->_opnds[2] = new iRegPdstOper(); // toc
+
+ m2->_opnds[0] = new iRegLdstOper(); // dst
+ m2->_opnds[1] = immSrc; // src
+ m2->_opnds[2] = new iRegLdstOper(); // base
+
+ m3->_opnds[0] = new vecXOper(); // dst
+ m3->_opnds[1] = new iRegLdstOper(); // src
+
+ m4->_opnds[0] = new vecXOper(); // dst
+ m4->_opnds[1] = new vecXOper(); // src
+ m4->_opnds[2] = zero;
+
+ // Initialize ins_attrib TOC fields.
+ m1->_const_toc_offset = -1;
+ m2->_const_toc_offset_hi_node = m1;
+
+ // Initialize ins_attrib instruction offset.
+ m1->_cbuf_insts_offset = -1;
+
+ // register allocation for new nodes
+ ra_->set_pair(m1->_idx, reg_second, reg_first);
+ ra_->set_pair(m2->_idx, reg_second, reg_first);
+ ra_->set1(m3->_idx, reg_second);
+ ra_->set2(m3->_idx, reg_vec_first);
+ ra_->set_pair(m4->_idx, reg_vec_second, reg_vec_first);
+
+ // Create result.
+ nodes._large_hi = m1;
+ nodes._large_lo = m2;
+ nodes._moved = m3;
+ nodes._replicated = m4;
+ nodes._small = NULL;
+ nodes._last = nodes._replicated;
+ assert(m2->bottom_type()->isa_long(), "must be long");
+ } else {
+ loadConLNode *m2 = new loadConLNode();
+ mtvsrdNode *m3 = new mtvsrdNode();
+ xxspltdNode *m4 = new xxspltdNode();
+
+ // inputs for new nodes
+ m2->add_req(NULL, toc);
+
+ // operands for new nodes
+ m2->_opnds[0] = new iRegLdstOper(); // dst
+ m2->_opnds[1] = immSrc; // src
+ m2->_opnds[2] = new iRegPdstOper(); // toc
+
+ m3->_opnds[0] = new vecXOper(); // dst
+ m3->_opnds[1] = new iRegLdstOper(); // src
+
+ m4->_opnds[0] = new vecXOper(); // dst
+ m4->_opnds[1] = new vecXOper(); // src
+ m4->_opnds[2] = zero;
+
+ // Initialize ins_attrib instruction offset.
+ m2->_cbuf_insts_offset = -1;
+ ra_->set1(m3->_idx, reg_second);
+ ra_->set2(m3->_idx, reg_vec_first);
+ ra_->set_pair(m4->_idx, reg_vec_second, reg_vec_first);
+
+ // register allocation for new nodes
+ ra_->set_pair(m2->_idx, reg_second, reg_first);
+
+ // Create result.
+ nodes._large_hi = NULL;
+ nodes._large_lo = NULL;
+ nodes._small = m2;
+ nodes._moved = m3;
+ nodes._replicated = m4;
+ nodes._last = nodes._replicated;
+ assert(m2->bottom_type()->isa_long(), "must be long");
+ }
+
+ return nodes;
+}
+
%} // source
encode %{
@@ -3212,6 +3525,27 @@
assert(loadConLNodes._last->bottom_type()->isa_long(), "must be long");
%}
+ enc_class postalloc_expand_load_replF_constant_vsx(vecX dst, immF src, iRegLdst toc) %{
+ // Create new nodes.
+
+ // Make an operand with the bit pattern to load as float.
+ immLOper *op_repl = new immLOper((jlong)replicate_immF(op_src->constantF()));
+ immI_0Oper *op_zero = new immI_0Oper(0);
+
+ loadConLReplicatedNodesTuple loadConLNodes =
+ loadConLReplicatedNodesTuple_create(C, ra_, n_toc, op_repl, op_dst, op_zero,
+ OptoReg::Name(R20_H_num), OptoReg::Name(R20_num),
+ OptoReg::Name(VSR11_num), OptoReg::Name(VSR10_num));
+
+ // Push new nodes.
+ if (loadConLNodes._large_hi) { nodes->push(loadConLNodes._large_hi); }
+ if (loadConLNodes._large_lo) { nodes->push(loadConLNodes._large_lo); }
+ if (loadConLNodes._moved) { nodes->push(loadConLNodes._moved); }
+ if (loadConLNodes._last) { nodes->push(loadConLNodes._last); }
+
+ assert(nodes->length() >= 1, "must have created at least 1 node");
+ %}
+
// This enc_class is needed so that scheduler gets proper
// input mapping for latency computation.
enc_class enc_poll(immI dst, iRegLdst poll) %{
@@ -3840,6 +4174,14 @@
//
// Formats are generated automatically for constants and base registers.
+operand vecX() %{
+ constraint(ALLOC_IN_RC(vs_reg));
+ match(VecX);
+
+ format %{ %}
+ interface(REG_INTER);
+%}
+
//----------Simple Operands----------------------------------------------------
// Immediate Operands
@@ -5372,6 +5714,20 @@
ins_pipe(pipe_class_memory);
%}
+// Load Aligned Packed Byte
+instruct loadV16(vecX dst, indirect mem) %{
+ predicate(n->as_LoadVector()->memory_size() == 16);
+ match(Set dst (LoadVector mem));
+ ins_cost(MEMORY_REF_COST);
+
+ format %{ "LXVD2X $dst, $mem \t// load 16-byte Vector" %}
+ size(4);
+ ins_encode %{
+ __ lxvd2x($dst$$VectorSRegister, $mem$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
// Load Range, range = array length (=jint)
instruct loadRange(iRegIdst dst, memory mem) %{
match(Set dst (LoadRange mem));
@@ -6368,6 +6724,20 @@
ins_pipe(pipe_class_memory);
%}
+// Store Packed Byte long register to memory
+instruct storeV16(indirect mem, vecX src) %{
+ predicate(n->as_StoreVector()->memory_size() == 16);
+ match(Set mem (StoreVector mem src));
+ ins_cost(MEMORY_REF_COST);
+
+ format %{ "STXVD2X $mem, $src \t// store 16-byte Vector" %}
+ size(4);
+ ins_encode %{
+ __ stxvd2x($src$$VectorSRegister, $mem$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
// Store Compressed Oop
instruct storeN(memory dst, iRegN_P2N src) %{
match(Set dst (StoreN dst src));
@@ -13239,6 +13609,26 @@
ins_pipe(pipe_class_default);
%}
+instruct mtvsrwz(vecX temp1, iRegIsrc src) %{
+ effect(DEF temp1, USE src);
+
+ size(4);
+ ins_encode %{
+ __ mtvsrwz($temp1$$VectorSRegister, $src$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct xxspltw(vecX dst, vecX src, immI8 imm1) %{
+ effect(DEF dst, USE src, USE imm1);
+
+ size(4);
+ ins_encode %{
+ __ xxspltw($dst$$VectorSRegister, $src$$VectorSRegister, $imm1$$constant);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
//---------- Replicate Vector Instructions ------------------------------------
// Insrdi does replicate if src == dst.
@@ -13318,6 +13708,46 @@
ins_pipe(pipe_class_default);
%}
+instruct repl16B_reg_Ex(vecX dst, iRegIsrc src) %{
+ match(Set dst (ReplicateB src));
+ predicate(n->as_Vector()->length() == 16);
+
+ expand %{
+ iRegLdst tmpL;
+ vecX tmpV;
+ immI8 imm1 %{ (int) 1 %}
+ moveReg(tmpL, src);
+ repl56(tmpL);
+ repl48(tmpL);
+ mtvsrwz(tmpV, tmpL);
+ xxspltw(dst, tmpV, imm1);
+ %}
+%}
+
+instruct repl16B_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateB zero));
+ predicate(n->as_Vector()->length() == 16);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl16B_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateB src));
+ predicate(n->as_Vector()->length() == 16);
+
+ format %{ "XXLEQV $dst, $src \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct repl4S_reg_Ex(iRegLdst dst, iRegIsrc src) %{
match(Set dst (ReplicateS src));
predicate(n->as_Vector()->length() == 4);
@@ -13352,6 +13782,46 @@
ins_pipe(pipe_class_default);
%}
+instruct repl8S_reg_Ex(vecX dst, iRegIsrc src) %{
+ match(Set dst (ReplicateS src));
+ predicate(n->as_Vector()->length() == 8);
+
+ expand %{
+ iRegLdst tmpL;
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+ moveReg(tmpL, src);
+ repl48(tmpL);
+ repl32(tmpL);
+ mtvsrd(tmpV, tmpL);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl8S_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateS zero));
+ predicate(n->as_Vector()->length() == 8);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate8S" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl8S_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateS src));
+ predicate(n->as_Vector()->length() == 8);
+
+ format %{ "XXLEQV $dst, $src \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct repl2I_reg_Ex(iRegLdst dst, iRegIsrc src) %{
match(Set dst (ReplicateI src));
predicate(n->as_Vector()->length() == 2);
@@ -13386,6 +13856,46 @@
ins_pipe(pipe_class_default);
%}
+instruct repl4I_reg_Ex(vecX dst, iRegIsrc src) %{
+ match(Set dst (ReplicateI src));
+ predicate(n->as_Vector()->length() == 4);
+ ins_cost(2 * DEFAULT_COST);
+
+ expand %{
+ iRegLdst tmpL;
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+ moveReg(tmpL, src);
+ repl32(tmpL);
+ mtvsrd(tmpV, tmpL);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl4I_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateI zero));
+ predicate(n->as_Vector()->length() == 4);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate4I" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl4I_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateI src));
+ predicate(n->as_Vector()->length() == 4);
+
+ format %{ "XXLEQV $dst, $dst, $dst \t// replicate4I" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
// Move float to int register via stack, replicate.
instruct repl2F_reg_Ex(iRegLdst dst, regF src) %{
match(Set dst (ReplicateF src));
@@ -13484,6 +13994,154 @@
%}
+instruct repl4F_reg_Ex(vecX dst, regF src) %{
+ match(Set dst (ReplicateF src));
+ predicate(n->as_Vector()->length() == 4);
+ ins_cost(2 * MEMORY_REF_COST + DEFAULT_COST);
+ expand %{
+ stackSlotL tmpS;
+ iRegIdst tmpI;
+ iRegLdst tmpL;
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+
+ moveF2I_reg_stack(tmpS, src); // Move float to stack.
+ moveF2I_stack_reg(tmpI, tmpS); // Move stack to int reg.
+ moveReg(tmpL, tmpI); // Move int to long reg.
+ repl32(tmpL); // Replicate bitpattern.
+ mtvsrd(tmpV, tmpL);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl4F_immF_Ex(vecX dst, immF src) %{
+ match(Set dst (ReplicateF src));
+ predicate(n->as_Vector()->length() == 4);
+ ins_cost(10 * DEFAULT_COST);
+
+ postalloc_expand( postalloc_expand_load_replF_constant_vsx(dst, src, constanttablebase) );
+%}
+
+instruct repl4F_immF0(vecX dst, immF_0 zero) %{
+ match(Set dst (ReplicateF zero));
+ predicate(n->as_Vector()->length() == 4);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate4F" %}
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl2D_reg_Ex(vecX dst, regD src) %{
+ match(Set dst (ReplicateD src));
+ predicate(n->as_Vector()->length() == 2);
+ expand %{
+ stackSlotL tmpS;
+ iRegLdst tmpL;
+ iRegLdst tmp;
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+ moveD2L_reg_stack(tmpS, src);
+ moveD2L_stack_reg(tmpL, tmpS);
+ mtvsrd(tmpV, tmpL);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl2D_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateD zero));
+ predicate(n->as_Vector()->length() == 2);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate2D" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl2D_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateD src));
+ predicate(n->as_Vector()->length() == 2);
+
+ format %{ "XXLEQV $dst, $src \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct mtvsrd(vecX dst, iRegLsrc src) %{
+ predicate(false);
+ effect(DEF dst, USE src);
+
+ format %{ "MTVSRD $dst, $src \t// Move to 16-byte register"%}
+ size(4);
+ ins_encode %{
+ __ mtvsrd($dst$$VectorSRegister, $src$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct xxspltd(vecX dst, vecX src, immI8 zero) %{
+ effect(DEF dst, USE src, USE zero);
+
+ format %{ "XXSPLATD $dst, $src, $zero \t// Permute 16-byte register"%}
+ size(4);
+ ins_encode %{
+ __ xxpermdi($dst$$VectorSRegister, $src$$VectorSRegister, $src$$VectorSRegister, $zero$$constant);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct xxpermdi(vecX dst, vecX src1, vecX src2, immI8 zero) %{
+ effect(DEF dst, USE src1, USE src2, USE zero);
+
+ format %{ "XXPERMDI $dst, $src1, $src2, $zero \t// Permute 16-byte register"%}
+ size(4);
+ ins_encode %{
+ __ xxpermdi($dst$$VectorSRegister, $src1$$VectorSRegister, $src2$$VectorSRegister, $zero$$constant);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl2L_reg_Ex(vecX dst, iRegLsrc src) %{
+ match(Set dst (ReplicateL src));
+ predicate(n->as_Vector()->length() == 2);
+ expand %{
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+ mtvsrd(tmpV, src);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl2L_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateL zero));
+ predicate(n->as_Vector()->length() == 2);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate2L" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl2L_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateL src));
+ predicate(n->as_Vector()->length() == 2);
+
+ format %{ "XXLEQV $dst, $src \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
// ============================================================================
// Safepoint Instruction
--- a/src/hotspot/cpu/ppc/register_definitions_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/register_definitions_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -31,3 +31,5 @@
REGISTER_DEFINITION(Register, noreg);
REGISTER_DEFINITION(FloatRegister, fnoreg);
+
+REGISTER_DEFINITION(VectorSRegister, vsnoreg);
--- a/src/hotspot/cpu/ppc/register_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/register_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -677,7 +677,7 @@
* 2 // register halves
+ ConditionRegisterImpl::number_of_registers // condition code registers
+ SpecialRegisterImpl::number_of_registers // special registers
- + VectorRegisterImpl::number_of_registers // VSX registers
+ + VectorSRegisterImpl::number_of_registers // VSX registers
};
static const int max_gpr;
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -479,8 +479,8 @@
// Is vector's size (in bytes) bigger than a size saved by default?
bool SharedRuntime::is_wide_vector(int size) {
- // Note, MaxVectorSize == 8 on PPC64.
- assert(size <= 8, "%d bytes vectors are not supported", size);
+ // Note, MaxVectorSize == 8/16 on PPC64.
+ assert(size <= (SuperwordUseVSX ? 16 : 8), "%d bytes vectors are not supported", size);
return size > 8;
}
@@ -2234,9 +2234,6 @@
__ release();
// TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
__ stw(R0, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
// The JNI call
@@ -2393,9 +2390,6 @@
__ release();
// TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
__ stw(R0, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
__ bind(after_transition);
// Reguard any pages if necessary.
--- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1470,10 +1470,6 @@
// TODO PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
__ stw(R0, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
-
//=============================================================================
// Call the native method. Argument registers must not have been
// overwritten since "__ call_stub(signature_handler);" (except for
@@ -1594,9 +1590,6 @@
__ li(R0/*thread_state*/, _thread_in_Java);
__ release();
__ stw(R0/*thread_state*/, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
if (CheckJNICalls) {
// clear_pending_jni_exception_check
--- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2224,6 +2224,7 @@
if (is_static) {
__ ld(Robj, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f1_offset()), Rcache);
__ ld(Robj, in_bytes(Klass::java_mirror_offset()), Robj);
+ __ resolve_oop_handle(Robj);
// Acquire not needed here. Following access has an address dependency on this value.
}
}
--- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -107,7 +107,17 @@
// TODO: PPC port PdScheduling::power6SectorSize = 0x20;
}
- MaxVectorSize = 8;
+ if (PowerArchitecturePPC64 >= 8) {
+ if (FLAG_IS_DEFAULT(SuperwordUseVSX)) {
+ FLAG_SET_ERGO(bool, SuperwordUseVSX, true);
+ }
+ } else {
+ if (SuperwordUseVSX) {
+ warning("SuperwordUseVSX specified, but needs at least Power8.");
+ FLAG_SET_DEFAULT(SuperwordUseVSX, false);
+ }
+ }
+ MaxVectorSize = SuperwordUseVSX ? 16 : 8;
#endif
// Create and print feature-string.
--- a/src/hotspot/cpu/s390/assembler_s390.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/assembler_s390.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1276,6 +1276,13 @@
// Test under Mask
#define VTM_ZOPC (unsigned long)(0xe7L << 40 | 0xd8L << 0) // Like TM, set CC according to state of selected bits.
+//---< Vector String Instructions >---
+#define VFAE_ZOPC (unsigned long)(0xe7L << 40 | 0x82L << 0) // Find any element
+#define VFEE_ZOPC (unsigned long)(0xe7L << 40 | 0x80L << 0) // Find element equal
+#define VFENE_ZOPC (unsigned long)(0xe7L << 40 | 0x81L << 0) // Find element not equal
+#define VSTRC_ZOPC (unsigned long)(0xe7L << 40 | 0x8aL << 0) // String range compare
+#define VISTR_ZOPC (unsigned long)(0xe7L << 40 | 0x5cL << 0) // Isolate String
+
//--------------------------------
//-- Miscellaneous Operations --
@@ -1475,10 +1482,18 @@
VRET_QW = 4
};
- // Vector Operation Condition Code Control.
- enum VOpCCC {
- VOP_CCIGN = 0, // ignore, don't set CC
- VOP_CCSET = 1 // set the CC
+ // Vector Operation Result Control.
+ // This is a set of flags used in some vector instructions to control
+ // the result (side) effects of instruction execution.
+ enum VOpRC {
+ VOPRC_CCSET = 0b0001, // set the CC.
+ VOPRC_CCIGN = 0b0000, // ignore, don't set CC.
+ VOPRC_ZS = 0b0010, // Zero Search. Additional, elementwise, comparison against zero.
+ VOPRC_NOZS = 0b0000, // No Zero Search.
+ VOPRC_RTBYTEIX = 0b0100, // generate byte index to lowest element with true comparison.
+ VOPRC_RTBITVEC = 0b0000, // generate bit vector, all 1s for true, all 0s for false element comparisons.
+ VOPRC_INVERT = 0b1000, // invert comparison results.
+ VOPRC_NOINVERT = 0b0000 // use comparison results as is, do not invert.
};
// Inverse condition code, i.e. determine "15 - cc" for a given condition code cc.
@@ -1625,10 +1640,15 @@
return uimm4(ix, pos, 48);
}
- // Vector Operation Condition Code Control. 4-bit field, one bit of which indicates if the condition code is to be set by the operation.
- static int64_t vccc_mask(int64_t flag, int pos) {
- assert((flag == VOP_CCIGN) || (flag == VOP_CCSET), "VCCC flag value out of range");
- return uimm4(flag, pos, 48);
+ // Vector Operation Result Control. 4-bit field.
+ static int64_t voprc_any(int64_t flags, int pos, int64_t allowed_flags = 0b1111) {
+ assert((flags & allowed_flags) == flags, "Invalid VOPRC_* flag combination: %d", (int)flags);
+ return uimm4(flags, pos, 48);
+ }
+
+ // Vector Operation Result Control. Condition code setting.
+ static int64_t voprc_ccmask(int64_t flags, int pos) {
+ return voprc_any(flags, pos, VOPRC_CCIGN | VOPRC_CCSET);
}
public:
@@ -2772,6 +2792,31 @@
// Test under Mask
inline void z_vtm( VectorRegister v1, VectorRegister v2);
+ //---< Vector String Instructions >---
+ inline void z_vfae( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5); // Find any element
+ inline void z_vfaeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfaeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfaef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfee( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5); // Find element equal
+ inline void z_vfeeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfeeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfeef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfene( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5); // Find element not equal
+ inline void z_vfeneb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfeneh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfenef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vstrc( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t imm5, int64_t cc6); // String range compare
+ inline void z_vstrcb( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6);
+ inline void z_vstrch( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6);
+ inline void z_vstrcf( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6);
+ inline void z_vistr( VectorRegister v1, VectorRegister v2, int64_t imm3, int64_t cc5); // Isolate String
+ inline void z_vistrb( VectorRegister v1, VectorRegister v2, int64_t cc5);
+ inline void z_vistrh( VectorRegister v1, VectorRegister v2, int64_t cc5);
+ inline void z_vistrf( VectorRegister v1, VectorRegister v2, int64_t cc5);
+ inline void z_vistrbs(VectorRegister v1, VectorRegister v2);
+ inline void z_vistrhs(VectorRegister v1, VectorRegister v2);
+ inline void z_vistrfs(VectorRegister v1, VectorRegister v2);
+
// Floatingpoint instructions
// ==========================
--- a/src/hotspot/cpu/s390/assembler_s390.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/assembler_s390.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -762,21 +762,21 @@
inline void Assembler::z_vpkf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpk(v1, v2, v3, VRET_FW); } // vector element type 'F'
inline void Assembler::z_vpkg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpk(v1, v2, v3, VRET_DW); } // vector element type 'G'
-inline void Assembler::z_vpks( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vpksh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vpksf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vpksg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vpkshs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', set CC
-inline void Assembler::z_vpksfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', set CC
-inline void Assembler::z_vpksgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', set CC
+inline void Assembler::z_vpks( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vpksh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vpksf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vpksg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vpkshs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', set CC
+inline void Assembler::z_vpksfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', set CC
+inline void Assembler::z_vpksgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', set CC
-inline void Assembler::z_vpkls( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKLS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vpklsh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vpklsf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vpklsg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vpklshs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', set CC
-inline void Assembler::z_vpklsfs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', set CC
-inline void Assembler::z_vpklsgs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', set CC
+inline void Assembler::z_vpkls( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKLS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vpklsh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vpklsf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vpklsg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vpklshs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', set CC
+inline void Assembler::z_vpklsfs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', set CC
+inline void Assembler::z_vpklsgs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', set CC
// vector register unpack (sign-extended)
inline void Assembler::z_vuph( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VUPH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_FW, 32)); }
@@ -967,33 +967,33 @@
inline void Assembler::z_vo( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); }
// Comparison (element-wise)
-inline void Assembler::z_vceq( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCEQ_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vceqb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOP_CCIGN); } // vector element type 'B', don't set CC
-inline void Assembler::z_vceqh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vceqf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vceqg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vceqbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOP_CCSET); } // vector element type 'B', don't set CC
-inline void Assembler::z_vceqhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', don't set CC
-inline void Assembler::z_vceqfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', don't set CC
-inline void Assembler::z_vceqgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', don't set CC
-inline void Assembler::z_vch( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vchb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOP_CCIGN); } // vector element type 'B', don't set CC
-inline void Assembler::z_vchh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vchf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vchg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vchbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOP_CCSET); } // vector element type 'B', don't set CC
-inline void Assembler::z_vchhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', don't set CC
-inline void Assembler::z_vchfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', don't set CC
-inline void Assembler::z_vchgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', don't set CC
-inline void Assembler::z_vchl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCHL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vchlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOP_CCIGN); } // vector element type 'B', don't set CC
-inline void Assembler::z_vchlh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vchlf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vchlg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vchlbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOP_CCSET); } // vector element type 'B', don't set CC
-inline void Assembler::z_vchlhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', don't set CC
-inline void Assembler::z_vchlfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', don't set CC
-inline void Assembler::z_vchlgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', don't set CC
+inline void Assembler::z_vceq( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCEQ_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vceqb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOPRC_CCIGN); } // vector element type 'B', don't set CC
+inline void Assembler::z_vceqh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vceqf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vceqg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vceqbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOPRC_CCSET); } // vector element type 'B', don't set CC
+inline void Assembler::z_vceqhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', don't set CC
+inline void Assembler::z_vceqfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', don't set CC
+inline void Assembler::z_vceqgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', don't set CC
+inline void Assembler::z_vch( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vchb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOPRC_CCIGN); } // vector element type 'B', don't set CC
+inline void Assembler::z_vchh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vchf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vchg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vchbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOPRC_CCSET); } // vector element type 'B', don't set CC
+inline void Assembler::z_vchhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', don't set CC
+inline void Assembler::z_vchfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', don't set CC
+inline void Assembler::z_vchgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', don't set CC
+inline void Assembler::z_vchl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCHL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vchlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOPRC_CCIGN); } // vector element type 'B', don't set CC
+inline void Assembler::z_vchlh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vchlf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vchlg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vchlbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOPRC_CCSET); } // vector element type 'B', don't set CC
+inline void Assembler::z_vchlhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', don't set CC
+inline void Assembler::z_vchlfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', don't set CC
+inline void Assembler::z_vchlgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', don't set CC
// Max/Min (element-wise)
inline void Assembler::z_vmx( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMX_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); }
@@ -1091,6 +1091,31 @@
// Test under Mask
inline void Assembler::z_vtm( VectorRegister v1, VectorRegister v2) {emit_48(VTM_ZOPC | vreg(v1, 8) | vreg(v2, 12)); }
+//---< Vector String Instructions >---
+inline void Assembler::z_vfae( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5) {emit_48(VFAE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(imm4, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // Find any element
+inline void Assembler::z_vfaeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfae(v1, v2, v3, VRET_BYTE, cc5); }
+inline void Assembler::z_vfaeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfae(v1, v2, v3, VRET_HW, cc5); }
+inline void Assembler::z_vfaef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfae(v1, v2, v3, VRET_FW, cc5); }
+inline void Assembler::z_vfee( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5) {emit_48(VFEE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(imm4, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // Find element equal
+inline void Assembler::z_vfeeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfee(v1, v2, v3, VRET_BYTE, cc5); }
+inline void Assembler::z_vfeeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfee(v1, v2, v3, VRET_HW, cc5); }
+inline void Assembler::z_vfeef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfee(v1, v2, v3, VRET_FW, cc5); }
+inline void Assembler::z_vfene( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5) {emit_48(VFENE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(imm4, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // Find element not equal
+inline void Assembler::z_vfeneb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfene(v1, v2, v3, VRET_BYTE, cc5); }
+inline void Assembler::z_vfeneh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfene(v1, v2, v3, VRET_HW, cc5); }
+inline void Assembler::z_vfenef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfene(v1, v2, v3, VRET_FW, cc5); }
+inline void Assembler::z_vstrc( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t imm5, int64_t cc6) {emit_48(VSTRC_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(imm5, VRET_BYTE, VRET_FW, 20) | voprc_any(cc6, 24) ); } // String range compare
+inline void Assembler::z_vstrcb( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6) {z_vstrc(v1, v2, v3, v4, VRET_BYTE, cc6); }
+inline void Assembler::z_vstrch( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6) {z_vstrc(v1, v2, v3, v4, VRET_HW, cc6); }
+inline void Assembler::z_vstrcf( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6) {z_vstrc(v1, v2, v3, v4, VRET_FW, cc6); }
+inline void Assembler::z_vistr( VectorRegister v1, VectorRegister v2, int64_t imm3, int64_t cc5) {emit_48(VISTR_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(imm3, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // isolate string
+inline void Assembler::z_vistrb( VectorRegister v1, VectorRegister v2, int64_t cc5) {z_vistr(v1, v2, VRET_BYTE, cc5); }
+inline void Assembler::z_vistrh( VectorRegister v1, VectorRegister v2, int64_t cc5) {z_vistr(v1, v2, VRET_HW, cc5); }
+inline void Assembler::z_vistrf( VectorRegister v1, VectorRegister v2, int64_t cc5) {z_vistr(v1, v2, VRET_FW, cc5); }
+inline void Assembler::z_vistrbs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_BYTE, VOPRC_CCSET); }
+inline void Assembler::z_vistrhs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_HW, VOPRC_CCSET); }
+inline void Assembler::z_vistrfs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_FW, VOPRC_CCSET); }
+
//-------------------------------
// FLOAT INSTRUCTIONS
--- a/src/hotspot/cpu/s390/globals_s390.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/globals_s390.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017 SAP SE. 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
@@ -34,7 +34,7 @@
// Sorted according to sparc.
// z/Architecture remembers branch targets, so don't share vtables.
-define_pd_global(bool, ShareVtableStubs, false);
+define_pd_global(bool, ShareVtableStubs, true);
define_pd_global(bool, NeedsDeoptSuspend, false); // Only register window machines need this.
define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks.
--- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -4671,6 +4671,7 @@
mem2reg_opt(mirror, Address(mirror, ConstMethod::constants_offset()));
mem2reg_opt(mirror, Address(mirror, ConstantPool::pool_holder_offset_in_bytes()));
mem2reg_opt(mirror, Address(mirror, Klass::java_mirror_offset()));
+ resolve_oop_handle(mirror);
}
//---------------------------------------------------------------
--- a/src/hotspot/cpu/s390/templateTable_s390.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/templateTable_s390.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2382,6 +2382,7 @@
if (is_static) {
__ mem2reg_opt(obj, Address(cache, index, cp_base_offset + ConstantPoolCacheEntry::f1_offset()));
__ mem2reg_opt(obj, Address(obj, Klass::java_mirror_offset()));
+ __ resolve_oop_handle(obj);
}
}
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3844,6 +3844,7 @@
ld_ptr(mirror, in_bytes(ConstMethod::constants_offset()), mirror);
ld_ptr(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror);
ld_ptr(mirror, mirror_offset, mirror);
+ resolve_oop_handle(mirror);
}
void MacroAssembler::load_klass(Register src_oop, Register klass) {
--- a/src/hotspot/cpu/sparc/templateTable_sparc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/sparc/templateTable_sparc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2049,6 +2049,7 @@
__ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f1_offset(), Robj);
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ ld_ptr( Robj, mirror_offset, Robj);
+ __ resolve_oop_handle(Robj);
}
}
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -6617,6 +6617,7 @@
movptr(mirror, Address(mirror, ConstMethod::constants_offset()));
movptr(mirror, Address(mirror, ConstantPool::pool_holder_offset_in_bytes()));
movptr(mirror, Address(mirror, mirror_offset));
+ resolve_oop_handle(mirror);
}
void MacroAssembler::load_klass(Register dst, Register src) {
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/x86/templateTable_x86.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2665,6 +2665,7 @@
ConstantPoolCacheEntry::f1_offset())));
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ movptr(obj, Address(obj, mirror_offset));
+ __ resolve_oop_handle(obj);
}
}
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -46,7 +46,7 @@
address VM_Version::_cpuinfo_cont_addr = 0;
static BufferBlob* stub_blob;
-static const int stub_size = 1000;
+static const int stub_size = 1100;
extern "C" {
typedef void (*get_cpu_info_stub_t)(void*);
@@ -70,7 +70,7 @@
bool use_evex = FLAG_IS_DEFAULT(UseAVX) || (UseAVX > 2);
Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4;
- Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done, wrapup;
+ Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, ext_cpuid8, done, wrapup;
Label legacy_setup, save_restore_except, legacy_save_restore, start_simd_check;
StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub");
@@ -267,14 +267,30 @@
__ cmpl(rax, 0x80000000); // Is cpuid(0x80000001) supported?
__ jcc(Assembler::belowEqual, done);
__ cmpl(rax, 0x80000004); // Is cpuid(0x80000005) supported?
- __ jccb(Assembler::belowEqual, ext_cpuid1);
+ __ jcc(Assembler::belowEqual, ext_cpuid1);
__ cmpl(rax, 0x80000006); // Is cpuid(0x80000007) supported?
__ jccb(Assembler::belowEqual, ext_cpuid5);
__ cmpl(rax, 0x80000007); // Is cpuid(0x80000008) supported?
__ jccb(Assembler::belowEqual, ext_cpuid7);
+ __ cmpl(rax, 0x80000008); // Is cpuid(0x80000009 and above) supported?
+ __ jccb(Assembler::belowEqual, ext_cpuid8);
+ __ cmpl(rax, 0x8000001E); // Is cpuid(0x8000001E) supported?
+ __ jccb(Assembler::below, ext_cpuid8);
+ //
+ // Extended cpuid(0x8000001E)
+ //
+ __ movl(rax, 0x8000001E);
+ __ cpuid();
+ __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid1E_offset())));
+ __ movl(Address(rsi, 0), rax);
+ __ movl(Address(rsi, 4), rbx);
+ __ movl(Address(rsi, 8), rcx);
+ __ movl(Address(rsi,12), rdx);
+
//
// Extended cpuid(0x80000008)
//
+ __ bind(ext_cpuid8);
__ movl(rax, 0x80000008);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid8_offset())));
@@ -1109,11 +1125,27 @@
}
#ifdef COMPILER2
- if (MaxVectorSize > 16) {
- // Limit vectors size to 16 bytes on current AMD cpus.
+ if (cpu_family() < 0x17 && MaxVectorSize > 16) {
+ // Limit vectors size to 16 bytes on AMD cpus < 17h.
FLAG_SET_DEFAULT(MaxVectorSize, 16);
}
#endif // COMPILER2
+
+ // Some defaults for AMD family 17h
+ if ( cpu_family() == 0x17 ) {
+ // On family 17h processors use XMM and UnalignedLoadStores for Array Copy
+ if (supports_sse2() && FLAG_IS_DEFAULT(UseXMMForArrayCopy)) {
+ FLAG_SET_DEFAULT(UseXMMForArrayCopy, true);
+ }
+ if (supports_sse2() && FLAG_IS_DEFAULT(UseUnalignedLoadStores)) {
+ FLAG_SET_DEFAULT(UseUnalignedLoadStores, true);
+ }
+#ifdef COMPILER2
+ if (supports_sse4_2() && FLAG_IS_DEFAULT(UseFPUForSpilling)) {
+ FLAG_SET_DEFAULT(UseFPUForSpilling, true);
+ }
+#endif
+ }
}
if( is_intel() ) { // Intel cpus specific settings
--- a/src/hotspot/cpu/x86/vm_version_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/x86/vm_version_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -228,6 +228,15 @@
} bits;
};
+ union ExtCpuid1EEbx {
+ uint32_t value;
+ struct {
+ uint32_t : 8,
+ threads_per_core : 8,
+ : 16;
+ } bits;
+ };
+
union XemXcr0Eax {
uint32_t value;
struct {
@@ -398,6 +407,12 @@
ExtCpuid8Ecx ext_cpuid8_ecx;
uint32_t ext_cpuid8_edx; // reserved
+ // cpuid function 0x8000001E // AMD 17h
+ uint32_t ext_cpuid1E_eax;
+ ExtCpuid1EEbx ext_cpuid1E_ebx; // threads per core (AMD17h)
+ uint32_t ext_cpuid1E_ecx;
+ uint32_t ext_cpuid1E_edx; // unused currently
+
// extended control register XCR0 (the XFEATURE_ENABLED_MASK register)
XemXcr0Eax xem_xcr0_eax;
uint32_t xem_xcr0_edx; // reserved
@@ -505,6 +520,14 @@
result |= CPU_CLMUL;
if (_cpuid_info.sef_cpuid7_ebx.bits.rtm != 0)
result |= CPU_RTM;
+ if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0)
+ result |= CPU_ADX;
+ if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0)
+ result |= CPU_BMI2;
+ if (_cpuid_info.sef_cpuid7_ebx.bits.sha != 0)
+ result |= CPU_SHA;
+ if (_cpuid_info.std_cpuid1_ecx.bits.fma != 0)
+ result |= CPU_FMA;
// AMD features.
if (is_amd()) {
@@ -518,16 +541,8 @@
}
// Intel features.
if(is_intel()) {
- if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0)
- result |= CPU_ADX;
- if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0)
- result |= CPU_BMI2;
- if (_cpuid_info.sef_cpuid7_ebx.bits.sha != 0)
- result |= CPU_SHA;
if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0)
result |= CPU_LZCNT;
- if (_cpuid_info.std_cpuid1_ecx.bits.fma != 0)
- result |= CPU_FMA;
// for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw
if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) {
result |= CPU_3DNOW_PREFETCH;
@@ -590,6 +605,7 @@
static ByteSize ext_cpuid5_offset() { return byte_offset_of(CpuidInfo, ext_cpuid5_eax); }
static ByteSize ext_cpuid7_offset() { return byte_offset_of(CpuidInfo, ext_cpuid7_eax); }
static ByteSize ext_cpuid8_offset() { return byte_offset_of(CpuidInfo, ext_cpuid8_eax); }
+ static ByteSize ext_cpuid1E_offset() { return byte_offset_of(CpuidInfo, ext_cpuid1E_eax); }
static ByteSize tpl_cpuidB0_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB0_eax); }
static ByteSize tpl_cpuidB1_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB1_eax); }
static ByteSize tpl_cpuidB2_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB2_eax); }
@@ -673,8 +689,12 @@
if (is_intel() && supports_processor_topology()) {
result = _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus;
} else if (_cpuid_info.std_cpuid1_edx.bits.ht != 0) {
- result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu /
- cores_per_cpu();
+ if (cpu_family() >= 0x17) {
+ result = _cpuid_info.ext_cpuid1E_ebx.bits.threads_per_core + 1;
+ } else {
+ result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu /
+ cores_per_cpu();
+ }
}
return (result == 0 ? 1 : result);
}
--- a/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -34,22 +34,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
//
// machine barrier instructions:
//
@@ -148,13 +132,15 @@
return result;
}
-
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
-
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
// Note that xchg_ptr doesn't necessarily do an acquire
// (see synchronizer.cpp).
- unsigned int old_value;
+ T old_value;
const uint64_t zero = 0;
__asm__ __volatile__ (
@@ -182,15 +168,18 @@
"memory"
);
- return (jint) old_value;
+ return old_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
-
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
// Note that xchg_ptr doesn't necessarily do an acquire
// (see synchronizer.cpp).
- long old_value;
+ T old_value;
const uint64_t zero = 0;
__asm__ __volatile__ (
@@ -218,11 +207,7 @@
"memory"
);
- return (intptr_t) old_value;
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
+ return old_value;
}
inline void cmpxchg_pre_membar(cmpxchg_memory_order order) {
--- a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -27,19 +27,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-
template<size_t byte_size>
struct Atomic::PlatformAdd
: Atomic::FetchAndAdd<Atomic::PlatformAdd<byte_size> >
@@ -61,7 +48,11 @@
return old_value;
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
__asm__ volatile ( "xchgl (%2),%0"
: "=r" (exchange_value)
: "0" (exchange_value), "r" (dest)
@@ -69,10 +60,6 @@
return exchange_value;
}
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
-
template<>
template<typename T>
inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
@@ -102,9 +89,6 @@
}
#ifdef AMD64
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::fetch_and_add(I add_value, D volatile* dest) const {
@@ -118,7 +102,11 @@
return old_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
__asm__ __volatile__ ("xchgq (%2),%0"
: "=r" (exchange_value)
: "0" (exchange_value), "r" (dest)
@@ -140,14 +128,8 @@
return exchange_value;
}
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#else // !AMD64
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
extern "C" {
// defined in bsd_x86.s
jlong _Atomic_cmpxchg_long(jlong, volatile jlong*, jlong, bool);
@@ -164,18 +146,21 @@
return cmpxchg_using_helper<jlong>(_Atomic_cmpxchg_long, exchange_value, dest, compare_value);
}
-inline jlong Atomic::load(const volatile jlong* src) {
+template<>
+template<typename T>
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
volatile jlong dest;
- _Atomic_move_long(src, &dest);
- return dest;
+ _Atomic_move_long(reinterpret_cast<const volatile jlong*>(src), reinterpret_cast<volatile jlong*>(&dest));
+ return PrimitiveConversions::cast<T>(dest);
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest);
-}
-
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- _Atomic_move_long((volatile jlong*)&store_value, dest);
+template<>
+template<typename T>
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ _Atomic_move_long(reinterpret_cast<const volatile jlong*>(&store_value), reinterpret_cast<volatile jlong*>(dest));
}
#endif // AMD64
--- a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -87,7 +87,7 @@
/* Atomically write VALUE into `*PTR' and returns the previous
contents of `*PTR'. */
-static inline int m68k_lock_test_and_set(volatile int *ptr, int newval) {
+static inline int m68k_lock_test_and_set(int newval, volatile int *ptr) {
for (;;) {
// Loop until success.
int prev = *ptr;
@@ -148,7 +148,7 @@
/* Atomically write VALUE into `*PTR' and returns the previous
contents of `*PTR'. */
-static inline int arm_lock_test_and_set(volatile int *ptr, int newval) {
+static inline int arm_lock_test_and_set(int newval, volatile int *ptr) {
for (;;) {
// Loop until a __kernel_cmpxchg succeeds.
int prev = *ptr;
@@ -159,20 +159,6 @@
}
#endif // ARM
-inline void Atomic::store(jint store_value, volatile jint* dest) {
-#if !defined(ARM) && !defined(M68K)
- __sync_synchronize();
-#endif
- *dest = store_value;
-}
-
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) {
-#if !defined(ARM) && !defined(M68K)
- __sync_synchronize();
-#endif
- *dest = store_value;
-}
-
template<size_t byte_size>
struct Atomic::PlatformAdd
: Atomic::AddAndFetch<Atomic::PlatformAdd<byte_size> >
@@ -207,18 +193,22 @@
return __sync_add_and_fetch(dest, add_value);
}
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
#ifdef ARM
- return arm_lock_test_and_set(dest, exchange_value);
+ return xchg_using_helper<int>(arm_lock_test_and_set, exchange_value, dest);
#else
#ifdef M68K
- return m68k_lock_test_and_set(dest, exchange_value);
+ return xchg_using_helper<int>(m68k_lock_test_and_set, exchange_value, dest);
#else
// __sync_lock_test_and_set is a bizarrely named atomic exchange
// operation. Note that some platforms only support this with the
// limitation that the only valid value to store is the immediate
// constant 1. There is a test for this in JNI_CreateJavaVM().
- jint result = __sync_lock_test_and_set (dest, exchange_value);
+ T result = __sync_lock_test_and_set (dest, exchange_value);
// All atomic operations are expected to be full memory barriers
// (see atomic.hpp). However, __sync_lock_test_and_set is not
// a full memory barrier, but an acquire barrier. Hence, this added
@@ -229,24 +219,14 @@
#endif // ARM
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value,
- volatile intptr_t* dest) {
-#ifdef ARM
- return arm_lock_test_and_set(dest, exchange_value);
-#else
-#ifdef M68K
- return m68k_lock_test_and_set(dest, exchange_value);
-#else
- intptr_t result = __sync_lock_test_and_set (dest, exchange_value);
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T result = __sync_lock_test_and_set (dest, exchange_value);
__sync_synchronize();
return result;
-#endif // M68K
-#endif // ARM
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void *) xchg_ptr((intptr_t) exchange_value,
- (volatile intptr_t*) dest);
}
// No direct support for cmpxchg of bytes; emulate using int.
@@ -281,18 +261,21 @@
return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
}
-inline jlong Atomic::load(const volatile jlong* src) {
+template<>
+template<typename T>
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
volatile jlong dest;
- os::atomic_copy64(src, &dest);
- return dest;
+ os::atomic_copy64(reinterpret_cast<const volatile jlong*>(src), reinterpret_cast<volatile jlong*>(&dest));
+ return PrimitiveConversions::cast<T>(dest);
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- os::atomic_copy64((volatile jlong*)&store_value, (volatile jlong*)dest);
-}
-
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- os::atomic_copy64((volatile jlong*)&store_value, dest);
+template<>
+template<typename T>
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ os::atomic_copy64(reinterpret_cast<const volatile jlong*>(&store_value), reinterpret_cast<volatile jlong*>(dest));
}
#endif // OS_CPU_BSD_ZERO_VM_ATOMIC_BSD_ZERO_HPP
--- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -34,19 +34,6 @@
#define READ_MEM_BARRIER __atomic_thread_fence(__ATOMIC_ACQUIRE);
#define WRITE_MEM_BARRIER __atomic_thread_fence(__ATOMIC_RELEASE);
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-
template<size_t byte_size>
struct Atomic::PlatformAdd
: Atomic::AddAndFetch<Atomic::PlatformAdd<byte_size> >
@@ -57,19 +44,16 @@
}
};
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest)
-{
- jint res = __sync_lock_test_and_set (dest, exchange_value);
+template<size_t byte_size>
+template<typename T>
+inline T Atomic::PlatformXchg<byte_size>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(byte_size == sizeof(T));
+ T res = __sync_lock_test_and_set(dest, exchange_value);
FULL_MEM_BARRIER;
return res;
}
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest)
-{
- return (void *) xchg_ptr((intptr_t) exchange_value,
- (volatile intptr_t*) dest);
-}
-
template<size_t byte_size>
template<typename T>
inline T Atomic::PlatformCmpxchg<byte_size>::operator()(T exchange_value,
@@ -87,16 +71,4 @@
}
}
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest)
-{
- intptr_t res = __sync_lock_test_and_set (dest, exchange_value);
- FULL_MEM_BARRIER;
- return res;
-}
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#endif // OS_CPU_LINUX_AARCH64_VM_ATOMIC_LINUX_AARCH64_HPP
--- a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -44,39 +44,24 @@
* kernel source or kernel_user_helpers.txt in Linux Doc.
*/
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline jlong Atomic::load (const volatile jlong* src) {
- assert(((intx)src & (sizeof(jlong)-1)) == 0, "Atomic load jlong mis-aligned");
-#ifdef AARCH64
- return *src;
-#else
- return (*os::atomic_load_long_func)(src);
-#endif
+#ifndef AARCH64
+template<>
+template<typename T>
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ return PrimitiveConversions::cast<T>(
+ (*os::atomic_load_long_func)(reinterpret_cast<const volatile jlong*>(src)));
}
-inline void Atomic::store (jlong value, volatile jlong* dest) {
- assert(((intx)dest & (sizeof(jlong)-1)) == 0, "Atomic store jlong mis-aligned");
-#ifdef AARCH64
- *dest = value;
-#else
- (*os::atomic_store_long_func)(value, dest);
+template<>
+template<typename T>
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ (*os::atomic_store_long_func)(
+ PrimitiveConversions::cast<jlong>(store_value), reinterpret_cast<volatile jlong*>(dest));
+}
#endif
-}
-
-inline void Atomic::store (jlong value, jlong* dest) {
- store(value, (volatile jlong*)dest);
-}
// As per atomic.hpp all read-modify-write operations have to provide two-way
// barriers semantics. For AARCH64 we are using load-acquire-with-reservation and
@@ -141,11 +126,15 @@
: "memory");
return val;
}
-#endif // AARCH64
+#endif
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
#ifdef AARCH64
- jint old_val;
+ T old_val;
int tmp;
__asm__ volatile(
"1:\n\t"
@@ -157,13 +146,17 @@
: "memory");
return old_val;
#else
- return (*os::atomic_xchg_func)(exchange_value, dest);
+ return xchg_using_helper<jint>(os::atomic_xchg_func, exchange_value, dest);
#endif
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
#ifdef AARCH64
- intptr_t old_val;
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T old_val;
int tmp;
__asm__ volatile(
"1:\n\t"
@@ -174,14 +167,8 @@
: [new_val] "r" (exchange_value), [dest] "r" (dest)
: "memory");
return old_val;
-#else
- return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
-#endif
}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
+#endif // AARCH64
// The memory_order parameter is ignored - we always provide the strongest/most-conservative ordering
--- a/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -32,22 +32,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
//
// machine barrier instructions:
//
@@ -146,12 +130,14 @@
return result;
}
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
-
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
// Note that xchg_ptr doesn't necessarily do an acquire
// (see synchronizer.cpp).
- unsigned int old_value;
+ T old_value;
const uint64_t zero = 0;
__asm__ __volatile__ (
@@ -179,15 +165,18 @@
"memory"
);
- return (jint) old_value;
+ return old_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
-
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
// Note that xchg_ptr doesn't necessarily do an acquire
// (see synchronizer.cpp).
- long old_value;
+ T old_value;
const uint64_t zero = 0;
__asm__ __volatile__ (
@@ -215,11 +204,7 @@
"memory"
);
- return (intptr_t) old_value;
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
+ return old_value;
}
inline void cmpxchg_pre_membar(cmpxchg_memory_order order) {
--- a/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -53,20 +53,6 @@
// is an integer multiple of the data length. Furthermore, all stores are ordered:
// a store which occurs conceptually before another store becomes visible to other CPUs
// before the other store becomes visible.
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
//------------
// Atomic::add
@@ -208,8 +194,12 @@
//
// The return value is the (unchanged) value from memory as it was when the
// replacement succeeded.
-inline jint Atomic::xchg (jint xchg_val, volatile jint* dest) {
- unsigned int old;
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T old;
__asm__ __volatile__ (
" LLGF %[old],%[mem] \n\t" // get old value
@@ -219,16 +209,20 @@
: [old] "=&d" (old) // write-only, prev value irrelevant
, [mem] "+Q" (*dest) // read/write, memory to be updated atomically
//---< inputs >---
- : [upd] "d" (xchg_val) // read-only, value to be written to memory
+ : [upd] "d" (exchange_value) // read-only, value to be written to memory
//---< clobbered >---
: "cc", "memory"
);
- return (jint)old;
+ return old;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t xchg_val, volatile intptr_t* dest) {
- unsigned long old;
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T old;
__asm__ __volatile__ (
" LG %[old],%[mem] \n\t" // get old value
@@ -238,16 +232,12 @@
: [old] "=&d" (old) // write-only, init from memory
, [mem] "+Q" (*dest) // read/write, memory to be updated atomically
//---< inputs >---
- : [upd] "d" (xchg_val) // read-only, value to be written to memory
+ : [upd] "d" (exchange_value) // read-only, value to be written to memory
//---< clobbered >---
: "cc", "memory"
);
- return (intptr_t)old;
-}
-
-inline void *Atomic::xchg_ptr(void *exchange_value, volatile void *dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
+ return old;
}
//----------------
@@ -331,6 +321,4 @@
return old;
}
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#endif // OS_CPU_LINUX_S390_VM_ATOMIC_LINUX_S390_INLINE_HPP
--- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017 SAP SE. 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
@@ -471,7 +471,7 @@
// Info->si_addr need not be the exact address, it is only
// guaranteed to be on the same page as the address that caused
// the SIGSEGV.
- if ((sig == SIGSEGV) &&
+ if ((sig == SIGSEGV) && !UseMembar &&
(os::get_memory_serialize_page() ==
(address)((uintptr_t)info->si_addr & ~(os::vm_page_size()-1)))) {
return true;
--- a/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -27,22 +27,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
template<size_t byte_size>
struct Atomic::PlatformAdd
: Atomic::AddAndFetch<Atomic::PlatformAdd<byte_size> >
@@ -95,9 +79,12 @@
return rv;
}
-
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
- intptr_t rv = exchange_value;
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T rv = exchange_value;
__asm__ volatile(
" swap [%2],%1\n\t"
: "=r" (rv)
@@ -106,8 +93,12 @@
return rv;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- intptr_t rv = exchange_value;
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T rv = exchange_value;
__asm__ volatile(
"1:\n\t"
" mov %1, %%o3\n\t"
@@ -123,10 +114,6 @@
return rv;
}
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
-
// No direct support for cmpxchg of bytes; emulate using int.
template<>
struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
--- a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -27,19 +27,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-
template<size_t byte_size>
struct Atomic::PlatformAdd
: Atomic::FetchAndAdd<Atomic::PlatformAdd<byte_size> >
@@ -61,7 +48,11 @@
return old_value;
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
__asm__ volatile ( "xchgl (%2),%0"
: "=r" (exchange_value)
: "0" (exchange_value), "r" (dest)
@@ -69,10 +60,6 @@
return exchange_value;
}
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
-
template<>
template<typename T>
inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
@@ -102,8 +89,6 @@
}
#ifdef AMD64
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
template<>
template<typename I, typename D>
@@ -118,7 +103,11 @@
return old_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
__asm__ __volatile__ ("xchgq (%2),%0"
: "=r" (exchange_value)
: "0" (exchange_value), "r" (dest)
@@ -140,14 +129,8 @@
return exchange_value;
}
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#else // !AMD64
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
extern "C" {
// defined in linux_x86.s
jlong _Atomic_cmpxchg_long(jlong, volatile jlong*, jlong);
@@ -164,18 +147,21 @@
return cmpxchg_using_helper<jlong>(_Atomic_cmpxchg_long, exchange_value, dest, compare_value);
}
-inline jlong Atomic::load(const volatile jlong* src) {
+template<>
+template<typename T>
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
volatile jlong dest;
- _Atomic_move_long(src, &dest);
- return dest;
+ _Atomic_move_long(reinterpret_cast<const volatile jlong*>(src), reinterpret_cast<volatile jlong*>(&dest));
+ return PrimitiveConversions::cast<T>(dest);
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest);
-}
-
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- _Atomic_move_long((volatile jlong*)&store_value, dest);
+template<>
+template<typename T>
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ _Atomic_move_long(reinterpret_cast<const volatile jlong*>(&store_value), reinterpret_cast<volatile jlong*>(dest));
}
#endif // AMD64
--- a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -87,7 +87,7 @@
/* Atomically write VALUE into `*PTR' and returns the previous
contents of `*PTR'. */
-static inline int m68k_lock_test_and_set(volatile int *ptr, int newval) {
+static inline int m68k_lock_test_and_set(int newval, volatile int *ptr) {
for (;;) {
// Loop until success.
int prev = *ptr;
@@ -148,7 +148,7 @@
/* Atomically write VALUE into `*PTR' and returns the previous
contents of `*PTR'. */
-static inline int arm_lock_test_and_set(volatile int *ptr, int newval) {
+static inline int arm_lock_test_and_set(int newval, volatile int *ptr) {
for (;;) {
// Loop until a __kernel_cmpxchg succeeds.
int prev = *ptr;
@@ -159,14 +159,6 @@
}
#endif // ARM
-inline void Atomic::store(jint store_value, volatile jint* dest) {
- *dest = store_value;
-}
-
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) {
- *dest = store_value;
-}
-
template<size_t byte_size>
struct Atomic::PlatformAdd
: Atomic::AddAndFetch<Atomic::PlatformAdd<byte_size> >
@@ -201,18 +193,22 @@
return __sync_add_and_fetch(dest, add_value);
}
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
#ifdef ARM
- return arm_lock_test_and_set(dest, exchange_value);
+ return xchg_using_helper<int>(arm_lock_test_and_set, exchange_value, dest);
#else
#ifdef M68K
- return m68k_lock_test_and_set(dest, exchange_value);
+ return xchg_using_helper<int>(m68k_lock_test_and_set, exchange_value, dest);
#else
// __sync_lock_test_and_set is a bizarrely named atomic exchange
// operation. Note that some platforms only support this with the
// limitation that the only valid value to store is the immediate
// constant 1. There is a test for this in JNI_CreateJavaVM().
- jint result = __sync_lock_test_and_set (dest, exchange_value);
+ T result = __sync_lock_test_and_set (dest, exchange_value);
// All atomic operations are expected to be full memory barriers
// (see atomic.hpp). However, __sync_lock_test_and_set is not
// a full memory barrier, but an acquire barrier. Hence, this added
@@ -223,24 +219,14 @@
#endif // ARM
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value,
- volatile intptr_t* dest) {
-#ifdef ARM
- return arm_lock_test_and_set(dest, exchange_value);
-#else
-#ifdef M68K
- return m68k_lock_test_and_set(dest, exchange_value);
-#else
- intptr_t result = __sync_lock_test_and_set (dest, exchange_value);
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T result = __sync_lock_test_and_set (dest, exchange_value);
__sync_synchronize();
return result;
-#endif // M68K
-#endif // ARM
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void *) xchg_ptr((intptr_t) exchange_value,
- (volatile intptr_t*) dest);
}
// No direct support for cmpxchg of bytes; emulate using int.
@@ -275,18 +261,21 @@
return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
}
-inline jlong Atomic::load(const volatile jlong* src) {
+template<>
+template<typename T>
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
volatile jlong dest;
- os::atomic_copy64(src, &dest);
- return dest;
+ os::atomic_copy64(reinterpret_cast<const volatile jlong*>(src), reinterpret_cast<volatile jlong*>(&dest));
+ return PrimitiveConversions::cast<T>(dest);
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- os::atomic_copy64((volatile jlong*)&store_value, (volatile jlong*)dest);
-}
-
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- os::atomic_copy64((volatile jlong*)&store_value, dest);
+template<>
+template<typename T>
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ os::atomic_copy64(reinterpret_cast<const volatile jlong*>(&store_value), reinterpret_cast<volatile jlong*>(dest));
}
#endif // OS_CPU_LINUX_ZERO_VM_ATOMIC_LINUX_ZERO_HPP
--- a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -27,32 +27,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline void Atomic::store(jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store(jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
-
-// This is the interface to the atomic instructions in solaris_sparc.il.
-// It's very messy because we need to support v8 and these instructions
-// are illegal there. When sparc v8 is dropped, we can drop out lots of
-// this code. Also compiler2 does not support v8 so the conditional code
-// omits the instruction set check.
-
-extern "C" jint _Atomic_swap32(jint exchange_value, volatile jint* dest);
-extern "C" intptr_t _Atomic_swap64(intptr_t exchange_value, volatile intptr_t* dest);
-
// Implement ADD using a CAS loop.
template<size_t byte_size>
struct Atomic::PlatformAdd VALUE_OBJ_CLASS_SPEC {
@@ -69,16 +43,30 @@
}
};
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
- return _Atomic_swap32(exchange_value, dest);
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ __asm__ volatile ( "swap [%2],%0"
+ : "=r" (exchange_value)
+ : "0" (exchange_value), "r" (dest)
+ : "memory");
+ return exchange_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return _Atomic_swap64(exchange_value, dest);
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T old_value = *dest;
+ while (true) {
+ T result = cmpxchg(exchange_value, dest, old_value);
+ if (result == old_value) break;
+ old_value = result;
+ }
+ return old_value;
}
// No direct support for cmpxchg of bytes; emulate using int.
--- a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il Mon Oct 09 07:08:53 2017 +0000
@@ -32,47 +32,6 @@
.end
- // Support for jint Atomic::xchg(jint exchange_value, volatile jint* dest).
- //
- // Arguments:
- // exchange_value: O0
- // dest: O1
- //
- // Results:
- // O0: the value previously stored in dest
-
- .inline _Atomic_swap32, 2
- .volatile
- swap [%o1],%o0
- .nonvolatile
- .end
-
-
- // Support for intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t * dest).
- //
- // 64-bit
- //
- // Arguments:
- // exchange_value: O0
- // dest: O1
- //
- // Results:
- // O0: the value previously stored in dest
-
- .inline _Atomic_swap64, 2
- .volatile
- 1:
- mov %o0, %o3
- ldx [%o1], %o2
- casx [%o1], %o2, %o3
- cmp %o2, %o3
- bne %xcc, 1b
- nop
- mov %o2, %o0
- .nonvolatile
- .end
-
-
// Support for jlong Atomic::load and Atomic::store on v9.
//
// void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst)
--- a/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -25,20 +25,6 @@
#ifndef OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP
#define OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-
-
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
// For Sun Studio - implementation is in solaris_x86_64.il.
extern "C" {
@@ -84,8 +70,26 @@
reinterpret_cast<jlong volatile*>(dest)));
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
- return _Atomic_xchg(exchange_value, dest);
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ return PrimitiveConversions::cast<T>(
+ _Atomic_xchg(PrimitiveConversions::cast<jint>(exchange_value),
+ reinterpret_cast<jint volatile*>(dest)));
+}
+
+extern "C" jlong _Atomic_xchg_long(jlong exchange_value, volatile jlong* dest);
+
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ return PrimitiveConversions::cast<T>(
+ _Atomic_xchg_long(PrimitiveConversions::cast<jlong>(exchange_value),
+ reinterpret_cast<jlong volatile*>(dest)));
}
// Not using cmpxchg_using_helper here, because some configurations of
@@ -133,18 +137,4 @@
PrimitiveConversions::cast<jlong>(compare_value)));
}
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-extern "C" jlong _Atomic_xchg_long(jlong exchange_value, volatile jlong* dest);
-
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest);
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest);
-}
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#endif // OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP
--- a/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -42,21 +42,6 @@
#pragma warning(disable: 4035) // Disables warnings reporting missing return statement
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-
-
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
template<size_t byte_size>
struct Atomic::PlatformAdd
: Atomic::AddAndFetch<Atomic::PlatformAdd<byte_size> >
@@ -66,9 +51,6 @@
};
#ifdef AMD64
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
@@ -81,17 +63,19 @@
return add_using_helper<intptr_t>(os::atomic_add_ptr_func, add_value, dest);
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
- return (jint)(*os::atomic_xchg_func)(exchange_value, dest);
-}
+#define DEFINE_STUB_XCHG(ByteSize, StubType, StubName) \
+ template<> \
+ template<typename T> \
+ inline T Atomic::PlatformXchg<ByteSize>::operator()(T exchange_value, \
+ T volatile* dest) const { \
+ STATIC_ASSERT(ByteSize == sizeof(T)); \
+ return xchg_using_helper<StubType>(StubName, exchange_value, dest); \
+ }
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)(os::atomic_xchg_ptr_func)(exchange_value, dest);
-}
+DEFINE_STUB_XCHG(4, jint, os::atomic_xchg_func)
+DEFINE_STUB_XCHG(8, jlong, os::atomic_xchg_ptr_func)
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void *)(os::atomic_xchg_ptr_func)((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
+#undef DEFINE_STUB_XCHG
#define DEFINE_STUB_CMPXCHG(ByteSize, StubType, StubName) \
template<> \
@@ -110,8 +94,6 @@
#undef DEFINE_STUB_CMPXCHG
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#else // !AMD64
template<>
@@ -128,7 +110,11 @@
}
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
// alternative for InterlockedExchange
__asm {
mov eax, exchange_value;
@@ -137,14 +123,6 @@
}
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
template<>
template<typename T>
inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
@@ -202,9 +180,12 @@
}
}
-inline jlong Atomic::load(const volatile jlong* src) {
- volatile jlong dest;
- volatile jlong* pdest = &dest;
+template<>
+template<typename T>
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ volatile T dest;
+ volatile T* pdest = &dest;
__asm {
mov eax, src
fild qword ptr [eax]
@@ -214,8 +195,12 @@
return dest;
}
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- volatile jlong* src = &store_value;
+template<>
+template<typename T>
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ volatile T* src = &store_value;
__asm {
mov eax, src
fild qword ptr [eax]
@@ -224,10 +209,6 @@
}
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- Atomic::store(store_value, (volatile jlong*)dest);
-}
-
#endif // AMD64
#pragma warning(default: 4035) // Enables warnings reporting missing return statement
--- a/src/hotspot/share/adlc/output_c.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/adlc/output_c.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2276,6 +2276,10 @@
if (strcmp(rep_var,"$XMMRegister") == 0) return "as_XMMRegister";
#endif
if (strcmp(rep_var,"$CondRegister") == 0) return "as_ConditionRegister";
+#if defined(PPC64)
+ if (strcmp(rep_var,"$VectorRegister") == 0) return "as_VectorRegister";
+ if (strcmp(rep_var,"$VectorSRegister") == 0) return "as_VectorSRegister";
+#endif
return NULL;
}
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1304,7 +1304,9 @@
// FIXME T_ADDRESS should actually be T_METADATA but it can't because the
// meaning of these two is mixed up (see JDK-8026837).
__ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), temp, info);
- __ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result);
+ __ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_ADDRESS), result);
+ // mirror = ((OopHandle)mirror)->resolve();
+ __ move_wide(new LIR_Address(result, T_OBJECT), result);
}
// java.lang.Class::isPrimitive()
--- a/src/hotspot/share/classfile/classLoaderData.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/classfile/classLoaderData.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -98,7 +98,8 @@
_keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0),
_metaspace(NULL), _unloading(false), _klasses(NULL),
_modules(NULL), _packages(NULL),
- _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
+ _claimed(0), _modified_oops(true), _accumulated_modified_oops(false),
+ _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
_next(NULL), _dependencies(dependencies),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
Monitor::_safepoint_check_never)) {
@@ -207,7 +208,7 @@
oops_do(&cl);
return cl.found();
}
-#endif
+#endif // ASSERT
bool ClassLoaderData::claim() {
if (_claimed == 1) {
@@ -236,19 +237,19 @@
}
}
-void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+void ClassLoaderData::oops_do(OopClosure* f, bool must_claim, bool clear_mod_oops) {
if (must_claim && !claim()) {
return;
}
+ // Only clear modified_oops after the ClassLoaderData is claimed.
+ if (clear_mod_oops) {
+ clear_modified_oops();
+ }
+
f->do_oop(&_class_loader);
_dependencies.oops_do(f);
-
_handles.oops_do(f);
-
- if (klass_closure != NULL) {
- classes_do(klass_closure);
- }
}
void ClassLoaderData::Dependencies::oops_do(OopClosure* f) {
@@ -368,6 +369,9 @@
// Must handle over GC point.
Handle dependency(THREAD, to);
from_cld->_dependencies.add(dependency, CHECK);
+
+ // Added a potentially young gen oop to the ClassLoaderData
+ record_modified_oops();
}
@@ -764,6 +768,7 @@
OopHandle ClassLoaderData::add_handle(Handle h) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
+ record_modified_oops();
return OopHandle(_handles.add(h()));
}
@@ -875,8 +880,7 @@
if (Verbose) {
Klass* k = _klasses;
while (k != NULL) {
- out->print_cr("klass " PTR_FORMAT ", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(),
- k->has_modified_oops(), k->has_accumulated_modified_oops());
+ out->print_cr("klass " PTR_FORMAT ", %s", p2i(k), k->name()->as_C_string());
assert(k != k->next_link(), "no loops!");
k = k->next_link();
}
@@ -1003,25 +1007,25 @@
}
-void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+void ClassLoaderDataGraph::oops_do(OopClosure* f, bool must_claim) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
- cld->oops_do(f, klass_closure, must_claim);
+ cld->oops_do(f, must_claim);
}
}
-void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, bool must_claim) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
if (cld->keep_alive()) {
- cld->oops_do(f, klass_closure, must_claim);
+ cld->oops_do(f, must_claim);
}
}
}
-void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, bool must_claim) {
if (ClassUnloading) {
- keep_alive_oops_do(f, klass_closure, must_claim);
+ keep_alive_oops_do(f, must_claim);
} else {
- oops_do(f, klass_closure, must_claim);
+ oops_do(f, must_claim);
}
}
--- a/src/hotspot/share/classfile/classLoaderData.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/classfile/classLoaderData.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -87,9 +87,9 @@
static void purge();
static void clear_claimed_marks();
// oops do
- static void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim);
- static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
- static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
+ static void oops_do(OopClosure* f, bool must_claim);
+ static void keep_alive_oops_do(OopClosure* blk, bool must_claim);
+ static void always_strong_oops_do(OopClosure* blk, bool must_claim);
// cld do
static void cld_do(CLDClosure* cl);
static void cld_unloading_do(CLDClosure* cl);
@@ -230,10 +230,16 @@
Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup.
bool _unloading; // true if this class loader goes away
bool _is_anonymous; // if this CLD is for an anonymous class
+
+ // Remembered sets support for the oops in the class loader data.
+ bool _modified_oops; // Card Table Equivalent (YC/CMS support)
+ bool _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
+
s2 _keep_alive; // if this CLD is kept alive without a keep_alive_object().
// Used for anonymous classes and the boot class
// loader. _keep_alive does not need to be volatile or
// atomic since there is one unique CLD per anonymous class.
+
volatile int _claimed; // true if claimed, for example during GC traces.
// To avoid applying oop closure more than once.
// Has to be an int because we cas it.
@@ -276,6 +282,19 @@
bool claimed() const { return _claimed == 1; }
bool claim();
+ // The CLD are not placed in the Heap, so the Card Table or
+ // the Mod Union Table can't be used to mark when CLD have modified oops.
+ // The CT and MUT bits saves this information for the whole class loader data.
+ void clear_modified_oops() { _modified_oops = false; }
+ public:
+ void record_modified_oops() { _modified_oops = true; }
+ bool has_modified_oops() { return _modified_oops; }
+
+ void accumulate_modified_oops() { if (has_modified_oops()) _accumulated_modified_oops = true; }
+ void clear_accumulated_modified_oops() { _accumulated_modified_oops = false; }
+ bool has_accumulated_modified_oops() { return _accumulated_modified_oops; }
+ private:
+
void unload();
bool keep_alive() const { return _keep_alive > 0; }
void classes_do(void f(Klass*));
@@ -346,8 +365,7 @@
inline unsigned int identity_hash() const { return (unsigned int)(((intptr_t)this) >> 3); }
- // Used when tracing from klasses.
- void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim);
+ void oops_do(OopClosure* f, bool must_claim, bool clear_modified_oops = false);
void classes_do(KlassClosure* klass_closure);
Klass* klasses() { return _klasses; }
--- a/src/hotspot/share/classfile/javaClasses.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/classfile/javaClasses.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -889,7 +889,7 @@
// Setup indirection from klass->mirror
// after any exceptions can happen during allocations.
- k->set_java_mirror(mirror());
+ k->set_java_mirror(mirror);
// Set the module field in the java_lang_Class instance. This must be done
// after the mirror is set.
--- a/src/hotspot/share/classfile/vmSymbols.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/classfile/vmSymbols.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -781,6 +781,7 @@
do_name(decrementExact_name,"decrementExact") \
do_name(incrementExact_name,"incrementExact") \
do_name(multiplyExact_name,"multiplyExact") \
+ do_name(multiplyHigh_name,"multiplyHigh") \
do_name(negateExact_name,"negateExact") \
do_name(subtractExact_name,"subtractExact") \
do_name(fma_name, "fma") \
@@ -805,6 +806,7 @@
do_intrinsic(_incrementExactL, java_lang_Math, incrementExact_name, long_long_signature, F_S) \
do_intrinsic(_multiplyExactI, java_lang_Math, multiplyExact_name, int2_int_signature, F_S) \
do_intrinsic(_multiplyExactL, java_lang_Math, multiplyExact_name, long2_long_signature, F_S) \
+ do_intrinsic(_multiplyHigh, java_lang_Math, multiplyHigh_name, long2_long_signature, F_S) \
do_intrinsic(_negateExactI, java_lang_Math, negateExact_name, int_int_signature, F_S) \
do_intrinsic(_negateExactL, java_lang_Math, negateExact_name, long_long_signature, F_S) \
do_intrinsic(_subtractExactI, java_lang_Math, subtractExact_name, int2_int_signature, F_S) \
--- a/src/hotspot/share/compiler/compileBroker.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/compiler/compileBroker.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -332,7 +332,7 @@
static void disable_compilation_forever() {
UseCompiler = false;
AlwaysCompileLoopMethods = false;
- Atomic::xchg(shutdown_compilation, &_should_compile_new_jobs);
+ Atomic::xchg(jint(shutdown_compilation), &_should_compile_new_jobs);
}
static bool is_compilation_disabled_forever() {
--- a/src/hotspot/share/compiler/methodMatcher.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/compiler/methodMatcher.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -96,7 +96,7 @@
bool have_colon = (colon != NULL);
if (have_colon) {
// Don't allow multiple '::'
- if (colon + 2 != '\0') {
+ if (colon[2] != '\0') {
if (strstr(colon+2, "::")) {
error_msg = "Method pattern only allows one '::' allowed";
return false;
--- a/src/hotspot/share/gc/cms/cmsOopClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/cmsOopClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -48,12 +48,7 @@
// because some CMS OopClosures derive from OopsInGenClosure. It would be
// good to get rid of them completely.
class MetadataAwareOopsInGenClosure: public OopsInGenClosure {
- KlassToOopClosure _klass_closure;
public:
- MetadataAwareOopsInGenClosure() {
- _klass_closure.initialize(this);
- }
-
virtual bool do_metadata() { return do_metadata_nv(); }
inline bool do_metadata_nv() { return true; }
--- a/src/hotspot/share/gc/cms/cmsOopClosures.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/cmsOopClosures.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -40,10 +40,8 @@
inline void MetadataAwareOopsInGenClosure::do_klass(Klass* k) { do_klass_nv(k); }
inline void MetadataAwareOopsInGenClosure::do_cld_nv(ClassLoaderData* cld) {
- assert(_klass_closure._oop_closure == this, "Must be");
-
bool claim = true; // Must claim the class loader data before processing.
- cld->oops_do(_klass_closure._oop_closure, &_klass_closure, claim);
+ cld->oops_do(this, claim);
}
// Decode the oop and call do_oop on it.
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1553,9 +1553,10 @@
assert(_collectorState != Idling || _modUnionTable.isAllClear(),
"_modUnionTable should be clear if the baton was not passed");
_modUnionTable.clear_all();
- assert(_collectorState != Idling || _ct->klass_rem_set()->mod_union_is_clear(),
+ assert(_collectorState != Idling || _ct->cld_rem_set()->mod_union_is_clear(),
"mod union for klasses should be clear if the baton was passed");
- _ct->klass_rem_set()->clear_mod_union();
+ _ct->cld_rem_set()->clear_mod_union();
+
// We must adjust the allocation statistics being maintained
// in the free list space. We do so by reading and clearing
@@ -2025,7 +2026,7 @@
// that information. Tell the young collection to save the union of all
// modified klasses.
if (duringMarking) {
- _ct->klass_rem_set()->set_accumulate_modified_oops(true);
+ _ct->cld_rem_set()->set_accumulate_modified_oops(true);
}
bool registerClosure = duringMarking;
@@ -2101,7 +2102,7 @@
assert(haveFreelistLocks(), "must have freelist locks");
assert_lock_strong(bitMapLock());
- _ct->klass_rem_set()->set_accumulate_modified_oops(false);
+ _ct->cld_rem_set()->set_accumulate_modified_oops(false);
_cmsGen->gc_epilogue_work(full);
@@ -2380,18 +2381,18 @@
}
}
-class VerifyKlassOopsKlassClosure : public KlassClosure {
- class VerifyKlassOopsClosure : public OopClosure {
+class VerifyCLDOopsCLDClosure : public CLDClosure {
+ class VerifyCLDOopsClosure : public OopClosure {
CMSBitMap* _bitmap;
public:
- VerifyKlassOopsClosure(CMSBitMap* bitmap) : _bitmap(bitmap) { }
+ VerifyCLDOopsClosure(CMSBitMap* bitmap) : _bitmap(bitmap) { }
void do_oop(oop* p) { guarantee(*p == NULL || _bitmap->isMarked((HeapWord*) *p), "Should be marked"); }
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
} _oop_closure;
public:
- VerifyKlassOopsKlassClosure(CMSBitMap* bitmap) : _oop_closure(bitmap) {}
- void do_klass(Klass* k) {
- k->oops_do(&_oop_closure);
+ VerifyCLDOopsCLDClosure(CMSBitMap* bitmap) : _oop_closure(bitmap) {}
+ void do_cld(ClassLoaderData* cld) {
+ cld->oops_do(&_oop_closure, false, false);
}
};
@@ -2437,8 +2438,8 @@
assert(verification_mark_stack()->isEmpty(), "Should have been drained");
verify_work_stacks_empty();
- VerifyKlassOopsKlassClosure verify_klass_oops(verification_mark_bm());
- ClassLoaderDataGraph::classes_do(&verify_klass_oops);
+ VerifyCLDOopsCLDClosure verify_cld_oops(verification_mark_bm());
+ ClassLoaderDataGraph::cld_do(&verify_cld_oops);
// Marking completed -- now verify that each bit marked in
// verification_mark_bm() is also marked in markBitMap(); flag all
@@ -2911,7 +2912,7 @@
" or no bits are set in the gc_prologue before the start of the next "
"subsequent marking phase.");
- assert(_ct->klass_rem_set()->mod_union_is_clear(), "Must be");
+ assert(_ct->cld_rem_set()->mod_union_is_clear(), "Must be");
// Save the end of the used_region of the constituent generations
// to be used to limit the extent of sweep in each generation.
@@ -3848,7 +3849,7 @@
}
}
- preclean_klasses(&mrias_cl, _cmsGen->freelistLock());
+ preclean_cld(&mrias_cl, _cmsGen->freelistLock());
curNumCards = preclean_card_table(_cmsGen, &smoac_cl);
cumNumCards += curNumCards;
@@ -4067,21 +4068,21 @@
return cumNumDirtyCards;
}
-class PrecleanKlassClosure : public KlassClosure {
- KlassToOopClosure _cm_klass_closure;
+class PrecleanCLDClosure : public CLDClosure {
+ MetadataAwareOopsInGenClosure* _cm_closure;
public:
- PrecleanKlassClosure(OopClosure* oop_closure) : _cm_klass_closure(oop_closure) {}
- void do_klass(Klass* k) {
- if (k->has_accumulated_modified_oops()) {
- k->clear_accumulated_modified_oops();
-
- _cm_klass_closure.do_klass(k);
+ PrecleanCLDClosure(MetadataAwareOopsInGenClosure* oop_closure) : _cm_closure(oop_closure) {}
+ void do_cld(ClassLoaderData* cld) {
+ if (cld->has_accumulated_modified_oops()) {
+ cld->clear_accumulated_modified_oops();
+
+ _cm_closure->do_cld(cld);
}
}
};
// The freelist lock is needed to prevent asserts, is it really needed?
-void CMSCollector::preclean_klasses(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock) {
+void CMSCollector::preclean_cld(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock) {
cl->set_freelistLock(freelistLock);
@@ -4089,8 +4090,8 @@
// SSS: Add equivalent to ScanMarkedObjectsAgainCarefullyClosure::do_yield_check and should_abort_preclean?
// SSS: We should probably check if precleaning should be aborted, at suitable intervals?
- PrecleanKlassClosure preclean_klass_closure(cl);
- ClassLoaderDataGraph::classes_do(&preclean_klass_closure);
+ PrecleanCLDClosure preclean_closure(cl);
+ ClassLoaderDataGraph::cld_do(&preclean_closure);
verify_work_stacks_empty();
verify_overflow_empty();
@@ -4250,7 +4251,7 @@
// Call isAllClear() under bitMapLock
assert(_modUnionTable.isAllClear(),
"Should be clear by end of the final marking");
- assert(_ct->klass_rem_set()->mod_union_is_clear(),
+ assert(_ct->cld_rem_set()->mod_union_is_clear(),
"Should be clear by end of the final marking");
}
@@ -4332,26 +4333,26 @@
void do_work_steal(int i, ParMarkRefsIntoAndScanClosure* cl, int* seed);
};
-class RemarkKlassClosure : public KlassClosure {
- KlassToOopClosure _cm_klass_closure;
+class RemarkCLDClosure : public CLDClosure {
+ CLDToOopClosure _cm_closure;
public:
- RemarkKlassClosure(OopClosure* oop_closure) : _cm_klass_closure(oop_closure) {}
- void do_klass(Klass* k) {
- // Check if we have modified any oops in the Klass during the concurrent marking.
- if (k->has_accumulated_modified_oops()) {
- k->clear_accumulated_modified_oops();
+ RemarkCLDClosure(OopClosure* oop_closure) : _cm_closure(oop_closure) {}
+ void do_cld(ClassLoaderData* cld) {
+ // Check if we have modified any oops in the CLD during the concurrent marking.
+ if (cld->has_accumulated_modified_oops()) {
+ cld->clear_accumulated_modified_oops();
// We could have transfered the current modified marks to the accumulated marks,
// like we do with the Card Table to Mod Union Table. But it's not really necessary.
- } else if (k->has_modified_oops()) {
+ } else if (cld->has_modified_oops()) {
// Don't clear anything, this info is needed by the next young collection.
} else {
- // No modified oops in the Klass.
+ // No modified oops in the ClassLoaderData.
return;
}
// The klass has modified fields, need to scan the klass.
- _cm_klass_closure.do_klass(k);
+ _cm_closure.do_cld(cld);
}
};
@@ -4439,24 +4440,24 @@
log_trace(gc, task)("Finished unhandled CLD scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
}
- // ---------- dirty klass scanning ----------
+ // We might have added oops to ClassLoaderData::_handles during the
+ // concurrent marking phase. These oops do not always point to newly allocated objects
+ // that are guaranteed to be kept alive. Hence,
+ // we do have to revisit the _handles block during the remark phase.
+
+ // ---------- dirty CLD scanning ----------
if (worker_id == 0) { // Single threaded at the moment.
_timer.reset();
_timer.start();
// Scan all classes that was dirtied during the concurrent marking phase.
- RemarkKlassClosure remark_klass_closure(&par_mrias_cl);
- ClassLoaderDataGraph::classes_do(&remark_klass_closure);
+ RemarkCLDClosure remark_closure(&par_mrias_cl);
+ ClassLoaderDataGraph::cld_do(&remark_closure);
_timer.stop();
- log_trace(gc, task)("Finished dirty klass scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
- }
-
- // We might have added oops to ClassLoaderData::_handles during the
- // concurrent marking phase. These oops point to newly allocated objects
- // that are guaranteed to be kept alive. Either by the direct allocation
- // code, or when the young collector processes the roots. Hence,
- // we don't have to revisit the _handles block during the remark phase.
+ log_trace(gc, task)("Finished dirty CLD scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
+ }
+
// ---------- rescan dirty cards ------------
_timer.reset();
@@ -4981,23 +4982,21 @@
verify_work_stacks_empty();
}
+ // We might have added oops to ClassLoaderData::_handles during the
+ // concurrent marking phase. These oops do not point to newly allocated objects
+ // that are guaranteed to be kept alive. Hence,
+ // we do have to revisit the _handles block during the remark phase.
{
- GCTraceTime(Trace, gc, phases) t("Dirty Klass Scan", _gc_timer_cm);
+ GCTraceTime(Trace, gc, phases) t("Dirty CLD Scan", _gc_timer_cm);
verify_work_stacks_empty();
- RemarkKlassClosure remark_klass_closure(&mrias_cl);
- ClassLoaderDataGraph::classes_do(&remark_klass_closure);
+ RemarkCLDClosure remark_closure(&mrias_cl);
+ ClassLoaderDataGraph::cld_do(&remark_closure);
verify_work_stacks_empty();
}
- // We might have added oops to ClassLoaderData::_handles during the
- // concurrent marking phase. These oops point to newly allocated objects
- // that are guaranteed to be kept alive. Either by the direct allocation
- // code, or when the young collector processes the roots. Hence,
- // we don't have to revisit the _handles block during the remark phase.
-
verify_work_stacks_empty();
// Restore evacuated mark words, if any, used for overflow list links
restore_preserved_marks_if_any();
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -777,7 +777,7 @@
// Does precleaning work, returning a quantity indicative of
// the amount of "useful work" done.
size_t preclean_work(bool clean_refs, bool clean_survivors);
- void preclean_klasses(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock);
+ void preclean_cld(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock);
void abortable_preclean(); // Preclean while looking for possible abort
void initialize_sequential_subtasks_for_young_gen_rescan(int i);
// Helper function for above; merge-sorts the per-thread plab samples
--- a/src/hotspot/share/gc/cms/parNewGeneration.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/parNewGeneration.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -493,7 +493,7 @@
ParScanClosure::ParScanClosure(ParNewGeneration* g,
ParScanThreadState* par_scan_state) :
- OopsInKlassOrGenClosure(g), _par_scan_state(par_scan_state), _g(g) {
+ OopsInClassLoaderDataOrGenClosure(g), _par_scan_state(par_scan_state), _g(g) {
_boundary = _g->reserved().end();
}
@@ -601,11 +601,8 @@
par_scan_state.set_young_old_boundary(_young_old_boundary);
- KlassScanClosure klass_scan_closure(&par_scan_state.to_space_root_closure(),
- gch->rem_set()->klass_rem_set());
- CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure,
- &par_scan_state.to_space_root_closure(),
- false);
+ CLDScanClosure cld_scan_closure(&par_scan_state.to_space_root_closure(),
+ gch->rem_set()->cld_rem_set()->accumulate_modified_oops());
par_scan_state.start_strong_roots();
gch->young_process_roots(_strong_roots_scope,
--- a/src/hotspot/share/gc/cms/parOopClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/parOopClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -37,7 +37,7 @@
typedef GenericTaskQueueSet<ObjToScanQueue, mtGC> ObjToScanQueueSet;
class ParallelTaskTerminator;
-class ParScanClosure: public OopsInKlassOrGenClosure {
+class ParScanClosure: public OopsInClassLoaderDataOrGenClosure {
protected:
ParScanThreadState* _par_scan_state;
ParNewGeneration* _g;
--- a/src/hotspot/share/gc/cms/parOopClosures.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/parOopClosures.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -126,8 +126,8 @@
(void)_par_scan_state->trim_queues(10 * ParallelGCThreads);
}
}
- if (is_scanning_a_klass()) {
- do_klass_barrier();
+ if (is_scanning_a_cld()) {
+ do_cld_barrier();
} else if (gc_barrier) {
// Now call parent closure
par_do_barrier(p);
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -63,7 +63,6 @@
class GenerationSpec;
class G1ParScanThreadState;
class G1ParScanThreadStateSet;
-class G1KlassScanClosure;
class G1ParScanThreadState;
class ObjectClosure;
class SpaceClosure;
--- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -161,18 +161,18 @@
void reset_count() { _count = 0; };
};
-class VerifyKlassClosure: public KlassClosure {
+class VerifyCLDClosure: public CLDClosure {
YoungRefCounterClosure _young_ref_counter_closure;
OopClosure *_oop_closure;
public:
- VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
- void do_klass(Klass* k) {
- k->oops_do(_oop_closure);
+ VerifyCLDClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
+ void do_cld(ClassLoaderData* cld) {
+ cld->oops_do(_oop_closure, false);
_young_ref_counter_closure.reset_count();
- k->oops_do(&_young_ref_counter_closure);
+ cld->oops_do(&_young_ref_counter_closure, false);
if (_young_ref_counter_closure.count() > 0) {
- guarantee(k->has_modified_oops(), "Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k));
+ guarantee(cld->has_modified_oops(), "CLD " PTR_FORMAT ", has young %d refs but is not dirty.", p2i(cld), _young_ref_counter_closure.count());
}
}
};
@@ -390,8 +390,7 @@
log_debug(gc, verify)("Roots");
VerifyRootsClosure rootsCl(vo);
- VerifyKlassClosure klassCl(_g1h, &rootsCl);
- CLDToKlassAndOopClosure cldCl(&klassCl, &rootsCl, false);
+ VerifyCLDClosure cldCl(_g1h, &rootsCl);
// We apply the relevant closures to all the oops in the
// system dictionary, class loader data graph, the string table
--- a/src/hotspot/share/gc/g1/g1OopClosures.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1OopClosures.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -34,7 +34,7 @@
_g1(g1),
_par_scan_state(par_scan_state),
_worker_id(par_scan_state->worker_id()),
- _scanned_klass(NULL),
+ _scanned_cld(NULL),
_cm(_g1->concurrent_mark())
{ }
@@ -42,20 +42,20 @@
_g1(g1), _par_scan_state(par_scan_state), _from(NULL)
{ }
-void G1KlassScanClosure::do_klass(Klass* klass) {
- // If the klass has not been dirtied we know that there's
+void G1CLDScanClosure::do_cld(ClassLoaderData* cld) {
+ // If the class loader data has not been dirtied we know that there's
// no references into the young gen and we can skip it.
- if (!_process_only_dirty || klass->has_modified_oops()) {
- // Clean the klass since we're going to scavenge all the metadata.
- klass->clear_modified_oops();
+ if (!_process_only_dirty || cld->has_modified_oops()) {
- // Tell the closure that this klass is the Klass to scavenge
+ // Tell the closure that this class loader data is the CLD to scavenge
// and is the one to dirty if oops are left pointing into the young gen.
- _closure->set_scanned_klass(klass);
+ _closure->set_scanned_cld(cld);
- klass->oops_do(_closure);
+ // Clean the cld since we're going to scavenge all the metadata.
+ // Clear modified oops only if this cld is claimed.
+ cld->oops_do(_closure, _must_claim, /*clear_modified_oops*/true);
- _closure->set_scanned_klass(NULL);
+ _closure->set_scanned_cld(NULL);
}
_count++;
}
--- a/src/hotspot/share/gc/g1/g1OopClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -107,7 +107,7 @@
G1CollectedHeap* _g1;
G1ParScanThreadState* _par_scan_state;
uint _worker_id; // Cache value from par_scan_state.
- Klass* _scanned_klass;
+ ClassLoaderData* _scanned_cld;
G1ConcurrentMark* _cm;
// Mark the object if it's not already marked. This is used to mark
@@ -124,13 +124,13 @@
~G1ParCopyHelper() { }
public:
- void set_scanned_klass(Klass* k) { _scanned_klass = k; }
- template <class T> inline void do_klass_barrier(T* p, oop new_obj);
+ void set_scanned_cld(ClassLoaderData* cld) { _scanned_cld = cld; }
+ inline void do_cld_barrier(oop new_obj);
};
enum G1Barrier {
G1BarrierNone,
- G1BarrierKlass
+ G1BarrierCLD
};
enum G1Mark {
@@ -150,14 +150,16 @@
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
};
-class G1KlassScanClosure : public KlassClosure {
+class G1CLDScanClosure : public CLDClosure {
G1ParCopyHelper* _closure;
bool _process_only_dirty;
+ bool _must_claim;
int _count;
public:
- G1KlassScanClosure(G1ParCopyHelper* closure, bool process_only_dirty)
- : _process_only_dirty(process_only_dirty), _closure(closure), _count(0) {}
- void do_klass(Klass* klass);
+ G1CLDScanClosure(G1ParCopyHelper* closure,
+ bool process_only_dirty, bool must_claim)
+ : _process_only_dirty(process_only_dirty), _must_claim(must_claim), _closure(closure), _count(0) {}
+ void do_cld(ClassLoaderData* cld);
};
// Closure for iterating over object fields during concurrent marking
--- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -195,10 +195,9 @@
}
}
-template <class T>
-void G1ParCopyHelper::do_klass_barrier(T* p, oop new_obj) {
+void G1ParCopyHelper::do_cld_barrier(oop new_obj) {
if (_g1->heap_region_containing(new_obj)->is_young()) {
- _scanned_klass->record_modified_oops();
+ _scanned_cld->record_modified_oops();
}
}
@@ -249,8 +248,8 @@
mark_forwarded_object(obj, forwardee);
}
- if (barrier == G1BarrierKlass) {
- do_klass_barrier(p, forwardee);
+ if (barrier == G1BarrierCLD) {
+ do_cld_barrier(forwardee);
}
} else {
if (state.is_humongous()) {
@@ -267,5 +266,4 @@
}
}
}
-
#endif // SHARE_VM_GC_G1_G1OOPCLOSURES_INLINE_HPP
--- a/src/hotspot/share/gc/g1/g1SharedClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1SharedClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 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
@@ -34,18 +34,17 @@
template <G1Mark Mark, bool use_ext = false>
class G1SharedClosures VALUE_OBJ_CLASS_SPEC {
public:
- G1ParCopyClosure<G1BarrierNone, Mark, use_ext> _oops;
- G1ParCopyClosure<G1BarrierKlass, Mark, use_ext> _oop_in_klass;
- G1KlassScanClosure _klass_in_cld_closure;
- CLDToKlassAndOopClosure _clds;
- G1CodeBlobClosure _codeblobs;
- BufferingOopClosure _buffered_oops;
+ G1ParCopyClosure<G1BarrierNone, Mark, use_ext> _oops;
+ G1ParCopyClosure<G1BarrierCLD, Mark, use_ext> _oops_in_cld;
- G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty_klasses, bool must_claim_cld) :
+ G1CLDScanClosure _clds;
+ G1CodeBlobClosure _codeblobs;
+ BufferingOopClosure _buffered_oops;
+
+ G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty, bool must_claim_cld) :
_oops(g1h, pss),
- _oop_in_klass(g1h, pss),
- _klass_in_cld_closure(&_oop_in_klass, process_only_dirty_klasses),
- _clds(&_klass_in_cld_closure, &_oops, must_claim_cld),
+ _oops_in_cld(g1h, pss),
+ _clds(&_oops_in_cld, process_only_dirty, must_claim_cld),
_codeblobs(&_oops),
_buffered_oops(&_oops) {}
};
--- a/src/hotspot/share/gc/parallel/pcTasks.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/pcTasks.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -81,7 +81,6 @@
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm);
- ParCompactionManager::FollowKlassClosure follow_klass_closure(&mark_and_push_closure);
switch (_root_type) {
case universe:
@@ -117,7 +116,7 @@
break;
case class_loader_data:
- ClassLoaderDataGraph::always_strong_oops_do(&mark_and_push_closure, &follow_klass_closure, true);
+ ClassLoaderDataGraph::always_strong_oops_do(&mark_and_push_closure, true);
break;
case code_cache:
--- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -196,17 +196,6 @@
FollowStackClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
virtual void do_void();
};
-
- // The one and only place to start following the classes.
- // Should only be applied to the ClassLoaderData klasses list.
- class FollowKlassClosure : public KlassClosure {
- private:
- MarkAndPushClosure* _mark_and_push_closure;
- public:
- FollowKlassClosure(MarkAndPushClosure* mark_and_push_closure) :
- _mark_and_push_closure(mark_and_push_closure) { }
- void do_klass(Klass* klass);
- };
};
inline ParCompactionManager* ParCompactionManager::manager_array(uint index) {
--- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp Mon Oct 09 07:08:53 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
@@ -98,15 +98,10 @@
_compaction_manager->follow_marking_stacks();
}
-inline void ParCompactionManager::FollowKlassClosure::do_klass(Klass* klass) {
- klass->oops_do(_mark_and_push_closure);
-}
-
inline void ParCompactionManager::follow_class_loader(ClassLoaderData* cld) {
MarkAndPushClosure mark_and_push_closure(this);
- FollowKlassClosure follow_klass_closure(&mark_and_push_closure);
- cld->oops_do(&mark_and_push_closure, &follow_klass_closure, true);
+ cld->oops_do(&mark_and_push_closure, true);
}
inline void ParCompactionManager::follow_contents(oop obj) {
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -838,11 +838,6 @@
bool PSParallelCompact::IsAliveClosure::do_object_b(oop p) { return mark_bitmap()->is_marked(p); }
-void PSParallelCompact::AdjustKlassClosure::do_klass(Klass* klass) {
- PSParallelCompact::AdjustPointerClosure closure(_cm);
- klass->oops_do(&closure);
-}
-
void PSParallelCompact::post_initialize() {
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
MemRegion mr = heap->reserved_region();
@@ -2162,7 +2157,6 @@
ClassLoaderDataGraph::clear_claimed_marks();
PSParallelCompact::AdjustPointerClosure oop_closure(cm);
- PSParallelCompact::AdjustKlassClosure klass_closure(cm);
// General strong roots.
Universe::oops_do(&oop_closure);
@@ -2172,7 +2166,7 @@
Management::oops_do(&oop_closure);
JvmtiExport::oops_do(&oop_closure);
SystemDictionary::oops_do(&oop_closure);
- ClassLoaderDataGraph::oops_do(&oop_closure, &klass_closure, true);
+ ClassLoaderDataGraph::oops_do(&oop_closure, true);
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
--- a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psScavenge.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -85,15 +85,15 @@
typedef PSRootsClosure</*promote_immediately=*/false> PSScavengeRootsClosure;
typedef PSRootsClosure</*promote_immediately=*/true> PSPromoteRootsClosure;
-// Scavenges a single oop in a Klass.
-class PSScavengeFromKlassClosure: public OopClosure {
+// Scavenges a single oop in a ClassLoaderData.
+class PSScavengeFromCLDClosure: public OopClosure {
private:
PSPromotionManager* _pm;
- // Used to redirty a scanned klass if it has oops
+ // Used to redirty a scanned cld if it has oops
// pointing to the young generation after being scanned.
- Klass* _scanned_klass;
+ ClassLoaderData* _scanned_cld;
public:
- PSScavengeFromKlassClosure(PSPromotionManager* pm) : _pm(pm), _scanned_klass(NULL) { }
+ PSScavengeFromCLDClosure(PSPromotionManager* pm) : _pm(pm), _scanned_cld(NULL) { }
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
void do_oop(oop* p) {
ParallelScavengeHeap* psh = ParallelScavengeHeap::heap();
@@ -111,48 +111,46 @@
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
if (PSScavenge::is_obj_in_young(new_obj)) {
- do_klass_barrier();
+ do_cld_barrier();
}
}
}
- void set_scanned_klass(Klass* klass) {
- assert(_scanned_klass == NULL || klass == NULL, "Should always only handling one klass at a time");
- _scanned_klass = klass;
+ void set_scanned_cld(ClassLoaderData* cld) {
+ assert(_scanned_cld == NULL || cld == NULL, "Should always only handling one cld at a time");
+ _scanned_cld = cld;
}
private:
- void do_klass_barrier() {
- assert(_scanned_klass != NULL, "Should not be called without having a scanned klass");
- _scanned_klass->record_modified_oops();
+ void do_cld_barrier() {
+ assert(_scanned_cld != NULL, "Should not be called without having a scanned cld");
+ _scanned_cld->record_modified_oops();
}
-
};
-// Scavenges the oop in a Klass.
-class PSScavengeKlassClosure: public KlassClosure {
+// Scavenges the oop in a ClassLoaderData.
+class PSScavengeCLDClosure: public CLDClosure {
private:
- PSScavengeFromKlassClosure _oop_closure;
+ PSScavengeFromCLDClosure _oop_closure;
protected:
public:
- PSScavengeKlassClosure(PSPromotionManager* pm) : _oop_closure(pm) { }
- void do_klass(Klass* klass) {
- // If the klass has not been dirtied we know that there's
+ PSScavengeCLDClosure(PSPromotionManager* pm) : _oop_closure(pm) { }
+ void do_cld(ClassLoaderData* cld) {
+ // If the cld has not been dirtied we know that there's
// no references into the young gen and we can skip it.
- if (klass->has_modified_oops()) {
- // Clean the klass since we're going to scavenge all the metadata.
- klass->clear_modified_oops();
-
- // Setup the promotion manager to redirty this klass
+ if (cld->has_modified_oops()) {
+ // Setup the promotion manager to redirty this cld
// if references are left in the young gen.
- _oop_closure.set_scanned_klass(klass);
+ _oop_closure.set_scanned_cld(cld);
- klass->oops_do(&_oop_closure);
+ // Clean the cld since we're going to scavenge all the metadata.
+ cld->oops_do(&_oop_closure, false, /*clear_modified_oops*/true);
- _oop_closure.set_scanned_klass(NULL);
+ _oop_closure.set_scanned_cld(NULL);
}
}
};
+
#endif // SHARE_VM_GC_PARALLEL_PSSCAVENGE_INLINE_HPP
--- a/src/hotspot/share/gc/parallel/psTasks.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psTasks.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -79,8 +79,8 @@
case class_loader_data:
{
- PSScavengeKlassClosure klass_closure(pm);
- ClassLoaderDataGraph::oops_do(&roots_closure, &klass_closure, false);
+ PSScavengeCLDClosure cld_closure(pm);
+ ClassLoaderDataGraph::cld_do(&cld_closure);
}
break;
--- a/src/hotspot/share/gc/serial/defNewGeneration.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -121,7 +121,7 @@
}
ScanClosure::ScanClosure(DefNewGeneration* g, bool gc_barrier) :
- OopsInKlassOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
+ OopsInClassLoaderDataOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
{
_boundary = _g->reserved().end();
}
@@ -130,7 +130,7 @@
void ScanClosure::do_oop(narrowOop* p) { ScanClosure::do_oop_work(p); }
FastScanClosure::FastScanClosure(DefNewGeneration* g, bool gc_barrier) :
- OopsInKlassOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
+ OopsInClassLoaderDataOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
{
_boundary = _g->reserved().end();
}
@@ -138,30 +138,28 @@
void FastScanClosure::do_oop(oop* p) { FastScanClosure::do_oop_work(p); }
void FastScanClosure::do_oop(narrowOop* p) { FastScanClosure::do_oop_work(p); }
-void KlassScanClosure::do_klass(Klass* klass) {
+void CLDScanClosure::do_cld(ClassLoaderData* cld) {
NOT_PRODUCT(ResourceMark rm);
- log_develop_trace(gc, scavenge)("KlassScanClosure::do_klass " PTR_FORMAT ", %s, dirty: %s",
- p2i(klass),
- klass->external_name(),
- klass->has_modified_oops() ? "true" : "false");
+ log_develop_trace(gc, scavenge)("CLDScanClosure::do_cld " PTR_FORMAT ", %s, dirty: %s",
+ p2i(cld),
+ cld->loader_name(),
+ cld->has_modified_oops() ? "true" : "false");
- // If the klass has not been dirtied we know that there's
+ // If the cld has not been dirtied we know that there's
// no references into the young gen and we can skip it.
- if (klass->has_modified_oops()) {
+ if (cld->has_modified_oops()) {
if (_accumulate_modified_oops) {
- klass->accumulate_modified_oops();
+ cld->accumulate_modified_oops();
}
- // Clear this state since we're going to scavenge all the metadata.
- klass->clear_modified_oops();
-
- // Tell the closure which Klass is being scanned so that it can be dirtied
+ // Tell the closure which CLD is being scanned so that it can be dirtied
// if oops are left pointing into the young gen.
- _scavenge_closure->set_scanned_klass(klass);
+ _scavenge_closure->set_scanned_cld(cld);
- klass->oops_do(_scavenge_closure);
+ // Clean the cld since we're going to scavenge all the metadata.
+ cld->oops_do(_scavenge_closure, false, /*clear_modified_oops*/true);
- _scavenge_closure->set_scanned_klass(NULL);
+ _scavenge_closure->set_scanned_cld(NULL);
}
}
@@ -177,12 +175,6 @@
void FilteringClosure::do_oop(oop* p) { FilteringClosure::do_oop_work(p); }
void FilteringClosure::do_oop(narrowOop* p) { FilteringClosure::do_oop_work(p); }
-KlassScanClosure::KlassScanClosure(OopsInKlassOrGenClosure* scavenge_closure,
- KlassRemSet* klass_rem_set)
- : _scavenge_closure(scavenge_closure),
- _accumulate_modified_oops(klass_rem_set->accumulate_modified_oops()) {}
-
-
DefNewGeneration::DefNewGeneration(ReservedSpace rs,
size_t initial_size,
const char* policy)
@@ -629,11 +621,8 @@
FastScanClosure fsc_with_no_gc_barrier(this, false);
FastScanClosure fsc_with_gc_barrier(this, true);
- KlassScanClosure klass_scan_closure(&fsc_with_no_gc_barrier,
- gch->rem_set()->klass_rem_set());
- CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure,
- &fsc_with_no_gc_barrier,
- false);
+ CLDScanClosure cld_scan_closure(&fsc_with_no_gc_barrier,
+ gch->rem_set()->cld_rem_set()->accumulate_modified_oops());
set_promo_failure_scan_stack_closure(&fsc_with_no_gc_barrier);
FastEvacuateFollowersClosure evacuate_followers(gch,
--- a/src/hotspot/share/gc/shared/cardTableRS.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/shared/cardTableRS.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -34,16 +34,16 @@
#include "runtime/os.hpp"
#include "utilities/macros.hpp"
-class HasAccumulatedModifiedOopsClosure : public KlassClosure {
+class HasAccumulatedModifiedOopsClosure : public CLDClosure {
bool _found;
public:
HasAccumulatedModifiedOopsClosure() : _found(false) {}
- void do_klass(Klass* klass) {
+ void do_cld(ClassLoaderData* cld) {
if (_found) {
return;
}
- if (klass->has_accumulated_modified_oops()) {
+ if (cld->has_accumulated_modified_oops()) {
_found = true;
}
}
@@ -52,28 +52,29 @@
}
};
-bool KlassRemSet::mod_union_is_clear() {
+bool CLDRemSet::mod_union_is_clear() {
HasAccumulatedModifiedOopsClosure closure;
- ClassLoaderDataGraph::classes_do(&closure);
+ ClassLoaderDataGraph::cld_do(&closure);
return !closure.found();
}
-class ClearKlassModUnionClosure : public KlassClosure {
+class ClearCLDModUnionClosure : public CLDClosure {
public:
- void do_klass(Klass* klass) {
- if (klass->has_accumulated_modified_oops()) {
- klass->clear_accumulated_modified_oops();
+ void do_cld(ClassLoaderData* cld) {
+ if (cld->has_accumulated_modified_oops()) {
+ cld->clear_accumulated_modified_oops();
}
}
};
-void KlassRemSet::clear_mod_union() {
- ClearKlassModUnionClosure closure;
- ClassLoaderDataGraph::classes_do(&closure);
+void CLDRemSet::clear_mod_union() {
+ ClearCLDModUnionClosure closure;
+ ClassLoaderDataGraph::cld_do(&closure);
}
+
CardTableRS::CardTableRS(MemRegion whole_heap) :
_bs(NULL),
_cur_youngergen_card_val(youngergenP1_card)
--- a/src/hotspot/share/gc/shared/cardTableRS.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/shared/cardTableRS.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -31,11 +31,11 @@
class Space;
class OopsInGenClosure;
-// Helper to remember modified oops in all klasses.
-class KlassRemSet {
+// Helper to remember modified oops in all clds.
+class CLDRemSet {
bool _accumulate_modified_oops;
public:
- KlassRemSet() : _accumulate_modified_oops(false) {}
+ CLDRemSet() : _accumulate_modified_oops(false) {}
void set_accumulate_modified_oops(bool value) { _accumulate_modified_oops = value; }
bool accumulate_modified_oops() { return _accumulate_modified_oops; }
bool mod_union_is_clear();
@@ -64,7 +64,7 @@
return CardTableModRefBSForCTRS::card_is_dirty_wrt_gen_iter(cv);
}
- KlassRemSet _klass_rem_set;
+ CLDRemSet _cld_rem_set;
BarrierSet* _bs;
CardTableModRefBSForCTRS* _ct_bs;
@@ -121,7 +121,7 @@
// Set the barrier set.
void set_bs(BarrierSet* bs) { _bs = bs; }
- KlassRemSet* klass_rem_set() { return &_klass_rem_set; }
+ CLDRemSet* cld_rem_set() { return &_cld_rem_set; }
CardTableModRefBSForCTRS* ct_bs() { return _ct_bs; }
--- a/src/hotspot/share/gc/shared/genOopClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/shared/genOopClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -81,24 +81,25 @@
};
-// Super class for scan closures. It contains code to dirty scanned Klasses.
-class OopsInKlassOrGenClosure: public OopsInGenClosure {
- Klass* _scanned_klass;
+// Super class for scan closures. It contains code to dirty scanned class loader data.
+class OopsInClassLoaderDataOrGenClosure: public OopsInGenClosure {
+ ClassLoaderData* _scanned_cld;
public:
- OopsInKlassOrGenClosure(Generation* g) : OopsInGenClosure(g), _scanned_klass(NULL) {}
- void set_scanned_klass(Klass* k) {
- assert(k == NULL || _scanned_klass == NULL, "Must be");
- _scanned_klass = k;
+ OopsInClassLoaderDataOrGenClosure(Generation* g) : OopsInGenClosure(g), _scanned_cld(NULL) {}
+ void set_scanned_cld(ClassLoaderData* cld) {
+ assert(cld == NULL || _scanned_cld == NULL, "Must be");
+ _scanned_cld = cld;
}
- bool is_scanning_a_klass() { return _scanned_klass != NULL; }
- void do_klass_barrier();
+ bool is_scanning_a_cld() { return _scanned_cld != NULL; }
+ void do_cld_barrier();
};
+
// Closure for scanning DefNewGeneration.
//
// This closure will perform barrier store calls for ALL
// pointers in scanned oops.
-class ScanClosure: public OopsInKlassOrGenClosure {
+class ScanClosure: public OopsInClassLoaderDataOrGenClosure {
protected:
DefNewGeneration* _g;
HeapWord* _boundary;
@@ -117,7 +118,7 @@
// This closure only performs barrier store calls on
// pointers into the DefNewGeneration. This is less
// precise, but faster, than a ScanClosure
-class FastScanClosure: public OopsInKlassOrGenClosure {
+class FastScanClosure: public OopsInClassLoaderDataOrGenClosure {
protected:
DefNewGeneration* _g;
HeapWord* _boundary;
@@ -131,14 +132,15 @@
inline void do_oop_nv(narrowOop* p);
};
-class KlassScanClosure: public KlassClosure {
- OopsInKlassOrGenClosure* _scavenge_closure;
+class CLDScanClosure: public CLDClosure {
+ OopsInClassLoaderDataOrGenClosure* _scavenge_closure;
// true if the the modified oops state should be saved.
- bool _accumulate_modified_oops;
+ bool _accumulate_modified_oops;
public:
- KlassScanClosure(OopsInKlassOrGenClosure* scavenge_closure,
- KlassRemSet* klass_rem_set_policy);
- void do_klass(Klass* k);
+ CLDScanClosure(OopsInClassLoaderDataOrGenClosure* scavenge_closure,
+ bool accumulate_modified_oops) :
+ _scavenge_closure(scavenge_closure), _accumulate_modified_oops(accumulate_modified_oops) {}
+ void do_cld(ClassLoaderData* cld);
};
class FilteringClosure: public ExtendedOopClosure {
--- a/src/hotspot/share/gc/shared/genOopClosures.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/shared/genOopClosures.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -68,9 +68,11 @@
}
}
-inline void OopsInKlassOrGenClosure::do_klass_barrier() {
- assert(_scanned_klass != NULL, "Must be");
- _scanned_klass->record_modified_oops();
+inline void OopsInClassLoaderDataOrGenClosure::do_cld_barrier() {
+ assert(_scanned_cld != NULL, "Must be");
+ if (!_scanned_cld->has_modified_oops()) {
+ _scanned_cld->record_modified_oops();
+ }
}
// NOTE! Any changes made here should also be made
@@ -87,8 +89,8 @@
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
}
- if (is_scanning_a_klass()) {
- do_klass_barrier();
+ if (is_scanning_a_cld()) {
+ do_cld_barrier();
} else if (_gc_barrier) {
// Now call parent closure
do_barrier(p);
@@ -111,8 +113,8 @@
oop new_obj = obj->is_forwarded() ? obj->forwardee()
: _g->copy_to_survivor_space(obj);
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
- if (is_scanning_a_klass()) {
- do_klass_barrier();
+ if (is_scanning_a_cld()) {
+ do_cld_barrier();
} else if (_gc_barrier) {
// Now call parent closure
do_barrier(p);
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -412,6 +412,7 @@
} else if (strcmp(vmField.typeString, "address") == 0 ||
strcmp(vmField.typeString, "intptr_t") == 0 ||
strcmp(vmField.typeString, "uintptr_t") == 0 ||
+ strcmp(vmField.typeString, "OopHandle") == 0 ||
strcmp(vmField.typeString, "size_t") == 0 ||
// All foo* types are addresses.
vmField.typeString[strlen(vmField.typeString) - 1] == '*') {
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Mon Oct 09 07:08:53 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
@@ -33,6 +33,7 @@
#include "jvmci/vmStructs_compiler_runtime.hpp"
#include "jvmci/vmStructs_jvmci.hpp"
#include "oops/oop.hpp"
+#include "oops/oopHandle.hpp"
#include "oops/objArrayKlass.hpp"
#include "runtime/globals.hpp"
#include "runtime/sharedRuntime.hpp"
@@ -192,7 +193,7 @@
nonstatic_field(Klass, _name, Symbol*) \
nonstatic_field(Klass, _prototype_header, markOop) \
nonstatic_field(Klass, _next_sibling, Klass*) \
- nonstatic_field(Klass, _java_mirror, oop) \
+ nonstatic_field(Klass, _java_mirror, OopHandle) \
nonstatic_field(Klass, _modifier_flags, jint) \
nonstatic_field(Klass, _access_flags, AccessFlags) \
\
--- a/src/hotspot/share/memory/allocation.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/allocation.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -233,7 +233,6 @@
void print_address_on(outputStream* st) const; // nonvirtual address printing
#define METASPACE_OBJ_TYPES_DO(f) \
- f(Unknown) \
f(Class) \
f(Symbol) \
f(TypeArrayU1) \
--- a/src/hotspot/share/memory/filemap.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/filemap.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -182,6 +182,7 @@
_obj_alignment = ObjectAlignmentInBytes;
_compact_strings = CompactStrings;
_narrow_oop_mode = Universe::narrow_oop_mode();
+ _narrow_oop_base = Universe::narrow_oop_base();
_narrow_oop_shift = Universe::narrow_oop_shift();
_max_heap_size = MaxHeapSize;
_narrow_klass_base = Universe::narrow_klass_base();
@@ -687,8 +688,14 @@
// open archive objects.
void FileMapInfo::map_heap_regions() {
if (MetaspaceShared::is_heap_object_archiving_allowed()) {
+ log_info(cds)("Archived narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
+ narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift());
+ log_info(cds)("Archived narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+ p2i(narrow_klass_base()), narrow_klass_shift());
+
// Check that all the narrow oop and klass encodings match the archive
if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
+ narrow_oop_base() != Universe::narrow_oop_base() ||
narrow_oop_shift() != Universe::narrow_oop_shift() ||
narrow_klass_base() != Universe::narrow_klass_base() ||
narrow_klass_shift() != Universe::narrow_klass_shift()) {
@@ -697,6 +704,11 @@
"The current CompressedOops/CompressedClassPointers encoding differs from "
"that archived due to heap size change. The archive was dumped using max heap "
"size " UINTX_FORMAT "M.", max_heap_size()/M);
+ log_info(cds)("Current narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
+ Universe::narrow_oop_mode(), p2i(Universe::narrow_oop_base()),
+ Universe::narrow_oop_shift());
+ log_info(cds)("Current narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+ p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
}
} else {
// First, map string regions as closed archive heap regions.
--- a/src/hotspot/share/memory/filemap.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/filemap.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -112,6 +112,7 @@
int _version; // (from enum, above.)
size_t _alignment; // how shared archive should be aligned
int _obj_alignment; // value of ObjectAlignmentInBytes
+ address _narrow_oop_base; // compressed oop encoding base
int _narrow_oop_shift; // compressed oop encoding shift
bool _compact_strings; // value of CompactStrings
uintx _max_heap_size; // java max heap size during dumping
@@ -203,12 +204,13 @@
int version() { return _header->_version; }
size_t alignment() { return _header->_alignment; }
Universe::NARROW_OOP_MODE narrow_oop_mode() { return _header->_narrow_oop_mode; }
- int narrow_oop_shift() { return _header->_narrow_oop_shift; }
- uintx max_heap_size() { return _header->_max_heap_size; }
- address narrow_klass_base() const { return _header->_narrow_klass_base; }
+ address narrow_oop_base() const { return _header->_narrow_oop_base; }
+ int narrow_oop_shift() const { return _header->_narrow_oop_shift; }
+ uintx max_heap_size() const { return _header->_max_heap_size; }
+ address narrow_klass_base() const { return _header->_narrow_klass_base; }
int narrow_klass_shift() const { return _header->_narrow_klass_shift; }
- struct FileMapHeader* header() { return _header; }
- char* misc_data_patching_start() { return _header->_misc_data_patching_start; }
+ struct FileMapHeader* header() { return _header; }
+ char* misc_data_patching_start() { return _header->_misc_data_patching_start; }
void set_misc_data_patching_start(char* p) { _header->_misc_data_patching_start = p; }
char* read_only_tables_start() { return _header->_read_only_tables_start; }
void set_read_only_tables_start(char* p) { _header->_read_only_tables_start = p; }
--- a/src/hotspot/share/memory/iterator.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/iterator.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, 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
@@ -29,17 +29,8 @@
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
-void KlassToOopClosure::do_klass(Klass* k) {
- assert(_oop_closure != NULL, "Not initialized?");
- k->oops_do(_oop_closure);
-}
-
void CLDToOopClosure::do_cld(ClassLoaderData* cld) {
- cld->oops_do(_oop_closure, &_klass_closure, _must_claim_cld);
-}
-
-void CLDToKlassAndOopClosure::do_cld(ClassLoaderData* cld) {
- cld->oops_do(_oop_closure, _klass_closure, _must_claim_cld);
+ cld->oops_do(_oop_closure, _must_claim_cld);
}
void ObjectToOopClosure::do_object(oop obj) {
--- a/src/hotspot/share/memory/iterator.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/iterator.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -138,67 +138,27 @@
virtual void do_cld(ClassLoaderData* cld) = 0;
};
-class KlassToOopClosure : public KlassClosure {
- friend class MetadataAwareOopClosure;
- friend class MetadataAwareOopsInGenClosure;
-
- OopClosure* _oop_closure;
-
- // Used when _oop_closure couldn't be set in an initialization list.
- void initialize(OopClosure* oop_closure) {
- assert(_oop_closure == NULL, "Should only be called once");
- _oop_closure = oop_closure;
- }
-
- public:
- KlassToOopClosure(OopClosure* oop_closure = NULL) : _oop_closure(oop_closure) {}
-
- virtual void do_klass(Klass* k);
-};
class CLDToOopClosure : public CLDClosure {
OopClosure* _oop_closure;
- KlassToOopClosure _klass_closure;
bool _must_claim_cld;
public:
CLDToOopClosure(OopClosure* oop_closure, bool must_claim_cld = true) :
_oop_closure(oop_closure),
- _klass_closure(oop_closure),
_must_claim_cld(must_claim_cld) {}
void do_cld(ClassLoaderData* cld);
};
-class CLDToKlassAndOopClosure : public CLDClosure {
- friend class G1CollectedHeap;
- protected:
- OopClosure* _oop_closure;
- KlassClosure* _klass_closure;
- bool _must_claim_cld;
- public:
- CLDToKlassAndOopClosure(KlassClosure* klass_closure,
- OopClosure* oop_closure,
- bool must_claim_cld) :
- _oop_closure(oop_closure),
- _klass_closure(klass_closure),
- _must_claim_cld(must_claim_cld) {}
- void do_cld(ClassLoaderData* cld);
-};
-
// The base class for all concurrent marking closures,
// that participates in class unloading.
// It's used to proxy through the metadata to the oops defined in them.
class MetadataAwareOopClosure: public ExtendedOopClosure {
- KlassToOopClosure _klass_closure;
public:
- MetadataAwareOopClosure() : ExtendedOopClosure() {
- _klass_closure.initialize(this);
- }
- MetadataAwareOopClosure(ReferenceProcessor* rp) : ExtendedOopClosure(rp) {
- _klass_closure.initialize(this);
- }
+ MetadataAwareOopClosure() : ExtendedOopClosure() { }
+ MetadataAwareOopClosure(ReferenceProcessor* rp) : ExtendedOopClosure(rp) { }
bool do_metadata_nv() { return true; }
virtual bool do_metadata() { return do_metadata_nv(); }
--- a/src/hotspot/share/memory/iterator.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/iterator.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -37,10 +37,8 @@
#include "utilities/debug.hpp"
inline void MetadataAwareOopClosure::do_cld_nv(ClassLoaderData* cld) {
- assert(_klass_closure._oop_closure == this, "Must be");
-
bool claim = true; // Must claim the class loader data before processing.
- cld->oops_do(_klass_closure._oop_closure, &_klass_closure, claim);
+ cld->oops_do(this, claim);
}
inline void MetadataAwareOopClosure::do_klass_nv(Klass* k) {
--- a/src/hotspot/share/memory/metaspace.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/metaspace.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3103,10 +3103,16 @@
Universe::set_narrow_klass_base(lower_base);
- if ((uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax) {
+ // CDS uses LogKlassAlignmentInBytes for narrow_klass_shift. See
+ // MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() for
+ // how dump time narrow_klass_shift is set. Although, CDS can work
+ // with zero-shift mode also, to be consistent with AOT it uses
+ // LogKlassAlignmentInBytes for klass shift so archived java heap objects
+ // can be used at same time as AOT code.
+ if (!UseSharedSpaces
+ && (uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax) {
Universe::set_narrow_klass_shift(0);
} else {
- assert(!UseSharedSpaces, "Cannot shift with UseSharedSpaces");
Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes);
}
AOTLoader::set_narrow_klass_shift();
@@ -3325,50 +3331,25 @@
#if INCLUDE_CDS
if (DumpSharedSpaces) {
- MetaspaceShared::initialize_shared_rs();
+ MetaspaceShared::initialize_dumptime_shared_and_meta_spaces();
} else if (UseSharedSpaces) {
- // If using shared space, open the file that contains the shared space
- // and map in the memory before initializing the rest of metaspace (so
- // the addresses don't conflict)
- address cds_address = NULL;
- FileMapInfo* mapinfo = new FileMapInfo();
-
- // Open the shared archive file, read and validate the header. If
- // initialization fails, shared spaces [UseSharedSpaces] are
- // disabled and the file is closed.
- // Map in spaces now also
- if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) {
- size_t cds_total = MetaspaceShared::core_spaces_size();
- cds_address = (address)mapinfo->header()->region_addr(0);
+ // If any of the archived space fails to map, UseSharedSpaces
+ // is reset to false. Fall through to the
+ // (!DumpSharedSpaces && !UseSharedSpaces) case to set up class
+ // metaspace.
+ MetaspaceShared::initialize_runtime_shared_and_meta_spaces();
+ }
+
+ if (!DumpSharedSpaces && !UseSharedSpaces)
+#endif // INCLUDE_CDS
+ {
#ifdef _LP64
- if (using_class_space()) {
- char* cds_end = (char*)(cds_address + cds_total);
- cds_end = (char *)align_up(cds_end, _reserve_alignment);
- // If UseCompressedClassPointers is set then allocate the metaspace area
- // above the heap and above the CDS area (if it exists).
- allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
- // map_heap_regions() compares the current narrow oop and klass encodings
- // with the archived ones, so it must be done after all encodings are determined.
- mapinfo->map_heap_regions();
- }
-#endif // _LP64
- } else {
- assert(!mapinfo->is_open() && !UseSharedSpaces,
- "archive file not closed or shared spaces not disabled.");
- }
- }
-#endif // INCLUDE_CDS
-
-#ifdef _LP64
- if (!UseSharedSpaces && using_class_space()) {
- if (DumpSharedSpaces) {
- // Already initialized inside MetaspaceShared::initialize_shared_rs()
- } else {
+ if (using_class_space()) {
char* base = (char*)align_up(Universe::heap()->reserved_region().end(), _reserve_alignment);
allocate_metaspace_compressed_klass_ptrs(base, 0);
}
+#endif // _LP64
}
-#endif // _LP64
// Initialize these before initializing the VirtualSpaceList
_first_chunk_word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord;
--- a/src/hotspot/share/memory/metaspace.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/metaspace.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -179,6 +179,10 @@
assert(DumpSharedSpaces, "sanity");
DEBUG_ONLY(_frozen = true;)
}
+#ifdef _LP64
+ static void allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base);
+#endif
+
private:
#ifdef _LP64
@@ -187,8 +191,6 @@
// Returns true if can use CDS with metaspace allocated as specified address.
static bool can_use_cds_with_metaspace_addr(char* metaspace_base, address cds_base);
- static void allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base);
-
static void initialize_class_space(ReservedSpace rs);
#endif
size_t class_chunk_size(size_t word_size);
--- a/src/hotspot/share/memory/metaspaceShared.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/metaspaceShared.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -165,7 +165,7 @@
}
void print(size_t total_bytes) const {
- tty->print_cr("%s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT,
+ tty->print_cr("%-3s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT,
_name, used(), perc(used(), total_bytes), reserved(), perc(used(), reserved()), p2i(_base));
}
void print_out_of_space_msg(const char* failing_region, size_t needed_bytes) {
@@ -214,7 +214,42 @@
return _ro_region.allocate(num_bytes);
}
-void MetaspaceShared::initialize_shared_rs() {
+void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
+ assert(UseSharedSpaces, "Must be called when UseSharedSpaces is enabled");
+
+ // If using shared space, open the file that contains the shared space
+ // and map in the memory before initializing the rest of metaspace (so
+ // the addresses don't conflict)
+ address cds_address = NULL;
+ FileMapInfo* mapinfo = new FileMapInfo();
+
+ // Open the shared archive file, read and validate the header. If
+ // initialization fails, shared spaces [UseSharedSpaces] are
+ // disabled and the file is closed.
+ // Map in spaces now also
+ if (mapinfo->initialize() && map_shared_spaces(mapinfo)) {
+ size_t cds_total = core_spaces_size();
+ cds_address = (address)mapinfo->header()->region_addr(0);
+#ifdef _LP64
+ if (Metaspace::using_class_space()) {
+ char* cds_end = (char*)(cds_address + cds_total);
+ cds_end = (char *)align_up(cds_end, Metaspace::reserve_alignment());
+ // If UseCompressedClassPointers is set then allocate the metaspace area
+ // above the heap and above the CDS area (if it exists).
+ Metaspace::allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
+ // map_heap_regions() compares the current narrow oop and klass encodings
+ // with the archived ones, so it must be done after all encodings are determined.
+ mapinfo->map_heap_regions();
+ }
+#endif // _LP64
+ } else {
+ assert(!mapinfo->is_open() && !UseSharedSpaces,
+ "archive file not closed or shared spaces not disabled.");
+ }
+}
+
+void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
+ assert(DumpSharedSpaces, "should be called for dump time only");
const size_t reserve_alignment = Metaspace::reserve_alignment();
bool large_pages = false; // No large pages when dumping the CDS archive.
char* shared_base = (char*)align_up((char*)SharedBaseAddress, reserve_alignment);
@@ -223,12 +258,12 @@
// On 64-bit VM, the heap and class space layout will be the same as if
// you're running in -Xshare:on mode:
//
- // +-- SharedBaseAddress (default = 0x800000000)
- // v
- // +-..---------+----+ ... +----+----+----+----+----+---------------+
- // | Heap | ST | | MC | RW | RO | MD | OD | class space |
- // +-..---------+----+ ... +----+----+----+----+----+---------------+
- // |<--MaxHeapSize->| |<-- UnscaledClassSpaceMax = 4GB ------->|
+ // +-- SharedBaseAddress (default = 0x800000000)
+ // v
+ // +-..---------+---------+ ... +----+----+----+----+----+---------------+
+ // | Heap | Archive | | MC | RW | RO | MD | OD | class space |
+ // +-..---------+---------+ ... +----+----+----+----+----+---------------+
+ // |<-- MaxHeapSize -->| |<-- UnscaledClassSpaceMax = 4GB ------->|
//
const uint64_t UnscaledClassSpaceMax = (uint64_t(max_juint) + 1);
const size_t cds_total = align_down(UnscaledClassSpaceMax, reserve_alignment);
@@ -268,12 +303,9 @@
// Set up compress class pointers.
Universe::set_narrow_klass_base((address)_shared_rs.base());
- if (UseAOT || cds_total > UnscaledClassSpaceMax) {
- // AOT forces narrow_klass_shift=LogKlassAlignmentInBytes
- Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes);
- } else {
- Universe::set_narrow_klass_shift(0);
- }
+ // Set narrow_klass_shift to be LogKlassAlignmentInBytes. This is consistent
+ // with AOT.
+ Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes);
Metaspace::initialize_class_space(tmp_class_space);
tty->print_cr("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
@@ -1405,7 +1437,7 @@
print_heap_region_stats(_string_regions, "st", total_reserved);
print_heap_region_stats(_open_archive_heap_regions, "oa", total_reserved);
- tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
+ tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
total_bytes, total_reserved, total_u_perc);
}
@@ -1416,7 +1448,7 @@
char* start = (char*)heap_mem->at(i).start();
size_t size = heap_mem->at(i).byte_size();
char* top = start + size;
- tty->print_cr("%s%d space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [100%% used] at " INTPTR_FORMAT,
+ tty->print_cr("%s%d space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [100.0%% used] at " INTPTR_FORMAT,
name, i, size, size/double(total_size)*100.0, size, p2i(start));
}
--- a/src/hotspot/share/memory/metaspaceShared.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/metaspaceShared.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -146,7 +146,8 @@
static size_t core_spaces_size() {
return _core_spaces_size;
}
- static void initialize_shared_rs() NOT_CDS_RETURN;
+ static void initialize_dumptime_shared_and_meta_spaces() NOT_CDS_RETURN;
+ static void initialize_runtime_shared_and_meta_spaces() NOT_CDS_RETURN;
// Delta of this object from the bottom of the archive.
static uintx object_delta(void* obj) {
--- a/src/hotspot/share/memory/resourceArea.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/resourceArea.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, 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
@@ -27,6 +27,15 @@
#include "memory/resourceArea.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.inline.hpp"
+#include "services/memTracker.hpp"
+
+void ResourceArea::bias_to(MEMFLAGS new_flags) {
+ if (new_flags != _flags) {
+ MemTracker::record_arena_free(_flags);
+ MemTracker::record_new_arena(new_flags);
+ _flags = new_flags;
+ }
+}
//------------------------------ResourceMark-----------------------------------
debug_only(int ResourceArea::_warned;) // to suppress multiple warnings
--- a/src/hotspot/share/memory/resourceArea.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/resourceArea.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -70,7 +70,11 @@
return (char*)Amalloc(size, alloc_failmode);
}
- debug_only(int nesting() const { return _nesting; });
+ // Bias this resource area to specific memory type
+ // (by default, ResourceArea is tagged as mtThread, per-thread general purpose storage)
+ void bias_to(MEMFLAGS flags);
+
+ debug_only(int nesting() const { return _nesting; })
};
--- a/src/hotspot/share/oops/instanceKlass.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/oops/instanceKlass.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -285,6 +285,9 @@
java_lang_Class::set_klass(java_mirror(), NULL);
}
+ // Also remove mirror from handles
+ loader_data->remove_handle(_java_mirror);
+
// Need to take this class off the class loader data list.
loader_data->remove_class(this);
--- a/src/hotspot/share/oops/klass.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/oops/klass.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -43,9 +43,16 @@
#include "trace/traceMacros.hpp"
#include "utilities/macros.hpp"
#include "utilities/stack.inline.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1SATBCardTableModRefBS.hpp"
-#endif // INCLUDE_ALL_GCS
+
+void Klass::set_java_mirror(Handle m) {
+ assert(!m.is_null(), "New mirror should never be null.");
+ assert(_java_mirror.resolve() == NULL, "should only be used to initialize mirror");
+ _java_mirror = class_loader_data()->add_handle(m);
+}
+
+oop Klass::java_mirror() const {
+ return _java_mirror.resolve();
+}
bool Klass::is_cloneable() const {
return _access_flags.is_cloneable_fast() ||
@@ -441,51 +448,6 @@
}
}
-void Klass::klass_update_barrier_set(oop v) {
- record_modified_oops();
-}
-
-// This barrier is used by G1 to remember the old oop values, so
-// that we don't forget any objects that were live at the snapshot at
-// the beginning. This function is only used when we write oops into Klasses.
-void Klass::klass_update_barrier_set_pre(oop* p, oop v) {
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- oop obj = *p;
- if (obj != NULL) {
- G1SATBCardTableModRefBS::enqueue(obj);
- }
- }
-#endif
-}
-
-void Klass::klass_oop_store(oop* p, oop v) {
- assert(!Universe::heap()->is_in_reserved((void*)p), "Should store pointer into metadata");
- assert(v == NULL || Universe::heap()->is_in_reserved((void*)v), "Should store pointer to an object");
-
- // do the store
- if (always_do_update_barrier) {
- klass_oop_store((volatile oop*)p, v);
- } else {
- klass_update_barrier_set_pre(p, v);
- *p = v;
- klass_update_barrier_set(v);
- }
-}
-
-void Klass::klass_oop_store(volatile oop* p, oop v) {
- assert(!Universe::heap()->is_in_reserved((void*)p), "Should store pointer into metadata");
- assert(v == NULL || Universe::heap()->is_in_reserved((void*)v), "Should store pointer to an object");
-
- klass_update_barrier_set_pre((oop*)p, v); // Cast away volatile.
- OrderAccess::release_store_ptr(p, v);
- klass_update_barrier_set(v);
-}
-
-void Klass::oops_do(OopClosure* cl) {
- cl->do_oop(&_java_mirror);
-}
-
void Klass::metaspace_pointers_do(MetaspaceClosure* it) {
if (log_is_enabled(Trace, cds)) {
ResourceMark rm;
@@ -532,7 +494,8 @@
ResourceMark rm;
log_trace(cds, unshareable)("remove java_mirror: %s", external_name());
}
- set_java_mirror(NULL);
+ // Just null out the mirror. The class_loader_data() no longer exists.
+ _java_mirror = NULL;
}
void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
--- a/src/hotspot/share/oops/klass.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/oops/klass.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -30,6 +30,7 @@
#include "memory/memRegion.hpp"
#include "oops/metadata.hpp"
#include "oops/oop.hpp"
+#include "oops/oopHandle.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/accessFlags.hpp"
#include "utilities/macros.hpp"
@@ -119,7 +120,7 @@
// Ordered list of all primary supertypes
Klass* _primary_supers[_primary_super_limit];
// java/lang/Class instance mirroring this class
- oop _java_mirror;
+ OopHandle _java_mirror;
// Superclass
Klass* _super;
// First subclass (NULL if none); _subklass->next_sibling() is next one
@@ -148,10 +149,6 @@
// vtable length
int _vtable_len;
- // Remembered sets support for the oops in the klasses.
- jbyte _modified_oops; // Card Table Equivalent (YC/CMS support)
- jbyte _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
-
private:
// This is an index into FileMapHeader::_classpath_entry_table[], to
// associate this class with the JAR file where it's loaded from during
@@ -228,13 +225,15 @@
}
}
- // store an oop into a field of a Klass
- void klass_oop_store(oop* p, oop v);
- void klass_oop_store(volatile oop* p, oop v);
+ // java mirror
+ oop java_mirror() const;
+ void set_java_mirror(Handle m);
- // java mirror
- oop java_mirror() const { return _java_mirror; }
- void set_java_mirror(oop m) { klass_oop_store(&_java_mirror, m); }
+ // Temporary mirror switch used by RedefineClasses
+ // Both mirrors are on the ClassLoaderData::_handles list already so no
+ // barriers are needed.
+ void set_java_mirror_handle(OopHandle mirror) { _java_mirror = mirror; }
+ OopHandle java_mirror_handle() const { return _java_mirror; }
// modifier flags
jint modifier_flags() const { return _modifier_flags; }
@@ -260,17 +259,6 @@
ClassLoaderData* class_loader_data() const { return _class_loader_data; }
void set_class_loader_data(ClassLoaderData* loader_data) { _class_loader_data = loader_data; }
- // The Klasses are not placed in the Heap, so the Card Table or
- // the Mod Union Table can't be used to mark when klasses have modified oops.
- // The CT and MUT bits saves this information for the individual Klasses.
- void record_modified_oops() { _modified_oops = 1; }
- void clear_modified_oops() { _modified_oops = 0; }
- bool has_modified_oops() { return _modified_oops == 1; }
-
- void accumulate_modified_oops() { if (has_modified_oops()) _accumulated_modified_oops = 1; }
- void clear_accumulated_modified_oops() { _accumulated_modified_oops = 0; }
- bool has_accumulated_modified_oops() { return _accumulated_modified_oops == 1; }
-
int shared_classpath_index() const {
return _shared_class_path_index;
};
@@ -598,9 +586,6 @@
TRACE_DEFINE_TRACE_ID_METHODS;
- // garbage collection support
- void oops_do(OopClosure* cl);
-
virtual void metaspace_pointers_do(MetaspaceClosure* iter);
virtual MetaspaceObj::Type type() const { return ClassType; }
@@ -687,11 +672,6 @@
static Klass* decode_klass_not_null(narrowKlass v);
static Klass* decode_klass(narrowKlass v);
-
- private:
- // barriers used by klass_oop_store
- void klass_update_barrier_set(oop v);
- void klass_update_barrier_set_pre(oop* p, oop v);
};
// Helper to convert the oop iterate macro suffixes into bool values that can be used by template functions.
--- a/src/hotspot/share/opto/c2compiler.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/c2compiler.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -410,6 +410,9 @@
case vmIntrinsics::_multiplyExactL:
if (!Matcher::match_rule_supported(Op_OverflowMulL)) return false;
break;
+ case vmIntrinsics::_multiplyHigh:
+ if (!Matcher::match_rule_supported(Op_MulHiL)) return false;
+ break;
case vmIntrinsics::_getCallerClass:
if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) return false;
break;
--- a/src/hotspot/share/opto/library_call.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/library_call.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -231,6 +231,7 @@
bool inline_math_addExactL(bool is_increment);
bool inline_math_multiplyExactI();
bool inline_math_multiplyExactL();
+ bool inline_math_multiplyHigh();
bool inline_math_negateExactI();
bool inline_math_negateExactL();
bool inline_math_subtractExactI(bool is_decrement);
@@ -549,6 +550,7 @@
case vmIntrinsics::_incrementExactL: return inline_math_addExactL(true /* increment */);
case vmIntrinsics::_multiplyExactI: return inline_math_multiplyExactI();
case vmIntrinsics::_multiplyExactL: return inline_math_multiplyExactL();
+ case vmIntrinsics::_multiplyHigh: return inline_math_multiplyHigh();
case vmIntrinsics::_negateExactI: return inline_math_negateExactI();
case vmIntrinsics::_negateExactL: return inline_math_negateExactL();
case vmIntrinsics::_subtractExactI: return inline_math_subtractExactI(false /* subtract */);
@@ -1897,6 +1899,11 @@
return inline_math_overflow<OverflowMulLNode>(argument(0), argument(2));
}
+bool LibraryCallKit::inline_math_multiplyHigh() {
+ set_result(_gvn.transform(new MulHiLNode(argument(0), argument(2))));
+ return true;
+}
+
Node*
LibraryCallKit::generate_min_max(vmIntrinsics::ID id, Node* x0, Node* y0) {
// These are the candidate return value:
@@ -3453,7 +3460,8 @@
// Given a klass oop, load its java mirror (a java.lang.Class oop).
Node* LibraryCallKit::load_mirror_from_klass(Node* klass) {
Node* p = basic_plus_adr(klass, in_bytes(Klass::java_mirror_offset()));
- return make_load(NULL, p, TypeInstPtr::MIRROR, T_OBJECT, MemNode::unordered);
+ Node* load = make_load(NULL, p, TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered);
+ return make_load(NULL, load, TypeInstPtr::MIRROR, T_OBJECT, MemNode::unordered);
}
//-----------------------load_klass_from_mirror_common-------------------------
--- a/src/hotspot/share/opto/loopTransform.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/loopTransform.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -666,7 +666,7 @@
_local_loop_unroll_limit = LoopUnrollLimit;
_local_loop_unroll_factor = 4;
int future_unroll_ct = cl->unrolled_count() * 2;
- if (!cl->do_unroll_only()) {
+ if (!cl->is_vectorized_loop()) {
if (future_unroll_ct > LoopMaxUnroll) return false;
} else {
// obey user constraints on vector mapped loops with additional unrolling applied
--- a/src/hotspot/share/opto/loopopts.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/loopopts.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -311,6 +311,7 @@
}
return NULL;
}
+ assert(m->is_Phi() || is_dominator(get_ctrl(m), n_ctrl), "m has strange control");
}
return n_ctrl;
@@ -615,6 +616,7 @@
// Now replace all Phis with CMOV's
Node *cmov_ctrl = iff->in(0);
uint flip = (lp->Opcode() == Op_IfTrue);
+ Node_List wq;
while (1) {
PhiNode* phi = NULL;
for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) {
@@ -627,17 +629,21 @@
if (phi == NULL) break;
if (PrintOpto && VerifyLoopOptimizations) { tty->print_cr("CMOV"); }
// Move speculative ops
- for (uint j = 1; j < region->req(); j++) {
- Node *proj = region->in(j);
- Node *inp = phi->in(j);
- if (get_ctrl(inp) == proj) { // Found local op
+ wq.push(phi);
+ while (wq.size() > 0) {
+ Node *n = wq.pop();
+ for (uint j = 1; j < n->req(); j++) {
+ Node* m = n->in(j);
+ if (m != NULL && !is_dominator(get_ctrl(m), cmov_ctrl)) {
#ifndef PRODUCT
- if (PrintOpto && VerifyLoopOptimizations) {
- tty->print(" speculate: ");
- inp->dump();
+ if (PrintOpto && VerifyLoopOptimizations) {
+ tty->print(" speculate: ");
+ m->dump();
+ }
+#endif
+ set_ctrl(m, cmov_ctrl);
+ wq.push(m);
}
-#endif
- set_ctrl(inp, cmov_ctrl);
}
}
Node *cmov = CMoveNode::make(cmov_ctrl, iff->in(1), phi->in(1+flip), phi->in(2-flip), _igvn.type(phi));
--- a/src/hotspot/share/opto/machnode.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/machnode.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -115,6 +115,18 @@
ConditionRegister as_ConditionRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const {
return ::as_ConditionRegister(reg(ra_, node, idx));
}
+ VectorRegister as_VectorRegister(PhaseRegAlloc *ra_, const Node *node) const {
+ return ::as_VectorRegister(reg(ra_, node));
+ }
+ VectorRegister as_VectorRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const {
+ return ::as_VectorRegister(reg(ra_, node, idx));
+ }
+ VectorSRegister as_VectorSRegister(PhaseRegAlloc *ra_, const Node *node) const {
+ return ::as_VectorSRegister(reg(ra_, node));
+ }
+ VectorSRegister as_VectorSRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const {
+ return ::as_VectorSRegister(reg(ra_, node, idx));
+ }
#endif
virtual intptr_t constant() const;
--- a/src/hotspot/share/opto/memnode.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/memnode.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1771,6 +1771,23 @@
Opcode() == Op_LoadKlass,
"Field accesses must be precise" );
// For klass/static loads, we expect the _type to be precise
+ } else if (tp->base() == Type::RawPtr && adr->is_Load() && off == 0) {
+ /* With mirrors being an indirect in the Klass*
+ * the VM is now using two loads. LoadKlass(LoadP(LoadP(Klass, mirror_offset), zero_offset))
+ * The LoadP from the Klass has a RawPtr type (see LibraryCallKit::load_mirror_from_klass).
+ *
+ * So check the type and klass of the node before the LoadP.
+ */
+ Node* adr2 = adr->in(MemNode::Address);
+ const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr();
+ if (tkls != NULL && !StressReflectiveCode) {
+ ciKlass* klass = tkls->klass();
+ if (klass->is_loaded() && tkls->klass_is_exact() && tkls->offset() == in_bytes(Klass::java_mirror_offset())) {
+ assert(adr->Opcode() == Op_LoadP, "must load an oop from _java_mirror");
+ assert(Opcode() == Op_LoadP, "must load an oop from _java_mirror");
+ return TypeInstPtr::make(klass->java_mirror());
+ }
+ }
}
const TypeKlassPtr *tkls = tp->isa_klassptr();
@@ -1798,12 +1815,6 @@
}
const Type* aift = load_array_final_field(tkls, klass);
if (aift != NULL) return aift;
- if (tkls->offset() == in_bytes(Klass::java_mirror_offset())) {
- // The field is Klass::_java_mirror. Return its (constant) value.
- // (Folds up the 2nd indirection in anObjConstant.getClass().)
- assert(Opcode() == Op_LoadP, "must load an oop from _java_mirror");
- return TypeInstPtr::make(klass->java_mirror());
- }
}
// We can still check if we are loading from the primary_supers array at a
@@ -2203,22 +2214,24 @@
// This improves reflective code, often making the Class
// mirror go completely dead. (Current exception: Class
// mirrors may appear in debug info, but we could clean them out by
- // introducing a new debug info operator for Klass*.java_mirror).
+ // introducing a new debug info operator for Klass.java_mirror).
+
if (toop->isa_instptr() && toop->klass() == phase->C->env()->Class_klass()
&& offset == java_lang_Class::klass_offset_in_bytes()) {
- // We are loading a special hidden field from a Class mirror,
- // the field which points to its Klass or ArrayKlass metaobject.
if (base->is_Load()) {
- Node* adr2 = base->in(MemNode::Address);
- const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr();
- if (tkls != NULL && !tkls->empty()
- && (tkls->klass()->is_instance_klass() ||
+ Node* base2 = base->in(MemNode::Address);
+ if (base2->is_Load()) { /* direct load of a load which is the oophandle */
+ Node* adr2 = base2->in(MemNode::Address);
+ const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr();
+ if (tkls != NULL && !tkls->empty()
+ && (tkls->klass()->is_instance_klass() ||
tkls->klass()->is_array_klass())
- && adr2->is_AddP()
- ) {
- int mirror_field = in_bytes(Klass::java_mirror_offset());
- if (tkls->offset() == mirror_field) {
- return adr2->in(AddPNode::Base);
+ && adr2->is_AddP()
+ ) {
+ int mirror_field = in_bytes(Klass::java_mirror_offset());
+ if (tkls->offset() == mirror_field) {
+ return adr2->in(AddPNode::Base);
+ }
}
}
}
--- a/src/hotspot/share/opto/subnode.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/subnode.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -877,8 +877,8 @@
}
static inline Node* isa_java_mirror_load(PhaseGVN* phase, Node* n) {
- // Return the klass node for
- // LoadP(AddP(foo:Klass, #java_mirror))
+ // Return the klass node for (indirect load from OopHandle)
+ // LoadP(LoadP(AddP(foo:Klass, #java_mirror)))
// or NULL if not matching.
if (n->Opcode() != Op_LoadP) return NULL;
@@ -886,6 +886,10 @@
if (!tp || tp->klass() != phase->C->env()->Class_klass()) return NULL;
Node* adr = n->in(MemNode::Address);
+ // First load from OopHandle
+ if (adr->Opcode() != Op_LoadP || !phase->type(adr)->isa_rawptr()) return NULL;
+ adr = adr->in(MemNode::Address);
+
intptr_t off = 0;
Node* k = AddPNode::Ideal_base_and_offset(adr, phase, off);
if (k == NULL) return NULL;
--- a/src/hotspot/share/opto/superword.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/superword.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -145,6 +145,8 @@
// Skip any loops already optimized by slp
if (cl->is_vectorized_loop()) return;
+ if (cl->do_unroll_only()) return;
+
if (cl->is_main_loop()) {
// Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit))))
CountedLoopEndNode* pre_end = get_pre_loop_end(cl);
@@ -2163,7 +2165,15 @@
//------------------------------output---------------------------
// Convert packs into vector node operations
void SuperWord::output() {
- if (_packset.length() == 0) return;
+ CountedLoopNode *cl = lpt()->_head->as_CountedLoop();
+ Compile* C = _phase->C;
+ if (_packset.length() == 0) {
+ // Instigate more unrolling for optimization when vectorization fails.
+ C->set_major_progress();
+ cl->set_notpassed_slp();
+ cl->mark_do_unroll_only();
+ return;
+ }
#ifndef PRODUCT
if (TraceLoopOpts) {
@@ -2172,7 +2182,6 @@
}
#endif
- CountedLoopNode *cl = lpt()->_head->as_CountedLoop();
if (cl->is_main_loop()) {
// MUST ENSURE main loop's initial value is properly aligned:
// (iv_initial_value + min_iv_offset) % vector_width_in_bytes() == 0
@@ -2185,7 +2194,6 @@
}
}
- Compile* C = _phase->C;
uint max_vlen_in_bytes = 0;
uint max_vlen = 0;
bool can_process_post_loop = (PostLoopMultiversioning && Matcher::has_predicated_vectors() && cl->is_post_loop());
@@ -4493,4 +4501,3 @@
return true;
}
-
--- a/src/hotspot/share/opto/type.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/type.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -67,7 +67,13 @@
{ Bad, T_ILLEGAL, "vectorx:", false, 0, relocInfo::none }, // VectorX
{ Bad, T_ILLEGAL, "vectory:", false, 0, relocInfo::none }, // VectorY
{ Bad, T_ILLEGAL, "vectorz:", false, 0, relocInfo::none }, // VectorZ
-#elif defined(PPC64) || defined(S390)
+#elif defined(PPC64)
+ { Bad, T_ILLEGAL, "vectors:", false, 0, relocInfo::none }, // VectorS
+ { Bad, T_ILLEGAL, "vectord:", false, Op_RegL, relocInfo::none }, // VectorD
+ { Bad, T_ILLEGAL, "vectorx:", false, Op_VecX, relocInfo::none }, // VectorX
+ { Bad, T_ILLEGAL, "vectory:", false, 0, relocInfo::none }, // VectorY
+ { Bad, T_ILLEGAL, "vectorz:", false, 0, relocInfo::none }, // VectorZ
+#elif defined(S390)
{ Bad, T_ILLEGAL, "vectors:", false, 0, relocInfo::none }, // VectorS
{ Bad, T_ILLEGAL, "vectord:", false, Op_RegL, relocInfo::none }, // VectorD
{ Bad, T_ILLEGAL, "vectorx:", false, 0, relocInfo::none }, // VectorX
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -158,6 +158,11 @@
ClassLoaderData* cld = _scratch_classes[i]->class_loader_data();
// Free the memory for this class at class unloading time. Not before
// because CMS might think this is still live.
+ InstanceKlass* ik = get_ik(_class_defs[i].klass);
+ if (ik->get_cached_class_file() == _scratch_classes[i]->get_cached_class_file()) {
+ // Don't double-free cached_class_file copied from the original class if error.
+ _scratch_classes[i]->set_cached_class_file(NULL);
+ }
cld->add_to_deallocate_list(InstanceKlass::cast(_scratch_classes[i]));
}
}
@@ -3946,12 +3951,12 @@
// with them was cached on the scratch class, move to the_class.
// Note: we still want to do this if nothing needed caching since it
// should get cleared in the_class too.
- if (the_class->get_cached_class_file_bytes() == 0) {
+ if (the_class->get_cached_class_file() == 0) {
// the_class doesn't have a cache yet so copy it
the_class->set_cached_class_file(scratch_class->get_cached_class_file());
}
- else if (scratch_class->get_cached_class_file_bytes() !=
- the_class->get_cached_class_file_bytes()) {
+ else if (scratch_class->get_cached_class_file() !=
+ the_class->get_cached_class_file()) {
// The same class can be present twice in the scratch classes list or there
// are multiple concurrent RetransformClasses calls on different threads.
// In such cases we have to deallocate scratch_class cached_class_file.
--- a/src/hotspot/share/prims/jvmtiTagMap.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/prims/jvmtiTagMap.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3026,8 +3026,7 @@
// Preloaded classes and loader from the system dictionary
blk.set_kind(JVMTI_HEAP_REFERENCE_SYSTEM_CLASS);
SystemDictionary::always_strong_oops_do(&blk);
- KlassToOopClosure klass_blk(&blk);
- ClassLoaderDataGraph::always_strong_oops_do(&blk, &klass_blk, false);
+ ClassLoaderDataGraph::always_strong_oops_do(&blk, false);
if (blk.stopped()) {
return false;
}
--- a/src/hotspot/share/prims/jvmtiThreadState.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/prims/jvmtiThreadState.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -411,21 +411,21 @@
private:
JvmtiThreadState* _state;
Klass* _scratch_class;
- Handle _scratch_mirror;
+ OopHandle _scratch_mirror;
public:
RedefineVerifyMark(Klass* the_class, Klass* scratch_class,
JvmtiThreadState *state) : _state(state), _scratch_class(scratch_class)
{
_state->set_class_versions_map(the_class, scratch_class);
- _scratch_mirror = Handle(Thread::current(), _scratch_class->java_mirror());
- _scratch_class->set_java_mirror(the_class->java_mirror());
+ _scratch_mirror = _scratch_class->java_mirror_handle();
+ _scratch_class->set_java_mirror_handle(the_class->java_mirror_handle());
}
~RedefineVerifyMark() {
// Restore the scratch class's mirror, so when scratch_class is removed
// the correct mirror pointing to it can be cleared.
- _scratch_class->set_java_mirror(_scratch_mirror());
+ _scratch_class->set_java_mirror_handle(_scratch_mirror);
_state->clear_class_versions_map();
}
};
--- a/src/hotspot/share/prims/whitebox.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/prims/whitebox.cpp Mon Oct 09 07:08:53 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/hotspot/share/runtime/arguments.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/arguments.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -377,6 +377,7 @@
// --- Non-alias flags - sorted by obsolete_in then expired_in:
{ "MaxGCMinorPauseMillis", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },
{ "UseConcMarkSweepGC", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() },
+ { "AssumeMP", JDK_Version::jdk(10),JDK_Version::undefined(), JDK_Version::undefined() },
{ "MonitorInUseLists", JDK_Version::jdk(10),JDK_Version::undefined(), JDK_Version::undefined() },
{ "MaxRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
{ "MinRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
@@ -4476,16 +4477,6 @@
set_shared_spaces_flags();
-#if defined(SPARC)
- // BIS instructions require 'membar' instruction regardless of the number
- // of CPUs because in virtualized/container environments which might use only 1
- // CPU, BIS instructions may produce incorrect results.
-
- if (FLAG_IS_DEFAULT(AssumeMP)) {
- FLAG_SET_DEFAULT(AssumeMP, true);
- }
-#endif
-
// Check the GC selections again.
if (!check_gc_consistency()) {
return JNI_EINVAL;
--- a/src/hotspot/share/runtime/atomic.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/atomic.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -64,24 +64,25 @@
// we can prove that a weaker form is sufficiently safe.
// Atomically store to a location
- inline static void store (jbyte store_value, jbyte* dest);
- inline static void store (jshort store_value, jshort* dest);
- inline static void store (jint store_value, jint* dest);
- // See comment above about using jlong atomics on 32-bit platforms
- inline static void store (jlong store_value, jlong* dest);
- inline static void store_ptr(intptr_t store_value, intptr_t* dest);
- inline static void store_ptr(void* store_value, void* dest);
+ // The type T must be either a pointer type convertible to or equal
+ // to D, an integral/enum type equal to D, or a type equal to D that
+ // is primitive convertible using PrimitiveConversions.
+ template<typename T, typename D>
+ inline static void store(T store_value, volatile D* dest);
+
+ inline static void store_ptr(intptr_t store_value, volatile intptr_t* dest) {
+ Atomic::store(store_value, dest);
+ }
- inline static void store (jbyte store_value, volatile jbyte* dest);
- inline static void store (jshort store_value, volatile jshort* dest);
- inline static void store (jint store_value, volatile jint* dest);
- // See comment above about using jlong atomics on 32-bit platforms
- inline static void store (jlong store_value, volatile jlong* dest);
- inline static void store_ptr(intptr_t store_value, volatile intptr_t* dest);
- inline static void store_ptr(void* store_value, volatile void* dest);
+ inline static void store_ptr(void* store_value, volatile void* dest) {
+ Atomic::store(store_value, reinterpret_cast<void* volatile*>(dest));
+ }
- // See comment above about using jlong atomics on 32-bit platforms
- inline static jlong load(const volatile jlong* src);
+ // Atomically load from a location
+ // The type T must be either a pointer type, an integral/enum type,
+ // or a type that is primitive convertible using PrimitiveConversions.
+ template<typename T>
+ inline static T load(const volatile T* dest);
// Atomically add to a location. Returns updated value. add*() provide:
// <fence> add-value-to-dest <membar StoreLoad|StoreStore>
@@ -116,10 +117,19 @@
// Performs atomic exchange of *dest with exchange_value. Returns old
// prior value of *dest. xchg*() provide:
// <fence> exchange-value-with-dest <membar StoreLoad|StoreStore>
- inline static jint xchg (jint exchange_value, volatile jint* dest);
- inline static unsigned int xchg (unsigned int exchange_value, volatile unsigned int* dest);
- inline static intptr_t xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest);
- inline static void* xchg_ptr(void* exchange_value, volatile void* dest);
+ // The type T must be either a pointer type convertible to or equal
+ // to D, an integral/enum type equal to D, or a type equal to D that
+ // is primitive convertible using PrimitiveConversions.
+ template<typename T, typename D>
+ inline static D xchg(T exchange_value, volatile D* dest);
+
+ inline static intptr_t xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
+ return xchg(exchange_value, dest);
+ }
+
+ inline static void* xchg_ptr(void* exchange_value, volatile void* dest) {
+ return xchg(exchange_value, reinterpret_cast<void* volatile*>(dest));
+ }
// Performs atomic compare of *dest and compare_value, and exchanges
// *dest with exchange_value if the comparison succeeded. Returns prior
@@ -165,6 +175,57 @@
// that is needed here.
template<typename From, typename To> struct IsPointerConvertible;
+ // Dispatch handler for store. Provides type-based validity
+ // checking and limited conversions around calls to the platform-
+ // specific implementation layer provided by PlatformOp.
+ template<typename T, typename D, typename PlatformOp, typename Enable = void>
+ struct StoreImpl;
+
+ // Platform-specific implementation of store. Support for sizes
+ // of 1, 2, 4, and (if different) pointer size bytes are required.
+ // The class is a function object that must be default constructable,
+ // with these requirements:
+ //
+ // either:
+ // - dest is of type D*, an integral, enum or pointer type.
+ // - new_value are of type T, an integral, enum or pointer type D or
+ // pointer type convertible to D.
+ // or:
+ // - T and D are the same and are primitive convertible using PrimitiveConversions
+ // and either way:
+ // - platform_store is an object of type PlatformStore<sizeof(T)>.
+ //
+ // Then
+ // platform_store(new_value, dest)
+ // must be a valid expression.
+ //
+ // The default implementation is a volatile store. If a platform
+ // requires more for e.g. 64 bit stores, a specialization is required
+ template<size_t byte_size> struct PlatformStore;
+
+ // Dispatch handler for load. Provides type-based validity
+ // checking and limited conversions around calls to the platform-
+ // specific implementation layer provided by PlatformOp.
+ template<typename T, typename PlatformOp, typename Enable = void>
+ struct LoadImpl;
+
+ // Platform-specific implementation of load. Support for sizes of
+ // 1, 2, 4 bytes and (if different) pointer size bytes are required.
+ // The class is a function object that must be default
+ // constructable, with these requirements:
+ //
+ // - dest is of type T*, an integral, enum or pointer type, or
+ // T is convertible to a primitive type using PrimitiveConversions
+ // - platform_load is an object of type PlatformLoad<sizeof(T)>.
+ //
+ // Then
+ // platform_load(src)
+ // must be a valid expression, returning a result convertible to T.
+ //
+ // The default implementation is a volatile load. If a platform
+ // requires more for e.g. 64 bit loads, a specialization is required
+ template<size_t byte_size> struct PlatformLoad;
+
// Dispatch handler for add. Provides type-based validity checking
// and limited conversions around calls to the platform-specific
// implementation layer provided by PlatformAdd.
@@ -280,6 +341,45 @@
public: // Temporary, can't be private: C++03 11.4/2. Fixed by C++11.
struct CmpxchgByteUsingInt;
private:
+
+ // Dispatch handler for xchg. Provides type-based validity
+ // checking and limited conversions around calls to the
+ // platform-specific implementation layer provided by
+ // PlatformXchg.
+ template<typename T, typename D, typename Enable = void>
+ struct XchgImpl;
+
+ // Platform-specific implementation of xchg. Support for sizes
+ // of 4, and sizeof(intptr_t) are required. The class is a function
+ // object that must be default constructable, with these requirements:
+ //
+ // - dest is of type T*.
+ // - exchange_value is of type T.
+ // - platform_xchg is an object of type PlatformXchg<sizeof(T)>.
+ //
+ // Then
+ // platform_xchg(exchange_value, dest)
+ // must be a valid expression, returning a result convertible to T.
+ //
+ // A default definition is provided, which declares a function template
+ // T operator()(T, T volatile*, T, cmpxchg_memory_order) const
+ //
+ // For each required size, a platform must either provide an
+ // appropriate definition of that function, or must entirely
+ // specialize the class template for that size.
+ template<size_t byte_size> struct PlatformXchg;
+
+ // Support for platforms that implement some variants of xchg
+ // using a (typically out of line) non-template helper function.
+ // The generic arguments passed to PlatformXchg need to be
+ // translated to the appropriate type for the helper function, the
+ // helper invoked on the translated arguments, and the result
+ // translated back. Type is the parameter / return type of the
+ // helper function.
+ template<typename Type, typename Fn, typename T>
+ static T xchg_using_helper(Fn fn,
+ T exchange_value,
+ T volatile* dest);
};
template<typename From, typename To>
@@ -296,6 +396,131 @@
static const bool value = (sizeof(yes) == sizeof(test(test_value)));
};
+// Handle load for pointer, integral and enum types.
+template<typename T, typename PlatformOp>
+struct Atomic::LoadImpl<
+ T,
+ PlatformOp,
+ typename EnableIf<IsIntegral<T>::value || IsRegisteredEnum<T>::value || IsPointer<T>::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ T operator()(T const volatile* dest) const {
+ // Forward to the platform handler for the size of T.
+ return PlatformOp()(dest);
+ }
+};
+
+// Handle load for types that have a translator.
+//
+// All the involved types must be identical.
+//
+// This translates the original call into a call on the decayed
+// arguments, and returns the recovered result of that translated
+// call.
+template<typename T, typename PlatformOp>
+struct Atomic::LoadImpl<
+ T,
+ PlatformOp,
+ typename EnableIf<PrimitiveConversions::Translate<T>::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ T operator()(T const volatile* dest) const {
+ typedef PrimitiveConversions::Translate<T> Translator;
+ typedef typename Translator::Decayed Decayed;
+ STATIC_ASSERT(sizeof(T) == sizeof(Decayed));
+ Decayed result = PlatformOp()(reinterpret_cast<Decayed const volatile*>(dest));
+ return Translator::recover(result);
+ }
+};
+
+// Default implementation of atomic load if a specific platform
+// does not provide a specialization for a certain size class.
+// For increased safety, the default implementation only allows
+// load types that are pointer sized or smaller. If a platform still
+// supports wide atomics, then it has to use specialization
+// of Atomic::PlatformLoad for that wider size class.
+template<size_t byte_size>
+struct Atomic::PlatformLoad VALUE_OBJ_CLASS_SPEC {
+ template<typename T>
+ T operator()(T const volatile* dest) const {
+ STATIC_ASSERT(sizeof(T) <= sizeof(void*)); // wide atomics need specialization
+ return *dest;
+ }
+};
+
+// Handle store for integral and enum types.
+//
+// All the involved types must be identical.
+template<typename T, typename PlatformOp>
+struct Atomic::StoreImpl<
+ T, T,
+ PlatformOp,
+ typename EnableIf<IsIntegral<T>::value || IsRegisteredEnum<T>::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ void operator()(T new_value, T volatile* dest) const {
+ // Forward to the platform handler for the size of T.
+ PlatformOp()(new_value, dest);
+ }
+};
+
+// Handle store for pointer types.
+//
+// The new_value must be implicitly convertible to the
+// destination's type; it must be type-correct to store the
+// new_value in the destination.
+template<typename T, typename D, typename PlatformOp>
+struct Atomic::StoreImpl<
+ T*, D*,
+ PlatformOp,
+ typename EnableIf<Atomic::IsPointerConvertible<T*, D*>::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ void operator()(T* new_value, D* volatile* dest) const {
+ // Allow derived to base conversion, and adding cv-qualifiers.
+ D* value = new_value;
+ PlatformOp()(value, dest);
+ }
+};
+
+// Handle store for types that have a translator.
+//
+// All the involved types must be identical.
+//
+// This translates the original call into a call on the decayed
+// arguments.
+template<typename T, typename PlatformOp>
+struct Atomic::StoreImpl<
+ T, T,
+ PlatformOp,
+ typename EnableIf<PrimitiveConversions::Translate<T>::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ void operator()(T new_value, T volatile* dest) const {
+ typedef PrimitiveConversions::Translate<T> Translator;
+ typedef typename Translator::Decayed Decayed;
+ STATIC_ASSERT(sizeof(T) == sizeof(Decayed));
+ PlatformOp()(Translator::decay(new_value),
+ reinterpret_cast<Decayed volatile*>(dest));
+ }
+};
+
+// Default implementation of atomic store if a specific platform
+// does not provide a specialization for a certain size class.
+// For increased safety, the default implementation only allows
+// storing types that are pointer sized or smaller. If a platform still
+// supports wide atomics, then it has to use specialization
+// of Atomic::PlatformStore for that wider size class.
+template<size_t byte_size>
+struct Atomic::PlatformStore VALUE_OBJ_CLASS_SPEC {
+ template<typename T>
+ void operator()(T new_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(sizeof(T) <= sizeof(void*)); // wide atomics need specialization
+ (void)const_cast<T&>(*dest = new_value);
+ }
+};
+
// Define FetchAndAdd and AddAndFetch helper classes before including
// platform file, which may use these as base classes, requiring they
// be complete.
@@ -353,6 +578,18 @@
cmpxchg_memory_order order) const;
};
+// Define the class before including platform file, which may specialize
+// the operator definition. No generic definition of specializations
+// of the operator template are provided, nor are there any generic
+// specializations of the class. The platform file is responsible for
+// providing those.
+template<size_t byte_size>
+struct Atomic::PlatformXchg VALUE_OBJ_CLASS_SPEC {
+ template<typename T>
+ T operator()(T exchange_value,
+ T volatile* dest) const;
+};
+
// platform specific in-line definitions - must come before shared definitions
#include OS_CPU_HEADER(atomic)
@@ -364,6 +601,16 @@
#error size_t is not WORD_SIZE, interesting platform, but missing implementation here
#endif
+template<typename T>
+inline T Atomic::load(const volatile T* dest) {
+ return LoadImpl<T, PlatformLoad<sizeof(T)> >()(dest);
+}
+
+template<typename T, typename D>
+inline void Atomic::store(T store_value, volatile D* dest) {
+ StoreImpl<T, D, PlatformStore<sizeof(D)> >()(store_value, dest);
+}
+
template<typename I, typename D>
inline D Atomic::add(I add_value, D volatile* dest) {
return AddImpl<I, D>()(add_value, dest);
@@ -594,9 +841,75 @@
return PrimitiveConversions::cast<T>(cur_as_bytes[offset]);
}
-inline unsigned Atomic::xchg(unsigned int exchange_value, volatile unsigned int* dest) {
- assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
- return (unsigned int)Atomic::xchg((jint)exchange_value, (volatile jint*)dest);
+// Handle xchg for integral and enum types.
+//
+// All the involved types must be identical.
+template<typename T>
+struct Atomic::XchgImpl<
+ T, T,
+ typename EnableIf<IsIntegral<T>::value || IsRegisteredEnum<T>::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ T operator()(T exchange_value, T volatile* dest) const {
+ // Forward to the platform handler for the size of T.
+ return PlatformXchg<sizeof(T)>()(exchange_value, dest);
+ }
+};
+
+// Handle xchg for pointer types.
+//
+// The exchange_value must be implicitly convertible to the
+// destination's type; it must be type-correct to store the
+// exchange_value in the destination.
+template<typename T, typename D>
+struct Atomic::XchgImpl<
+ T*, D*,
+ typename EnableIf<Atomic::IsPointerConvertible<T*, D*>::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ D* operator()(T* exchange_value, D* volatile* dest) const {
+ // Allow derived to base conversion, and adding cv-qualifiers.
+ D* new_value = exchange_value;
+ return PlatformXchg<sizeof(D*)>()(new_value, dest);
+ }
+};
+
+// Handle xchg for types that have a translator.
+//
+// All the involved types must be identical.
+//
+// This translates the original call into a call on the decayed
+// arguments, and returns the recovered result of that translated
+// call.
+template<typename T>
+struct Atomic::XchgImpl<
+ T, T,
+ typename EnableIf<PrimitiveConversions::Translate<T>::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ T operator()(T exchange_value, T volatile* dest) const {
+ typedef PrimitiveConversions::Translate<T> Translator;
+ typedef typename Translator::Decayed Decayed;
+ STATIC_ASSERT(sizeof(T) == sizeof(Decayed));
+ return Translator::recover(
+ xchg(Translator::decay(exchange_value),
+ reinterpret_cast<Decayed volatile*>(dest)));
+ }
+};
+
+template<typename Type, typename Fn, typename T>
+inline T Atomic::xchg_using_helper(Fn fn,
+ T exchange_value,
+ T volatile* dest) {
+ STATIC_ASSERT(sizeof(Type) == sizeof(T));
+ return PrimitiveConversions::cast<T>(
+ fn(PrimitiveConversions::cast<Type>(exchange_value),
+ reinterpret_cast<Type volatile*>(dest)));
+}
+
+template<typename T, typename D>
+inline D Atomic::xchg(T exchange_value, volatile D* dest) {
+ return XchgImpl<T, D>()(exchange_value, dest);
}
#endif // SHARE_VM_RUNTIME_ATOMIC_HPP
--- a/src/hotspot/share/runtime/globals.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/globals.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -592,8 +592,8 @@
range(8, 256) \
constraint(ObjectAlignmentInBytesConstraintFunc,AtParse) \
\
- product(bool, AssumeMP, false, \
- "Instruct the VM to assume multiple processors are available") \
+ product(bool, AssumeMP, true, \
+ "(Deprecated) Instruct the VM to assume multiple processors are available")\
\
/* UseMembar is theoretically a temp flag used for memory barrier */ \
/* removal testing. It was supposed to be removed before FCS but has */ \
--- a/src/hotspot/share/runtime/os.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/os.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -213,7 +213,7 @@
// the bootstrap routine for the stub generator needs to check
// the processor count directly and leave the bootstrap routine
// in place until called after initialization has ocurred.
- return (_processor_count != 1) || AssumeMP;
+ return AssumeMP || (_processor_count != 1);
}
static julong available_memory();
static julong physical_memory();
--- a/src/hotspot/share/runtime/thread.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/thread.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3263,6 +3263,9 @@
_buffer_blob = NULL;
_compiler = NULL;
+ // Compiler uses resource area for compilation, let's bias it to mtCompiler
+ resource_area()->bias_to(mtCompiler);
+
#ifndef PRODUCT
_ideal_graph_printer = NULL;
#endif
--- a/src/hotspot/share/runtime/vmStructs.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/vmStructs.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -277,7 +277,7 @@
nonstatic_field(Klass, _secondary_super_cache, Klass*) \
nonstatic_field(Klass, _secondary_supers, Array<Klass*>*) \
nonstatic_field(Klass, _primary_supers[0], Klass*) \
- nonstatic_field(Klass, _java_mirror, oop) \
+ nonstatic_field(Klass, _java_mirror, OopHandle) \
nonstatic_field(Klass, _modifier_flags, jint) \
nonstatic_field(Klass, _super, Klass*) \
nonstatic_field(Klass, _subklass, Klass*) \
--- a/src/hotspot/share/services/jmm.h Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/services/jmm.h Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, 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
@@ -50,7 +50,8 @@
JMM_VERSION_1_2 = 0x20010200, // JDK 7
JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
JMM_VERSION_1_2_2 = 0x20010202,
- JMM_VERSION = 0x20010203
+ JMM_VERSION_2 = 0x20020000, // JDK 10
+ JMM_VERSION = 0x20020000
};
typedef struct {
@@ -315,7 +316,8 @@
jobjectArray (JNICALL *DumpThreads) (JNIEnv *env,
jlongArray ids,
jboolean lockedMonitors,
- jboolean lockedSynchronizers);
+ jboolean lockedSynchronizers,
+ jint maxDepth);
void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env,
jobject mgr,
jboolean enabled);
--- a/src/hotspot/share/services/management.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/services/management.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1160,7 +1160,8 @@
// locked_monitors - if true, dump locked object monitors
// locked_synchronizers - if true, dump locked JSR-166 synchronizers
//
-JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboolean locked_monitors, jboolean locked_synchronizers))
+JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboolean locked_monitors,
+ jboolean locked_synchronizers, jint maxDepth))
ResourceMark rm(THREAD);
// make sure the AbstractOwnableSynchronizer klass is loaded before taking thread snapshots
@@ -1181,14 +1182,14 @@
do_thread_dump(&dump_result,
ids_ah,
num_threads,
- -1, /* entire stack */
+ maxDepth, /* stack depth */
(locked_monitors ? true : false), /* with locked monitors */
(locked_synchronizers ? true : false), /* with locked synchronizers */
CHECK_NULL);
} else {
// obtain thread dump of all threads
VM_ThreadDump op(&dump_result,
- -1, /* entire stack */
+ maxDepth, /* stack depth */
(locked_monitors ? true : false), /* with locked monitors */
(locked_synchronizers ? true : false) /* with locked synchronizers */);
VMThread::execute(&op);
@@ -2237,7 +2238,7 @@
void* Management::get_jmm_interface(int version) {
#if INCLUDE_MANAGEMENT
- if (version == JMM_VERSION_1_0) {
+ if (version == JMM_VERSION) {
return (void*) &jmm_interface;
}
#endif // INCLUDE_MANAGEMENT
--- a/src/hotspot/share/services/threadService.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/services/threadService.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -562,6 +562,10 @@
vframe* start_vf = _thread->last_java_vframe(®_map);
int count = 0;
for (vframe* f = start_vf; f; f = f->sender() ) {
+ if (maxDepth >= 0 && count == maxDepth) {
+ // Skip frames if more than maxDepth
+ break;
+ }
if (f->is_java_frame()) {
javaVFrame* jvf = javaVFrame::cast(f);
add_stack_frame(jvf);
@@ -569,10 +573,6 @@
} else {
// Ignore non-Java frames
}
- if (maxDepth > 0 && count == maxDepth) {
- // Skip frames if more than maxDepth
- break;
- }
}
}
--- a/src/java.base/share/classes/java/lang/ClassLoader.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java Mon Oct 09 07:08:53 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/Math.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/Math.java Mon Oct 09 07:08:53 2017 +0000
@@ -1094,6 +1094,7 @@
* @return the result
* @since 9
*/
+ @HotSpotIntrinsicCandidate
public static long multiplyHigh(long x, long y) {
if (x < 0 || y < 0) {
// Use technique from section 8-2 of Henry S. Warren, Jr.,
--- a/src/java.base/share/classes/java/lang/StackFrameInfo.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/StackFrameInfo.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/StackWalker.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/ArrayDeque.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/HashMap.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/Executors.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/FutureTask.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/TimeUnit.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/locks/Condition.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/sun/security/util/ManifestDigester.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/lib/security/default.policy Mon Oct 09 07:08:53 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;
};
@@ -150,6 +154,10 @@
permission java.security.AllPermission;
};
+grant codeBase "jrt:/jdk.internal.vm.compiler.management" {
+ permission java.security.AllPermission;
+};
+
grant codeBase "jrt:/jdk.jsobject" {
permission java.security.AllPermission;
};
--- a/src/java.base/unix/native/libnet/PlainSocketImpl.c Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/windows/native/libjava/io_util_md.c Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java Mon Oct 09 07:08:53 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/java.management/share/classes/java/lang/management/ThreadMXBean.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.management/share/classes/java/lang/management/ThreadMXBean.java Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, 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
@@ -687,52 +687,13 @@
/**
* Returns the thread info for each thread
- * whose ID is in the input array {@code ids}, with stack trace
- * and synchronization information.
- *
- * <p>
- * This method obtains a snapshot of the thread information
- * for each thread including:
- * <ul>
- * <li>the entire stack trace,</li>
- * <li>the object monitors currently locked by the thread
- * if {@code lockedMonitors} is {@code true}, and</li>
- * <li>the <a href="LockInfo.html#OwnableSynchronizer">
- * ownable synchronizers</a> currently locked by the thread
- * if {@code lockedSynchronizers} is {@code true}.</li>
- * </ul>
- * <p>
- * This method returns an array of the {@code ThreadInfo} objects,
- * each is the thread information about the thread with the same index
- * as in the {@code ids} array.
- * If a thread of the given ID is not alive or does not exist,
- * {@code null} will be set in the corresponding element
- * in the returned array. A thread is alive if
- * it has been started and has not yet died.
- * <p>
- * If a thread does not lock any object monitor or {@code lockedMonitors}
- * is {@code false}, the returned {@code ThreadInfo} object will have an
- * empty {@code MonitorInfo} array. Similarly, if a thread does not
- * lock any synchronizer or {@code lockedSynchronizers} is {@code false},
- * the returned {@code ThreadInfo} object
- * will have an empty {@code LockInfo} array.
- *
- * <p>
- * When both {@code lockedMonitors} and {@code lockedSynchronizers}
- * parameters are {@code false}, it is equivalent to calling:
- * <blockquote><pre>
- * {@link #getThreadInfo(long[], int) getThreadInfo(ids, Integer.MAX_VALUE)}
- * </pre></blockquote>
- *
- * <p>
- * This method is designed for troubleshooting use, but not for
- * synchronization control. It might be an expensive operation.
- *
- * <p>
- * <b>MBeanServer access</b>:<br>
- * The mapped type of {@code ThreadInfo} is
- * {@code CompositeData} with attributes as specified in the
- * {@link ThreadInfo#from ThreadInfo.from} method.
+ * whose ID is in the input array {@code ids},
+ * with stack trace and synchronization information.
+ * This is equivalent to calling:
+ * <blockquote>
+ * {@link #getThreadInfo(long[], boolean, boolean, int)
+ * getThreadInfo(ids, lockedMonitors, lockedSynchronizers, Integer.MAX_VALUE)}
+ * </blockquote>
*
* @param ids an array of thread IDs.
* @param lockedMonitors if {@code true}, retrieves all locked monitors.
@@ -763,18 +724,110 @@
*
* @since 1.6
*/
- public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers);
+ public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors,
+ boolean lockedSynchronizers);
+
+ /**
+ * Returns the thread info for each thread whose ID
+ * is in the input array {@code ids},
+ * with stack trace of the specified maximum number of elements
+ * and synchronization information.
+ * If {@code maxDepth == 0}, no stack trace of the thread
+ * will be dumped.
+ *
+ * <p>
+ * This method obtains a snapshot of the thread information
+ * for each thread including:
+ * <ul>
+ * <li>stack trace of the specified maximum number of elements,</li>
+ * <li>the object monitors currently locked by the thread
+ * if {@code lockedMonitors} is {@code true}, and</li>
+ * <li>the <a href="LockInfo.html#OwnableSynchronizer">
+ * ownable synchronizers</a> currently locked by the thread
+ * if {@code lockedSynchronizers} is {@code true}.</li>
+ * </ul>
+ * <p>
+ * This method returns an array of the {@code ThreadInfo} objects,
+ * each is the thread information about the thread with the same index
+ * as in the {@code ids} array.
+ * If a thread of the given ID is not alive or does not exist,
+ * {@code null} will be set in the corresponding element
+ * in the returned array. A thread is alive if
+ * it has been started and has not yet died.
+ * <p>
+ * If a thread does not lock any object monitor or {@code lockedMonitors}
+ * is {@code false}, the returned {@code ThreadInfo} object will have an
+ * empty {@code MonitorInfo} array. Similarly, if a thread does not
+ * lock any synchronizer or {@code lockedSynchronizers} is {@code false},
+ * the returned {@code ThreadInfo} object
+ * will have an empty {@code LockInfo} array.
+ *
+ * <p>
+ * When both {@code lockedMonitors} and {@code lockedSynchronizers}
+ * parameters are {@code false}, it is equivalent to calling:
+ * <blockquote><pre>
+ * {@link #getThreadInfo(long[], int) getThreadInfo(ids, maxDepth)}
+ * </pre></blockquote>
+ *
+ * <p>
+ * This method is designed for troubleshooting use, but not for
+ * synchronization control. It might be an expensive operation.
+ *
+ * <p>
+ * <b>MBeanServer access</b>:<br>
+ * The mapped type of {@code ThreadInfo} is
+ * {@code CompositeData} with attributes as specified in the
+ * {@link ThreadInfo#from ThreadInfo.from} method.
+ *
+ * @implSpec The default implementation throws
+ * {@code UnsupportedOperationException}.
+ *
+ * @param ids an array of thread IDs.
+ * @param lockedMonitors if {@code true}, retrieves all locked monitors.
+ * @param lockedSynchronizers if {@code true}, retrieves all locked
+ * ownable synchronizers.
+ * @param maxDepth indicates the maximum number of
+ * {@link StackTraceElement} to be retrieved from the stack trace.
+ *
+ * @return an array of the {@link ThreadInfo} objects, each containing
+ * information about a thread whose ID is in the corresponding
+ * element of the input array of IDs.
+ *
+ * @throws IllegalArgumentException if {@code maxDepth} is negative.
+ * @throws java.lang.SecurityException if a security manager
+ * exists and the caller does not have
+ * ManagementPermission("monitor").
+ * @throws java.lang.UnsupportedOperationException
+ * <ul>
+ * <li>if {@code lockedMonitors} is {@code true} but
+ * the Java virtual machine does not support monitoring
+ * of {@linkplain #isObjectMonitorUsageSupported
+ * object monitor usage}; or</li>
+ * <li>if {@code lockedSynchronizers} is {@code true} but
+ * the Java virtual machine does not support monitoring
+ * of {@linkplain #isSynchronizerUsageSupported
+ * ownable synchronizer usage}.</li>
+ * </ul>
+ *
+ * @see #isObjectMonitorUsageSupported
+ * @see #isSynchronizerUsageSupported
+ *
+ * @since 10
+ */
+
+ public default ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors,
+ boolean lockedSynchronizers, int maxDepth) {
+ throw new UnsupportedOperationException();
+ }
/**
* Returns the thread info for all live threads with stack trace
* and synchronization information.
- * Some threads included in the returned array
- * may have been terminated when this method returns.
- *
- * <p>
- * This method returns an array of {@link ThreadInfo} objects
- * as specified in the {@link #getThreadInfo(long[], boolean, boolean)}
- * method.
+ * This is equivalent to calling:
+ * <blockquote>
+ * {@link #dumpAllThreads(boolean, boolean, int)
+ * dumpAllThreads(lockedMonitors, lockedSynchronizers, Integer.MAX_VALUE)}
+ * </blockquote>
*
* @param lockedMonitors if {@code true}, dump all locked monitors.
* @param lockedSynchronizers if {@code true}, dump all locked
@@ -803,4 +856,56 @@
* @since 1.6
*/
public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers);
+
+
+ /**
+ * Returns the thread info for all live threads
+ * with stack trace of the specified maximum number of elements
+ * and synchronization information.
+ * if {@code maxDepth == 0}, no stack trace of the thread
+ * will be dumped.
+ * Some threads included in the returned array
+ * may have been terminated when this method returns.
+ *
+ * <p>
+ * This method returns an array of {@link ThreadInfo} objects
+ * as specified in the {@link #getThreadInfo(long[], boolean, boolean, int)}
+ * method.
+ *
+ * @implSpec The default implementation throws
+ * {@code UnsupportedOperationException}.
+ *
+ * @param lockedMonitors if {@code true}, dump all locked monitors.
+ * @param lockedSynchronizers if {@code true}, dump all locked
+ * ownable synchronizers.
+ * @param maxDepth indicates the maximum number of
+ * {@link StackTraceElement} to be retrieved from the stack trace.
+ *
+ * @return an array of {@link ThreadInfo} for all live threads.
+ *
+ * @throws IllegalArgumentException if {@code maxDepth} is negative.
+ * @throws java.lang.SecurityException if a security manager
+ * exists and the caller does not have
+ * ManagementPermission("monitor").
+ * @throws java.lang.UnsupportedOperationException
+ * <ul>
+ * <li>if {@code lockedMonitors} is {@code true} but
+ * the Java virtual machine does not support monitoring
+ * of {@linkplain #isObjectMonitorUsageSupported
+ * object monitor usage}; or</li>
+ * <li>if {@code lockedSynchronizers} is {@code true} but
+ * the Java virtual machine does not support monitoring
+ * of {@linkplain #isSynchronizerUsageSupported
+ * ownable synchronizer usage}.</li>
+ * </ul>
+ *
+ * @see #isObjectMonitorUsageSupported
+ * @see #isSynchronizerUsageSupported
+ *
+ * @since 10
+ */
+ public default ThreadInfo[] dumpAllThreads(boolean lockedMonitors,
+ boolean lockedSynchronizers, int maxDepth) {
+ throw new UnsupportedOperationException();
+ }
}
--- a/src/java.management/share/classes/sun/management/ThreadImpl.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.management/share/classes/sun/management/ThreadImpl.java Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, 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
@@ -463,20 +463,43 @@
public ThreadInfo[] getThreadInfo(long[] ids,
boolean lockedMonitors,
boolean lockedSynchronizers) {
+ return dumpThreads0(ids, lockedMonitors, lockedSynchronizers,
+ Integer.MAX_VALUE);
+ }
+
+ public ThreadInfo[] getThreadInfo(long[] ids,
+ boolean lockedMonitors,
+ boolean lockedSynchronizers,
+ int maxDepth) {
+ if (maxDepth < 0) {
+ throw new IllegalArgumentException(
+ "Invalid maxDepth parameter: " + maxDepth);
+ }
verifyThreadIds(ids);
// ids has been verified to be non-null
// an empty array of ids should return an empty array of ThreadInfos
if (ids.length == 0) return new ThreadInfo[0];
verifyDumpThreads(lockedMonitors, lockedSynchronizers);
- return dumpThreads0(ids, lockedMonitors, lockedSynchronizers);
+ return dumpThreads0(ids, lockedMonitors, lockedSynchronizers, maxDepth);
}
@Override
public ThreadInfo[] dumpAllThreads(boolean lockedMonitors,
boolean lockedSynchronizers) {
+ return dumpAllThreads(lockedMonitors, lockedSynchronizers,
+ Integer.MAX_VALUE);
+ }
+
+ public ThreadInfo[] dumpAllThreads(boolean lockedMonitors,
+ boolean lockedSynchronizers,
+ int maxDepth) {
+ if (maxDepth < 0) {
+ throw new IllegalArgumentException(
+ "Invalid maxDepth parameter: " + maxDepth);
+ }
verifyDumpThreads(lockedMonitors, lockedSynchronizers);
- return dumpThreads0(null, lockedMonitors, lockedSynchronizers);
+ return dumpThreads0(null, lockedMonitors, lockedSynchronizers, maxDepth);
}
// VM support where maxDepth == -1 to request entire stack dump
@@ -497,7 +520,8 @@
private static native void resetPeakThreadCount0();
private static native ThreadInfo[] dumpThreads0(long[] ids,
boolean lockedMonitors,
- boolean lockedSynchronizers);
+ boolean lockedSynchronizers,
+ int maxDepth);
// tid == 0 to reset contention times for all threads
private static native void resetContentionTimes0(long tid);
--- a/src/java.management/share/native/include/jmm.h Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.management/share/native/include/jmm.h Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, 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
@@ -50,7 +50,8 @@
JMM_VERSION_1_2 = 0x20010200, // JDK 7
JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
JMM_VERSION_1_2_2 = 0x20010202,
- JMM_VERSION = 0x20010203
+ JMM_VERSION_2 = 0x20020000, // JDK 10
+ JMM_VERSION = 0x20020000
};
typedef struct {
@@ -315,7 +316,8 @@
jobjectArray (JNICALL *DumpThreads) (JNIEnv *env,
jlongArray ids,
jboolean lockedMonitors,
- jboolean lockedSynchronizers);
+ jboolean lockedSynchronizers,
+ jint maxDepth);
void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env,
jobject mgr,
jboolean enabled);
--- a/src/java.management/share/native/libmanagement/ThreadImpl.c Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.management/share/native/libmanagement/ThreadImpl.c Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, 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
@@ -135,7 +135,9 @@
JNIEXPORT jobjectArray JNICALL
Java_sun_management_ThreadImpl_dumpThreads0
- (JNIEnv *env, jclass cls, jlongArray ids, jboolean lockedMonitors, jboolean lockedSynchronizers)
+ (JNIEnv *env, jclass cls, jlongArray ids, jboolean lockedMonitors,
+ jboolean lockedSynchronizers, jint maxDepth)
{
- return jmm_interface->DumpThreads(env, ids, lockedMonitors, lockedSynchronizers);
+ return jmm_interface->DumpThreads(env, ids, lockedMonitors,
+ lockedSynchronizers, maxDepth);
}
--- a/src/java.management/share/native/libmanagement/management.c Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.management/share/native/libmanagement/management.c Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, 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
@@ -44,7 +44,7 @@
return JNI_ERR;
}
- jmm_interface = (JmmInterface*) JVM_GetManagement(JMM_VERSION_1_0);
+ jmm_interface = (JmmInterface*) JVM_GetManagement(JMM_VERSION);
if (jmm_interface == NULL) {
JNU_ThrowInternalError(env, "Unsupported Management version");
return JNI_ERR;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.compiler/share/classes/module-info.java Mon Oct 09 07:08:53 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.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Mon Oct 09 07:08:53 2017 +0000
@@ -269,13 +269,12 @@
public static int decodeInvokedynamicIndex(int i) { Assert.that(isInvokedynamicIndex(i), ""); return ~i; }
- // The invokedynamic points at the object index. The object map points at
- // the cpCache index and the cpCache entry points at the original constant
- // pool index.
+ // The invokedynamic points at a CP cache entry. This entry points back
+ // at the original CP entry (CONSTANT_InvokeDynamic) and also (via f2) at an entry
+ // in the resolved_references array (which provides the appendix argument).
public int invokedynamicCPCacheIndex(int index) {
Assert.that(isInvokedynamicIndex(index), "should be a invokedynamic index");
- int rawIndex = decodeInvokedynamicIndex(index);
- return referenceMap().at(rawIndex);
+ return decodeInvokedynamicIndex(index);
}
ConstantPoolCacheEntry invokedynamicCPCacheEntryAt(int index) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java Mon Oct 09 07:08:53 2017 +0000
@@ -51,7 +51,7 @@
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("Klass");
- javaMirror = new OopField(type.getOopField("_java_mirror"), 0);
+ javaMirror = type.getAddressField("_java_mirror");
superField = new MetadataField(type.getAddressField("_super"), 0);
layoutHelper = new IntField(type.getJIntField("_layout_helper"), 0);
name = type.getAddressField("_name");
@@ -88,7 +88,7 @@
public boolean isKlass() { return true; }
// Fields
- private static OopField javaMirror;
+ private static AddressField javaMirror;
private static MetadataField superField;
private static IntField layoutHelper;
private static AddressField name;
@@ -109,7 +109,15 @@
}
// Accessors for declared fields
- public Instance getJavaMirror() { return (Instance) javaMirror.getValue(this); }
+ public Instance getJavaMirror() {
+ Address handle = javaMirror.getValue(getAddress());
+ if (handle != null) {
+ // Load through the handle
+ OopHandle refs = handle.getOopHandleAt(0);
+ return (Instance)VM.getVM().getObjectHeap().newOop(refs);
+ }
+ return null;
+ }
public Klass getSuper() { return (Klass) superField.getValue(this); }
public Klass getJavaSuper() { return null; }
public int getLayoutHelper() { return (int) layoutHelper.getValue(this); }
@@ -185,7 +193,7 @@
}
public void iterateFields(MetadataVisitor visitor) {
- visitor.doOop(javaMirror, true);
+ // visitor.doOop(javaMirror, true);
visitor.doMetadata(superField, true);
visitor.doInt(layoutHelper, true);
// visitor.doOop(name, true);
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java Mon Oct 09 07:08:53 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
@@ -138,21 +138,6 @@
return true;
}
- private boolean isValidObjectFieldDisplacement(Constant base, long displacement) {
- if (base instanceof HotSpotMetaspaceConstant) {
- MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
- if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
- if (displacement == runtime.getConfig().classMirrorOffset) {
- // Klass::_java_mirror is valid for all Klass* values
- return true;
- }
- } else {
- throw new IllegalArgumentException(String.valueOf(metaspaceObject));
- }
- }
- return false;
- }
-
private static long asRawPointer(Constant base) {
if (base instanceof HotSpotMetaspaceConstantImpl) {
MetaspaceWrapperObject meta = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
@@ -202,7 +187,7 @@
if (base instanceof HotSpotMetaspaceConstant) {
MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
- if (displacement == runtime.getConfig().classMirrorOffset) {
+ if (displacement == runtime.getConfig().classMirrorHandleOffset) {
assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror();
}
}
@@ -294,10 +279,18 @@
Object o = readRawObject(base, displacement, runtime.getConfig().useCompressedOops);
return HotSpotObjectConstantImpl.forObject(o);
}
- if (!isValidObjectFieldDisplacement(base, displacement)) {
- return null;
+ if (base instanceof HotSpotMetaspaceConstant) {
+ MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
+ if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) {
+ if (displacement == runtime.getConfig().classMirrorHandleOffset) {
+ // Klass::_java_mirror is valid for all Klass* values
+ return HotSpotObjectConstantImpl.forObject(((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror());
+ }
+ } else {
+ throw new IllegalArgumentException(String.valueOf(metaspaceObject));
+ }
}
- return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, false));
+ return null;
}
@Override
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Mon Oct 09 07:08:53 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
@@ -77,7 +77,7 @@
/**
* The offset of the _java_mirror field (of type {@link Class}) in a Klass.
*/
- final int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "oop");
+ final int classMirrorHandleOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle");
final int klassAccessFlagsOffset = getFieldOffset("Klass::_access_flags", Integer.class, "AccessFlags");
final int klassLayoutHelperOffset = getFieldOffset("Klass::_layout_helper", Integer.class, "jint");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Mon Oct 09 07:08:53 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
@@ -280,14 +280,14 @@
}
if (offset == -1) {
try {
- offset = getFieldOffset(name, Integer.class, "jobject");
+ offset = getFieldOffset(name, Integer.class, "OopHandle");
isHandle = true;
} catch (JVMCIError e) {
}
}
if (offset == -1) {
- throw new JVMCIError("cannot get offset of field " + name + " with type oop or jobject");
+ throw new JVMCIError("cannot get offset of field " + name + " with type oop or OopHandle");
}
classMirrorOffset = offset;
classMirrorIsHandle = isHandle;
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeBuilder.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DeprecatedAPIListBuilder.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Eval.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ /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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java Mon Oct 09 07:08:53 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.management/share/native/libmanagement_ext/management_ext.c Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.management/share/native/libmanagement_ext/management_ext.c Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 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
@@ -44,7 +44,7 @@
return JNI_ERR;
}
- jmm_interface = (JmmInterface*) JVM_GetManagement(JMM_VERSION_1_0);
+ jmm_interface = (JmmInterface*) JVM_GetManagement(JMM_VERSION);
if (jmm_interface == NULL) {
JNU_ThrowInternalError(env, "Unsupported Management version");
return JNI_ERR;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeMap.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Source.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/jdk.scripting.nashorn/share/classes/module-info.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/sample/nashorn/autoimports.js Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/sample/nashorn/dynalink/README Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/sample/nashorn/dynalink/array_stream_linker.js Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/sample/nashorn/dynalink/buffer_indexing_linker.js Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/sample/nashorn/dynalink/dom_linker.js Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/sample/nashorn/dynalink/missing_method_linker.js Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/src/sample/nashorn/dynalink/underscore_linker.js Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/TestCommon.gmk Mon Oct 09 07:08:53 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
--- a/test/hotspot/jtreg/ProblemList.txt Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/ProblemList.txt Mon Oct 09 07:08:53 2017 +0000
@@ -64,6 +64,7 @@
gc/g1/humongousObjects/TestHeapCounters.java 8178918 generic-all
gc/stress/gclocker/TestGCLockerWithG1.java 8179226 generic-all
gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java 8177765 generic-all
+gc/logging/TestPrintReferences.java 8188245 generic-all
#############################################################################
--- a/test/hotspot/jtreg/TEST.ROOT Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/TEST.ROOT Mon Oct 09 07:08:53 2017 +0000
@@ -52,7 +52,8 @@
vm.rtm.cpu \
vm.rtm.os \
vm.aot \
- vm.cds
+ vm.cds \
+ vm.graal.enabled
# Minimum jtreg version
requiredVersion=4.2 b08
--- a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyNoInitDeopt.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyNoInitDeopt.java Mon Oct 09 07:08:53 2017 +0000
@@ -25,7 +25,7 @@
* @test
* @bug 8072016
* @summary Infinite deoptimization/recompilation cycles in case of arraycopy with tightly coupled allocation
- * @requires vm.flavor == "server" & !vm.emulatedClient
+ * @requires vm.flavor == "server" & !vm.emulatedClient & !vm.graal.enabled
* @library /test/lib /
* @modules java.base/jdk.internal.misc
* java.management
--- a/test/hotspot/jtreg/compiler/c2/Test8004741.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/c2/Test8004741.java Mon Oct 09 07:08:53 2017 +0000
@@ -26,6 +26,7 @@
* @bug 8004741
* @summary Missing compiled exception handle table entry for multidimensional array allocation
*
+ * @requires !vm.graal.enabled
* @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
* -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers
* -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100
--- a/test/hotspot/jtreg/compiler/compilercontrol/jcmd/PrintDirectivesTest.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/compilercontrol/jcmd/PrintDirectivesTest.java Mon Oct 09 07:08:53 2017 +0000
@@ -27,7 +27,7 @@
* @summary Tests jcmd to be able to add a directive to compile only specified methods
* @modules java.base/jdk.internal.misc
* @library /test/lib /
- * @requires vm.flavor != "minimal"
+ * @requires vm.flavor != "minimal" & !vm.graal.enabled
*
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/hotspot/jtreg/compiler/compilercontrol/logcompilation/LogTest.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/compilercontrol/logcompilation/LogTest.java Mon Oct 09 07:08:53 2017 +0000
@@ -25,6 +25,8 @@
* @test
* @bug 8137167
* @summary Tests LogCompilation executed standalone without log commands or directives
+ *
+ * @requires !vm.graal.enabled
* @modules java.base/jdk.internal.misc
* @library /test/lib /
*
--- a/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java Mon Oct 09 07:08:53 2017 +0000
@@ -26,7 +26,7 @@
* @library /test/lib /
* @modules java.base/jdk.internal.misc
* java.management
- * @requires vm.cpu.features ~= ".*aes.*"
+ * @requires vm.cpu.features ~= ".*aes.*" & !vm.graal.enabled
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- a/test/hotspot/jtreg/compiler/intrinsics/IntrinsicDisabledTest.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/intrinsics/IntrinsicDisabledTest.java Mon Oct 09 07:08:53 2017 +0000
@@ -24,6 +24,8 @@
/*
* @test
* @bug 8138651
+ *
+ * @requires !vm.graal.enabled
* @modules java.base/jdk.internal.misc
* @library /test/lib /
*
--- a/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/intrinsics/klass/CastNullCheckDroppingsTest.java Mon Oct 09 07:08:53 2017 +0000
@@ -25,7 +25,7 @@
* @test NullCheckDroppingsTest
* @bug 8054492
* @summary Casting can result in redundant null checks in generated code
- * @requires vm.flavor == "server" & !vm.emulatedClient
+ * @requires vm.flavor == "server" & !vm.emulatedClient & !vm.graal.enabled
* @library /test/lib
* @modules java.base/jdk.internal.misc
* java.management
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java Mon Oct 09 07:08:53 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
@@ -110,7 +110,7 @@
test(asm -> {
ResolvedJavaType type = metaAccess.lookupJavaType(getConstClass());
Register klass = asm.emitLoadPointer((HotSpotConstant) constantReflection.asObjectHub(type));
- Register ret = asm.emitLoadPointer(klass, config.classMirrorOffset);
+ Register ret = asm.emitLoadPointer(asm.emitLoadPointer(klass, config.classMirrorHandleOffset), 0);
asm.emitPointerRet(ret);
});
}
@@ -123,7 +123,7 @@
HotSpotConstant hub = (HotSpotConstant) constantReflection.asObjectHub(type);
Register narrowKlass = asm.emitLoadPointer((HotSpotConstant) hub.compress());
Register klass = asm.emitUncompressPointer(narrowKlass, config.narrowKlassBase, config.narrowKlassShift);
- Register ret = asm.emitLoadPointer(klass, config.classMirrorOffset);
+ Register ret = asm.emitLoadPointer(asm.emitLoadPointer(klass, config.classMirrorHandleOffset), 0);
asm.emitPointerRet(ret);
});
}
@@ -135,7 +135,7 @@
HotSpotConstant hub = (HotSpotConstant) constantReflection.asObjectHub(type);
DataSectionReference ref = asm.emitDataItem(hub);
Register klass = asm.emitLoadPointer(ref);
- Register ret = asm.emitLoadPointer(klass, config.classMirrorOffset);
+ Register ret = asm.emitLoadPointer(asm.emitLoadPointer(klass, config.classMirrorHandleOffset), 0);
asm.emitPointerRet(ret);
});
}
@@ -150,7 +150,7 @@
DataSectionReference ref = asm.emitDataItem(narrowHub);
Register narrowKlass = asm.emitLoadNarrowPointer(ref);
Register klass = asm.emitUncompressPointer(narrowKlass, config.narrowKlassBase, config.narrowKlassShift);
- Register ret = asm.emitLoadPointer(klass, config.classMirrorOffset);
+ Register ret = asm.emitLoadPointer(asm.emitLoadPointer(klass, config.classMirrorHandleOffset), 0);
asm.emitPointerRet(ret);
});
}
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -40,7 +40,7 @@
public final long narrowKlassBase = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_base", Long.class, "address");
public final int narrowKlassShift = getFieldValue("CompilerToVM::Data::Universe_narrow_klass_shift", Integer.class, "int");
- public final int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "oop");
+ public final int classMirrorHandleOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle");
public final int MARKID_DEOPT_HANDLER_ENTRY = getConstant("CodeInstaller::DEOPT_HANDLER_ENTRY", Integer.class);
public final long handleDeoptStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address");
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderData.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MemoryAccessProviderData.java Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -64,7 +64,7 @@
@DataProvider(name = "positiveObject")
public static Object[][] getPositiveObjectJavaKind() {
HotSpotJVMCIRuntimeProvider runtime = (HotSpotJVMCIRuntimeProvider) JVMCI.getRuntime();
- int offset = new HotSpotVMConfigAccess(runtime.getConfigStore()).getFieldOffset("Klass::_java_mirror", Integer.class, "oop");
+ int offset = new HotSpotVMConfigAccess(runtime.getConfigStore()).getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle");
Constant wrappedKlassPointer = ((HotSpotResolvedObjectType) runtime.fromClass(TestClass.class)).klass();
return new Object[][]{new Object[]{JavaKind.Object, wrappedKlassPointer, (long) offset, TEST_CLASS_CONSTANT, 0}};
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/loopopts/TestCMovSplitThruPhi.java Mon Oct 09 07:08:53 2017 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017, Red Hat, Inc. 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 8187822
+ * @summary C2 conditonal move optimization might create broken graph
+ * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestCMovSplitThruPhi::not_inlined -XX:CompileOnly=TestCMovSplitThruPhi::test -XX:-LoopUnswitching TestCMovSplitThruPhi
+ *
+ */
+
+public class TestCMovSplitThruPhi {
+ static int f;
+
+ static int test(boolean flag1, boolean flag2, boolean flag3, boolean flag4) {
+ int v3 = 0;
+ if (flag4) {
+ for (int i = 0; i < 10; i++) {
+ int v1 = 0;
+ if (flag1) {
+ v1 = not_inlined();
+ }
+ // AddI below will be candidate for split through Phi
+ int v2 = v1;
+ if (flag2) {
+ v2 = f + v1;
+ }
+ // test above will be converted to CMovI
+ if (flag3) {
+ v3 = v2 * 2;
+ break;
+ }
+ }
+ }
+ return v3;
+ }
+
+ private static int not_inlined() {
+ return 0;
+ }
+
+ public static void main(String[] args) {
+ for (int i = 0; i < 20000; i++) {
+ test((i % 2) == 0, (i % 2) == 0, (i % 100) == 1, (i % 1000) == 1);
+ }
+ }
+}
--- a/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java Mon Oct 09 07:08:53 2017 +0000
@@ -28,7 +28,7 @@
* @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop
* @library /test/lib /
* @requires vm.compMode != "Xint" & vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) & vm.debug == true
- * @requires !vm.emulatedClient
+ * @requires !vm.emulatedClient & !vm.graal.enabled
* @modules java.base/jdk.internal.misc
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java Mon Oct 09 07:08:53 2017 +0000
@@ -46,6 +46,7 @@
{"MaxRAMFraction", "8"},
{"MinRAMFraction", "2"},
{"InitialRAMFraction", "64"},
+ {"AssumeMP", "false"},
// deprecated alias flags (see also aliased_jvm_flags):
{"DefaultMaxRAMFraction", "4"},
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/RedefineTests/RedefineDoubleDelete.java Mon Oct 09 07:08:53 2017 +0000
@@ -0,0 +1,88 @@
+/*
+ * 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 8178870
+ * @summary Redefine class with CFLH twice to test deleting the cached_class_file
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @modules java.compiler
+ * java.instrument
+ * jdk.jartool/sun.tools.jar
+ * @run main RedefineClassHelper
+ * @run main/othervm/native -Xlog:redefine+class+load+exceptions -agentlib:RedefineDoubleDelete -javaagent:redefineagent.jar RedefineDoubleDelete
+ */
+
+public class RedefineDoubleDelete {
+
+ // Class gets a redefinition error because it adds a data member
+ public static String newB =
+ "class RedefineDoubleDelete$B {" +
+ " int count1 = 0;" +
+ "}";
+
+ public static String newerB =
+ "class RedefineDoubleDelete$B { " +
+ " int faa() { System.out.println(\"baa\"); return 2; }" +
+ "}";
+
+ // The ClassFileLoadHook for this class turns foo into faa and prints out faa.
+ static class B {
+ int faa() { System.out.println("foo"); return 1; }
+ }
+
+ public static void main(String args[]) throws Exception {
+
+ B b = new B();
+ int val = b.faa();
+ if (val != 1) {
+ throw new RuntimeException("return value wrong " + val);
+ }
+
+ // Redefine B twice to get cached_class_file in both B scratch classes
+ try {
+ RedefineClassHelper.redefineClass(B.class, newB);
+ } catch (java.lang.UnsupportedOperationException e) {
+ // this is expected
+ }
+ try {
+ RedefineClassHelper.redefineClass(B.class, newB);
+ } catch (java.lang.UnsupportedOperationException e) {
+ // this is expected
+ }
+
+ // Do a full GC.
+ System.gc();
+
+ // Redefine with a compatible class
+ RedefineClassHelper.redefineClass(B.class, newerB);
+ val = b.faa();
+ if (val != 2) {
+ throw new RuntimeException("return value wrong " + val);
+ }
+
+ // Do another full GC to clean things up.
+ System.gc();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/RedefineTests/libRedefineDoubleDelete.c Mon Oct 09 07:08:53 2017 +0000
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "jvmti.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_ARG
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG(x, y) y
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG(x,y) x, y
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+#define TranslateError(err) "JVMTI error"
+
+static jvmtiEnv *jvmti = NULL;
+
+static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
+
+JNIEXPORT
+jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+ return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
+ return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
+ return JNI_VERSION_9;
+}
+
+
+static jint newClassDataLen = 0;
+static unsigned char* newClassData = NULL;
+
+static jint
+getBytecodes(jvmtiEnv *jvmti_env,
+ jint class_data_len, const unsigned char* class_data) {
+ int i;
+ jint res;
+
+ newClassDataLen = class_data_len;
+ res = (*jvmti_env)->Allocate(jvmti_env, newClassDataLen, &newClassData);
+ if (res != JNI_OK) {
+ printf(" Unable to allocate bytes\n");
+ return JNI_ERR;
+ }
+ for (i = 0; i < newClassDataLen; i++) {
+ newClassData[i] = class_data[i];
+ // Rewrite oo in class to aa
+ if (i > 0 && class_data[i] == 'o' && class_data[i-1] == 'o') {
+ newClassData[i] = newClassData[i-1] = 'a';
+ }
+ }
+ printf(" ... copied bytecode: %d bytes\n", (int)newClassDataLen);
+ return JNI_OK;
+}
+
+
+static void JNICALL
+Callback_ClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv *env,
+ jclass class_being_redefined,
+ jobject loader, const char* name, jobject protection_domain,
+ jint class_data_len, const unsigned char* class_data,
+ jint *new_class_data_len, unsigned char** new_class_data) {
+ if (name != NULL && strcmp(name, "RedefineDoubleDelete$B") == 0) {
+ if (newClassData == NULL) {
+ jint res = getBytecodes(jvmti_env, class_data_len, class_data);
+ if (res == JNI_ERR) {
+ printf(">>> ClassFileLoadHook event: class name %s FAILED\n", name);
+ return;
+ }
+ // Only change for first CFLH event.
+ *new_class_data_len = newClassDataLen;
+ *new_class_data = newClassData;
+ }
+ printf(">>> ClassFileLoadHook event: class name %s\n", name);
+ }
+}
+
+static
+jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
+ jint res, size;
+ jvmtiCapabilities caps;
+ jvmtiEventCallbacks callbacks;
+ jvmtiError err;
+
+ res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
+ JVMTI_VERSION_9);
+ if (res != JNI_OK || jvmti == NULL) {
+ printf(" Error: wrong result of a valid call to GetEnv!\n");
+ return JNI_ERR;
+ }
+
+ printf("Enabling following capabilities: can_generate_all_class_hook_events, "
+ "can_retransform_classes, can_redefine_classes");
+ memset(&caps, 0, sizeof(caps));
+ caps.can_generate_all_class_hook_events = 1;
+ caps.can_retransform_classes = 1;
+ caps.can_redefine_classes = 1;
+ printf("\n");
+
+ err = (*jvmti)->AddCapabilities(jvmti, &caps);
+ if (err != JVMTI_ERROR_NONE) {
+ printf(" Error in AddCapabilites: %s (%d)\n", TranslateError(err), err);
+ return JNI_ERR;
+ }
+
+ size = (jint)sizeof(callbacks);
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.ClassFileLoadHook = Callback_ClassFileLoadHook;
+
+ err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size);
+ if (err != JVMTI_ERROR_NONE) {
+ printf(" Error in SetEventCallbacks: %s (%d)\n", TranslateError(err), err);
+ return JNI_ERR;
+ }
+
+ err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
+ if (err != JVMTI_ERROR_NONE) {
+ printf(" Error in SetEventNotificationMode: %s (%d)\n", TranslateError(err), err);
+ return JNI_ERR;
+ }
+
+ return JNI_OK;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- a/test/hotspot/jtreg/runtime/SharedArchiveFile/SpaceUtilizationCheck.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/SpaceUtilizationCheck.java Mon Oct 09 07:08:53 2017 +0000
@@ -64,7 +64,7 @@
static void test(String... extra_options) throws Exception {
OutputAnalyzer output = CDSTestUtils.createArchive(extra_options);
CDSTestUtils.checkDump(output);
- Pattern pattern = Pattern.compile("^(..) space: *([0-9]+).* out of *([0-9]+) bytes .* at 0x([0-9a0-f]+)");
+ Pattern pattern = Pattern.compile("^(..) *space: *([0-9]+).* out of *([0-9]+) bytes .* at 0x([0-9a0-f]+)");
WhiteBox wb = WhiteBox.getWhiteBox();
long reserve_alignment = wb.metaspaceReserveAlignment();
System.out.println("Metaspace::reserve_alignment() = " + reserve_alignment);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/execstack/TestCheckJDK.java Mon Oct 09 07:08:53 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/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java Mon Oct 09 07:08:53 2017 +0000
@@ -50,7 +50,7 @@
"-Xlog:class+path=info",
"-version");
new OutputAnalyzer(pb.start())
- .shouldContain("ro space:"); // Make sure archive got created.
+ .shouldContain("ro space:"); // Make sure archive got created.
// Case 2: Test that directory in --patch-module is supported for CDS dumping
// Create a class file in the module java.base.
@@ -73,7 +73,7 @@
"-Xlog:class+path=info",
"-version");
new OutputAnalyzer(pb.start())
- .shouldContain("ro space:"); // Make sure archive got created.
+ .shouldContain("ro space:"); // Make sure archive got created.
// Case 3a: Test CDS dumping with jar file in --patch-module
BasicJarBuilder.build("javanaming", "javax/naming/spi/NamingManager");
@@ -87,7 +87,7 @@
"-Xlog:class+path=info",
"PatchModuleMain", "javax.naming.spi.NamingManager");
new OutputAnalyzer(pb.start())
- .shouldContain("ro space:"); // Make sure archive got created.
+ .shouldContain("ro space:"); // Make sure archive got created.
// Case 3b: Test CDS run with jar file in --patch-module
pb = ProcessTools.createJavaProcessBuilder(
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/sa/TestRevPtrsForInvokeDynamic.java Mon Oct 09 07:08:53 2017 +0000
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import sun.jvm.hotspot.HotSpotAgent;
+import sun.jvm.hotspot.utilities.ReversePtrsAnalysis;
+
+import jdk.test.lib.apps.LingeredApp;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.Platform;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.Utils;
+
+/*
+ * @test
+ * @library /test/lib
+ * @requires os.family != "mac"
+ * @modules java.base/jdk.internal.misc
+ * jdk.hotspot.agent/sun.jvm.hotspot
+ * jdk.hotspot.agent/sun.jvm.hotspot.utilities
+ * @run main/othervm TestRevPtrsForInvokeDynamic
+ */
+
+public class TestRevPtrsForInvokeDynamic {
+
+ private static LingeredAppWithInvokeDynamic theApp = null;
+
+ private static void computeReversePointers(String pid) throws Exception {
+ HotSpotAgent agent = new HotSpotAgent();
+
+ try {
+ agent.attach(Integer.parseInt(pid));
+ ReversePtrsAnalysis analysis = new ReversePtrsAnalysis();
+ analysis.run();
+ } finally {
+ agent.detach();
+ }
+ }
+
+ private static void createAnotherToAttach(long lingeredAppPid)
+ throws Exception {
+ String[] toolArgs = {
+ "--add-modules=jdk.hotspot.agent",
+ "--add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED",
+ "--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.utilities=ALL-UNNAMED",
+ "TestRevPtrsForInvokeDynamic",
+ Long.toString(lingeredAppPid)
+ };
+
+ // Start a new process to attach to the lingered app
+ ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(toolArgs);
+ OutputAnalyzer SAOutput = ProcessTools.executeProcess(processBuilder);
+ SAOutput.shouldHaveExitValue(0);
+ System.out.println(SAOutput.getOutput());
+ }
+
+ public static void main (String... args) throws Exception {
+ if (!Platform.shouldSAAttach()) {
+ System.out.println(
+ "SA attach not expected to work - test skipped.");
+ return;
+ }
+
+ if (args == null || args.length == 0) {
+ try {
+ List<String> vmArgs = new ArrayList<String>();
+ vmArgs.add("-XX:+UsePerfData");
+ vmArgs.addAll(Utils.getVmOptions());
+
+ theApp = new LingeredAppWithInvokeDynamic();
+ LingeredApp.startApp(vmArgs, theApp);
+ createAnotherToAttach(theApp.getPid());
+ } finally {
+ LingeredApp.stopApp(theApp);
+ }
+ } else {
+ computeReversePointers(args[0]);
+ }
+ }
+}
--- a/test/jdk/java/lang/StackWalker/Basic.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/lang/StackWalker/Basic.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/lang/StackWalker/SanityTest.java Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java Mon Oct 09 07:08:53 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/lang/management/ThreadMXBean/MaxDepthForThreadInfoTest.java Mon Oct 09 07:08:53 2017 +0000
@@ -0,0 +1,101 @@
+/*
+ * 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 8185003
+ * @build ThreadDump
+ * @run main MaxDepthForThreadInfoTest
+ * @summary verifies the functionality of ThreadMXBean.dumpAllThreads
+ * and ThreadMXBean.getThreadInfo with maxDepth argument
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+
+
+
+public class MaxDepthForThreadInfoTest {
+
+
+ public static void main(String[] Args) {
+
+ ThreadMXBean tmxb = ManagementFactory.getThreadMXBean();
+
+ long[] threadIds = tmxb.getAllThreadIds();
+
+ ThreadInfo[] tinfos = tmxb.getThreadInfo(threadIds, true, true, 0);
+ for (ThreadInfo ti : tinfos) {
+ if (ti.getStackTrace().length > 0) {
+ ThreadDump.printThreadInfo(ti);
+ throw new RuntimeException("more than requested " +
+ "number of frames dumped");
+ }
+ }
+
+ tinfos = tmxb.getThreadInfo(threadIds, true, true, 3);
+ for (ThreadInfo ti : tinfos) {
+ if (ti.getStackTrace().length > 3) {
+ ThreadDump.printThreadInfo(ti);
+ throw new RuntimeException("more than requested " +
+ "number of frames dumped");
+ }
+ }
+
+ try {
+ tmxb.getThreadInfo(threadIds, true, true, -1);
+ throw new RuntimeException("Didn't throw IllegalArgumentException " +
+ "for negative maxdepth value");
+ } catch (IllegalArgumentException e) {
+ System.out.println("Throwed IllegalArgumentException as expected");
+ }
+
+ tinfos = tmxb.dumpAllThreads(true, true, 0);
+ for (ThreadInfo ti : tinfos) {
+ if (ti.getStackTrace().length > 0) {
+ ThreadDump.printThreadInfo(ti);
+ throw new RuntimeException("more than requested " +
+ "number of frames dumped");
+ }
+ }
+ tinfos = tmxb.dumpAllThreads(true, true, 2);
+ for (ThreadInfo ti : tinfos) {
+ if (ti.getStackTrace().length > 2) {
+ ThreadDump.printThreadInfo(ti);
+ throw new RuntimeException("more than requested " +
+ "number of frames dumped");
+ }
+ }
+
+ try {
+ tmxb.dumpAllThreads(true, true, -1);
+ throw new RuntimeException("Didn't throw IllegalArgumentException " +
+ "for negative maxdepth value");
+ } catch (IllegalArgumentException e) {
+ System.out.println("Throwed IllegalArgumentException as expected");
+ }
+
+ System.out.println("Test passed");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/HugeDataTransferTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/net/httpclient/websocket/DummyWebSocketServer.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/net/httpclient/websocket/LoggingHelper.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/Collection/IteratorMicroBenchmark.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/Collection/RemoveMicroBenchmark.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/Collection/testlibrary/CollectionAsserts.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/Collection/testlibrary/ExtendsAbstractCollection.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/List/ListDefaults.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/CompletableFuture/Basic.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/AtomicIntegerFieldUpdaterTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/AtomicLongFieldUpdaterTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/AtomicReferenceFieldUpdaterTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/Collection8Test.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/CompletableFutureTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/ConcurrentHashMapTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/ConcurrentSkipListMapTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/ExecutorsTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/ForkJoinTaskTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/FutureTaskTest.java Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/LinkedTransferQueueTest.java Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/ReentrantLockTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/StampedLockTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/ThreadLocalRandomTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/java/util/concurrent/tck/TreeMapTest.java Mon Oct 09 07:08:53 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()));
}
/**
--- a/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java Mon Oct 09 07:08:53 2017 +0000
@@ -70,6 +70,7 @@
static Set<String> KNOWN_EXCEPTIONS =
Set.of("jdk.internal.vm.ci/jdk.vm.ci.services",
+ "jdk.internal.vm.ci/jdk.vm.ci.runtime",
"jdk.jsobject/jdk.internal.netscape.javascript.spi");
static void checkExports(ModuleDescriptor md) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketCloseHang.java Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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/jtreg-ext/requires/VMProps.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/jtreg-ext/requires/VMProps.java Mon Oct 09 07:08:53 2017 +0000
@@ -73,6 +73,8 @@
map.put("vm.aot", vmAOT());
// vm.cds is true if the VM is compiled with cds support.
map.put("vm.cds", vmCDS());
+ // vm.graal.enabled is true if Graal is used as JIT
+ map.put("vm.graal.enabled", isGraalEnabled());
vmGC(map); // vm.gc.X = true/false
VMProps.dump(map);
@@ -293,6 +295,41 @@
}
/**
+ * Check if Graal is used as JIT compiler.
+ *
+ * @return true if Graal is used as JIT compiler.
+ */
+ protected String isGraalEnabled() {
+ // Graal is enabled if following conditions are true:
+ // - we are not in Interpreter mode
+ // - UseJVMCICompiler flag is true
+ // - jvmci.Compiler variable is equal to 'graal'
+ // - TieredCompilation is not used or TieredStopAtLevel is greater than 3
+
+ Boolean useCompiler = WB.getBooleanVMFlag("UseCompiler");
+ if (useCompiler == null || !useCompiler)
+ return "false";
+
+ Boolean useJvmciComp = WB.getBooleanVMFlag("UseJVMCICompiler");
+ if (useJvmciComp == null || !useJvmciComp)
+ return "false";
+
+ // This check might be redundant but let's keep it for now.
+ String jvmciCompiler = System.getProperty("jvmci.Compiler");
+ if (jvmciCompiler == null || !jvmciCompiler.equals("graal")) {
+ return "false";
+ }
+
+ Boolean tieredCompilation = WB.getBooleanVMFlag("TieredCompilation");
+ Long compLevel = WB.getIntxVMFlag("TieredStopAtLevel");
+ // if TieredCompilation is enabled and compilation level is <= 3 then no Graal is used
+ if (tieredCompilation != null && tieredCompilation && compLevel != null && compLevel <= 3)
+ return "false";
+
+ return "true";
+ }
+
+ /**
* Dumps the map to the file if the file name is given as the property.
* This functionality could be helpful to know context in the real
* execution.
--- a/test/langtools/jdk/javadoc/doclet/testClassLinks/TestClassLinks.java Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testClassLinks/TestClassLinks.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testConstructors/TestConstructors.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/pkg/TestClass.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlDefinitionListTag/TestHtmlDefinitionListTag.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlTableStyles/TestHtmlTableStyles.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlTableTags/TestHtmlTableTags.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testHtmlVersion/TestHtmlVersion.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testLambdaFeature/TestLambdaFeature.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testLiteralCodeInPre/TestLiteralCodeInPre.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testMemberSummary/TestMemberSummary.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testOptions/TestOptions.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testOverridenMethods/TestBadOverride.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testPackageDeprecation/TestPackageDeprecation.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testSummaryTag/TestSummaryTag.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testTagOutput/TestTagOutput.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testTypeAnnotations/TestTypeAnnotations.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/javadoc/doclet/testUseOption/TestUseOption.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/jshell/ToolSimpleTest.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/jdk/jshell/VariablesTest.java Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/tools/javac/capture/Martin.out Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/tools/javac/lambda/8019480/T8019480.out Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/tools/javac/parser/extend/TrialParser.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/tools/javac/processing/model/TestSourceVersion.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/langtools/tools/lib/types/TypeHarness.java Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/lib/sun/hotspot/WhiteBox.java Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 2017 +0000
@@ -0,0 +1,2 @@
+5-14 VARIABLE
+0-44 FOR_LOOP
--- a/test/nashorn/script/currently-failing/JDK-8055034.js Sat Oct 07 22:45:12 2017 +0900
+++ /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 Sat Oct 07 22:45:12 2017 +0900
+++ /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 Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/nashorn/script/trusted/JDK-8006529.js Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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 Sat Oct 07 22:45:12 2017 +0900
+++ b/test/nashorn/src/jdk/nashorn/test/models/ClassWithFinalFinalizer.java Mon Oct 09 07:08:53 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 Mon Oct 09 07:08:53 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);
+
+ }
+
+}
+