--- a/make/CreateJmods.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/CreateJmods.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -117,6 +117,17 @@
--hash-modules '^(?!$(EXCLUDE_PATTERN)$$)'
endif
endif
+else # not java.base
+ ifeq ($(OPENJDK_TARGET_OS), windows)
+ # Only java.base needs to include the MSVC*_DLLs. Make sure no other module
+ # tries to include them (typically imported ones).
+ ifneq ($(wildcard $(LIBS_DIR)/$(notdir $(MSVCR_DLL))), )
+ JMOD_FLAGS += --exclude '$(notdir $(MSVCR_DLL))'
+ endif
+ ifneq ($(wildcard $(LIBS_DIR)/$(notdir $(MSVCP_DLL))), )
+ JMOD_FLAGS += --exclude '$(notdir $(MSVCP_DLL))'
+ endif
+ endif
endif
# Changes to the jmod tool itself should also trigger a rebuild of all jmods.
@@ -133,18 +144,21 @@
DEPS := $(filter-out $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/classlist, $(DEPS))
endif
+JMOD_FLAGS += --exclude '**{_the.*,_*.marker,*.diz,*.debuginfo,*.dSYM/**,*.dSYM,*.pdb,*.map}'
+
# Create jmods in a temp dir and then move them into place to keep the
# module path in $(IMAGES_OUTPUTDIR)/jmods valid at all times.
$(JMODS_DIR)/$(MODULE).jmod: $(DEPS)
$(call LogWarn, Creating $(patsubst $(OUTPUTDIR)/%, %, $@))
$(call MakeDir, $(JMODS_DIR) $(JMODS_TEMPDIR))
$(RM) $@ $(JMODS_TEMPDIR)/$(notdir $@)
- $(JMOD) create \
- --module-version $(VERSION_SHORT) \
- --target-platform '$(OPENJDK_MODULE_TARGET_PLATFORM)' \
- --module-path $(JMODS_DIR) \
- --exclude '**{_the.*,_*.marker,*.diz,*.debuginfo,*.dSYM/**,*.dSYM,*.pdb,*.map}' \
- $(JMOD_FLAGS) $(JMODS_TEMPDIR)/$(notdir $@)
+ $(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/jmods/$(MODULE).jmod, \
+ $(JMOD) create \
+ --module-version $(VERSION_SHORT) \
+ --target-platform '$(OPENJDK_MODULE_TARGET_PLATFORM)' \
+ --module-path $(JMODS_DIR) \
+ $(JMOD_FLAGS) $(JMODS_TEMPDIR)/$(notdir $@) \
+ )
$(MV) $(JMODS_TEMPDIR)/$(notdir $@) $@
TARGETS += $(JMODS_DIR)/$(MODULE).jmod
--- a/make/autoconf/toolchain_windows.m4 Mon Apr 09 08:34:30 2018 -0700
+++ b/make/autoconf/toolchain_windows.m4 Tue Apr 10 13:58:47 2018 -0700
@@ -522,7 +522,6 @@
if $ECHO "$MSVC_DLL_FILETYPE" | $GREP "$CORRECT_MSVCR_ARCH" 2>&1 > /dev/null; then
AC_MSG_RESULT([ok])
MSVC_DLL="$POSSIBLE_MSVC_DLL"
- BASIC_FIXUP_PATH(MSVC_DLL)
AC_MSG_CHECKING([for $DLL_NAME])
AC_MSG_RESULT([$MSVC_DLL])
else
--- a/make/common/NativeCompilation.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/common/NativeCompilation.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -297,7 +297,7 @@
endif
$$($1_OBJ): $$($1_SRC_FILE) $$($$($1_BASE)_COMPILE_VARDEPS_FILE) \
- $$($1_VARDEPS_FILE) | $$($$($1_BASE)_BUILD_INFO)
+ $$($$($1_BASE)_EXTRA_DEPS) $$($1_VARDEPS_FILE) | $$($$($1_BASE)_BUILD_INFO)
$$(call LogInfo, Compiling $$($1_FILENAME) (for $$($$($1_BASE)_BASENAME)))
$$(call MakeDir, $$(@D))
ifneq ($(TOOLCHAIN_TYPE), microsoft)
@@ -366,6 +366,7 @@
# EXCLUDE_PATTERN exclude files matching any of these substrings
# EXTRA_FILES List of extra files not in any of the SRC dirs
# EXTRA_OBJECT_FILES List of extra object files to include when linking
+# EXTRA_DEPS List of extra dependencies to be added to each compiled file
# VERSIONINFO_RESOURCE Input file for RC. Setting this implies that RC will be run
# RC_FLAGS flags for RC.
# EMBED_MANIFEST if true, embed manifest on Windows.
@@ -904,20 +905,22 @@
$1_IMPORT_LIBRARY := $$($1_OBJECT_DIR)/$$($1_NAME).lib
$1_EXTRA_LDFLAGS += "-implib:$$($1_IMPORT_LIBRARY)"
- # To properly trigger downstream dependants of the import library, just as
- # for debug files, we must have a recipe in the rule. To avoid rerunning
- # the recipe every time have it touch the target. If an import library
- # file is deleted by something external, explicitly delete the target to
- # trigger a rebuild of both.
- ifneq ($$(wildcard $$($1_IMPORT_LIBRARY)), $$($1_IMPORT_LIBRARY))
- $$(call LogDebug, Deleting $$($1_BASENAME) because import library is missing)
- $$(shell $(RM) $$($1_TARGET))
- endif
- $$($1_IMPORT_LIBRARY): $$($1_TARGET)
+ ifeq ($$($1_TYPE), LIBRARY)
+ # To properly trigger downstream dependants of the import library, just as
+ # for debug files, we must have a recipe in the rule. To avoid rerunning
+ # the recipe every time have it touch the target. If an import library
+ # file is deleted by something external, explicitly delete the target to
+ # trigger a rebuild of both.
+ ifneq ($$(wildcard $$($1_IMPORT_LIBRARY)), $$($1_IMPORT_LIBRARY))
+ $$(call LogDebug, Deleting $$($1_BASENAME) because import library is missing)
+ $$(shell $(RM) $$($1_TARGET))
+ endif
+ $$($1_IMPORT_LIBRARY): $$($1_TARGET)
$$(if $$(CORRECT_FUNCTION_IN_RECIPE_EVALUATION), \
$$(if $$(wildcard $$@), , $$(error $$@ was not created for $$<)) \
)
$(TOUCH) $$@
+ endif
endif
$1_VARDEPS := $$($1_LD) $$($1_SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \
--- a/make/hotspot/gensrc/GensrcDtrace.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/hotspot/gensrc/GensrcDtrace.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -54,4 +54,56 @@
TARGETS += $(patsubst $(DTRACE_SOURCE_DIR)/%.d, \
$(DTRACE_GENSRC_DIR)/%.h, $(wildcard $(DTRACE_SOURCE_DIR)/*.d))
+ ifeq ($(OPENJDK_TARGET_OS), solaris)
+ ############################################################################
+ # First we need to generate the dtraceGenOffsets tool. When run, this will
+ # produce two header files and a C++ file. Note that generateJvmOffsets.cpp
+ # is using the same JVM_CFLAGS as libjvm.so.
+
+ # Include support files that will setup JVM compiler flags.
+ include lib/JvmFeatures.gmk
+ include lib/JvmFlags.gmk
+
+ # We cannot compile until the JVMTI gensrc has finished
+ JVMTI_H := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.h
+
+ $(eval $(call SetupNativeCompilation, BUILD_DTRACE_GEN_OFFSETS, \
+ NAME := dtraceGenOffsets, \
+ TYPE := EXECUTABLE, \
+ SRC := $(TOPDIR)/make/hotspot/src/native/dtrace, \
+ TOOLCHAIN := $(TOOLCHAIN_BUILD), \
+ LDFLAGS := -m64, \
+ CFLAGS := -m64 $(JVM_CFLAGS), \
+ EXTRA_DEPS := $(JVMTI_H), \
+ OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \
+ OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \
+ ))
+
+ DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET)
+
+ # Argument 1: Output filename
+ # Argument 2: dtrace-gen-offset tool command line option
+ define SetupDtraceOffsetsGeneration
+ $1: $$(BUILD_DTRACE_GEN_OFFSETS)
+ $$(call LogInfo, Generating dtrace $2 file $$(@F))
+ $$(call MakeDir, $$(@D))
+ $$(call ExecuteWithLog, $$@, ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@ ) )
+
+ TARGETS += $1
+ endef
+
+ JVM_OFFSETS_H := $(DTRACE_GENSRC_DIR)/JvmOffsets.h
+ JVM_OFFSETS_CPP := $(DTRACE_GENSRC_DIR)/JvmOffsets.cpp
+ JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h
+
+ ############################################################################
+ # Run the dtrace-gen-offset tool to generate these three files.
+ # The generated JvmOffsets.cpp is compiled with the rest of libjvm.
+ # The header files are used by libjvm_db and jhelper.d, respectively.
+
+ $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_H), header))
+ $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_INDEX_H), index))
+ $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_CPP), table))
+ endif
+
endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/hotspot/lib/CompileDtraceLibraries.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,60 @@
+#
+# Copyright (c) 2013, 2018, 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.
+#
+
+ifeq ($(call check-jvm-feature, dtrace), true)
+ ifeq ($(OPENJDK_TARGET_OS), solaris)
+
+ ############################################################################
+ # Build the stand-alone dtrace libraries.
+
+ LIBJVM_DTRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_dtrace
+ $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DTRACE, \
+ NAME := jvm_dtrace, \
+ OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
+ SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_dtrace, \
+ CFLAGS := -m64 -G -mt -KPIC, \
+ LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
+ LIBS := $(LIBDL) -lthread -ldoor, \
+ MAPFILE := $(TOPDIR)/make/mapfiles/libjvm_dtrace/mapfile-vers, \
+ OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \
+ ))
+
+ # Note that libjvm_db.c has tests for COMPILER2, but this was never set by
+ # the old build.
+ LIBJVM_DB_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_db
+ $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DB, \
+ NAME := jvm_db, \
+ OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
+ SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_db, \
+ CFLAGS := -I$(DTRACE_GENSRC_DIR) -m64 -G -mt -KPIC, \
+ LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
+ MAPFILE := $(TOPDIR)/make/mapfiles/libjvm_db/mapfile-vers, \
+ OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \
+ ))
+
+ TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB)
+
+ endif
+endif
--- a/make/hotspot/lib/CompileDtracePostJvm.gmk Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-#
-# Copyright (c) 2013, 2018, 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.
-#
-
-################################################################################
-# Support for dtrace integration with libjvm, and stand-alone dtrace library
-# compilation.
-
-ifeq ($(call check-jvm-feature, dtrace), true)
- ##############################################################################
-
- ifeq ($(OPENJDK_TARGET_OS), solaris)
- ############################################################################
- # Integrate with libjvm. Here we generate three object files which are
- # linked with libjvm.so. This step is complicated from a dependency
- # perspective, since it needs the rest of the compiled object files from the
- # libjvm compilation, but the output is object files that are to be included
- # when linking libjvm.so. So this generation must happen as a part of the
- # libjvm compilation.
-
- # First we need to generate the dtraceGenOffsets tool. When run, this will
- # produce more header files and a C++ file.
-
- # Note that generateJvmOffsets.cpp must be compiled as if it were a file
- # in the libjvm.so, using JVM_CFLAGS as setup in CompileJvm.gmk. Otherwise
- # this would preferrably have been done as a part of GensrcDtrace.gmk.
- $(eval $(call SetupNativeCompilation, BUILD_DTRACE_GEN_OFFSETS, \
- NAME := dtraceGenOffsets, \
- TYPE := EXECUTABLE, \
- SRC := $(TOPDIR)/make/hotspot/src/native/dtrace, \
- TOOLCHAIN := $(TOOLCHAIN_BUILD), \
- LDFLAGS := -m64, \
- CFLAGS := -m64 $(JVM_CFLAGS), \
- OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \
- OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \
- ))
-
- DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET)
-
- # Argument 1: Output filename
- # Argument 2: dtrace-gen-offset tool command line option
- define SetupDtraceOffsetsGeneration
- $1: $$(BUILD_DTRACE_GEN_OFFSETS)
- $$(call LogInfo, Generating dtrace $2 file $$(@F))
- $$(call MakeDir, $$(@D))
- $$(call ExecuteWithLog, $$@, ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@ ) )
-
- TARGETS += $1
- endef
-
- JVM_OFFSETS_H := $(DTRACE_SUPPORT_DIR)/JvmOffsets.h
- JVM_OFFSETS_CPP := $(DTRACE_SUPPORT_DIR)/JvmOffsets.cpp
- JVM_OFFSETS_INDEX_H := $(DTRACE_SUPPORT_DIR)/JvmOffsetsIndex.h
-
- # Run the dtrace-gen-offset tool to generate these three files.
- # The generated JvmOffsets.cpp is compiled with the rest of libjvm.
- $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_H), header))
- $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_INDEX_H), index))
- $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_CPP), table))
-
- ############################################################################
- # Generate DTRACE_OBJ which is linked with libjvm.so.
-
- # Concatenate all *.d files into a single file
- DTRACE_SOURCE_FILES := $(addprefix $(TOPDIR)/src/hotspot/os/posix/dtrace/, \
- hotspot_jni.d \
- hotspot.d \
- hs_private.d \
- )
-
- $(JVM_OUTPUTDIR)/objs/dtrace.d: $(DTRACE_SOURCE_FILES)
- $(call LogInfo, Generating $(@F))
- $(call MakeDir, $(@D))
- $(CAT) $^ > $@
-
- DTRACE_INSTRUMENTED_OBJS := $(addprefix $(JVM_OUTPUTDIR)/objs/, \
- ciEnv.o \
- classLoadingService.o \
- compileBroker.o \
- hashtable.o \
- instanceKlass.o \
- java.o \
- jni.o \
- jvm.o \
- memoryManager.o \
- nmethod.o \
- objectMonitor.o \
- runtimeService.o \
- sharedRuntime.o \
- synchronizer.o \
- thread.o \
- unsafe.o \
- vmThread.o \
- vmGCOperations.o \
- )
-
- ifeq ($(call check-jvm-feature, all-gcs), true)
- DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \
- vmCMSOperations.o \
- vmPSOperations.o \
- )
- endif
-
- DTRACE_FLAGS := -64 -G
- DTRACE_CPP_FLAGS := -D_LP64
-
- # Make sure we run our selected compiler for preprocessing instead of letting
- # the dtrace tool pick it on it's own.
- $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.d $(DTRACE_INSTRUMENTED_OBJS)
- $(call LogInfo, Generating $(@F) from $(<F) and object files)
- $(call MakeDir, $(DTRACE_SUPPORT_DIR))
- $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
- ($(CPP) $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d))
- $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -xlazyload -o $@ \
- -s $(DTRACE_SUPPORT_DIR)/$(@F).d $(sort $(DTRACE_INSTRUMENTED_OBJS)))
-
- ############################################################################
- # Generate DTRACE_JHELPER_OBJ which is linked with libjvm.so.
-
- # Unfortunately dtrace generates incorrect types for some symbols in
- # dtrace_jhelper.o, resulting in "warning: symbol X has differing types"
- # See JDK-6890703 for details.
- # We work around this by fixing the types for these symbols using elfedit,
- # after dtrace has generated the .o file.
- JHELPER_DTRACE_SRC := $(TOPDIR)/src/hotspot/os/solaris/dtrace/jhelper.d
-
- GetElfeditCommands = \
- $(foreach symbol, \
- $(shell $(GREP) ^extern $(JHELPER_DTRACE_SRC) | $(AWK) '{ gsub(";","") ; print $$3 }'), \
- -e 'sym:st_type $(symbol) 1')
-
- # Make sure we run our selected compiler for preprocessing instead of letting
- # the dtrace tool pick it on it's own.
- $(DTRACE_JHELPER_OBJ): $(JHELPER_DTRACE_SRC) $(JVM_OFFSETS_INDEX_H)
- $(call LogInfo, Running dtrace for $(<F))
- $(call MakeDir, $(DTRACE_SUPPORT_DIR))
- $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
- ($(CPP) $(DTRACE_CPP_FLAGS) -I$(DTRACE_SUPPORT_DIR) $^ \
- > $(DTRACE_SUPPORT_DIR)/$(@F).d))
- $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -o $@ \
- -s $(DTRACE_SUPPORT_DIR)/$(@F).d)
- ifeq ($(OPENJDK_TARGET_CPU_ARCH), sparc)
- $(call ExecuteWithLog, $@.elfedit, $(ELFEDIT) $(call GetElfeditCommands) $@)
- endif
-
- ############################################################################
- # Build the stand-alone dtrace libraries
-
- LIBJVM_DTRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_dtrace
-
- $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DTRACE, \
- NAME := jvm_dtrace, \
- OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
- SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_dtrace, \
- CFLAGS := -m64 -G -mt -KPIC, \
- LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
- LIBS := $(LIBDL) -lthread -ldoor, \
- MAPFILE := $(TOPDIR)/make/mapfiles/libjvm_dtrace/mapfile-vers, \
- OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \
- ))
-
- LIBJVM_DB_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_db
-
- # Note that libjvm_db.c has tests for COMPILER2, but this was never set by
- # the old build.
- $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DB, \
- NAME := jvm_db, \
- OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
- SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_db, \
- CFLAGS := -I$(JVM_VARIANT_OUTPUTDIR)/gensrc -I$(DTRACE_SUPPORT_DIR) \
- -m64 -G -mt -KPIC, \
- LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
- MAPFILE := $(TOPDIR)/make/mapfiles/libjvm_db/mapfile-vers, \
- OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \
- ))
-
- # We need the generated JvmOffsets.h before we can compile the libjvm_db source code.
- $(BUILD_LIBJVM_DB_ALL_OBJS): $(JVM_OFFSETS_H)
-
- TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB)
- endif
-endif
--- a/make/hotspot/lib/CompileDtracePreJvm.gmk Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-#
-# Copyright (c) 2016, 2018, 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.
-#
-
-ifeq ($(call check-jvm-feature, dtrace), true)
- ifeq ($(OPENJDK_TARGET_OS), solaris)
- # These files are are generated by CompileDtrace.gmk but consumed by
- # CompileJvm.gmk
- DTRACE_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace.o
- DTRACE_JHELPER_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace_jhelper.o
- DTRACE_EXTRA_OBJECT_FILES := $(DTRACE_OBJ) $(DTRACE_JHELPER_OBJ)
-
- # Since we cannot generate JvmOffsets.cpp as part of the gensrc step,
- # we need this special hook to get it to compile with the rest of libjvm.
- JVM_OFFSETS_CPP := $(DTRACE_SUPPORT_DIR)/JvmOffsets.cpp
- DTRACE_EXTRA_SOURCE_FILES := $(JVM_OFFSETS_CPP)
- endif
-endif
--- a/make/hotspot/lib/CompileJvm.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/hotspot/lib/CompileJvm.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -24,11 +24,13 @@
#
# Include support files that will setup compiler flags due to the selected
-# jvm feature set, and specific file overrides.
+# jvm feature set, specific file overrides, and general flags.
include lib/JvmFeatures.gmk
include lib/JvmOverrideFiles.gmk
+include lib/JvmFlags.gmk
-$(eval $(call IncludeCustomExtension, hotspot/lib/CompileJvm.gmk))
+# Include support files that will setup DTRACE_EXTRA_OBJECT_FILES.
+include lib/JvmDtraceObjects.gmk
################################################################################
# Setup compilation of the main Hotspot native library (libjvm).
@@ -39,71 +41,6 @@
################################################################################
# Platform independent setup
-# This variable may be added to by a custom extension
-JVM_SRC_ROOTS += $(TOPDIR)/src/hotspot
-
-JVM_SRC_DIRS += $(call uniq, $(wildcard $(foreach d, $(JVM_SRC_ROOTS), \
- $d/share \
- $d/os/$(HOTSPOT_TARGET_OS) \
- $d/os/$(HOTSPOT_TARGET_OS_TYPE) \
- $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH) \
- $d/os_cpu/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH) \
- ))) \
- $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles \
- $(JVM_VARIANT_OUTPUTDIR)/gensrc/tracefiles \
- #
-
-JVM_CFLAGS_INCLUDES += \
- $(patsubst %,-I%,$(filter-out $(JVM_VARIANT_OUTPUTDIR)/gensrc/%, $(JVM_SRC_DIRS))) \
- -I$(JVM_VARIANT_OUTPUTDIR)/gensrc \
- -I$(TOPDIR)/src/hotspot/share/precompiled \
- -I$(TOPDIR)/src/hotspot/share/include \
- -I$(TOPDIR)/src/hotspot/os/$(HOTSPOT_TARGET_OS_TYPE)/include \
- -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base \
- -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base/$(OPENJDK_TARGET_OS_INCLUDE_SUBDIR) \
- -I$(TOPDIR)/src/java.base/share/native/libjimage \
- #
-
-# INCLUDE_SUFFIX_* is only meant for including the proper
-# platform files. Don't use it to guard code. Use the value of
-# HOTSPOT_TARGET_CPU_DEFINE etc. instead.
-# Remaining TARGET_ARCH_* is needed to select the cpu specific
-# sources for 64-bit ARM ports (arm versus aarch64).
-JVM_CFLAGS_TARGET_DEFINES += \
- -DTARGET_ARCH_$(HOTSPOT_TARGET_CPU_ARCH) \
- -DINCLUDE_SUFFIX_OS=_$(HOTSPOT_TARGET_OS) \
- -DINCLUDE_SUFFIX_CPU=_$(HOTSPOT_TARGET_CPU_ARCH) \
- -DINCLUDE_SUFFIX_COMPILER=_$(HOTSPOT_TOOLCHAIN_TYPE) \
- -DTARGET_COMPILER_$(HOTSPOT_TOOLCHAIN_TYPE) \
- -D$(HOTSPOT_TARGET_CPU_DEFINE) \
- -DHOTSPOT_LIB_ARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' \
- #
-
-ifeq ($(DEBUG_LEVEL), release)
- # For hotspot, release builds differ internally between "optimized" and "product"
- # in that "optimize" does not define PRODUCT.
- ifneq ($(HOTSPOT_DEBUG_LEVEL), optimized)
- JVM_CFLAGS_DEBUGLEVEL := -DPRODUCT
- endif
-else ifeq ($(DEBUG_LEVEL), fastdebug)
- JVM_CFLAGS_DEBUGLEVEL := -DASSERT
- ifeq ($(filter $(OPENJDK_TARGET_OS), windows aix), )
- # NOTE: Old build did not define CHECK_UNHANDLED_OOPS on Windows and AIX.
- JVM_CFLAGS_DEBUGLEVEL += -DCHECK_UNHANDLED_OOPS
- endif
-else ifeq ($(DEBUG_LEVEL), slowdebug)
- # _NMT_NOINLINE_ informs NMT that no inlining is done by the compiler
- JVM_CFLAGS_DEBUGLEVEL := -DASSERT -D_NMT_NOINLINE_
-endif
-
-JVM_CFLAGS += \
- $(JVM_CFLAGS_DEBUGLEVEL) \
- $(JVM_CFLAGS_TARGET_DEFINES) \
- $(JVM_CFLAGS_FEATURES) \
- $(JVM_CFLAGS_INCLUDES) \
- $(EXTRA_CFLAGS) \
- #
-
JVM_LDFLAGS += \
$(SHARED_LIBRARY_FLAGS) \
$(JVM_LDFLAGS_FEATURES) \
@@ -142,11 +79,6 @@
-DCPU='"$(OPENJDK_TARGET_CPU_VM_VERSION)"' \
#
-# -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp.
-ifeq ($(USE_PRECOMPILED_HEADER), false)
- JVM_CFLAGS += -DDONT_USE_PRECOMPILED_HEADER
-endif
-
################################################################################
# Platform specific setup
@@ -214,7 +146,6 @@
TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
SRC := $(JVM_SRC_DIRS), \
- EXTRA_FILES := $(DTRACE_EXTRA_SOURCE_FILES), \
EXCLUDES := $(JVM_EXCLUDES), \
EXCLUDE_FILES := $(JVM_EXCLUDE_FILES), \
EXCLUDE_PATTERNS := $(JVM_EXCLUDE_PATTERNS), \
--- a/make/hotspot/lib/CompileLibraries.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/hotspot/lib/CompileLibraries.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2018, 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,8 @@
include HotspotCommon.gmk
-# The dtrace setup must be done both before and after CompileJvm.gmk, due to
-# intricate dependencies.
-include lib/CompileDtracePreJvm.gmk
include lib/CompileJvm.gmk
-include lib/CompileDtracePostJvm.gmk
+include lib/CompileDtraceLibraries.gmk
ifeq ($(BUILD_GTEST), true)
include lib/CompileGtest.gmk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/hotspot/lib/JvmDtraceObjects.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,134 @@
+#
+# Copyright (c) 2013, 2018, 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.
+#
+
+ifeq ($(call check-jvm-feature, dtrace), true)
+ ifeq ($(OPENJDK_TARGET_OS), solaris)
+
+ ############################################################################
+ # Integrate with libjvm. Here we generate two object files which are
+ # linked with libjvm.so. This step is complicated from a dependency
+ # perspective. We add these two files to the linking of libjvm using
+ # EXTRA_OBJECT_FILES, but they need to be created outside the call to
+ # SetupNativeCompilation. Also, one of the files is dependent on compiled
+ # object files from the libjvm compilation, so this generation must happen
+ # as a part of the libjvm compilation.
+
+ DTRACE_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace.o
+ DTRACE_JHELPER_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace_jhelper.o
+
+ DTRACE_EXTRA_OBJECT_FILES := $(DTRACE_OBJ) $(DTRACE_JHELPER_OBJ)
+
+ ############################################################################
+ # Generate DTRACE_OBJ which is linked with libjvm.so. It depends on a set of
+ # object files from the compilation.
+
+ # Concatenate all *.d files into a single file
+ DTRACE_SOURCE_FILES := $(addprefix $(TOPDIR)/src/hotspot/os/posix/dtrace/, \
+ hotspot_jni.d \
+ hotspot.d \
+ hs_private.d \
+ )
+
+ $(JVM_OUTPUTDIR)/objs/dtrace.d: $(DTRACE_SOURCE_FILES)
+ $(call LogInfo, Generating $(@F))
+ $(call MakeDir, $(@D))
+ $(CAT) $^ > $@
+
+ DTRACE_INSTRUMENTED_OBJS := $(addprefix $(JVM_OUTPUTDIR)/objs/, \
+ ciEnv.o \
+ classLoadingService.o \
+ compileBroker.o \
+ hashtable.o \
+ instanceKlass.o \
+ java.o \
+ jni.o \
+ jvm.o \
+ memoryManager.o \
+ nmethod.o \
+ objectMonitor.o \
+ runtimeService.o \
+ sharedRuntime.o \
+ synchronizer.o \
+ thread.o \
+ unsafe.o \
+ vmThread.o \
+ vmGCOperations.o \
+ )
+
+ ifeq ($(call check-jvm-feature, all-gcs), true)
+ DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \
+ vmCMSOperations.o \
+ vmPSOperations.o \
+ )
+ endif
+
+ DTRACE_FLAGS := -64 -G
+ DTRACE_CPP_FLAGS := -D_LP64
+
+ # Make sure we run our selected compiler for preprocessing instead of letting
+ # the dtrace tool pick it on it's own.
+ $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.d $(DTRACE_INSTRUMENTED_OBJS)
+ $(call LogInfo, Generating $(@F) from $(<F) and object files)
+ $(call MakeDir, $(DTRACE_SUPPORT_DIR))
+ $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
+ ($(CPP) $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d))
+ $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -xlazyload -o $@ \
+ -s $(DTRACE_SUPPORT_DIR)/$(@F).d $(sort $(DTRACE_INSTRUMENTED_OBJS)))
+
+ ############################################################################
+ # Generate DTRACE_JHELPER_OBJ which is linked with libjvm.so.
+
+ JHELPER_DTRACE_SRC := $(TOPDIR)/src/hotspot/os/solaris/dtrace/jhelper.d
+
+ # jhelper.d includes JvmOffsetsIndex.h which was created by the gensrc step.
+ DTRACE_GENSRC_DIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/dtracefiles
+ JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h
+
+ # Unfortunately dtrace generates incorrect types for some symbols in
+ # dtrace_jhelper.o, resulting in "warning: symbol X has differing types"
+ # See JDK-6890703 for details.
+ # We work around this by fixing the types for these symbols using elfedit,
+ # after dtrace has generated the .o file.
+ GetElfeditCommands = \
+ $(foreach symbol, \
+ $(shell $(GREP) ^extern $(JHELPER_DTRACE_SRC) | $(AWK) '{ gsub(";","") ; print $$3 }'), \
+ -e 'sym:st_type $(symbol) 1')
+
+ # Make sure we run our selected compiler for preprocessing instead of letting
+ # the dtrace tool pick it on it's own.
+ $(DTRACE_JHELPER_OBJ): $(JHELPER_DTRACE_SRC) $(JVM_OFFSETS_INDEX_H)
+ $(call LogInfo, Running dtrace for $(<F))
+ $(call MakeDir, $(DTRACE_SUPPORT_DIR))
+ $(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
+ ($(CPP) $(DTRACE_CPP_FLAGS) -I$(DTRACE_GENSRC_DIR) $^ \
+ > $(DTRACE_SUPPORT_DIR)/$(@F).d))
+ $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -o $@ \
+ -s $(DTRACE_SUPPORT_DIR)/$(@F).d)
+ ifeq ($(OPENJDK_TARGET_CPU_ARCH), sparc)
+ $(call ExecuteWithLog, $@.elfedit, $(ELFEDIT) $(call GetElfeditCommands) $@)
+ endif
+
+ endif
+endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make/hotspot/lib/JvmFlags.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,97 @@
+#
+# Copyright (c) 2013, 2018, 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.
+#
+
+$(eval $(call IncludeCustomExtension, hotspot/lib/JvmFlags.gmk))
+
+################################################################################
+# Setup JVM_CFLAGS. These are shared between GensrcDtrace.gmk and CompileJvm.gmk.
+
+# This variable may be added to by a custom extension
+JVM_SRC_ROOTS += $(TOPDIR)/src/hotspot
+
+JVM_SRC_DIRS += $(call uniq, $(wildcard $(foreach d, $(JVM_SRC_ROOTS), \
+ $d/share \
+ $d/os/$(HOTSPOT_TARGET_OS) \
+ $d/os/$(HOTSPOT_TARGET_OS_TYPE) \
+ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH) \
+ $d/os_cpu/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH) \
+ ))) \
+ $(JVM_VARIANT_OUTPUTDIR)/gensrc
+ #
+
+JVM_CFLAGS_INCLUDES += \
+ $(patsubst %,-I%,$(JVM_SRC_DIRS)) \
+ -I$(TOPDIR)/src/hotspot/share/precompiled \
+ -I$(TOPDIR)/src/hotspot/share/include \
+ -I$(TOPDIR)/src/hotspot/os/$(HOTSPOT_TARGET_OS_TYPE)/include \
+ -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base \
+ -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base/$(OPENJDK_TARGET_OS_INCLUDE_SUBDIR) \
+ -I$(TOPDIR)/src/java.base/share/native/libjimage \
+ #
+
+# INCLUDE_SUFFIX_* is only meant for including the proper
+# platform files. Don't use it to guard code. Use the value of
+# HOTSPOT_TARGET_CPU_DEFINE etc. instead.
+# Remaining TARGET_ARCH_* is needed to select the cpu specific
+# sources for 64-bit ARM ports (arm versus aarch64).
+JVM_CFLAGS_TARGET_DEFINES += \
+ -DTARGET_ARCH_$(HOTSPOT_TARGET_CPU_ARCH) \
+ -DINCLUDE_SUFFIX_OS=_$(HOTSPOT_TARGET_OS) \
+ -DINCLUDE_SUFFIX_CPU=_$(HOTSPOT_TARGET_CPU_ARCH) \
+ -DINCLUDE_SUFFIX_COMPILER=_$(HOTSPOT_TOOLCHAIN_TYPE) \
+ -DTARGET_COMPILER_$(HOTSPOT_TOOLCHAIN_TYPE) \
+ -D$(HOTSPOT_TARGET_CPU_DEFINE) \
+ -DHOTSPOT_LIB_ARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' \
+ #
+
+ifeq ($(DEBUG_LEVEL), release)
+ # For hotspot, release builds differ internally between "optimized" and "product"
+ # in that "optimize" does not define PRODUCT.
+ ifneq ($(HOTSPOT_DEBUG_LEVEL), optimized)
+ JVM_CFLAGS_DEBUGLEVEL := -DPRODUCT
+ endif
+else ifeq ($(DEBUG_LEVEL), fastdebug)
+ JVM_CFLAGS_DEBUGLEVEL := -DASSERT
+ ifeq ($(filter $(OPENJDK_TARGET_OS), windows aix), )
+ # NOTE: Old build did not define CHECK_UNHANDLED_OOPS on Windows and AIX.
+ JVM_CFLAGS_DEBUGLEVEL += -DCHECK_UNHANDLED_OOPS
+ endif
+else ifeq ($(DEBUG_LEVEL), slowdebug)
+ # _NMT_NOINLINE_ informs NMT that no inlining is done by the compiler
+ JVM_CFLAGS_DEBUGLEVEL := -DASSERT -D_NMT_NOINLINE_
+endif
+
+JVM_CFLAGS += \
+ $(JVM_CFLAGS_DEBUGLEVEL) \
+ $(JVM_CFLAGS_TARGET_DEFINES) \
+ $(JVM_CFLAGS_FEATURES) \
+ $(JVM_CFLAGS_INCLUDES) \
+ $(EXTRA_CFLAGS) \
+ #
+
+# -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp.
+ifeq ($(USE_PRECOMPILED_HEADER), false)
+ JVM_CFLAGS += -DDONT_USE_PRECOMPILED_HEADER
+endif
--- a/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp Mon Apr 09 08:34:30 2018 -0700
+++ b/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp Tue Apr 10 13:58:47 2018 -0700
@@ -31,29 +31,23 @@
* GENOFFS_SCCS_VER 34
*/
-#include "generateJvmOffsets.h"
+#include <stdio.h>
+#include <strings.h>
/* A workaround for private and protected fields */
#define private public
#define protected public
#include <proc_service.h>
-#include "code/codeBlob.hpp"
-#include "code/nmethod.hpp"
-#include "code/pcDesc.hpp"
#include "gc/shared/collectedHeap.hpp"
-#include "memory/heap.hpp"
-#include "memory/memRegion.hpp"
-#include "memory/universe.hpp"
-#include "memory/virtualspace.hpp"
-#include "oops/constMethod.hpp"
-#include "oops/klass.hpp"
-#include "oops/method.hpp"
-#include "oops/oop.hpp"
-#include "oops/symbol.hpp"
#include "runtime/vmStructs.hpp"
-#include "utilities/accessFlags.hpp"
-#include "utilities/globalDefinitions.hpp"
+
+typedef enum GEN_variant {
+ GEN_OFFSET = 0,
+ GEN_INDEX = 1,
+ GEN_TABLE = 2
+} GEN_variant;
+
#ifdef COMPILER1
#ifdef ASSERT
--- a/make/hotspot/src/native/dtrace/generateJvmOffsets.h Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, 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.
- *
- */
-
-#ifndef OS_SOLARIS_DTRACE_GENERATEJVMOFFSETS_H
-#define OS_SOLARIS_DTRACE_GENERATEJVMOFFSETS_H
-
-#include <stdio.h>
-#include <strings.h>
-
-typedef enum GEN_variant {
- GEN_OFFSET = 0,
- GEN_INDEX = 1,
- GEN_TABLE = 2
-} GEN_variant;
-
-extern "C" {
- int generateJvmOffsets(GEN_variant gen_var);
- void gen_prologue(GEN_variant gen_var);
- void gen_epilogue(GEN_variant gen_var);
-}
-
-#endif // OS_SOLARIS_DTRACE_GENERATEJVMOFFSETS_H
--- a/make/launcher/Launcher-jdk.pack.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/launcher/Launcher-jdk.pack.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -88,6 +88,7 @@
CFLAGS_solaris := -KPIC, \
CFLAGS_macosx := -fPIC, \
DISABLED_WARNINGS_gcc := unused-result implicit-fallthrough, \
+ DISABLED_WARNINGS_microsoft := 4005, \
LDFLAGS := $(UNPACKEXE_ZIPOBJS) \
$(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
--- a/make/lib/Awt2dLibraries.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Awt2dLibraries.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -543,7 +543,7 @@
DISABLED_WARNINGS_solstudio := \
E_STATEMENT_NOT_REACHED \
E_END_OF_LOOP_CODE_NOT_REACHED, \
- DISABLED_WARNINGS_microsoft := 4267 4244, \
+ DISABLED_WARNINGS_microsoft := 4267 4244 4312, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
))
--- a/make/lib/Lib-java.base.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Lib-java.base.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -155,10 +155,10 @@
################################################################################
# Create the jsig library
-ifneq ($(OPENJDK_TARGET_OS), windows)
+ifeq ($(OPENJDK_TARGET_OS_TYPE), unix)
ifeq ($(STATIC_BUILD), false)
- LIBJSIG_SRC_DIR := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjsig
+ LIBJSIG_SRC_DIR := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjsig
LIBJSIG_MAPFILE := $(wildcard $(TOPDIR)/make/mapfiles/libjsig/mapfile-vers-$(OPENJDK_TARGET_OS))
ifeq ($(OPENJDK_TARGET_OS), linux)
--- a/make/lib/Lib-java.desktop.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Lib-java.desktop.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -50,6 +50,7 @@
LIBJSOUND_CFLAGS := \
-I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \
+ $(ALSA_CFLAGS) \
$(LIBJAVA_HEADER_FLAGS) \
$(foreach dir, $(LIBJSOUND_SRC_DIRS), -I$(dir)) \
-DX_PLATFORM=X_$(OPENJDK_TARGET_OS_UPPERCASE) \
--- a/make/lib/Lib-jdk.accessibility.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Lib-jdk.accessibility.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -45,6 +45,7 @@
NAME := javaaccessbridge$1, \
SRC := $(JAVA_AB_SRCDIR), \
OPTIMIZATION := LOW, \
+ DISABLED_WARNINGS_microsoft := 4311 4302 4312, \
CFLAGS := $(CFLAGS_JDKLIB) $(ACCESSBRIDGE_CFLAGS) \
$(addprefix -I,$(JAVA_AB_SRCDIR)) \
-I$(ROOT_SRCDIR)/include/bridge \
@@ -69,6 +70,7 @@
NAME := windowsaccessbridge$1, \
SRC := $(WIN_AB_SRCDIR), \
OPTIMIZATION := LOW, \
+ DISABLED_WARNINGS_microsoft := 4311 4302 4312, \
CFLAGS := $(filter-out -MD, $(CFLAGS_JDKLIB)) -MT $(ACCESSBRIDGE_CFLAGS) \
$(addprefix -I,$(WIN_AB_SRCDIR)) \
-I$(ROOT_SRCDIR)/include/bridge \
--- a/make/lib/Lib-jdk.pack.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Lib-jdk.pack.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -40,6 +40,7 @@
$(LIBJAVA_HEADER_FLAGS), \
CFLAGS_release := -DPRODUCT, \
DISABLED_WARNINGS_gcc := implicit-fallthrough, \
+ DISABLED_WARNINGS_microsoft := 4005, \
LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_windows := -map:$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpack.map -debug, \
--- a/make/mapfiles/libjsig/mapfile-vers-solaris Mon Apr 09 08:34:30 2018 -0700
+++ b/make/mapfiles/libjsig/mapfile-vers-solaris Tue Apr 10 13:58:47 2018 -0700
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2018, 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,7 +28,6 @@
global:
JVM_begin_signal_setting;
JVM_end_signal_setting;
- JVM_get_libjsig_version;
JVM_get_signal_action;
sigaction;
signal;
--- a/src/hotspot/os/solaris/os_solaris.cpp Mon Apr 09 08:34:30 2018 -0700
+++ b/src/hotspot/os/solaris/os_solaris.cpp Tue Apr 10 13:58:47 2018 -0700
@@ -2101,8 +2101,6 @@
static int *preinstalled_sigs = NULL;
static struct sigaction *chainedsigactions = NULL;
static Semaphore* sig_sem = NULL;
-typedef int (*version_getting_t)();
-version_getting_t os::Solaris::get_libjsig_version = NULL;
int os::sigexitnum_pd() {
assert(Sigexit > 0, "signal memory not yet initialized");
@@ -3968,13 +3966,7 @@
dlsym(RTLD_DEFAULT, "JVM_end_signal_setting"));
get_signal_action = CAST_TO_FN_PTR(get_signal_t,
dlsym(RTLD_DEFAULT, "JVM_get_signal_action"));
- get_libjsig_version = CAST_TO_FN_PTR(version_getting_t,
- dlsym(RTLD_DEFAULT, "JVM_get_libjsig_version"));
libjsig_is_loaded = true;
- if (os::Solaris::get_libjsig_version != NULL) {
- int libjsigversion = (*os::Solaris::get_libjsig_version)();
- assert(libjsigversion == JSIG_VERSION_1_4_1, "libjsig version mismatch");
- }
assert(UseSignalChaining, "should enable signal-chaining");
}
if (libjsig_is_loaded) {
--- a/src/java.base/linux/native/libjsig/jsig.c Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,230 +0,0 @@
-/*
- * Copyright (c) 2001, 2013, 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.
- *
- */
-
-/* CopyrightVersion 1.2 */
-
-/* This is a special library that should be loaded before libc &
- * libthread to interpose the signal handler installation functions:
- * sigaction(), signal(), sigset().
- * Used for signal-chaining. See RFE 4381843.
- */
-
-#include <signal.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#define bool int
-#define true 1
-#define false 0
-
-#define MASK(sig) ((uint64_t)1 << (sig-1)) // 0 is not a signal.
-// Check whether all signals fit into jvmsigs. -1 as MASK shifts by -1.
-#if (64 < NSIG-1)
-#error "Not all signals can be encoded in jvmsigs. Adapt its type!"
-#endif
-static struct sigaction sact[NSIG]; /* saved signal handlers */
-static uint64_t jvmsigs = 0; /* signals used by jvm */
-
-/* used to synchronize the installation of signal handlers */
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
-static pthread_t tid = 0;
-
-typedef void (*sa_handler_t)(int);
-typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
-typedef sa_handler_t (*signal_t)(int, sa_handler_t);
-typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
-
-static signal_t os_signal = 0; /* os's version of signal()/sigset() */
-static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
-
-static bool jvm_signal_installing = false;
-static bool jvm_signal_installed = false;
-
-static void signal_lock() {
- pthread_mutex_lock(&mutex);
- /* When the jvm is installing its set of signal handlers, threads
- * other than the jvm thread should wait */
- if (jvm_signal_installing) {
- if (tid != pthread_self()) {
- pthread_cond_wait(&cond, &mutex);
- }
- }
-}
-
-static void signal_unlock() {
- pthread_mutex_unlock(&mutex);
-}
-
-static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
- bool is_sigset) {
- if (os_signal == NULL) {
- if (!is_sigset) {
- os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
- } else {
- os_signal = (signal_t)dlsym(RTLD_NEXT, "sigset");
- }
- if (os_signal == NULL) {
- printf("%s\n", dlerror());
- exit(0);
- }
- }
- return (*os_signal)(sig, disp);
-}
-
-static void save_signal_handler(int sig, sa_handler_t disp) {
- sigset_t set;
- sact[sig].sa_handler = disp;
- sigemptyset(&set);
- sact[sig].sa_mask = set;
- sact[sig].sa_flags = 0;
-}
-
-static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
- sa_handler_t oldhandler;
- bool sigused;
-
- signal_lock();
-
- sigused = (sig < NSIG) && ((MASK(sig) & jvmsigs) != 0);
- if (jvm_signal_installed && sigused) {
- /* jvm has installed its signal handler for this signal. */
- /* Save the handler. Don't really install it. */
- oldhandler = sact[sig].sa_handler;
- save_signal_handler(sig, disp);
-
- signal_unlock();
- return oldhandler;
- } else if (sig < NSIG && jvm_signal_installing) {
- /* jvm is installing its signal handlers. Install the new
- * handlers and save the old ones. jvm uses sigaction().
- * Leave the piece here just in case. */
- oldhandler = call_os_signal(sig, disp, is_sigset);
- save_signal_handler(sig, oldhandler);
-
- /* Record the signals used by jvm */
- jvmsigs |= MASK(sig);
-
- signal_unlock();
- return oldhandler;
- } else {
- /* jvm has no relation with this signal (yet). Install the
- * the handler. */
- oldhandler = call_os_signal(sig, disp, is_sigset);
-
- signal_unlock();
- return oldhandler;
- }
-}
-
-sa_handler_t signal(int sig, sa_handler_t disp) {
- return set_signal(sig, disp, false);
-}
-
-sa_handler_t sigset(int sig, sa_handler_t disp) {
- return set_signal(sig, disp, true);
- }
-
-static int call_os_sigaction(int sig, const struct sigaction *act,
- struct sigaction *oact) {
- if (os_sigaction == NULL) {
- os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
- if (os_sigaction == NULL) {
- printf("%s\n", dlerror());
- exit(0);
- }
- }
- return (*os_sigaction)(sig, act, oact);
-}
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
- int res;
- bool sigused;
- struct sigaction oldAct;
-
- signal_lock();
-
- sigused = (sig < NSIG) && ((MASK(sig) & jvmsigs) != 0);
- if (jvm_signal_installed && sigused) {
- /* jvm has installed its signal handler for this signal. */
- /* Save the handler. Don't really install it. */
- if (oact != NULL) {
- *oact = sact[sig];
- }
- if (act != NULL) {
- sact[sig] = *act;
- }
-
- signal_unlock();
- return 0;
- } else if (sig < NSIG && jvm_signal_installing) {
- /* jvm is installing its signal handlers. Install the new
- * handlers and save the old ones. */
- res = call_os_sigaction(sig, act, &oldAct);
- sact[sig] = oldAct;
- if (oact != NULL) {
- *oact = oldAct;
- }
-
- /* Record the signals used by jvm */
- jvmsigs |= MASK(sig);
-
- signal_unlock();
- return res;
- } else {
- /* jvm has no relation with this signal (yet). Install the
- * the handler. */
- res = call_os_sigaction(sig, act, oact);
-
- signal_unlock();
- return res;
- }
-}
-
-/* The three functions for the jvm to call into */
-void JVM_begin_signal_setting() {
- signal_lock();
- jvm_signal_installing = true;
- tid = pthread_self();
- signal_unlock();
-}
-
-void JVM_end_signal_setting() {
- signal_lock();
- jvm_signal_installed = true;
- jvm_signal_installing = false;
- pthread_cond_broadcast(&cond);
- signal_unlock();
-}
-
-struct sigaction *JVM_get_signal_action(int sig) {
- /* Does race condition make sense here? */
- if ((MASK(sig) & jvmsigs) != 0) {
- return &sact[sig];
- }
- return NULL;
-}
--- a/src/java.base/macosx/native/libjsig/jsig.c Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-/* CopyrightVersion 1.2 */
-
-/* This is a special library that should be loaded before libc &
- * libthread to interpose the signal handler installation functions:
- * sigaction(), signal(), sigset().
- * Used for signal-chaining. See RFE 4381843.
- */
-
-#include <signal.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#define MASK(sig) ((uint32_t)1 << (sig-1)) // 0 is not a signal.
-#if (32 < NSIG-1)
-#error "Not all signals can be encoded in jvmsigs. Adapt its type!"
-#endif
-static struct sigaction sact[NSIG]; /* saved signal handlers */
-static uint32_t jvmsigs = 0; /* signals used by jvm */
-static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */
-
-/* used to synchronize the installation of signal handlers */
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
-static pthread_t tid = 0;
-
-typedef void (*sa_handler_t)(int);
-typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
-typedef sa_handler_t (*signal_t)(int, sa_handler_t);
-typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
-
-static signal_t os_signal = 0; /* os's version of signal()/sigset() */
-static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
-
-static bool jvm_signal_installing = false;
-static bool jvm_signal_installed = false;
-
-static void signal_lock() {
- pthread_mutex_lock(&mutex);
- /* When the jvm is installing its set of signal handlers, threads
- * other than the jvm thread should wait */
- if (jvm_signal_installing) {
- if (tid != pthread_self()) {
- pthread_cond_wait(&cond, &mutex);
- }
- }
-}
-
-static void signal_unlock() {
- pthread_mutex_unlock(&mutex);
-}
-
-static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
- bool is_sigset) {
- sa_handler_t res;
-
- if (os_signal == NULL) {
- if (!is_sigset) {
- os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
- } else {
- os_signal = (signal_t)dlsym(RTLD_NEXT, "sigset");
- }
- if (os_signal == NULL) {
- printf("%s\n", dlerror());
- exit(0);
- }
- }
- reentry = true;
- res = (*os_signal)(sig, disp);
- reentry = false;
- return res;
-}
-
-static void save_signal_handler(int sig, sa_handler_t disp) {
- sigset_t set;
- sact[sig].sa_handler = disp;
- sigemptyset(&set);
- sact[sig].sa_mask = set;
- sact[sig].sa_flags = 0;
-}
-
-static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
- sa_handler_t oldhandler;
- bool sigused;
-
- signal_lock();
-
- sigused = (MASK(sig) & jvmsigs) != 0;
- if (jvm_signal_installed && sigused) {
- /* jvm has installed its signal handler for this signal. */
- /* Save the handler. Don't really install it. */
- oldhandler = sact[sig].sa_handler;
- save_signal_handler(sig, disp);
-
- signal_unlock();
- return oldhandler;
- } else if (jvm_signal_installing) {
- /* jvm is installing its signal handlers. Install the new
- * handlers and save the old ones. jvm uses sigaction().
- * Leave the piece here just in case. */
- oldhandler = call_os_signal(sig, disp, is_sigset);
- save_signal_handler(sig, oldhandler);
-
- /* Record the signals used by jvm */
- jvmsigs |= MASK(sig);
-
- signal_unlock();
- return oldhandler;
- } else {
- /* jvm has no relation with this signal (yet). Install the
- * the handler. */
- oldhandler = call_os_signal(sig, disp, is_sigset);
-
- signal_unlock();
- return oldhandler;
- }
-}
-
-sa_handler_t signal(int sig, sa_handler_t disp) {
- return set_signal(sig, disp, false);
-}
-
-sa_handler_t sigset(int sig, sa_handler_t disp) {
- printf("sigset() is not supported by BSD");
- exit(0);
- }
-
-static int call_os_sigaction(int sig, const struct sigaction *act,
- struct sigaction *oact) {
- if (os_sigaction == NULL) {
- os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
- if (os_sigaction == NULL) {
- printf("%s\n", dlerror());
- exit(0);
- }
- }
- return (*os_sigaction)(sig, act, oact);
-}
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
- int res;
- bool sigused;
- struct sigaction oldAct;
-
- if (reentry) {
- return call_os_sigaction(sig, act, oact);
- }
-
- signal_lock();
-
- sigused = (MASK(sig) & jvmsigs) != 0;
- if (jvm_signal_installed && sigused) {
- /* jvm has installed its signal handler for this signal. */
- /* Save the handler. Don't really install it. */
- if (oact != NULL) {
- *oact = sact[sig];
- }
- if (act != NULL) {
- sact[sig] = *act;
- }
-
- signal_unlock();
- return 0;
- } else if (jvm_signal_installing) {
- /* jvm is installing its signal handlers. Install the new
- * handlers and save the old ones. */
- res = call_os_sigaction(sig, act, &oldAct);
- sact[sig] = oldAct;
- if (oact != NULL) {
- *oact = oldAct;
- }
-
- /* Record the signals used by jvm */
- jvmsigs |= MASK(sig);
-
- signal_unlock();
- return res;
- } else {
- /* jvm has no relation with this signal (yet). Install the
- * the handler. */
- res = call_os_sigaction(sig, act, oact);
-
- signal_unlock();
- return res;
- }
-}
-
-/* The three functions for the jvm to call into */
-void JVM_begin_signal_setting() {
- signal_lock();
- jvm_signal_installing = true;
- tid = pthread_self();
- signal_unlock();
-}
-
-void JVM_end_signal_setting() {
- signal_lock();
- jvm_signal_installed = true;
- jvm_signal_installing = false;
- pthread_cond_broadcast(&cond);
- signal_unlock();
-}
-
-struct sigaction *JVM_get_signal_action(int sig) {
- /* Does race condition make sense here? */
- if ((MASK(sig) & jvmsigs) != 0) {
- return &sact[sig];
- }
- return NULL;
-}
--- a/src/java.base/share/classes/java/lang/StringCoding.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/lang/StringCoding.java Tue Apr 10 13:58:47 2018 -0700
@@ -42,7 +42,6 @@
import sun.nio.cs.HistoricallyNamedCharset;
import sun.nio.cs.ArrayDecoder;
import sun.nio.cs.ArrayEncoder;
-import sun.nio.cs.StandardCharsets;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
@@ -52,9 +51,6 @@
import static java.lang.Character.lowSurrogate;
import static java.lang.Character.isSupplementaryCodePoint;
import static java.lang.StringUTF16.putChar;
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-import static java.nio.charset.StandardCharsets.US_ASCII;
-import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Utility class for string encoding and decoding.
@@ -70,6 +66,10 @@
private static final ThreadLocal<SoftReference<StringEncoder>> encoder =
new ThreadLocal<>();
+ private static final Charset ISO_8859_1 = sun.nio.cs.ISO_8859_1.INSTANCE;
+ private static final Charset US_ASCII = sun.nio.cs.US_ASCII.INSTANCE;
+ private static final Charset UTF_8 = sun.nio.cs.UTF_8.INSTANCE;
+
private static <T> T deref(ThreadLocal<SoftReference<T>> tl) {
SoftReference<T> sr = tl.get();
if (sr == null)
--- a/src/java.base/share/classes/java/nio/charset/Charset.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/nio/charset/Charset.java Tue Apr 10 13:58:47 2018 -0700
@@ -609,7 +609,7 @@
if (cs != null)
defaultCharset = cs;
else
- defaultCharset = StandardCharsets.UTF_8;
+ defaultCharset = sun.nio.cs.UTF_8.INSTANCE;
}
}
return defaultCharset;
--- a/src/java.base/share/classes/java/nio/charset/StandardCharsets.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/nio/charset/StandardCharsets.java Tue Apr 10 13:58:47 2018 -0700
@@ -34,22 +34,28 @@
*/
public final class StandardCharsets {
+ // To avoid accidental eager initialization of often unused Charsets
+ // from happening while the VM is booting up, which may delay
+ // initialization of VM components, we should generally avoid depending
+ // on this class from elsewhere in java.base.
+
private StandardCharsets() {
throw new AssertionError("No java.nio.charset.StandardCharsets instances for you!");
}
+
/**
* Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the
* Unicode character set
*/
- public static final Charset US_ASCII = new sun.nio.cs.US_ASCII();
+ public static final Charset US_ASCII = sun.nio.cs.US_ASCII.INSTANCE;
/**
* ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
*/
- public static final Charset ISO_8859_1 = new sun.nio.cs.ISO_8859_1();
+ public static final Charset ISO_8859_1 = sun.nio.cs.ISO_8859_1.INSTANCE;
/**
* Eight-bit UCS Transformation Format
*/
- public static final Charset UTF_8 = new sun.nio.cs.UTF_8();
+ public static final Charset UTF_8 = sun.nio.cs.UTF_8.INSTANCE;
/**
* Sixteen-bit UCS Transformation Format, big-endian byte order
*/
--- a/src/java.base/share/classes/java/util/ArrayDeque.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/ArrayDeque.java Tue Apr 10 13:58:47 2018 -0700
@@ -208,7 +208,7 @@
*/
public ArrayDeque(Collection<? extends E> c) {
this(c.size());
- addAll(c);
+ copyElements(c);
}
/**
@@ -322,8 +322,12 @@
final int s, needed;
if ((needed = (s = size()) + c.size() + 1 - elements.length) > 0)
grow(needed);
+ copyElements(c);
+ return size() > s;
+ }
+
+ private void copyElements(Collection<? extends E> c) {
c.forEach(this::addLast);
- return size() > s;
}
/**
--- a/src/java.base/share/classes/java/util/Deque.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/Deque.java Tue Apr 10 13:58:47 2018 -0700
@@ -141,8 +141,8 @@
* <p>Deques can also be used as LIFO (Last-In-First-Out) stacks. This
* interface should be used in preference to the legacy {@link Stack} class.
* When a deque is used as a stack, elements are pushed and popped from the
- * beginning of the deque. Stack methods are precisely equivalent to
- * {@code Deque} methods as indicated in the table below:
+ * beginning of the deque. Stack methods are equivalent to {@code Deque}
+ * methods as indicated in the table below:
*
* <table class="striped">
* <caption>Comparison of Stack and Deque methods</caption>
@@ -163,7 +163,7 @@
* </tr>
* <tr>
* <th scope="row">{@link #peek() peek()}</th>
- * <td>{@link #peekFirst() peekFirst()}</td>
+ * <td>{@link #getFirst() getFirst()}</td>
* </tr>
* </tbody>
* </table>
--- a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Tue Apr 10 13:58:47 2018 -0700
@@ -2883,7 +2883,7 @@
STACK = l.findVarHandle(CompletableFuture.class, "stack", Completion.class);
NEXT = l.findVarHandle(Completion.class, "next", Completion.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Tue Apr 10 13:58:47 2018 -0700
@@ -6383,7 +6383,7 @@
ABASE = U.arrayBaseOffset(Node[].class);
int scale = U.arrayIndexScale(Node[].class);
if ((scale & (scale - 1)) != 0)
- throw new Error("array index scale not a power of two");
+ throw new ExceptionInInitializerError("array index scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
// Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Tue Apr 10 13:58:47 2018 -0700
@@ -1671,7 +1671,7 @@
NEXT = l.findVarHandle(Node.class, "next", Node.class);
ITEM = l.findVarHandle(Node.class, "item", Object.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Tue Apr 10 13:58:47 2018 -0700
@@ -1069,7 +1069,7 @@
ITEM = l.findVarHandle(Node.class, "item", Object.class);
NEXT = l.findVarHandle(Node.class, "next", Node.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Tue Apr 10 13:58:47 2018 -0700
@@ -3412,7 +3412,7 @@
VAL = l.findVarHandle(Node.class, "val", Object.class);
RIGHT = l.findVarHandle(Index.class, "right", Index.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
--- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Tue Apr 10 13:58:47 2018 -0700
@@ -35,7 +35,6 @@
package java.util.concurrent;
import java.lang.reflect.Field;
-import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
@@ -134,17 +133,17 @@
* @throws NullPointerException if the specified collection is null
*/
public CopyOnWriteArrayList(Collection<? extends E> c) {
- Object[] elements;
+ Object[] es;
if (c.getClass() == CopyOnWriteArrayList.class)
- elements = ((CopyOnWriteArrayList<?>)c).getArray();
+ es = ((CopyOnWriteArrayList<?>)c).getArray();
else {
- elements = c.toArray();
+ es = c.toArray();
// defend against c.toArray (incorrectly) not returning Object[]
// (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
- if (elements.getClass() != Object[].class)
- elements = Arrays.copyOf(elements, elements.length, Object[].class);
+ if (es.getClass() != Object[].class)
+ es = Arrays.copyOf(es, es.length, Object[].class);
}
- setArray(elements);
+ setArray(es);
}
/**
@@ -180,20 +179,19 @@
* static version of indexOf, to allow repeated calls without
* needing to re-acquire array each time.
* @param o element to search for
- * @param elements the array
- * @param index first index to search
- * @param fence one past last index to search
+ * @param es the array
+ * @param from first index to search
+ * @param to one past last index to search
* @return index of element, or -1 if absent
*/
- private static int indexOf(Object o, Object[] elements,
- int index, int fence) {
+ private static int indexOfRange(Object o, Object[] es, int from, int to) {
if (o == null) {
- for (int i = index; i < fence; i++)
- if (elements[i] == null)
+ for (int i = from; i < to; i++)
+ if (es[i] == null)
return i;
} else {
- for (int i = index; i < fence; i++)
- if (o.equals(elements[i]))
+ for (int i = from; i < to; i++)
+ if (o.equals(es[i]))
return i;
}
return -1;
@@ -202,18 +200,19 @@
/**
* static version of lastIndexOf.
* @param o element to search for
- * @param elements the array
- * @param index first index to search
+ * @param es the array
+ * @param from index of first element of range, last element to search
+ * @param to one past last element of range, first element to search
* @return index of element, or -1 if absent
*/
- private static int lastIndexOf(Object o, Object[] elements, int index) {
+ private static int lastIndexOfRange(Object o, Object[] es, int from, int to) {
if (o == null) {
- for (int i = index; i >= 0; i--)
- if (elements[i] == null)
+ for (int i = to - 1; i >= from; i--)
+ if (es[i] == null)
return i;
} else {
- for (int i = index; i >= 0; i--)
- if (o.equals(elements[i]))
+ for (int i = to - 1; i >= from; i--)
+ if (o.equals(es[i]))
return i;
}
return -1;
@@ -228,16 +227,15 @@
* @return {@code true} if this list contains the specified element
*/
public boolean contains(Object o) {
- Object[] elements = getArray();
- return indexOf(o, elements, 0, elements.length) >= 0;
+ return indexOf(o) >= 0;
}
/**
* {@inheritDoc}
*/
public int indexOf(Object o) {
- Object[] elements = getArray();
- return indexOf(o, elements, 0, elements.length);
+ Object[] es = getArray();
+ return indexOfRange(o, es, 0, es.length);
}
/**
@@ -256,16 +254,16 @@
* @throws IndexOutOfBoundsException if the specified index is negative
*/
public int indexOf(E e, int index) {
- Object[] elements = getArray();
- return indexOf(e, elements, index, elements.length);
+ Object[] es = getArray();
+ return indexOfRange(e, es, index, es.length);
}
/**
* {@inheritDoc}
*/
public int lastIndexOf(Object o) {
- Object[] elements = getArray();
- return lastIndexOf(o, elements, elements.length - 1);
+ Object[] es = getArray();
+ return lastIndexOfRange(o, es, 0, es.length);
}
/**
@@ -285,8 +283,8 @@
* than or equal to the current size of this list
*/
public int lastIndexOf(E e, int index) {
- Object[] elements = getArray();
- return lastIndexOf(e, elements, index);
+ Object[] es = getArray();
+ return lastIndexOfRange(e, es, 0, index + 1);
}
/**
@@ -322,8 +320,7 @@
* @return an array containing all the elements in this list
*/
public Object[] toArray() {
- Object[] elements = getArray();
- return Arrays.copyOf(elements, elements.length);
+ return getArray().clone();
}
/**
@@ -366,12 +363,12 @@
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (a.length < len)
- return (T[]) Arrays.copyOf(elements, len, a.getClass());
+ return (T[]) Arrays.copyOf(es, len, a.getClass());
else {
- System.arraycopy(elements, 0, a, 0, len);
+ System.arraycopy(es, 0, a, 0, len);
if (a.length > len)
a[len] = null;
return a;
@@ -406,17 +403,13 @@
*/
public E set(int index, E element) {
synchronized (lock) {
- Object[] elements = getArray();
- E oldValue = elementAt(elements, index);
+ Object[] es = getArray();
+ E oldValue = elementAt(es, index);
if (oldValue != element) {
- int len = elements.length;
- Object[] newElements = Arrays.copyOf(elements, len);
- newElements[index] = element;
- setArray(newElements);
- } else {
- // Not quite a no-op; ensures volatile write semantics
- setArray(elements);
+ es = es.clone();
+ es[index] = element;
+ setArray(es);
}
return oldValue;
}
@@ -430,11 +423,11 @@
*/
public boolean add(E e) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- Object[] newElements = Arrays.copyOf(elements, len + 1);
- newElements[len] = e;
- setArray(newElements);
+ Object[] es = getArray();
+ int len = es.length;
+ es = Arrays.copyOf(es, len + 1);
+ es[len] = e;
+ setArray(es);
return true;
}
}
@@ -448,18 +441,18 @@
*/
public void add(int index, E element) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException(outOfBounds(index, len));
Object[] newElements;
int numMoved = len - index;
if (numMoved == 0)
- newElements = Arrays.copyOf(elements, len + 1);
+ newElements = Arrays.copyOf(es, len + 1);
else {
newElements = new Object[len + 1];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index, newElements, index + 1,
+ System.arraycopy(es, 0, newElements, 0, index);
+ System.arraycopy(es, index, newElements, index + 1,
numMoved);
}
newElements[index] = element;
@@ -476,19 +469,20 @@
*/
public E remove(int index) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- E oldValue = elementAt(elements, index);
+ Object[] es = getArray();
+ int len = es.length;
+ E oldValue = elementAt(es, index);
int numMoved = len - index - 1;
+ Object[] newElements;
if (numMoved == 0)
- setArray(Arrays.copyOf(elements, len - 1));
+ newElements = Arrays.copyOf(es, len - 1);
else {
- Object[] newElements = new Object[len - 1];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index + 1, newElements, index,
+ newElements = new Object[len - 1];
+ System.arraycopy(es, 0, newElements, 0, index);
+ System.arraycopy(es, index + 1, newElements, index,
numMoved);
- setArray(newElements);
}
+ setArray(newElements);
return oldValue;
}
}
@@ -507,7 +501,7 @@
*/
public boolean remove(Object o) {
Object[] snapshot = getArray();
- int index = indexOf(o, snapshot, 0, snapshot.length);
+ int index = indexOfRange(o, snapshot, 0, snapshot.length);
return index >= 0 && remove(o, snapshot, index);
}
@@ -532,7 +526,7 @@
return false;
if (current[index] == o)
break findIndex;
- index = indexOf(o, current, index, len);
+ index = indexOfRange(o, current, index, len);
if (index < 0)
return false;
}
@@ -560,19 +554,19 @@
*/
void removeRange(int fromIndex, int toIndex) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
throw new IndexOutOfBoundsException();
int newlen = len - (toIndex - fromIndex);
int numMoved = len - toIndex;
if (numMoved == 0)
- setArray(Arrays.copyOf(elements, newlen));
+ setArray(Arrays.copyOf(es, newlen));
else {
Object[] newElements = new Object[newlen];
- System.arraycopy(elements, 0, newElements, 0, fromIndex);
- System.arraycopy(elements, toIndex, newElements,
+ System.arraycopy(es, 0, newElements, 0, fromIndex);
+ System.arraycopy(es, toIndex, newElements,
fromIndex, numMoved);
setArray(newElements);
}
@@ -587,7 +581,7 @@
*/
public boolean addIfAbsent(E e) {
Object[] snapshot = getArray();
- return indexOf(e, snapshot, 0, snapshot.length) < 0
+ return indexOfRange(e, snapshot, 0, snapshot.length) < 0
&& addIfAbsent(e, snapshot);
}
@@ -606,7 +600,7 @@
if (current[i] != snapshot[i]
&& Objects.equals(e, current[i]))
return false;
- if (indexOf(e, current, common, len) >= 0)
+ if (indexOfRange(e, current, common, len) >= 0)
return false;
}
Object[] newElements = Arrays.copyOf(current, len + 1);
@@ -627,10 +621,10 @@
* @see #contains(Object)
*/
public boolean containsAll(Collection<?> c) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
for (Object e : c) {
- if (indexOf(e, elements, 0, len) < 0)
+ if (indexOfRange(e, es, 0, len) < 0)
return false;
}
return true;
@@ -694,18 +688,18 @@
if (cs.length == 0)
return 0;
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
int added = 0;
// uniquify and compact elements in cs
for (int i = 0; i < cs.length; ++i) {
Object e = cs[i];
- if (indexOf(e, elements, 0, len) < 0 &&
- indexOf(e, cs, 0, added) < 0)
+ if (indexOfRange(e, es, 0, len) < 0 &&
+ indexOfRange(e, cs, 0, added) < 0)
cs[added++] = e;
}
if (added > 0) {
- Object[] newElements = Arrays.copyOf(elements, len + added);
+ Object[] newElements = Arrays.copyOf(es, len + added);
System.arraycopy(cs, 0, newElements, len, added);
setArray(newElements);
}
@@ -739,15 +733,16 @@
if (cs.length == 0)
return false;
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
+ Object[] newElements;
if (len == 0 && cs.getClass() == Object[].class)
- setArray(cs);
+ newElements = cs;
else {
- Object[] newElements = Arrays.copyOf(elements, len + cs.length);
+ newElements = Arrays.copyOf(es, len + cs.length);
System.arraycopy(cs, 0, newElements, len, cs.length);
- setArray(newElements);
}
+ setArray(newElements);
return true;
}
}
@@ -771,8 +766,8 @@
public boolean addAll(int index, Collection<? extends E> c) {
Object[] cs = c.toArray();
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException(outOfBounds(index, len));
if (cs.length == 0)
@@ -780,11 +775,11 @@
int numMoved = len - index;
Object[] newElements;
if (numMoved == 0)
- newElements = Arrays.copyOf(elements, len + cs.length);
+ newElements = Arrays.copyOf(es, len + cs.length);
else {
newElements = new Object[len + cs.length];
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index,
+ System.arraycopy(es, 0, newElements, 0, index);
+ System.arraycopy(es, index,
newElements, index + cs.length,
numMoved);
}
@@ -866,14 +861,14 @@
}
public void replaceAll(UnaryOperator<E> operator) {
- Objects.requireNonNull(operator);
synchronized (lock) {
- replaceAll(operator, 0, getArray().length);
+ replaceAllRange(operator, 0, getArray().length);
}
}
- void replaceAll(UnaryOperator<E> operator, int i, int end) {
+ void replaceAllRange(UnaryOperator<E> operator, int i, int end) {
// assert Thread.holdsLock(lock);
+ Objects.requireNonNull(operator);
final Object[] es = getArray().clone();
for (; i < end; i++)
es[i] = operator.apply(elementAt(es, i));
@@ -882,12 +877,12 @@
public void sort(Comparator<? super E> c) {
synchronized (lock) {
- sort(c, 0, getArray().length);
+ sortRange(c, 0, getArray().length);
}
}
@SuppressWarnings("unchecked")
- void sort(Comparator<? super E> c, int i, int end) {
+ void sortRange(Comparator<? super E> c, int i, int end) {
// assert Thread.holdsLock(lock);
final Object[] es = getArray().clone();
Arrays.sort(es, i, end, (Comparator<Object>)c);
@@ -908,12 +903,12 @@
s.defaultWriteObject();
- Object[] elements = getArray();
+ Object[] es = getArray();
// Write out array length
- s.writeInt(elements.length);
+ s.writeInt(es.length);
// Write out all elements in the proper order.
- for (Object element : elements)
+ for (Object element : es)
s.writeObject(element);
}
@@ -935,12 +930,12 @@
// Read in array length and allocate array
int len = s.readInt();
SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len);
- Object[] elements = new Object[len];
+ Object[] es = new Object[len];
// Read in all elements in the proper order.
for (int i = 0; i < len; i++)
- elements[i] = s.readObject();
- setArray(elements);
+ es[i] = s.readObject();
+ setArray(es);
}
/**
@@ -986,6 +981,15 @@
return !it.hasNext();
}
+ private static int hashCodeOfRange(Object[] es, int from, int to) {
+ int hashCode = 1;
+ for (int i = from; i < to; i++) {
+ Object x = es[i];
+ hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
+ }
+ return hashCode;
+ }
+
/**
* Returns the hash code value for this list.
*
@@ -994,10 +998,8 @@
* @return the hash code value for this list
*/
public int hashCode() {
- int hashCode = 1;
- for (Object x : getArray())
- hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
- return hashCode;
+ Object[] es = getArray();
+ return hashCodeOfRange(es, 0, es.length);
}
/**
@@ -1037,12 +1039,12 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public ListIterator<E> listIterator(int index) {
- Object[] elements = getArray();
- int len = elements.length;
+ Object[] es = getArray();
+ int len = es.length;
if (index < 0 || index > len)
throw new IndexOutOfBoundsException(outOfBounds(index, len));
- return new COWIterator<E>(elements, index);
+ return new COWIterator<E>(es, index);
}
/**
@@ -1070,9 +1072,9 @@
/** Index of element to be returned by subsequent call to next. */
private int cursor;
- COWIterator(Object[] elements, int initialCursor) {
+ COWIterator(Object[] es, int initialCursor) {
cursor = initialCursor;
- snapshot = elements;
+ snapshot = es;
}
public boolean hasNext() {
@@ -1102,7 +1104,7 @@
}
public int previousIndex() {
- return cursor-1;
+ return cursor - 1;
}
/**
@@ -1133,14 +1135,13 @@
}
@Override
- @SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int size = snapshot.length;
- for (int i = cursor; i < size; i++) {
- action.accept((E) snapshot[i]);
- }
+ int i = cursor;
cursor = size;
+ for (; i < size; i++)
+ action.accept(elementAt(snapshot, i));
}
}
@@ -1161,136 +1162,264 @@
*/
public List<E> subList(int fromIndex, int toIndex) {
synchronized (lock) {
- Object[] elements = getArray();
- int len = elements.length;
- if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
+ Object[] es = getArray();
+ int len = es.length;
+ int size = toIndex - fromIndex;
+ if (fromIndex < 0 || toIndex > len || size < 0)
throw new IndexOutOfBoundsException();
- return new COWSubList<E>(this, fromIndex, toIndex);
+ return new COWSubList(es, fromIndex, size);
}
}
/**
* Sublist for CopyOnWriteArrayList.
*/
- private static class COWSubList<E>
- extends AbstractList<E>
- implements RandomAccess
- {
- private final CopyOnWriteArrayList<E> l;
+ private class COWSubList implements List<E>, RandomAccess {
private final int offset;
private int size;
private Object[] expectedArray;
- // only call this holding l's lock
- COWSubList(CopyOnWriteArrayList<E> list,
- int fromIndex, int toIndex) {
- // assert Thread.holdsLock(list.lock);
- l = list;
- expectedArray = l.getArray();
- offset = fromIndex;
- size = toIndex - fromIndex;
+ COWSubList(Object[] es, int offset, int size) {
+ // assert Thread.holdsLock(lock);
+ expectedArray = es;
+ this.offset = offset;
+ this.size = size;
}
- // only call this holding l's lock
private void checkForComodification() {
- // assert Thread.holdsLock(l.lock);
- if (l.getArray() != expectedArray)
+ // assert Thread.holdsLock(lock);
+ if (getArray() != expectedArray)
throw new ConcurrentModificationException();
}
private Object[] getArrayChecked() {
- // assert Thread.holdsLock(l.lock);
- Object[] a = l.getArray();
+ // assert Thread.holdsLock(lock);
+ Object[] a = getArray();
if (a != expectedArray)
throw new ConcurrentModificationException();
return a;
}
- // only call this holding l's lock
private void rangeCheck(int index) {
- // assert Thread.holdsLock(l.lock);
+ // assert Thread.holdsLock(lock);
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException(outOfBounds(index, size));
}
+ private void rangeCheckForAdd(int index) {
+ // assert Thread.holdsLock(lock);
+ if (index < 0 || index > size)
+ throw new IndexOutOfBoundsException(outOfBounds(index, size));
+ }
+
+ public Object[] toArray() {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ return Arrays.copyOfRange(es, offset, offset + size);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T[] toArray(T[] a) {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ if (a.length < size)
+ return (T[]) Arrays.copyOfRange(
+ es, offset, offset + size, a.getClass());
+ else {
+ System.arraycopy(es, offset, a, 0, size);
+ if (a.length > size)
+ a[size] = null;
+ return a;
+ }
+ }
+
+ public int indexOf(Object o) {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ int i = indexOfRange(o, es, offset, offset + size);
+ return (i == -1) ? -1 : i - offset;
+ }
+
+ public int lastIndexOf(Object o) {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ int i = lastIndexOfRange(o, es, offset, offset + size);
+ return (i == -1) ? -1 : i - offset;
+ }
+
+ public boolean contains(Object o) {
+ return indexOf(o) >= 0;
+ }
+
+ public boolean containsAll(Collection<?> c) {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ for (Object o : c)
+ if (indexOfRange(o, es, offset, offset + size) < 0)
+ return false;
+ return true;
+ }
+
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ public String toString() {
+ return Arrays.toString(toArray());
+ }
+
+ public int hashCode() {
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+ return hashCodeOfRange(es, offset, offset + size);
+ }
+
+ public boolean equals(Object o) {
+ if (o == this)
+ return true;
+ if (!(o instanceof List))
+ return false;
+ Iterator<?> it = ((List<?>)o).iterator();
+
+ final Object[] es;
+ final int offset;
+ final int size;
+ synchronized (lock) {
+ es = getArrayChecked();
+ offset = this.offset;
+ size = this.size;
+ }
+
+ for (int i = offset, end = offset + size; i < end; i++)
+ if (!it.hasNext() || !Objects.equals(es[i], it.next()))
+ return false;
+ return !it.hasNext();
+ }
+
public E set(int index, E element) {
- synchronized (l.lock) {
+ synchronized (lock) {
rangeCheck(index);
checkForComodification();
- E x = l.set(offset + index, element);
- expectedArray = l.getArray();
+ E x = CopyOnWriteArrayList.this.set(offset + index, element);
+ expectedArray = getArray();
return x;
}
}
public E get(int index) {
- synchronized (l.lock) {
+ synchronized (lock) {
rangeCheck(index);
checkForComodification();
- return l.get(offset + index);
+ return CopyOnWriteArrayList.this.get(offset + index);
}
}
public int size() {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
return size;
}
}
public boolean add(E element) {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
- l.add(offset + size, element);
- expectedArray = l.getArray();
+ CopyOnWriteArrayList.this.add(offset + size, element);
+ expectedArray = getArray();
size++;
}
return true;
}
public void add(int index, E element) {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
- if (index < 0 || index > size)
- throw new IndexOutOfBoundsException
- (outOfBounds(index, size));
- l.add(offset + index, element);
- expectedArray = l.getArray();
+ rangeCheckForAdd(index);
+ CopyOnWriteArrayList.this.add(offset + index, element);
+ expectedArray = getArray();
size++;
}
}
public boolean addAll(Collection<? extends E> c) {
- synchronized (l.lock) {
+ synchronized (lock) {
final Object[] oldArray = getArrayChecked();
- boolean modified = l.addAll(offset + size, c);
- size += (expectedArray = l.getArray()).length - oldArray.length;
+ boolean modified =
+ CopyOnWriteArrayList.this.addAll(offset + size, c);
+ size += (expectedArray = getArray()).length - oldArray.length;
+ return modified;
+ }
+ }
+
+ public boolean addAll(int index, Collection<? extends E> c) {
+ synchronized (lock) {
+ rangeCheckForAdd(index);
+ final Object[] oldArray = getArrayChecked();
+ boolean modified =
+ CopyOnWriteArrayList.this.addAll(offset + index, c);
+ size += (expectedArray = getArray()).length - oldArray.length;
return modified;
}
}
public void clear() {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
- l.removeRange(offset, offset + size);
- expectedArray = l.getArray();
+ removeRange(offset, offset + size);
+ expectedArray = getArray();
size = 0;
}
}
public E remove(int index) {
- synchronized (l.lock) {
+ synchronized (lock) {
rangeCheck(index);
checkForComodification();
- E result = l.remove(offset + index);
- expectedArray = l.getArray();
+ E result = CopyOnWriteArrayList.this.remove(offset + index);
+ expectedArray = getArray();
size--;
return result;
}
}
public boolean remove(Object o) {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
int index = indexOf(o);
if (index == -1)
@@ -1301,36 +1430,35 @@
}
public Iterator<E> iterator() {
- synchronized (l.lock) {
- checkForComodification();
- return new COWSubListIterator<E>(l, 0, offset, size);
- }
+ return listIterator(0);
+ }
+
+ public ListIterator<E> listIterator() {
+ return listIterator(0);
}
public ListIterator<E> listIterator(int index) {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
- if (index < 0 || index > size)
- throw new IndexOutOfBoundsException
- (outOfBounds(index, size));
- return new COWSubListIterator<E>(l, index, offset, size);
+ rangeCheckForAdd(index);
+ return new COWSubListIterator<E>(
+ CopyOnWriteArrayList.this, index, offset, size);
}
}
public List<E> subList(int fromIndex, int toIndex) {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
throw new IndexOutOfBoundsException();
- return new COWSubList<E>(l, fromIndex + offset,
- toIndex + offset);
+ return new COWSubList(expectedArray, fromIndex + offset, toIndex - fromIndex);
}
}
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
int i, end; final Object[] es;
- synchronized (l.lock) {
+ synchronized (lock) {
es = getArrayChecked();
i = offset;
end = i + size;
@@ -1340,19 +1468,18 @@
}
public void replaceAll(UnaryOperator<E> operator) {
- Objects.requireNonNull(operator);
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
- l.replaceAll(operator, offset, offset + size);
- expectedArray = l.getArray();
+ replaceAllRange(operator, offset, offset + size);
+ expectedArray = getArray();
}
}
public void sort(Comparator<? super E> c) {
- synchronized (l.lock) {
+ synchronized (lock) {
checkForComodification();
- l.sort(c, offset, offset + size);
- expectedArray = l.getArray();
+ sortRange(c, offset, offset + size);
+ expectedArray = getArray();
}
}
@@ -1372,16 +1499,17 @@
}
private boolean bulkRemove(Predicate<? super E> filter) {
- synchronized (l.lock) {
+ synchronized (lock) {
final Object[] oldArray = getArrayChecked();
- boolean modified = l.bulkRemove(filter, offset, offset + size);
- size += (expectedArray = l.getArray()).length - oldArray.length;
+ boolean modified = CopyOnWriteArrayList.this.bulkRemove(
+ filter, offset, offset + size);
+ size += (expectedArray = getArray()).length - oldArray.length;
return modified;
}
}
public Spliterator<E> spliterator() {
- synchronized (l.lock) {
+ synchronized (lock) {
return Spliterators.spliterator(
getArrayChecked(), offset, offset + size,
Spliterator.IMMUTABLE | Spliterator.ORDERED);
@@ -1398,7 +1526,7 @@
COWSubListIterator(List<E> l, int index, int offset, int size) {
this.offset = offset;
this.size = size;
- it = l.listIterator(index+offset);
+ it = l.listIterator(index + offset);
}
public boolean hasNext() {
@@ -1447,7 +1575,7 @@
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
- while (nextIndex() < size) {
+ while (hasNext()) {
action.accept(it.next());
}
}
--- a/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java Tue Apr 10 13:58:47 2018 -0700
@@ -775,7 +775,7 @@
PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
--- a/src/java.base/share/classes/java/util/concurrent/Exchanger.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/Exchanger.java Tue Apr 10 13:58:47 2018 -0700
@@ -641,7 +641,7 @@
MATCH = l.findVarHandle(Node.class, "match", Object.class);
AA = MethodHandles.arrayElementVarHandle(Node[].class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java Tue Apr 10 13:58:47 2018 -0700
@@ -184,17 +184,22 @@
* functionality and control for a set of worker threads:
* Submissions from non-FJ threads enter into submission queues.
* Workers take these tasks and typically split them into subtasks
- * that may be stolen by other workers. Preference rules give
- * first priority to processing tasks from their own queues (LIFO
- * or FIFO, depending on mode), then to randomized FIFO steals of
- * tasks in other queues. This framework began as vehicle for
- * supporting tree-structured parallelism using work-stealing.
- * Over time, its scalability advantages led to extensions and
- * changes to better support more diverse usage contexts. Because
- * most internal methods and nested classes are interrelated,
- * their main rationale and descriptions are presented here;
- * individual methods and nested classes contain only brief
- * comments about details.
+ * that may be stolen by other workers. Work-stealing based on
+ * randomized scans generally leads to better throughput than
+ * "work dealing" in which producers assign tasks to idle threads,
+ * in part because threads that have finished other tasks before
+ * the signalled thread wakes up (which can be a long time) can
+ * take the task instead. Preference rules give first priority to
+ * processing tasks from their own queues (LIFO or FIFO, depending
+ * on mode), then to randomized FIFO steals of tasks in other
+ * queues. This framework began as vehicle for supporting
+ * tree-structured parallelism using work-stealing. Over time,
+ * its scalability advantages led to extensions and changes to
+ * better support more diverse usage contexts. Because most
+ * internal methods and nested classes are interrelated, their
+ * main rationale and descriptions are presented here; individual
+ * methods and nested classes contain only brief comments about
+ * details.
*
* WorkQueues
* ==========
@@ -227,9 +232,10 @@
*
* (The actual code needs to null-check and size-check the array,
* uses masking, not mod, for indexing a power-of-two-sized array,
- * properly fences accesses, and possibly signals waiting workers
- * to start scanning -- see below.) Both a successful pop and
- * poll mainly entail a CAS of a slot from non-null to null.
+ * adds a release fence for publication, and possibly signals
+ * waiting workers to start scanning -- see below.) Both a
+ * successful pop and poll mainly entail a CAS of a slot from
+ * non-null to null.
*
* The pop operation (always performed by owner) is:
* if ((the task at top slot is not null) and
@@ -241,9 +247,14 @@
* (CAS slot to null))
* increment base and return task;
*
- * There are several variants of each of these. In particular,
- * almost all uses of poll occur within scan operations that also
- * interleave contention tracking (with associated code sprawl.)
+ * There are several variants of each of these. Most uses occur
+ * within operations that also interleave contention or emptiness
+ * tracking or inspection of elements before extracting them, so
+ * must interleave these with the above code. When performed by
+ * owner, getAndSet is used instead of CAS (see for example method
+ * nextLocalTask) which is usually more efficient, and possible
+ * because the top index cannot independently change during the
+ * operation.
*
* Memory ordering. See "Correct and Efficient Work-Stealing for
* Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
@@ -252,30 +263,37 @@
* algorithms similar to (but different than) the one used here.
* Extracting tasks in array slots via (fully fenced) CAS provides
* primary synchronization. The base and top indices imprecisely
- * guide where to extract from. We do not always require strict
- * orderings of array and index updates, so sometimes let them be
- * subject to compiler and processor reorderings. However, the
- * volatile "base" index also serves as a basis for memory
- * ordering: Slot accesses are preceded by a read of base,
- * ensuring happens-before ordering with respect to stealers (so
- * the slots themselves can be read via plain array reads.) The
- * only other memory orderings relied on are maintained in the
- * course of signalling and activation (see below). A check that
- * base == top indicates (momentary) emptiness, but otherwise may
- * err on the side of possibly making the queue appear nonempty
- * when a push, pop, or poll have not fully committed, or making
- * it appear empty when an update of top has not yet been visibly
- * written. (Method isEmpty() checks the case of a partially
- * completed removal of the last element.) Because of this, the
- * poll operation, considered individually, is not wait-free. One
- * thief cannot successfully continue until another in-progress
- * one (or, if previously empty, a push) visibly completes.
- * However, in the aggregate, we ensure at least probabilistic
+ * guide where to extract from. We do not usually require strict
+ * orderings of array and index updates. Many index accesses use
+ * plain mode, with ordering constrained by surrounding context
+ * (usually with respect to element CASes or the two WorkQueue
+ * volatile fields source and phase). When not otherwise already
+ * constrained, reads of "base" by queue owners use acquire-mode,
+ * and some externally callable methods preface accesses with
+ * acquire fences. Additionally, to ensure that index update
+ * writes are not coalesced or postponed in loops etc, "opaque"
+ * mode is used in a few cases where timely writes are not
+ * otherwise ensured. The "locked" versions of push- and pop-
+ * based methods for shared queues differ from owned versions
+ * because locking already forces some of the ordering.
+ *
+ * Because indices and slot contents cannot always be consistent,
+ * a check that base == top indicates (momentary) emptiness, but
+ * otherwise may err on the side of possibly making the queue
+ * appear nonempty when a push, pop, or poll have not fully
+ * committed, or making it appear empty when an update of top has
+ * not yet been visibly written. (Method isEmpty() checks the
+ * case of a partially completed removal of the last element.)
+ * Because of this, the poll operation, considered individually,
+ * is not wait-free. One thief cannot successfully continue until
+ * another in-progress one (or, if previously empty, a push)
+ * visibly completes. This can stall threads when required to
+ * consume from a given queue (see method poll()). However, in
+ * the aggregate, we ensure at least probabilistic
* non-blockingness. If an attempted steal fails, a scanning
* thief chooses a different random victim target to try next. So,
* in order for one thief to progress, it suffices for any
- * in-progress poll or new push on any empty queue to
- * complete.
+ * in-progress poll or new push on any empty queue to complete.
*
* This approach also enables support of a user mode in which
* local task processing is in FIFO, not LIFO order, simply by
@@ -296,7 +314,7 @@
* different position to use or create other queues -- they block
* only when creating and registering new queues. Because it is
* used only as a spinlock, unlocking requires only a "releasing"
- * store (using setRelease).
+ * store (using setRelease) unless otherwise signalling.
*
* Management
* ==========
@@ -317,10 +335,10 @@
*
* Field "ctl" contains 64 bits holding information needed to
* atomically decide to add, enqueue (on an event queue), and
- * dequeue (and release)-activate workers. To enable this
- * packing, we restrict maximum parallelism to (1<<15)-1 (which is
- * far in excess of normal operating range) to allow ids, counts,
- * and their negations (used for thresholding) to fit into 16bit
+ * dequeue and release workers. To enable this packing, we
+ * restrict maximum parallelism to (1<<15)-1 (which is far in
+ * excess of normal operating range) to allow ids, counts, and
+ * their negations (used for thresholding) to fit into 16bit
* subfields.
*
* Field "mode" holds configuration parameters as well as lifetime
@@ -332,13 +350,14 @@
* lock (using field workerNamePrefix as lock), but is otherwise
* concurrently readable, and accessed directly. We also ensure
* that uses of the array reference itself never become too stale
- * in case of resizing. To simplify index-based operations, the
- * array size is always a power of two, and all readers must
- * tolerate null slots. Worker queues are at odd indices. Shared
- * (submission) queues are at even indices, up to a maximum of 64
- * slots, to limit growth even if array needs to expand to add
- * more workers. Grouping them together in this way simplifies and
- * speeds up task scanning.
+ * in case of resizing, by arranging that (re-)reads are separated
+ * by at least one acquiring read access. To simplify index-based
+ * operations, the array size is always a power of two, and all
+ * readers must tolerate null slots. Worker queues are at odd
+ * indices. Shared (submission) queues are at even indices, up to
+ * a maximum of 64 slots, to limit growth even if the array needs
+ * to expand to add more workers. Grouping them together in this
+ * way simplifies and speeds up task scanning.
*
* All worker thread creation is on-demand, triggered by task
* submissions, replacement of terminated workers, and/or
@@ -416,8 +435,8 @@
* releases so usage requires care -- seeing a negative phase does
* not guarantee that the worker is available. When queued, the
* lower 16 bits of scanState must hold its pool index. So we
- * place the index there upon initialization (see registerWorker)
- * and otherwise keep it there or restore it when necessary.
+ * place the index there upon initialization and otherwise keep it
+ * there or restore it when necessary.
*
* The ctl field also serves as the basis for memory
* synchronization surrounding activation. This uses a more
@@ -425,48 +444,56 @@
* consumers sync with each other by both writing/CASing ctl (even
* if to its current value). This would be extremely costly. So
* we relax it in several ways: (1) Producers only signal when
- * their queue is empty. Other workers propagate this signal (in
- * method scan) when they find tasks; to further reduce flailing,
- * each worker signals only one other per activation. (2) Workers
- * only enqueue after scanning (see below) and not finding any
- * tasks. (3) Rather than CASing ctl to its current value in the
- * common case where no action is required, we reduce write
+ * their queue is possibly empty at some point during a push
+ * operation (which requires conservatively checking size zero or
+ * one to cover races). (2) Other workers propagate this signal
+ * when they find tasks in a queue with size greater than one. (3)
+ * Workers only enqueue after scanning (see below) and not finding
+ * any tasks. (4) Rather than CASing ctl to its current value in
+ * the common case where no action is required, we reduce write
* contention by equivalently prefacing signalWork when called by
* an external task producer using a memory access with
* full-volatile semantics or a "fullFence".
*
- * Almost always, too many signals are issued. A task producer
- * cannot in general tell if some existing worker is in the midst
- * of finishing one task (or already scanning) and ready to take
- * another without being signalled. So the producer might instead
- * activate a different worker that does not find any work, and
- * then inactivates. This scarcely matters in steady-state
- * computations involving all workers, but can create contention
- * and bookkeeping bottlenecks during ramp-up, ramp-down, and small
- * computations involving only a few workers.
+ * Almost always, too many signals are issued, in part because a
+ * task producer cannot tell if some existing worker is in the
+ * midst of finishing one task (or already scanning) and ready to
+ * take another without being signalled. So the producer might
+ * instead activate a different worker that does not find any
+ * work, and then inactivates. This scarcely matters in
+ * steady-state computations involving all workers, but can create
+ * contention and bookkeeping bottlenecks during ramp-up,
+ * ramp-down, and small computations involving only a few workers.
*
- * Scanning. Method runWorker performs top-level scanning for
- * tasks. Each scan traverses and tries to poll from each queue
- * starting at a random index and circularly stepping. Scans are
- * not performed in ideal random permutation order, to reduce
- * cacheline contention. The pseudorandom generator need not have
+ * Scanning. Method scan (from runWorker) performs top-level
+ * scanning for tasks. (Similar scans appear in helpQuiesce and
+ * pollScan.) Each scan traverses and tries to poll from each
+ * queue starting at a random index. Scans are not performed in
+ * ideal random permutation order, to reduce cacheline
+ * contention. The pseudorandom generator need not have
* high-quality statistical properties in the long term, but just
* within computations; We use Marsaglia XorShifts (often via
* ThreadLocalRandom.nextSecondarySeed), which are cheap and
- * suffice. Scanning also employs contention reduction: When
+ * suffice. Scanning also includes contention reduction: When
* scanning workers fail to extract an apparently existing task,
- * they soon restart at a different pseudorandom index. This
- * improves throughput when many threads are trying to take tasks
- * from few queues, which can be common in some usages. Scans do
- * not otherwise explicitly take into account core affinities,
- * loads, cache localities, etc, However, they do exploit temporal
- * locality (which usually approximates these) by preferring to
- * re-poll (at most #workers times) from the same queue after a
- * successful poll before trying others.
+ * they soon restart at a different pseudorandom index. This form
+ * of backoff improves throughput when many threads are trying to
+ * take tasks from few queues, which can be common in some usages.
+ * Scans do not otherwise explicitly take into account core
+ * affinities, loads, cache localities, etc, However, they do
+ * exploit temporal locality (which usually approximates these) by
+ * preferring to re-poll from the same queue after a successful
+ * poll before trying others (see method topLevelExec). However
+ * this preference is bounded (see TOP_BOUND_SHIFT) as a safeguard
+ * against infinitely unfair looping under unbounded user task
+ * recursion, and also to reduce long-term contention when many
+ * threads poll few queues holding many small tasks. The bound is
+ * high enough to avoid much impact on locality and scheduling
+ * overhead.
*
* Trimming workers. To release resources after periods of lack of
* use, a worker starting to wait when the pool is quiescent will
- * time out and terminate (see method scan) if the pool has
+ * time out and terminate (see method runWorker) if the pool has
* remained quiescent for period given by field keepAlive.
*
* Shutdown and Termination. A call to shutdownNow invokes
@@ -534,13 +561,14 @@
* time. Some previous versions of this class employed immediate
* compensations for any blocked join. However, in practice, the
* vast majority of blockages are transient byproducts of GC and
- * other JVM or OS activities that are made worse by replacement.
- * Rather than impose arbitrary policies, we allow users to
- * override the default of only adding threads upon apparent
- * starvation. The compensation mechanism may also be bounded.
- * Bounds for the commonPool (see COMMON_MAX_SPARES) better enable
- * JVMs to cope with programming errors and abuse before running
- * out of resources to do so.
+ * other JVM or OS activities that are made worse by replacement
+ * when they cause longer-term oversubscription. Rather than
+ * impose arbitrary policies, we allow users to override the
+ * default of only adding threads upon apparent starvation. The
+ * compensation mechanism may also be bounded. Bounds for the
+ * commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope
+ * with programming errors and abuse before running out of
+ * resources to do so.
*
* Common Pool
* ===========
@@ -573,6 +601,18 @@
* in ForkJoinWorkerThread) may be JVM-dependent and must access
* particular Thread class fields to achieve this effect.
*
+ * Memory placement
+ * ================
+ *
+ * Performance can be very sensitive to placement of instances of
+ * ForkJoinPool and WorkQueues and their queue arrays. To reduce
+ * false-sharing impact, the @Contended annotation isolates
+ * adjacent WorkQueue instances, as well as the ForkJoinPool.ctl
+ * field. WorkQueue arrays are allocated (by their threads) with
+ * larger initial sizes than most ever need, mostly to reduce
+ * false sharing with current garbage collectors that use cardmark
+ * tables.
+ *
* Style notes
* ===========
*
@@ -580,13 +620,15 @@
* awkward and ugly, but also reflects the need to control
* outcomes across the unusual cases that arise in very racy code
* with very few invariants. All fields are read into locals
- * before use, and null-checked if they are references. This is
- * usually done in a "C"-like style of listing declarations at the
- * heads of methods or blocks, and using inline assignments on
- * first encounter. Nearly all explicit checks lead to
- * bypass/return, not exception throws, because they may
- * legitimately arise due to cancellation/revocation during
- * shutdown.
+ * before use, and null-checked if they are references. Array
+ * accesses using masked indices include checks (that are always
+ * true) that the array length is non-zero to avoid compilers
+ * inserting more expensive traps. This is usually done in a
+ * "C"-like style of listing declarations at the heads of methods
+ * or blocks, and using inline assignments on first encounter.
+ * Nearly all explicit checks lead to bypass/return, not exception
+ * throws, because they may legitimately arise due to
+ * cancellation/revocation during shutdown.
*
* There is a lot of representation-level coupling among classes
* ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask. The
@@ -596,10 +638,11 @@
* representations will need to be accompanied by algorithmic
* changes anyway. Several methods intrinsically sprawl because
* they must accumulate sets of consistent reads of fields held in
- * local variables. There are also other coding oddities
- * (including several unnecessary-looking hoisted null checks)
- * that help some methods perform reasonably even when interpreted
- * (not compiled).
+ * local variables. Some others are artificially broken up to
+ * reduce producer/consumer imbalances due to dynamic compilation.
+ * There are also other coding oddities (including several
+ * unnecessary-looking hoisted null checks) that help some methods
+ * perform reasonably even when interpreted (not compiled).
*
* The order of declarations in this file is (with a few exceptions):
* (1) Static utility functions
@@ -703,54 +746,43 @@
static final int DORMANT = QUIET | UNSIGNALLED;
/**
- * The maximum number of local polls from the same queue before
- * checking others. This is a safeguard against infinitely unfair
- * looping under unbounded user task recursion, and must be larger
- * than plausible cases of intentional bounded task recursion.
+ * Initial capacity of work-stealing queue array.
+ * Must be a power of two, at least 2.
*/
- static final int POLL_LIMIT = 1 << 10;
+ static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
+
+ /**
+ * Maximum capacity for queue arrays. Must be a power of two less
+ * than or equal to 1 << (31 - width of array entry) to ensure
+ * lack of wraparound of index calculations, but defined to a
+ * value a bit less than this to help users trap runaway programs
+ * before saturating systems.
+ */
+ static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
+
+ /**
+ * The maximum number of top-level polls per worker before
+ * checking other queues, expressed as a bit shift to, in effect,
+ * multiply by pool size, and then use as random value mask, so
+ * average bound is about poolSize*(1<<TOP_BOUND_SHIFT). See
+ * above for rationale.
+ */
+ static final int TOP_BOUND_SHIFT = 10;
/**
* Queues supporting work-stealing as well as external task
* submission. See above for descriptions and algorithms.
- * Performance on most platforms is very sensitive to placement of
- * instances of both WorkQueues and their arrays -- we absolutely
- * do not want multiple WorkQueue instances or multiple queue
- * arrays sharing cache lines. The @Contended annotation alerts
- * JVMs to try to keep instances apart.
*/
@jdk.internal.vm.annotation.Contended
static final class WorkQueue {
-
- /**
- * Capacity of work-stealing queue array upon initialization.
- * Must be a power of two; at least 4, but should be larger to
- * reduce or eliminate cacheline sharing among queues.
- * Currently, it is much larger, as a partial workaround for
- * the fact that JVMs often place arrays in locations that
- * share GC bookkeeping (especially cardmarks) such that
- * per-write accesses encounter serious memory contention.
- */
- static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
-
- /**
- * Maximum size for queue arrays. Must be a power of two less
- * than or equal to 1 << (31 - width of array entry) to ensure
- * lack of wraparound of index calculations, but defined to a
- * value a bit less than this to help users trap runaway
- * programs before saturating systems.
- */
- static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
-
- // Instance fields
+ volatile int source; // source queue id, or sentinel
+ int id; // pool index, mode, tag
+ int base; // index of next slot for poll
+ int top; // index of next slot for push
volatile int phase; // versioned, negative: queued, 1: locked
int stackPred; // pool stack (ctl) predecessor link
int nsteals; // number of steals
- int id; // index, mode, tag
- volatile int source; // source queue id, or sentinel
- volatile int base; // index of next slot for poll
- int top; // index of next slot for push
- ForkJoinTask<?>[] array; // the elements (initially unallocated)
+ ForkJoinTask<?>[] array; // the queued tasks; power of 2 size
final ForkJoinPool pool; // the containing pool (may be null)
final ForkJoinWorkerThread owner; // owning thread or null if shared
@@ -762,6 +794,17 @@
}
/**
+ * Tries to lock shared queue by CASing phase field.
+ */
+ final boolean tryLockPhase() {
+ return PHASE.compareAndSet(this, 0, 1);
+ }
+
+ final void releasePhaseLock() {
+ PHASE.setRelease(this, 0);
+ }
+
+ /**
* Returns an exportable index (used by ForkJoinWorkerThread).
*/
final int getPoolIndex() {
@@ -772,7 +815,7 @@
* Returns the approximate number of tasks in the queue.
*/
final int queueSize() {
- int n = base - top; // read base first
+ int n = (int)BASE.getAcquire(this) - top;
return (n >= 0) ? 0 : -n; // ignore transient negative
}
@@ -782,14 +825,14 @@
* near-empty queue has at least one unclaimed task.
*/
final boolean isEmpty() {
- ForkJoinTask<?>[] a; int n, al, b;
+ ForkJoinTask<?>[] a; int n, cap, b;
+ VarHandle.acquireFence(); // needed by external callers
return ((n = (b = base) - top) >= 0 || // possibly one task
(n == -1 && ((a = array) == null ||
- (al = a.length) == 0 ||
- a[(al - 1) & b] == null)));
+ (cap = a.length) == 0 ||
+ a[(cap - 1) & b] == null)));
}
-
/**
* Pushes a task. Call only by owner in unshared queues.
*
@@ -797,94 +840,99 @@
* @throws RejectedExecutionException if array cannot be resized
*/
final void push(ForkJoinTask<?> task) {
- int s = top; ForkJoinTask<?>[] a; int al, d;
- if ((a = array) != null && (al = a.length) > 0) {
- int index = (al - 1) & s;
- ForkJoinPool p = pool;
+ ForkJoinTask<?>[] a;
+ int s = top, d, cap, m;
+ ForkJoinPool p = pool;
+ if ((a = array) != null && (cap = a.length) > 0) {
+ QA.setRelease(a, (m = cap - 1) & s, task);
top = s + 1;
- QA.setRelease(a, index, task);
- if ((d = base - s) == 0 && p != null) {
+ if (((d = s - (int)BASE.getAcquire(this)) & ~1) == 0 &&
+ p != null) { // size 0 or 1
VarHandle.fullFence();
p.signalWork();
}
- else if (d + al == 1)
- growArray();
+ else if (d == m)
+ growArray(false);
}
}
/**
- * Initializes or doubles the capacity of array. Call either
- * by owner or with lock held -- it is OK for base, but not
- * top, to move while resizings are in progress.
+ * Version of push for shared queues. Call only with phase lock held.
+ * @return true if should signal work
*/
- final ForkJoinTask<?>[] growArray() {
- ForkJoinTask<?>[] oldA = array;
- int oldSize = oldA != null ? oldA.length : 0;
- int size = oldSize > 0 ? oldSize << 1 : INITIAL_QUEUE_CAPACITY;
- if (size < INITIAL_QUEUE_CAPACITY || size > MAXIMUM_QUEUE_CAPACITY)
- throw new RejectedExecutionException("Queue capacity exceeded");
- int oldMask, t, b;
- ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
- if (oldA != null && (oldMask = oldSize - 1) > 0 &&
- (t = top) - (b = base) > 0) {
- int mask = size - 1;
- do { // emulate poll from old array, push to new array
- int index = b & oldMask;
- ForkJoinTask<?> x = (ForkJoinTask<?>)
- QA.getAcquire(oldA, index);
- if (x != null &&
- QA.compareAndSet(oldA, index, x, null))
- a[b & mask] = x;
- } while (++b != t);
- VarHandle.releaseFence();
+ final boolean lockedPush(ForkJoinTask<?> task) {
+ ForkJoinTask<?>[] a;
+ boolean signal = false;
+ int s = top, b = base, cap, d;
+ if ((a = array) != null && (cap = a.length) > 0) {
+ a[(cap - 1) & s] = task;
+ top = s + 1;
+ if (b - s + cap - 1 == 0)
+ growArray(true);
+ else {
+ phase = 0; // full volatile unlock
+ if (((s - base) & ~1) == 0) // size 0 or 1
+ signal = true;
+ }
}
- return a;
+ return signal;
}
/**
- * Takes next task, if one exists, in LIFO order. Call only
- * by owner in unshared queues.
+ * Doubles the capacity of array. Call either by owner or with
+ * lock held -- it is OK for base, but not top, to move while
+ * resizings are in progress.
*/
- final ForkJoinTask<?> pop() {
- int b = base, s = top, al, i; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & --s;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.get(a, index);
- if (t != null &&
- QA.compareAndSet(a, index, t, null)) {
- top = s;
- VarHandle.releaseFence();
- return t;
+ final void growArray(boolean locked) {
+ ForkJoinTask<?>[] newA = null;
+ try {
+ ForkJoinTask<?>[] oldA; int oldSize, newSize;
+ if ((oldA = array) != null && (oldSize = oldA.length) > 0 &&
+ (newSize = oldSize << 1) <= MAXIMUM_QUEUE_CAPACITY &&
+ newSize > 0) {
+ try {
+ newA = new ForkJoinTask<?>[newSize];
+ } catch (OutOfMemoryError ex) {
+ }
+ if (newA != null) { // poll from old array, push to new
+ int oldMask = oldSize - 1, newMask = newSize - 1;
+ for (int s = top - 1, k = oldMask; k >= 0; --k) {
+ ForkJoinTask<?> x = (ForkJoinTask<?>)
+ QA.getAndSet(oldA, s & oldMask, null);
+ if (x != null)
+ newA[s-- & newMask] = x;
+ else
+ break;
+ }
+ array = newA;
+ VarHandle.releaseFence();
+ }
}
+ } finally {
+ if (locked)
+ phase = 0;
}
- return null;
+ if (newA == null)
+ throw new RejectedExecutionException("Queue capacity exceeded");
}
/**
* Takes next task, if one exists, in FIFO order.
*/
final ForkJoinTask<?> poll() {
- for (;;) {
- int b = base, s = top, d, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && (d = b - s) < 0 &&
- (al = a.length) > 0) {
- int index = (al - 1) & b;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.getAcquire(a, index);
- if (b++ == base) {
- if (t != null) {
- if (QA.compareAndSet(a, index, t, null)) {
- base = b;
- return t;
- }
- }
- else if (d == -1)
- break; // now empty
+ int b, k, cap; ForkJoinTask<?>[] a;
+ while ((a = array) != null && (cap = a.length) > 0 &&
+ top - (b = base) > 0) {
+ ForkJoinTask<?> t = (ForkJoinTask<?>)
+ QA.getAcquire(a, k = (cap - 1) & b);
+ if (base == b++) {
+ if (t == null)
+ Thread.yield(); // await index advance
+ else if (QA.compareAndSet(a, k, t, null)) {
+ BASE.setOpaque(this, b);
+ return t;
}
}
- else
- break;
}
return null;
}
@@ -893,33 +941,61 @@
* Takes next task, if one exists, in order specified by mode.
*/
final ForkJoinTask<?> nextLocalTask() {
- return ((id & FIFO) != 0) ? poll() : pop();
+ ForkJoinTask<?> t = null;
+ int md = id, b, s, d, cap; ForkJoinTask<?>[] a;
+ if ((a = array) != null && (cap = a.length) > 0 &&
+ (d = (s = top) - (b = base)) > 0) {
+ if ((md & FIFO) == 0 || d == 1) {
+ if ((t = (ForkJoinTask<?>)
+ QA.getAndSet(a, (cap - 1) & --s, null)) != null)
+ TOP.setOpaque(this, s);
+ }
+ else if ((t = (ForkJoinTask<?>)
+ QA.getAndSet(a, (cap - 1) & b++, null)) != null) {
+ BASE.setOpaque(this, b);
+ }
+ else // on contention in FIFO mode, use regular poll
+ t = poll();
+ }
+ return t;
}
/**
* Returns next task, if one exists, in order specified by mode.
*/
final ForkJoinTask<?> peek() {
- int al; ForkJoinTask<?>[] a;
- return ((a = array) != null && (al = a.length) > 0) ?
- a[(al - 1) &
- ((id & FIFO) != 0 ? base : top - 1)] : null;
+ int cap; ForkJoinTask<?>[] a;
+ return ((a = array) != null && (cap = a.length) > 0) ?
+ a[(cap - 1) & ((id & FIFO) != 0 ? base : top - 1)] : null;
}
/**
* Pops the given task only if it is at the current top.
*/
final boolean tryUnpush(ForkJoinTask<?> task) {
- int b = base, s = top, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & --s;
- if (QA.compareAndSet(a, index, task, null)) {
+ boolean popped = false;
+ int s, cap; ForkJoinTask<?>[] a;
+ if ((a = array) != null && (cap = a.length) > 0 &&
+ (s = top) != base &&
+ (popped = QA.compareAndSet(a, (cap - 1) & --s, task, null)))
+ TOP.setOpaque(this, s);
+ return popped;
+ }
+
+ /**
+ * Shared version of tryUnpush.
+ */
+ final boolean tryLockedUnpush(ForkJoinTask<?> task) {
+ boolean popped = false;
+ int s = top - 1, k, cap; ForkJoinTask<?>[] a;
+ if ((a = array) != null && (cap = a.length) > 0 &&
+ a[k = (cap - 1) & s] == task && tryLockPhase()) {
+ if (top == s + 1 && array == a &&
+ (popped = QA.compareAndSet(a, k, task, null)))
top = s;
- VarHandle.releaseFence();
- return true;
- }
+ releasePhaseLock();
}
- return false;
+ return popped;
}
/**
@@ -933,58 +1009,29 @@
// Specialized execution methods
/**
- * Pops and executes up to limit consecutive tasks or until empty.
- *
- * @param limit max runs, or zero for no limit
+ * Runs the given (stolen) task if nonnull, as well as
+ * remaining local tasks and others available from the given
+ * queue, up to bound n (to avoid infinite unfairness).
*/
- final void localPopAndExec(int limit) {
- for (;;) {
- int b = base, s = top, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & --s;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.getAndSet(a, index, null);
- if (t != null) {
- top = s;
- VarHandle.releaseFence();
- t.doExec();
- if (limit != 0 && --limit == 0)
+ final void topLevelExec(ForkJoinTask<?> t, WorkQueue q, int n) {
+ if (t != null && q != null) { // hoist checks
+ int nstolen = 1;
+ for (;;) {
+ t.doExec();
+ if (n-- < 0)
+ break;
+ else if ((t = nextLocalTask()) == null) {
+ if ((t = q.poll()) == null)
break;
+ else
+ ++nstolen;
}
- else
- break;
}
- else
- break;
- }
- }
-
- /**
- * Polls and executes up to limit consecutive tasks or until empty.
- *
- * @param limit, or zero for no limit
- */
- final void localPollAndExec(int limit) {
- for (int polls = 0;;) {
- int b = base, s = top, d, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && (d = b - s) < 0 &&
- (al = a.length) > 0) {
- int index = (al - 1) & b++;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.getAndSet(a, index, null);
- if (t != null) {
- base = b;
- t.doExec();
- if (limit != 0 && ++polls == limit)
- break;
- }
- else if (d == -1)
- break; // now empty
- else
- polls = 0; // stolen; reset
- }
- else
- break;
+ ForkJoinWorkerThread thread = owner;
+ nsteals += nstolen;
+ source = 0;
+ if (thread != null)
+ thread.afterTopLevelExec();
}
}
@@ -992,25 +1039,24 @@
* If present, removes task from queue and executes it.
*/
final void tryRemoveAndExec(ForkJoinTask<?> task) {
- ForkJoinTask<?>[] wa; int s, wal;
- if (base - (s = top) < 0 && // traverse from top
- (wa = array) != null && (wal = wa.length) > 0) {
- for (int m = wal - 1, ns = s - 1, i = ns; ; --i) {
+ ForkJoinTask<?>[] a; int s, cap;
+ if ((a = array) != null && (cap = a.length) > 0 &&
+ (s = top) - base > 0) { // traverse from top
+ for (int m = cap - 1, ns = s - 1, i = ns; ; --i) {
int index = i & m;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.get(wa, index);
+ ForkJoinTask<?> t = (ForkJoinTask<?>)QA.get(a, index);
if (t == null)
break;
else if (t == task) {
- if (QA.compareAndSet(wa, index, t, null)) {
+ if (QA.compareAndSet(a, index, t, null)) {
top = ns; // safely shift down
for (int j = i; j != ns; ++j) {
ForkJoinTask<?> f;
int pindex = (j + 1) & m;
- f = (ForkJoinTask<?>)QA.get(wa, pindex);
- QA.setVolatile(wa, pindex, null);
+ f = (ForkJoinTask<?>)QA.get(a, pindex);
+ QA.setVolatile(a, pindex, null);
int jindex = j & m;
- QA.setRelease(wa, jindex, f);
+ QA.setRelease(a, jindex, f);
}
VarHandle.releaseFence();
t.doExec();
@@ -1022,43 +1068,52 @@
}
/**
- * Tries to steal and run tasks within the target's
- * computation until done, not found, or limit exceeded.
+ * Tries to pop and run tasks within the target's computation
+ * until done, not found, or limit exceeded.
*
* @param task root of CountedCompleter computation
* @param limit max runs, or zero for no limit
+ * @param shared true if must lock to extract task
* @return task status on exit
*/
- final int localHelpCC(CountedCompleter<?> task, int limit) {
+ final int helpCC(CountedCompleter<?> task, int limit, boolean shared) {
int status = 0;
if (task != null && (status = task.status) >= 0) {
- for (;;) {
- boolean help = false;
- int b = base, s = top, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & (s - 1);
- ForkJoinTask<?> o = (ForkJoinTask<?>)
- QA.get(a, index);
- if (o instanceof CountedCompleter) {
- CountedCompleter<?> t = (CountedCompleter<?>)o;
- for (CountedCompleter<?> f = t;;) {
- if (f != task) {
- if ((f = f.completer) == null) // try parent
- break;
+ int s, k, cap; ForkJoinTask<?>[] a;
+ while ((a = array) != null && (cap = a.length) > 0 &&
+ (s = top) - base > 0) {
+ CountedCompleter<?> v = null;
+ ForkJoinTask<?> o = a[k = (cap - 1) & (s - 1)];
+ if (o instanceof CountedCompleter) {
+ CountedCompleter<?> t = (CountedCompleter<?>)o;
+ for (CountedCompleter<?> f = t;;) {
+ if (f != task) {
+ if ((f = f.completer) == null)
+ break;
+ }
+ else if (shared) {
+ if (tryLockPhase()) {
+ if (top == s && array == a &&
+ QA.compareAndSet(a, k, t, null)) {
+ top = s - 1;
+ v = t;
+ }
+ releasePhaseLock();
}
- else {
- if (QA.compareAndSet(a, index, t, null)) {
- top = s - 1;
- VarHandle.releaseFence();
- t.doExec();
- help = true;
- }
- break;
+ break;
+ }
+ else {
+ if (QA.compareAndSet(a, k, t, null)) {
+ top = s - 1;
+ v = t;
}
+ break;
}
}
}
- if ((status = task.status) < 0 || !help ||
+ if (v != null)
+ v.doExec();
+ if ((status = task.status) < 0 || v == null ||
(limit != 0 && --limit == 0))
break;
}
@@ -1066,79 +1121,31 @@
return status;
}
- // Operations on shared queues
-
/**
- * Tries to lock shared queue by CASing phase field.
- */
- final boolean tryLockSharedQueue() {
- return PHASE.compareAndSet(this, 0, QLOCK);
- }
-
- /**
- * Shared version of tryUnpush.
+ * Tries to poll and run AsynchronousCompletionTasks until
+ * none found or blocker is released
+ *
+ * @param blocker the blocker
*/
- final boolean trySharedUnpush(ForkJoinTask<?> task) {
- boolean popped = false;
- int s = top - 1, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && (al = a.length) > 0) {
- int index = (al - 1) & s;
- ForkJoinTask<?> t = (ForkJoinTask<?>) QA.get(a, index);
- if (t == task &&
- PHASE.compareAndSet(this, 0, QLOCK)) {
- if (top == s + 1 && array == a &&
- QA.compareAndSet(a, index, task, null)) {
- popped = true;
- top = s;
+ final void helpAsyncBlocker(ManagedBlocker blocker) {
+ if (blocker != null) {
+ int b, k, cap; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
+ while ((a = array) != null && (cap = a.length) > 0 &&
+ top - (b = base) > 0) {
+ t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
+ if (blocker.isReleasable())
+ break;
+ else if (base == b++ && t != null) {
+ if (!(t instanceof CompletableFuture.
+ AsynchronousCompletionTask))
+ break;
+ else if (QA.compareAndSet(a, k, t, null)) {
+ BASE.setOpaque(this, b);
+ t.doExec();
+ }
}
- PHASE.setRelease(this, 0);
}
}
- return popped;
- }
-
- /**
- * Shared version of localHelpCC.
- */
- final int sharedHelpCC(CountedCompleter<?> task, int limit) {
- int status = 0;
- if (task != null && (status = task.status) >= 0) {
- for (;;) {
- boolean help = false;
- int b = base, s = top, al; ForkJoinTask<?>[] a;
- if ((a = array) != null && b != s && (al = a.length) > 0) {
- int index = (al - 1) & (s - 1);
- ForkJoinTask<?> o = (ForkJoinTask<?>)
- QA.get(a, index);
- if (o instanceof CountedCompleter) {
- CountedCompleter<?> t = (CountedCompleter<?>)o;
- for (CountedCompleter<?> f = t;;) {
- if (f != task) {
- if ((f = f.completer) == null)
- break;
- }
- else {
- if (PHASE.compareAndSet(this, 0, QLOCK)) {
- if (top == s && array == a &&
- QA.compareAndSet(a, index, t, null)) {
- help = true;
- top = s - 1;
- }
- PHASE.setRelease(this, 0);
- if (help)
- t.doExec();
- }
- break;
- }
- }
- }
- }
- if ((status = task.status) < 0 || !help ||
- (limit != 0 && --limit == 0))
- break;
- }
- }
- return status;
}
/**
@@ -1153,13 +1160,17 @@
}
// VarHandle mechanics.
- private static final VarHandle PHASE;
+ static final VarHandle PHASE;
+ static final VarHandle BASE;
+ static final VarHandle TOP;
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
PHASE = l.findVarHandle(WorkQueue.class, "phase", int.class);
+ BASE = l.findVarHandle(WorkQueue.class, "base", int.class);
+ TOP = l.findVarHandle(WorkQueue.class, "top", int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -1356,39 +1367,37 @@
wt.setDaemon(true); // configure thread
if ((handler = ueh) != null)
wt.setUncaughtExceptionHandler(handler);
+ int tid = 0; // for thread name
+ int idbits = mode & FIFO;
+ String prefix = workerNamePrefix;
WorkQueue w = new WorkQueue(this, wt);
- int tid = 0; // for thread name
- int fifo = mode & FIFO;
- String prefix = workerNamePrefix;
if (prefix != null) {
synchronized (prefix) {
WorkQueue[] ws = workQueues; int n;
int s = indexSeed += SEED_INCREMENT;
+ idbits |= (s & ~(SMASK | FIFO | DORMANT));
if (ws != null && (n = ws.length) > 1) {
int m = n - 1;
- tid = s & m;
- int i = m & ((s << 1) | 1); // odd-numbered indices
+ tid = m & ((s << 1) | 1); // odd-numbered indices
for (int probes = n >>> 1;;) { // find empty slot
WorkQueue q;
- if ((q = ws[i]) == null || q.phase == QUIET)
+ if ((q = ws[tid]) == null || q.phase == QUIET)
break;
else if (--probes == 0) {
- i = n | 1; // resize below
+ tid = n | 1; // resize below
break;
}
else
- i = (i + 2) & m;
+ tid = (tid + 2) & m;
}
+ w.phase = w.id = tid | idbits; // now publishable
- int id = i | fifo | (s & ~(SMASK | FIFO | DORMANT));
- w.phase = w.id = id; // now publishable
-
- if (i < n)
- ws[i] = w;
+ if (tid < n)
+ ws[tid] = w;
else { // expand array
int an = n << 1;
WorkQueue[] as = new WorkQueue[an];
- as[i] = w;
+ as[tid] = w;
int am = an - 1;
for (int j = 0; j < n; ++j) {
WorkQueue v; // copy external queue
@@ -1421,14 +1430,14 @@
int phase = 0;
if (wt != null && (w = wt.workQueue) != null) {
Object lock = workerNamePrefix;
+ int wid = w.id;
long ns = (long)w.nsteals & 0xffffffffL;
- int idx = w.id & SMASK;
if (lock != null) {
- WorkQueue[] ws; // remove index from array
synchronized (lock) {
- if ((ws = workQueues) != null && ws.length > idx &&
- ws[idx] == w)
- ws[idx] = null;
+ WorkQueue[] ws; int n, i; // remove index from array
+ if ((ws = workQueues) != null && (n = ws.length) > 0 &&
+ ws[i = wid & (n - 1)] == w)
+ ws[i] = null;
stealCount += ns;
}
}
@@ -1480,7 +1489,7 @@
Thread vt = v.owner;
if (sp == vp && CTL.compareAndSet(this, c, nc)) {
v.phase = np;
- if (v.source < 0)
+ if (vt != null && v.source < 0)
LockSupport.unpark(vt);
break;
}
@@ -1521,7 +1530,7 @@
long nc = ((long)v.stackPred & SP_MASK) | uc;
if (vp == sp && CTL.compareAndSet(this, c, nc)) {
v.phase = np;
- if (v.source < 0)
+ if (vt != null && v.source < 0)
LockSupport.unpark(vt);
return (wp < 0) ? -1 : 1;
}
@@ -1578,101 +1587,88 @@
* See above for explanation.
*/
final void runWorker(WorkQueue w) {
- WorkQueue[] ws;
- w.growArray(); // allocate queue
- int r = w.id ^ ThreadLocalRandom.nextSecondarySeed();
- if (r == 0) // initial nonzero seed
- r = 1;
- int lastSignalId = 0; // avoid unneeded signals
- while ((ws = workQueues) != null) {
- boolean nonempty = false; // scan
- for (int n = ws.length, j = n, m = n - 1; j > 0; --j) {
- WorkQueue q; int i, b, al; ForkJoinTask<?>[] a;
- if ((i = r & m) >= 0 && i < n && // always true
- (q = ws[i]) != null && (b = q.base) - q.top < 0 &&
- (a = q.array) != null && (al = a.length) > 0) {
- int qid = q.id; // (never zero)
- int index = (al - 1) & b;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.getAcquire(a, index);
- if (t != null && b++ == q.base &&
- QA.compareAndSet(a, index, t, null)) {
- if ((q.base = b) - q.top < 0 && qid != lastSignalId)
- signalWork(); // propagate signal
- w.source = lastSignalId = qid;
- t.doExec();
- if ((w.id & FIFO) != 0) // run remaining locals
- w.localPollAndExec(POLL_LIMIT);
- else
- w.localPopAndExec(POLL_LIMIT);
- ForkJoinWorkerThread thread = w.owner;
- ++w.nsteals;
- w.source = 0; // now idle
- if (thread != null)
- thread.afterTopLevelExec();
- }
- nonempty = true;
- }
- else if (nonempty)
- break;
- else
- ++r;
+ int r = (w.id ^ ThreadLocalRandom.nextSecondarySeed()) | FIFO; // rng
+ w.array = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; // initialize
+ for (;;) {
+ int phase;
+ if (scan(w, r)) { // scan until apparently empty
+ r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // move (xorshift)
}
-
- if (nonempty) { // move (xorshift)
- r ^= r << 13; r ^= r >>> 17; r ^= r << 5;
+ else if ((phase = w.phase) >= 0) { // enqueue, then rescan
+ long np = (w.phase = (phase + SS_SEQ) | UNSIGNALLED) & SP_MASK;
+ long c, nc;
+ do {
+ w.stackPred = (int)(c = ctl);
+ nc = ((c - RC_UNIT) & UC_MASK) | np;
+ } while (!CTL.weakCompareAndSet(this, c, nc));
}
- else {
- int phase;
- lastSignalId = 0; // clear for next scan
- if ((phase = w.phase) >= 0) { // enqueue
- int np = w.phase = (phase + SS_SEQ) | UNSIGNALLED;
- long c, nc;
- do {
- w.stackPred = (int)(c = ctl);
- nc = ((c - RC_UNIT) & UC_MASK) | (SP_MASK & np);
- } while (!CTL.weakCompareAndSet(this, c, nc));
- }
- else { // already queued
- int pred = w.stackPred;
- w.source = DORMANT; // enable signal
- for (int steps = 0;;) {
- int md, rc; long c;
- if (w.phase >= 0) {
- w.source = 0;
- break;
- }
- else if ((md = mode) < 0) // shutting down
- return;
- else if ((rc = ((md & SMASK) + // possibly quiescent
- (int)((c = ctl) >> RC_SHIFT))) <= 0 &&
- (md & SHUTDOWN) != 0 &&
- tryTerminate(false, false))
- return; // help terminate
- else if ((++steps & 1) == 0)
- Thread.interrupted(); // clear between parks
- else if (rc <= 0 && pred != 0 && phase == (int)c) {
- long d = keepAlive + System.currentTimeMillis();
- LockSupport.parkUntil(this, d);
- if (ctl == c &&
- d - System.currentTimeMillis() <= TIMEOUT_SLOP) {
- long nc = ((UC_MASK & (c - TC_UNIT)) |
- (SP_MASK & pred));
- if (CTL.compareAndSet(this, c, nc)) {
- w.phase = QUIET;
- return; // drop on timeout
- }
- }
- }
- else
- LockSupport.park(this);
+ else { // already queued
+ int pred = w.stackPred;
+ Thread.interrupted(); // clear before park
+ w.source = DORMANT; // enable signal
+ long c = ctl;
+ int md = mode, rc = (md & SMASK) + (int)(c >> RC_SHIFT);
+ if (md < 0) // terminating
+ break;
+ else if (rc <= 0 && (md & SHUTDOWN) != 0 &&
+ tryTerminate(false, false))
+ break; // quiescent shutdown
+ else if (rc <= 0 && pred != 0 && phase == (int)c) {
+ long nc = (UC_MASK & (c - TC_UNIT)) | (SP_MASK & pred);
+ long d = keepAlive + System.currentTimeMillis();
+ LockSupport.parkUntil(this, d);
+ if (ctl == c && // drop on timeout if all idle
+ d - System.currentTimeMillis() <= TIMEOUT_SLOP &&
+ CTL.compareAndSet(this, c, nc)) {
+ w.phase = QUIET;
+ break;
}
}
+ else if (w.phase < 0)
+ LockSupport.park(this); // OK if spuriously woken
+ w.source = 0; // disable signal
}
}
}
/**
+ * Scans for and if found executes one or more top-level tasks from a queue.
+ *
+ * @return true if found an apparently non-empty queue, and
+ * possibly ran task(s).
+ */
+ private boolean scan(WorkQueue w, int r) {
+ WorkQueue[] ws; int n;
+ if ((ws = workQueues) != null && (n = ws.length) > 0 && w != null) {
+ for (int m = n - 1, j = r & m;;) {
+ WorkQueue q; int b;
+ if ((q = ws[j]) != null && q.top != (b = q.base)) {
+ int qid = q.id;
+ ForkJoinTask<?>[] a; int cap, k; ForkJoinTask<?> t;
+ if ((a = q.array) != null && (cap = a.length) > 0) {
+ t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
+ if (q.base == b++ && t != null &&
+ QA.compareAndSet(a, k, t, null)) {
+ q.base = b;
+ w.source = qid;
+ if (q.top - b > 0)
+ signalWork();
+ w.topLevelExec(t, q, // random fairness bound
+ r & ((n << TOP_BOUND_SHIFT) - 1));
+ }
+ }
+ return true;
+ }
+ else if (--n > 0)
+ j = (j + 1) & m;
+ else
+ break;
+ }
+ }
+ return false;
+ }
+
+ /**
* Helps and/or blocks until the given task is done or timeout.
* First tries locally helping, then scans other queues for a task
* produced by one of w's stealers; compensating and blocking if
@@ -1685,42 +1681,44 @@
*/
final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
int s = 0;
+ int seed = ThreadLocalRandom.nextSecondarySeed();
if (w != null && task != null &&
(!(task instanceof CountedCompleter) ||
- (s = w.localHelpCC((CountedCompleter<?>)task, 0)) >= 0)) {
+ (s = w.helpCC((CountedCompleter<?>)task, 0, false)) >= 0)) {
w.tryRemoveAndExec(task);
int src = w.source, id = w.id;
+ int r = (seed >>> 16) | 1, step = (seed & ~1) | 2;
s = task.status;
while (s >= 0) {
WorkQueue[] ws;
- boolean nonempty = false;
- int r = ThreadLocalRandom.nextSecondarySeed() | 1; // odd indices
- if ((ws = workQueues) != null) { // scan for matching id
- for (int n = ws.length, m = n - 1, j = -n; j < n; j += 2) {
- WorkQueue q; int i, b, al; ForkJoinTask<?>[] a;
- if ((i = (r + j) & m) >= 0 && i < n &&
- (q = ws[i]) != null && q.source == id &&
- (b = q.base) - q.top < 0 &&
- (a = q.array) != null && (al = a.length) > 0) {
- int qid = q.id;
- int index = (al - 1) & b;
+ int n = (ws = workQueues) == null ? 0 : ws.length, m = n - 1;
+ while (n > 0) {
+ WorkQueue q; int b;
+ if ((q = ws[r & m]) != null && q.source == id &&
+ q.top != (b = q.base)) {
+ ForkJoinTask<?>[] a; int cap, k;
+ int qid = q.id;
+ if ((a = q.array) != null && (cap = a.length) > 0) {
ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.getAcquire(a, index);
- if (t != null && b++ == q.base && id == q.source &&
- QA.compareAndSet(a, index, t, null)) {
+ QA.getAcquire(a, k = (cap - 1) & b);
+ if (q.source == id && q.base == b++ &&
+ t != null && QA.compareAndSet(a, k, t, null)) {
q.base = b;
w.source = qid;
t.doExec();
w.source = src;
}
- nonempty = true;
- break;
}
+ break;
+ }
+ else {
+ r += step;
+ --n;
}
}
if ((s = task.status) < 0)
break;
- else if (!nonempty) {
+ else if (n == 0) { // empty scan
long ms, ns; int block;
if (deadline == 0L)
ms = 0L; // untimed
@@ -1745,44 +1743,44 @@
* find tasks either.
*/
final void helpQuiescePool(WorkQueue w) {
- int prevSrc = w.source, fifo = w.id & FIFO;
+ int prevSrc = w.source;
+ int seed = ThreadLocalRandom.nextSecondarySeed();
+ int r = seed >>> 16, step = r | 1;
for (int source = prevSrc, released = -1;;) { // -1 until known
- WorkQueue[] ws;
- if (fifo != 0)
- w.localPollAndExec(0);
- else
- w.localPopAndExec(0);
- if (released == -1 && w.phase >= 0)
+ ForkJoinTask<?> localTask; WorkQueue[] ws;
+ while ((localTask = w.nextLocalTask()) != null)
+ localTask.doExec();
+ if (w.phase >= 0 && released == -1)
released = 1;
boolean quiet = true, empty = true;
- int r = ThreadLocalRandom.nextSecondarySeed();
- if ((ws = workQueues) != null) {
- for (int n = ws.length, j = n, m = n - 1; j > 0; --j) {
- WorkQueue q; int i, b, al; ForkJoinTask<?>[] a;
- if ((i = (r - j) & m) >= 0 && i < n && (q = ws[i]) != null) {
- if ((b = q.base) - q.top < 0 &&
- (a = q.array) != null && (al = a.length) > 0) {
- int qid = q.id;
+ int n = (ws = workQueues) == null ? 0 : ws.length;
+ for (int m = n - 1; n > 0; r += step, --n) {
+ WorkQueue q; int b;
+ if ((q = ws[r & m]) != null) {
+ int qs = q.source;
+ if (q.top != (b = q.base)) {
+ quiet = empty = false;
+ ForkJoinTask<?>[] a; int cap, k;
+ int qid = q.id;
+ if ((a = q.array) != null && (cap = a.length) > 0) {
if (released == 0) { // increment
released = 1;
CTL.getAndAdd(this, RC_UNIT);
}
- int index = (al - 1) & b;
ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.getAcquire(a, index);
- if (t != null && b++ == q.base &&
- QA.compareAndSet(a, index, t, null)) {
+ QA.getAcquire(a, k = (cap - 1) & b);
+ if (q.base == b++ && t != null &&
+ QA.compareAndSet(a, k, t, null)) {
q.base = b;
- w.source = source = q.id;
+ w.source = qid;
t.doExec();
w.source = source = prevSrc;
}
- quiet = empty = false;
- break;
}
- else if ((q.source & QUIET) == 0)
- quiet = false;
+ break;
}
+ else if ((qs & QUIET) == 0)
+ quiet = false;
}
}
if (quiet) {
@@ -1824,28 +1822,24 @@
origin = r & m;
step = h | 1;
}
- for (int k = origin, oldSum = 0, checkSum = 0;;) {
- WorkQueue q; int b, al; ForkJoinTask<?>[] a;
- if ((q = ws[k]) != null) {
- checkSum += b = q.base;
- if (b - q.top < 0 &&
- (a = q.array) != null && (al = a.length) > 0) {
- int index = (al - 1) & b;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.getAcquire(a, index);
- if (t != null && b++ == q.base &&
- QA.compareAndSet(a, index, t, null)) {
- q.base = b;
+ boolean nonempty = false;
+ for (int i = origin, oldSum = 0, checkSum = 0;;) {
+ WorkQueue q;
+ if ((q = ws[i]) != null) {
+ int b; ForkJoinTask<?> t;
+ if (q.top - (b = q.base) > 0) {
+ nonempty = true;
+ if ((t = q.poll()) != null)
return t;
- }
- else
- break; // restart
}
+ else
+ checkSum += b + q.id;
}
- if ((k = (k + step) & m) == origin) {
- if (oldSum == (oldSum = checkSum))
+ if ((i = (i + step) & m) == origin) {
+ if (!nonempty && oldSum == (oldSum = checkSum))
break rescan;
checkSum = 0;
+ nonempty = false;
}
}
}
@@ -1859,11 +1853,9 @@
*/
final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
ForkJoinTask<?> t;
- if (w != null &&
- (t = (w.id & FIFO) != 0 ? w.poll() : w.pop()) != null)
- return t;
- else
- return pollScan(false);
+ if (w == null || (t = w.nextLocalTask()) == null)
+ t = pollScan(false);
+ return t;
}
// External operations
@@ -1881,64 +1873,35 @@
r = ThreadLocalRandom.getProbe();
}
for (;;) {
+ WorkQueue q;
int md = mode, n;
WorkQueue[] ws = workQueues;
if ((md & SHUTDOWN) != 0 || ws == null || (n = ws.length) <= 0)
throw new RejectedExecutionException();
- else {
- WorkQueue q;
- boolean push = false, grow = false;
- if ((q = ws[(n - 1) & r & SQMASK]) == null) {
- Object lock = workerNamePrefix;
- int qid = (r | QUIET) & ~(FIFO | OWNED);
- q = new WorkQueue(this, null);
- q.id = qid;
- q.source = QUIET;
- q.phase = QLOCK; // lock queue
- if (lock != null) {
- synchronized (lock) { // lock pool to install
- int i;
- if ((ws = workQueues) != null &&
- (n = ws.length) > 0 &&
- ws[i = qid & (n - 1) & SQMASK] == null) {
- ws[i] = q;
- push = grow = true;
- }
- }
+ else if ((q = ws[(n - 1) & r & SQMASK]) == null) { // add queue
+ int qid = (r | QUIET) & ~(FIFO | OWNED);
+ Object lock = workerNamePrefix;
+ ForkJoinTask<?>[] qa =
+ new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
+ q = new WorkQueue(this, null);
+ q.array = qa;
+ q.id = qid;
+ q.source = QUIET;
+ if (lock != null) { // unless disabled, lock pool to install
+ synchronized (lock) {
+ WorkQueue[] vs; int i, vn;
+ if ((vs = workQueues) != null && (vn = vs.length) > 0 &&
+ vs[i = qid & (vn - 1) & SQMASK] == null)
+ vs[i] = q; // else another thread already installed
}
}
- else if (q.tryLockSharedQueue()) {
- int b = q.base, s = q.top, al, d; ForkJoinTask<?>[] a;
- if ((a = q.array) != null && (al = a.length) > 0 &&
- al - 1 + (d = b - s) > 0) {
- a[(al - 1) & s] = task;
- q.top = s + 1; // relaxed writes OK here
- q.phase = 0;
- if (d < 0 && q.base - s < -1)
- break; // no signal needed
- }
- else
- grow = true;
- push = true;
- }
- if (push) {
- if (grow) {
- try {
- q.growArray();
- int s = q.top, al; ForkJoinTask<?>[] a;
- if ((a = q.array) != null && (al = a.length) > 0) {
- a[(al - 1) & s] = task;
- q.top = s + 1;
- }
- } finally {
- q.phase = 0;
- }
- }
+ }
+ else if (!q.tryLockPhase()) // move if busy
+ r = ThreadLocalRandom.advanceProbe(r);
+ else {
+ if (q.lockedPush(task))
signalWork();
- break;
- }
- else // move if busy
- r = ThreadLocalRandom.advanceProbe(r);
+ return;
}
}
}
@@ -1980,7 +1943,7 @@
return ((ws = workQueues) != null &&
(n = ws.length) > 0 &&
(w = ws[(n - 1) & r & SQMASK]) != null &&
- w.trySharedUnpush(task));
+ w.tryLockedUnpush(task));
}
/**
@@ -1991,7 +1954,7 @@
WorkQueue[] ws; WorkQueue w; int n;
return ((ws = workQueues) != null && (n = ws.length) > 0 &&
(w = ws[(n - 1) & r & SQMASK]) != null) ?
- w.sharedHelpCC(task, maxTasks) : 0;
+ w.helpCC(task, maxTasks, true) : 0;
}
/**
@@ -2006,7 +1969,7 @@
*/
final int helpComplete(WorkQueue w, CountedCompleter<?> task,
int maxTasks) {
- return (w == null) ? 0 : w.localHelpCC(task, maxTasks);
+ return (w == null) ? 0 : w.helpCC(task, maxTasks, false);
}
/**
@@ -2097,15 +2060,18 @@
if ((md & SMASK) + (int)(checkSum >> RC_SHIFT) > 0)
running = true;
else if (ws != null) {
- WorkQueue w; int b;
+ WorkQueue w;
for (int i = 0; i < ws.length; ++i) {
if ((w = ws[i]) != null) {
- checkSum += (b = w.base) + w.id;
+ int s = w.source, p = w.phase;
+ int d = w.id, b = w.base;
if (b != w.top ||
- ((i & 1) == 1 && w.source >= 0)) {
+ ((d & 1) == 1 && (s >= 0 || p >= 0))) {
running = true;
- break;
+ break; // working, scanning, or have work
}
+ checkSum += (((long)s << 48) + ((long)p << 32) +
+ ((long)b << 16) + (long)d);
}
}
}
@@ -2136,7 +2102,7 @@
} catch (Throwable ignore) {
}
}
- checkSum += w.base + w.id;
+ checkSum += ((long)w.phase << 32) + w.base;
}
}
}
@@ -2629,8 +2595,9 @@
* @return the number of worker threads
*/
public int getRunningThreadCount() {
+ WorkQueue[] ws; WorkQueue w;
+ VarHandle.acquireFence();
int rc = 0;
- WorkQueue[] ws; WorkQueue w;
if ((ws = workQueues) != null) {
for (int i = 1; i < ws.length; i += 2) {
if ((w = ws[i]) != null && w.isApparentlyUnblocked())
@@ -2678,7 +2645,7 @@
if ((ws = workQueues) != null) {
for (int i = 1; i < ws.length; i += 2) {
if ((v = ws[i]) != null) {
- if ((v.source & QUIET) == 0)
+ if (v.source > 0)
return false;
--tc;
}
@@ -2724,8 +2691,9 @@
* @return the number of queued tasks
*/
public long getQueuedTaskCount() {
- long count = 0;
WorkQueue[] ws; WorkQueue w;
+ VarHandle.acquireFence();
+ int count = 0;
if ((ws = workQueues) != null) {
for (int i = 1; i < ws.length; i += 2) {
if ((w = ws[i]) != null)
@@ -2743,8 +2711,9 @@
* @return the number of queued submissions
*/
public int getQueuedSubmissionCount() {
+ WorkQueue[] ws; WorkQueue w;
+ VarHandle.acquireFence();
int count = 0;
- WorkQueue[] ws; WorkQueue w;
if ((ws = workQueues) != null) {
for (int i = 0; i < ws.length; i += 2) {
if ((w = ws[i]) != null)
@@ -2762,6 +2731,7 @@
*/
public boolean hasQueuedSubmissions() {
WorkQueue[] ws; WorkQueue w;
+ VarHandle.acquireFence();
if ((ws = workQueues) != null) {
for (int i = 0; i < ws.length; i += 2) {
if ((w = ws[i]) != null && !w.isEmpty())
@@ -2800,8 +2770,9 @@
* @return the number of elements transferred
*/
protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
+ WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
+ VarHandle.acquireFence();
int count = 0;
- WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
if ((ws = workQueues) != null) {
for (int i = 0; i < ws.length; ++i) {
if ((w = ws[i]) != null) {
@@ -2824,8 +2795,10 @@
*/
public String toString() {
// Use a single pass through workQueues to collect counts
+ int md = mode; // read volatile fields first
+ long c = ctl;
+ long st = stealCount;
long qt = 0L, qs = 0L; int rc = 0;
- long st = stealCount;
WorkQueue[] ws; WorkQueue w;
if ((ws = workQueues) != null) {
for (int i = 0; i < ws.length; ++i) {
@@ -2843,9 +2816,7 @@
}
}
- int md = mode;
int pc = (md & SMASK);
- long c = ctl;
int tc = pc + (short)(c >>> TC_SHIFT);
int ac = pc + (int)(c >> RC_SHIFT);
if (ac < 0) // ignore transient negative
@@ -3131,6 +3102,7 @@
*/
public static void managedBlock(ManagedBlocker blocker)
throws InterruptedException {
+ if (blocker == null) throw new NullPointerException();
ForkJoinPool p;
ForkJoinWorkerThread wt;
WorkQueue w;
@@ -3163,7 +3135,7 @@
* available or blocker is released.
*/
static void helpAsyncBlocker(Executor e, ManagedBlocker blocker) {
- if (blocker != null && (e instanceof ForkJoinPool)) {
+ if (e instanceof ForkJoinPool) {
WorkQueue w; ForkJoinWorkerThread wt; WorkQueue[] ws; int r, n;
ForkJoinPool p = (ForkJoinPool)e;
Thread thread = Thread.currentThread();
@@ -3175,34 +3147,8 @@
w = ws[(n - 1) & r & SQMASK];
else
w = null;
- if (w != null) {
- for (;;) {
- int b = w.base, s = w.top, d, al; ForkJoinTask<?>[] a;
- if ((a = w.array) != null && (d = b - s) < 0 &&
- (al = a.length) > 0) {
- int index = (al - 1) & b;
- ForkJoinTask<?> t = (ForkJoinTask<?>)
- QA.getAcquire(a, index);
- if (blocker.isReleasable())
- break;
- else if (b++ == w.base) {
- if (t == null) {
- if (d == -1)
- break;
- }
- else if (!(t instanceof CompletableFuture.
- AsynchronousCompletionTask))
- break;
- else if (QA.compareAndSet(a, index, t, null)) {
- w.base = b;
- t.doExec();
- }
- }
- }
- else
- break;
- }
- }
+ if (w != null)
+ w.helpAsyncBlocker(blocker);
}
}
@@ -3221,7 +3167,7 @@
// VarHandle mechanics
private static final VarHandle CTL;
private static final VarHandle MODE;
- private static final VarHandle QA;
+ static final VarHandle QA;
static {
try {
@@ -3230,7 +3176,7 @@
MODE = l.findVarHandle(ForkJoinPool.class, "mode", int.class);
QA = MethodHandles.arrayElementVarHandle(ForkJoinTask[].class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java Tue Apr 10 13:58:47 2018 -0700
@@ -1540,7 +1540,7 @@
MethodHandles.Lookup l = MethodHandles.lookup();
STATUS = l.findVarHandle(ForkJoinTask.class, "status", int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
--- a/src/java.base/share/classes/java/util/concurrent/FutureTask.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/FutureTask.java Tue Apr 10 13:58:47 2018 -0700
@@ -526,7 +526,7 @@
RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java Tue Apr 10 13:58:47 2018 -0700
@@ -1739,7 +1739,7 @@
NEXT = l.findVarHandle(Node.class, "next", Node.class);
WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/Phaser.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/Phaser.java Tue Apr 10 13:58:47 2018 -0700
@@ -1137,7 +1137,7 @@
MethodHandles.Lookup l = MethodHandles.lookup();
STATE = l.findVarHandle(Phaser.class, "state", long.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java Tue Apr 10 13:58:47 2018 -0700
@@ -1014,7 +1014,7 @@
"allocationSpinLock",
int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
--- a/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java Tue Apr 10 13:58:47 2018 -0700
@@ -1096,7 +1096,7 @@
if (cap > 0) {
boolean added;
if (n >= cap && cap < maxCapacity) // resize
- added = growAndoffer(item, a, t);
+ added = growAndOffer(item, a, t);
else if (n >= cap || unowned) // need volatile CAS
added = QA.compareAndSet(a, i, null, item);
else { // can use release mode
@@ -1115,7 +1115,7 @@
* Tries to expand buffer and add item, returning true on
* success. Currently fails only if out of memory.
*/
- final boolean growAndoffer(T item, Object[] a, int t) {
+ final boolean growAndOffer(T item, Object[] a, int t) {
int cap = 0, newCap = 0;
Object[] newArray = null;
if (a != null && (cap = a.length) > 0 && (newCap = cap << 1) > 0) {
@@ -1466,7 +1466,7 @@
long.class);
QA = MethodHandles.arrayElementVarHandle(Object[].class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java Tue Apr 10 13:58:47 2018 -0700
@@ -293,7 +293,7 @@
SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -516,7 +516,7 @@
MethodHandles.Lookup l = MethodHandles.lookup();
SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -583,7 +583,7 @@
QITEM = l.findVarHandle(QNode.class, "item", Object.class);
QNEXT = l.findVarHandle(QNode.class, "next", QNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -830,7 +830,7 @@
QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe",
QNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java Tue Apr 10 13:58:47 2018 -0700
@@ -56,7 +56,7 @@
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicBoolean.class, "value", int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java Tue Apr 10 13:58:47 2018 -0700
@@ -199,7 +199,7 @@
PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair",
Pair.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java Tue Apr 10 13:58:47 2018 -0700
@@ -56,7 +56,7 @@
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java Tue Apr 10 13:58:47 2018 -0700
@@ -199,7 +199,7 @@
PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
Pair.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
--- a/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java Tue Apr 10 13:58:47 2018 -0700
@@ -144,7 +144,7 @@
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(Cell.class, "value", long.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -396,13 +396,13 @@
try {
return MethodHandles.privateLookupIn(Thread.class, MethodHandles.lookup());
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}});
THREAD_PROBE = l.findVarHandle(Thread.class,
"threadLocalRandomProbe", int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Tue Apr 10 13:58:47 2018 -0700
@@ -1830,7 +1830,7 @@
HEAD = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "head", Node.class);
TAIL = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "tail", Node.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Tue Apr 10 13:58:47 2018 -0700
@@ -555,7 +555,7 @@
THREAD = l.findVarHandle(Node.class, "thread", Thread.class);
WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
@@ -2308,7 +2308,7 @@
HEAD = l.findVarHandle(AbstractQueuedSynchronizer.class, "head", Node.class);
TAIL = l.findVarHandle(AbstractQueuedSynchronizer.class, "tail", Node.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
// Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java Tue Apr 10 13:58:47 2018 -0700
@@ -1614,7 +1614,7 @@
WNEXT = l.findVarHandle(WNode.class, "next", WNode.class);
WCOWAIT = l.findVarHandle(WNode.class, "cowait", WNode.class);
} catch (ReflectiveOperationException e) {
- throw new Error(e);
+ throw new ExceptionInInitializerError(e);
}
}
}
--- a/src/java.base/share/classes/java/util/regex/Pattern.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/regex/Pattern.java Tue Apr 10 13:58:47 2018 -0700
@@ -5809,10 +5809,21 @@
static final Node lastAccept = new LastNode();
/**
- * Creates a predicate which can be used to match a string.
+ * Creates a predicate that tests if this pattern is found in a given input
+ * string.
*
- * @return The predicate which can be used for matching on a string
+ * @apiNote
+ * This method creates a predicate that behaves as if it creates a matcher
+ * from the input sequence and then calls {@code find}, for example a
+ * predicate of the form:
+ * <pre>{@code
+ * s -> matcher(s).find();
+ * }</pre>
+ *
+ * @return The predicate which can be used for finding a match on a
+ * subsequence of a string
* @since 1.8
+ * @see Matcher#find
*/
public Predicate<String> asPredicate() {
return s -> matcher(s).find();
--- a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java Tue Apr 10 13:58:47 2018 -0700
@@ -39,6 +39,8 @@
extends Charset
implements HistoricallyNamedCharset
{
+ public static final ISO_8859_1 INSTANCE = new ISO_8859_1();
+
public ISO_8859_1() {
super("ISO-8859-1", StandardCharsets.aliases_ISO_8859_1());
}
--- a/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template Tue Apr 10 13:58:47 2018 -0700
@@ -83,9 +83,9 @@
Map<String,Charset> map = cache;
if (map == null) {
map = new Cache();
- map.put("utf-8", java.nio.charset.StandardCharsets.UTF_8);
- map.put("iso-8859-1", java.nio.charset.StandardCharsets.ISO_8859_1);
- map.put("us-ascii", java.nio.charset.StandardCharsets.US_ASCII);
+ map.put("utf-8", UTF_8.INSTANCE);
+ map.put("iso-8859-1", ISO_8859_1.INSTANCE);
+ map.put("us-ascii", US_ASCII.INSTANCE);
map.put("utf-16", java.nio.charset.StandardCharsets.UTF_16);
map.put("utf-16be", java.nio.charset.StandardCharsets.UTF_16BE);
map.put("utf-16le", java.nio.charset.StandardCharsets.UTF_16LE);
@@ -122,15 +122,19 @@
private Charset lookup(String charsetName) {
init();
- // By checking these built-ins we can avoid initializing Aliases and
- // Classes eagerly during bootstrap
+ // By checking these built-ins we can avoid initializing Aliases,
+ // Classes and Cache eagerly during bootstrap.
+ //
+ // Initialization of java.nio.charset.StandardCharsets should be
+ // avoided here to minimize time spent in System.initPhase1, as it
+ // may delay initialization of performance critical VM subsystems.
String csn;
if (charsetName.equals("UTF-8")) {
- return java.nio.charset.StandardCharsets.UTF_8;
+ return UTF_8.INSTANCE;
} else if (charsetName.equals("US-ASCII")) {
- return java.nio.charset.StandardCharsets.US_ASCII;
+ return US_ASCII.INSTANCE;
} else if (charsetName.equals("ISO-8859-1")) {
- return java.nio.charset.StandardCharsets.ISO_8859_1;
+ return ISO_8859_1.INSTANCE;
} else {
csn = canonicalize(toLower(charsetName));
}
--- a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java Tue Apr 10 13:58:47 2018 -0700
@@ -36,6 +36,8 @@
extends Charset
implements HistoricallyNamedCharset
{
+ public static final US_ASCII INSTANCE = new US_ASCII();
+
public US_ASCII() {
super("US-ASCII", StandardCharsets.aliases_US_ASCII());
}
--- a/src/java.base/share/classes/sun/nio/cs/UTF_8.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_8.java Tue Apr 10 13:58:47 2018 -0700
@@ -55,6 +55,9 @@
*/
public final class UTF_8 extends Unicode {
+
+ public static final UTF_8 INSTANCE = new UTF_8();
+
public UTF_8() {
super("UTF-8", StandardCharsets.aliases_UTF_8());
}
--- a/src/java.base/share/native/libjava/jni_util.c Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/native/libjava/jni_util.c Tue Apr 10 13:58:47 2018 -0700
@@ -774,8 +774,10 @@
return newSizedStringJava(env, str, len);
}
-/* Initialize the fast encoding from the encoding name. */
-void
+/* Initialize the fast encoding from the encoding name.
+ * Export InitializeEncoding so that the VM can initialize it if required.
+ */
+JNIEXPORT void
InitializeEncoding(JNIEnv *env, const char *encname)
{
jclass strClazz = NULL;
--- a/src/java.base/share/native/libjava/jni_util.h Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/native/libjava/jni_util.h Tue Apr 10 13:58:47 2018 -0700
@@ -388,7 +388,7 @@
int getFastEncoding();
-void InitializeEncoding(JNIEnv *env, const char *name);
+JNIEXPORT void InitializeEncoding(JNIEnv *env, const char *name);
void* getProcessHandle();
--- a/src/java.base/solaris/native/libjsig/jsig.c Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2001, 2010, 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.
- *
- */
-
-/* CopyrightVersion 1.2 */
-
-/* This is a special library that should be loaded before libc &
- * libthread to interpose the signal handler installation functions:
- * sigaction(), signal(), sigset().
- * Used for signal-chaining. See RFE 4381843.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <dlfcn.h>
-#include <thread.h>
-#include <synch.h>
-#include "jni.h"
-#include "jvm_md.h"
-
-#define bool int
-#define true 1
-#define false 0
-
-static struct sigaction *sact = (struct sigaction *)NULL; /* saved signal handlers */
-static sigset_t jvmsigs;
-
-/* used to synchronize the installation of signal handlers */
-static mutex_t mutex = DEFAULTMUTEX;
-static cond_t cond = DEFAULTCV;
-static thread_t tid = 0;
-
-typedef void (*sa_handler_t)(int);
-typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
-typedef sa_handler_t (*signal_t)(int, sa_handler_t);
-typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
-
-static signal_t os_signal = 0; /* os's version of signal()/sigset() */
-static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
-
-static bool jvm_signal_installing = false;
-static bool jvm_signal_installed = false;
-
-
-/* assume called within signal_lock */
-static void allocate_sact() {
- size_t maxsignum;
- maxsignum = SIGRTMAX;
- if (sact == NULL) {
- sact = (struct sigaction *)malloc((maxsignum+1) * (size_t)sizeof(struct sigaction));
- memset(sact, 0, (maxsignum+1) * (size_t)sizeof(struct sigaction));
- }
-
- if (sact == NULL) {
- printf("%s\n", "libjsig.so unable to allocate memory");
- exit(0);
- }
-
- sigemptyset(&jvmsigs);
-}
-
-static void signal_lock() {
- mutex_lock(&mutex);
- /* When the jvm is installing its set of signal handlers, threads
- * other than the jvm thread should wait */
- if (jvm_signal_installing) {
- if (tid != thr_self()) {
- cond_wait(&cond, &mutex);
- }
- }
-}
-
-static void signal_unlock() {
- mutex_unlock(&mutex);
-}
-
-static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
- bool is_sigset) {
- if (os_signal == NULL) {
- if (!is_sigset) {
- os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
- } else {
- os_signal = (signal_t)dlsym(RTLD_NEXT, "sigset");
- }
- if (os_signal == NULL) {
- printf("%s\n", dlerror());
- exit(0);
- }
- }
- return (*os_signal)(sig, disp);
-}
-
-static void save_signal_handler(int sig, sa_handler_t disp, bool is_sigset) {
- sigset_t set;
- if (sact == NULL) {
- allocate_sact();
- }
- sact[sig].sa_handler = disp;
- sigemptyset(&set);
- sact[sig].sa_mask = set;
- if (!is_sigset) {
- sact[sig].sa_flags = SA_NODEFER;
- if (sig != SIGILL && sig != SIGTRAP && sig != SIGPWR) {
- sact[sig].sa_flags |= SA_RESETHAND;
- }
- } else {
- sact[sig].sa_flags = 0;
- }
-}
-
-static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
- sa_handler_t oldhandler;
- bool sigblocked;
-
- signal_lock();
- if (sact == NULL) {
- allocate_sact();
- }
-
- if (jvm_signal_installed && sigismember(&jvmsigs, sig)) {
- /* jvm has installed its signal handler for this signal. */
- /* Save the handler. Don't really install it. */
- if (is_sigset) {
- /* We won't honor the SIG_HOLD request to change the signal mask */
- sigblocked = sigismember(&(sact[sig].sa_mask), sig);
- }
- oldhandler = sact[sig].sa_handler;
- save_signal_handler(sig, disp, is_sigset);
-
- if (is_sigset && sigblocked) {
- oldhandler = SIG_HOLD;
- }
-
- signal_unlock();
- return oldhandler;
- } else if (jvm_signal_installing) {
- /* jvm is installing its signal handlers. Install the new
- * handlers and save the old ones. jvm uses sigaction().
- * Leave the piece here just in case. */
- oldhandler = call_os_signal(sig, disp, is_sigset);
- save_signal_handler(sig, oldhandler, is_sigset);
-
- /* Record the signals used by jvm */
- sigaddset(&jvmsigs, sig);
-
- signal_unlock();
- return oldhandler;
- } else {
- /* jvm has no relation with this signal (yet). Install the
- * the handler. */
- oldhandler = call_os_signal(sig, disp, is_sigset);
-
- signal_unlock();
- return oldhandler;
- }
-}
-
-sa_handler_t signal(int sig, sa_handler_t disp) {
- return set_signal(sig, disp, false);
-}
-
-sa_handler_t sigset(int sig, sa_handler_t disp) {
- return set_signal(sig, disp, true);
-}
-
-static int call_os_sigaction(int sig, const struct sigaction *act,
- struct sigaction *oact) {
- if (os_sigaction == NULL) {
- os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
- if (os_sigaction == NULL) {
- printf("%s\n", dlerror());
- exit(0);
- }
- }
- return (*os_sigaction)(sig, act, oact);
-}
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
- int res;
- struct sigaction oldAct;
-
- signal_lock();
-
- if (sact == NULL ) {
- allocate_sact();
- }
- if (jvm_signal_installed && sigismember(&jvmsigs, sig)) {
- /* jvm has installed its signal handler for this signal. */
- /* Save the handler. Don't really install it. */
- if (oact != NULL) {
- *oact = sact[sig];
- }
- if (act != NULL) {
- sact[sig] = *act;
- }
-
- signal_unlock();
- return 0;
- } else if (jvm_signal_installing) {
- /* jvm is installing its signal handlers. Install the new
- * handlers and save the old ones. */
- res = call_os_sigaction(sig, act, &oldAct);
- sact[sig] = oldAct;
- if (oact != NULL) {
- *oact = oldAct;
- }
-
- /* Record the signals used by jvm */
- sigaddset(&jvmsigs, sig);
-
- signal_unlock();
- return res;
- } else {
- /* jvm has no relation with this signal (yet). Install the
- * the handler. */
- res = call_os_sigaction(sig, act, oact);
-
- signal_unlock();
- return res;
- }
-}
-
-/* The four functions for the jvm to call into */
-JNIEXPORT void JNICALL
-JVM_begin_signal_setting() {
- signal_lock();
- jvm_signal_installing = true;
- tid = thr_self();
- signal_unlock();
-}
-
-JNIEXPORT void JNICALL
-JVM_end_signal_setting() {
- signal_lock();
- jvm_signal_installed = true;
- jvm_signal_installing = false;
- cond_broadcast(&cond);
- signal_unlock();
-}
-
-JNIEXPORT struct sigaction * JNICALL
-JVM_get_signal_action(int sig) {
- if (sact == NULL) {
- allocate_sact();
- }
- /* Does race condition make sense here? */
- if (sigismember(&jvmsigs, sig)) {
- return &sact[sig];
- }
- return NULL;
-}
-
-JNIEXPORT int JNICALL
-JVM_get_libjsig_version() {
- return JSIG_VERSION_1_4_1;
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/unix/native/libjsig/jsig.c Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015 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
+ * 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 is a special library that should be loaded before libc &
+ * libthread to interpose the signal handler installation functions:
+ * sigaction(), signal(), sigset().
+ * Used for signal-chaining. See RFE 4381843.
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if (__STDC_VERSION__ >= 199901L)
+ #include <stdbool.h>
+#else
+ #define bool int
+ #define true 1
+ #define false 0
+#endif
+
+#ifdef SOLARIS
+#define MAX_SIGNALS (SIGRTMAX+1)
+
+/* On solaris, MAX_SIGNALS is a macro, not a constant, so we must allocate sact dynamically. */
+static struct sigaction *sact = (struct sigaction *)NULL; /* saved signal handlers */
+#else
+#define MAX_SIGNALS NSIG
+
+static struct sigaction sact[MAX_SIGNALS]; /* saved signal handlers */
+#endif
+
+static sigset_t jvmsigs; /* Signals used by jvm. */
+
+#ifdef MACOSX
+static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */
+#endif
+
+/* Used to synchronize the installation of signal handlers. */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_t tid = 0;
+
+typedef void (*sa_handler_t)(int);
+typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
+typedef sa_handler_t (*signal_function_t)(int, sa_handler_t);
+typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
+
+static signal_function_t os_signal = 0; /* os's version of signal()/sigset() */
+static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
+
+static bool jvm_signal_installing = false;
+static bool jvm_signal_installed = false;
+
+
+/* assume called within signal_lock */
+static void allocate_sact() {
+#ifdef SOLARIS
+ if (sact == NULL) {
+ sact = (struct sigaction *)malloc((MAX_SIGNALS) * (size_t)sizeof(struct sigaction));
+ if (sact == NULL) {
+ printf("%s\n", "libjsig.so unable to allocate memory");
+ exit(0);
+ }
+ memset(sact, 0, (MAX_SIGNALS) * (size_t)sizeof(struct sigaction));
+ }
+#endif
+}
+
+static void signal_lock() {
+ pthread_mutex_lock(&mutex);
+ /* When the jvm is installing its set of signal handlers, threads
+ * other than the jvm thread should wait. */
+ if (jvm_signal_installing) {
+ if (tid != pthread_self()) {
+ pthread_cond_wait(&cond, &mutex);
+ }
+ }
+}
+
+static void signal_unlock() {
+ pthread_mutex_unlock(&mutex);
+}
+
+static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
+ bool is_sigset) {
+ sa_handler_t res;
+
+ if (os_signal == NULL) {
+ if (!is_sigset) {
+ os_signal = (signal_function_t)dlsym(RTLD_NEXT, "signal");
+ } else {
+ os_signal = (signal_function_t)dlsym(RTLD_NEXT, "sigset");
+ }
+ if (os_signal == NULL) {
+ printf("%s\n", dlerror());
+ exit(0);
+ }
+ }
+
+#ifdef MACOSX
+ /* On macosx, the OS implementation of signal calls sigaction.
+ * Make sure we do not deadlock with ourself. (See JDK-8072147). */
+ reentry = true;
+#endif
+
+ res = (*os_signal)(sig, disp);
+
+#ifdef MACOSX
+ reentry = false;
+#endif
+
+ return res;
+}
+
+static void save_signal_handler(int sig, sa_handler_t disp, bool is_sigset) {
+ sigset_t set;
+
+ sact[sig].sa_handler = disp;
+ sigemptyset(&set);
+ sact[sig].sa_mask = set;
+ if (!is_sigset) {
+#ifdef SOLARIS
+ sact[sig].sa_flags = SA_NODEFER;
+ if (sig != SIGILL && sig != SIGTRAP && sig != SIGPWR) {
+ sact[sig].sa_flags |= SA_RESETHAND;
+ }
+#else
+ sact[sig].sa_flags = 0;
+#endif
+ } else {
+ sact[sig].sa_flags = 0;
+ }
+}
+
+static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
+ sa_handler_t oldhandler;
+ bool sigused;
+ bool sigblocked;
+
+ signal_lock();
+ allocate_sact();
+
+ sigused = sigismember(&jvmsigs, sig);
+ if (jvm_signal_installed && sigused) {
+ /* jvm has installed its signal handler for this signal. */
+ /* Save the handler. Don't really install it. */
+ if (is_sigset) {
+ sigblocked = sigismember(&(sact[sig].sa_mask), sig);
+ }
+ oldhandler = sact[sig].sa_handler;
+ save_signal_handler(sig, disp, is_sigset);
+
+#ifdef SOLARIS
+ if (is_sigset && sigblocked) {
+ /* We won't honor the SIG_HOLD request to change the signal mask */
+ oldhandler = SIG_HOLD;
+ }
+#endif
+
+ signal_unlock();
+ return oldhandler;
+ } else if (jvm_signal_installing) {
+ /* jvm is installing its signal handlers. Install the new
+ * handlers and save the old ones. jvm uses sigaction().
+ * Leave the piece here just in case. */
+ oldhandler = call_os_signal(sig, disp, is_sigset);
+ save_signal_handler(sig, oldhandler, is_sigset);
+
+ /* Record the signals used by jvm */
+ sigaddset(&jvmsigs, sig);
+
+ signal_unlock();
+ return oldhandler;
+ } else {
+ /* jvm has no relation with this signal (yet). Install the
+ * the handler. */
+ oldhandler = call_os_signal(sig, disp, is_sigset);
+
+ signal_unlock();
+ return oldhandler;
+ }
+}
+
+sa_handler_t signal(int sig, sa_handler_t disp) {
+ if (sig < 0 || sig >= MAX_SIGNALS) {
+ errno = EINVAL;
+ return SIG_ERR;
+ }
+
+ return set_signal(sig, disp, false);
+}
+
+sa_handler_t sigset(int sig, sa_handler_t disp) {
+#ifdef _ALLBSD_SOURCE
+ printf("sigset() is not supported by BSD");
+ exit(0);
+#else
+ if (sig < 0 || sig >= MAX_SIGNALS) {
+ errno = EINVAL;
+ return (sa_handler_t)-1;
+ }
+
+ return set_signal(sig, disp, true);
+#endif
+}
+
+static int call_os_sigaction(int sig, const struct sigaction *act,
+ struct sigaction *oact) {
+ if (os_sigaction == NULL) {
+ os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
+ if (os_sigaction == NULL) {
+ printf("%s\n", dlerror());
+ exit(0);
+ }
+ }
+ return (*os_sigaction)(sig, act, oact);
+}
+
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
+ int res;
+ bool sigused;
+ struct sigaction oldAct;
+
+ if (sig < 0 || sig >= MAX_SIGNALS) {
+ errno = EINVAL;
+ return -1;
+ }
+
+#ifdef MACOSX
+ if (reentry) {
+ return call_os_sigaction(sig, act, oact);
+ }
+#endif
+
+ signal_lock();
+
+ allocate_sact();
+ sigused = sigismember(&jvmsigs, sig);
+ if (jvm_signal_installed && sigused) {
+ /* jvm has installed its signal handler for this signal. */
+ /* Save the handler. Don't really install it. */
+ if (oact != NULL) {
+ *oact = sact[sig];
+ }
+ if (act != NULL) {
+ sact[sig] = *act;
+ }
+
+ signal_unlock();
+ return 0;
+ } else if (jvm_signal_installing) {
+ /* jvm is installing its signal handlers. Install the new
+ * handlers and save the old ones. */
+ res = call_os_sigaction(sig, act, &oldAct);
+ sact[sig] = oldAct;
+ if (oact != NULL) {
+ *oact = oldAct;
+ }
+
+ /* Record the signals used by jvm. */
+ sigaddset(&jvmsigs, sig);
+
+ signal_unlock();
+ return res;
+ } else {
+ /* jvm has no relation with this signal (yet). Install the
+ * the handler. */
+ res = call_os_sigaction(sig, act, oact);
+
+ signal_unlock();
+ return res;
+ }
+}
+
+/* The three functions for the jvm to call into. */
+void JVM_begin_signal_setting() {
+ signal_lock();
+ sigemptyset(&jvmsigs);
+ jvm_signal_installing = true;
+ tid = pthread_self();
+ signal_unlock();
+}
+
+void JVM_end_signal_setting() {
+ signal_lock();
+ jvm_signal_installed = true;
+ jvm_signal_installing = false;
+ pthread_cond_broadcast(&cond);
+ signal_unlock();
+}
+
+struct sigaction *JVM_get_signal_action(int sig) {
+ allocate_sact();
+ /* Does race condition make sense here? */
+ if (sigismember(&jvmsigs, sig)) {
+ return &sact[sig];
+ }
+ return NULL;
+}
--- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java Tue Apr 10 13:58:47 2018 -0700
@@ -746,12 +746,7 @@
value = lookup(aValue, Object.class);
break;
case 1: // boolean
- if (aValue.toUpperCase().equals("TRUE")) {
- value = Boolean.TRUE;
- }
- else {
- value = Boolean.FALSE;
- }
+ value = Boolean.parseBoolean(aValue);
break;
case 2: // dimension
StringTokenizer tok = new StringTokenizer(aValue);
@@ -939,11 +934,11 @@
": destinationInsets must be top left bottom right");
}
else if (key.equals(ATTRIBUTE_PAINT_CENTER)) {
- paintCenter = value.toLowerCase().equals("true");
+ paintCenter = Boolean.parseBoolean(value);
paintCenterSpecified = true;
}
else if (key.equals(ATTRIBUTE_STRETCH)) {
- stretch = value.toLowerCase().equals("true");
+ stretch = Boolean.parseBoolean(value);
stretchSpecified = true;
}
else if (key.equals(ATTRIBUTE_DIRECTION)) {
@@ -989,7 +984,7 @@
}
}
else if (key.equals(ATTRIBUTE_CENTER)) {
- center = value.toLowerCase().equals("true");
+ center = Boolean.parseBoolean(value);
}
}
if (painter == null) {
--- a/src/java.instrument/share/native/libinstrument/Reentrancy.c Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.instrument/share/native/libinstrument/Reentrancy.c Tue Apr 10 13:58:47 2018 -0700
@@ -90,7 +90,7 @@
jthread thread,
const void * expected) {
jvmtiError error;
- void * test = (void *) 0x99999999UL;
+ void * test = (void *) 0x99999999ULL;
/* now check if we do a fetch we get what we wrote */
error = (*jvmtienv)->GetThreadLocalStorage(
--- a/src/java.management/share/classes/sun/management/MemoryPoolImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.management/share/classes/sun/management/MemoryPoolImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -55,10 +55,10 @@
private long usageThreshold;
private long collectionThreshold;
- private boolean usageSensorRegistered;
- private boolean gcSensorRegistered;
- private Sensor usageSensor;
- private Sensor gcSensor;
+ private boolean usageSensorRegistered; // VM-initialized to false
+ private boolean gcSensorRegistered; // VM-initialized to false
+ private final Sensor usageSensor;
+ private final Sensor gcSensor;
MemoryPoolImpl(String name, boolean isHeap, long usageThreshold,
long gcThreshold) {
@@ -72,8 +72,6 @@
this.collectionThresholdSupported = (gcThreshold >= 0);
this.usageSensor = new PoolSensor(this, name + " usage sensor");
this.gcSensor = new CollectionSensor(this, name + " collection sensor");
- this.usageSensorRegistered = false;
- this.gcSensorRegistered = false;
}
public String getName() {
@@ -290,7 +288,7 @@
* unless the memory usage has returned below the threshold.
*/
class PoolSensor extends Sensor {
- MemoryPoolImpl pool;
+ final MemoryPoolImpl pool;
PoolSensor(MemoryPoolImpl pool, String name) {
super(name);
@@ -316,10 +314,10 @@
* when the memory usage of a memory pool after GC is crossing
* the collection threshold.
* The VM will trigger this sensor in subsequent crossing
- * regardless if the memory usage has changed siince the previous GC.
+ * regardless if the memory usage has changed since the previous GC.
*/
class CollectionSensor extends Sensor {
- MemoryPoolImpl pool;
+ final MemoryPoolImpl pool;
CollectionSensor(MemoryPoolImpl pool, String name) {
super(name);
this.pool = pool;
--- a/src/java.management/share/classes/sun/management/Sensor.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.management/share/classes/sun/management/Sensor.java Tue Apr 10 13:58:47 2018 -0700
@@ -48,10 +48,10 @@
*/
public abstract class Sensor {
- private Object lock;
- private String name;
- private long count;
- private boolean on;
+ private final Object lock = new Object();
+ private final String name;
+ private long count; // VM-initialized to 0
+ private boolean on; // VM-initialized to false
/**
* Constructs a {@code Sensor} object.
@@ -60,9 +60,6 @@
*/
public Sensor(String name) {
this.name = name;
- this.count = 0;
- this.on = false;
- this.lock = new Object();
}
/**
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/util/KerberosString.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/util/KerberosString.java Tue Apr 10 13:58:47 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2018, 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
@@ -26,8 +26,7 @@
package sun.security.krb5.internal.util;
import java.io.IOException;
-import java.security.AccessController;
-import sun.security.action.GetBooleanAction;
+import sun.security.action.GetPropertyAction;
import sun.security.util.DerValue;
/**
@@ -45,15 +44,21 @@
public final class KerberosString {
/**
* RFC 4120 defines KerberosString as GeneralString (IA5String), which
- * only includes ASCII characters. However, other implementations have been
- * known to use GeneralString to contain UTF-8 encoding. To interop
- * with these implementations, the following system property is defined.
- * When set as true, KerberosString is encoded as UTF-8. Note that this
- * only affects the byte encoding, the tag of the ASN.1 type is still
- * GeneralString.
+ * only includes ASCII characters. However, most implementations have been
+ * known to use GeneralString to contain UTF-8 encoding. The following
+ * system property is defined. When set as true, KerberosString is encoded
+ * as UTF-8. Otherwise, it's ASCII. The default is true.
+ *
+ * Note that this only affects the byte encoding, the tag of the ASN.1
+ * type is still GeneralString.
*/
- public static final boolean MSNAME = AccessController.doPrivileged(
- new GetBooleanAction("sun.security.krb5.msinterop.kstring"));
+ public static final boolean MSNAME;
+
+ static {
+ String prop = GetPropertyAction.privilegedGetProperty(
+ "sun.security.krb5.msinterop.kstring", "true");
+ MSNAME = Boolean.parseBoolean(prop);
+ }
private final String s;
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -42,6 +42,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
@@ -72,6 +74,8 @@
*/
protected IndexBuilder indexbuilder;
+ protected Navigation navBar;
+
/**
* This constructor will be used by {@link SplitIndexWriter}. Initializes
* path to this file and relative path from this file.
@@ -85,17 +89,7 @@
IndexBuilder indexbuilder) {
super(configuration, path);
this.indexbuilder = indexbuilder;
- }
-
- /**
- * Get the index label for navigation bar.
- *
- * @return a content tree for the tree label
- */
- @Override
- protected Content getNavLinkIndex() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.indexLabel);
- return li;
+ this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.INDEX, path);
}
/**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -45,6 +45,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
@@ -215,23 +216,6 @@
protected abstract Content getDeprecatedLink(Element member);
/**
- * Get the navigation summary link.
- *
- * @param typeElement the TypeElement to be documented
- * @param link true if its a link else the label to be printed
- * @return a content tree for the navigation summary link.
- */
- protected abstract Content getNavSummaryLink(TypeElement typeElement, boolean link);
-
- /**
- * Add the navigation detail link.
- *
- * @param link true if its a link else the label to be printed
- * @param liNav the content tree to which the navigation detail link will be added
- */
- protected abstract void addNavDetailLink(boolean link, Content liNav);
-
- /**
* Add the member name to the content tree.
*
* @param name the member name to be added to the content tree.
@@ -474,41 +458,6 @@
}
}
- /**
- * Add the navigation detail link.
- *
- * @param members the members to be linked
- * @param liNav the content tree to which the navigation detail link will be added
- */
- protected void addNavDetailLink(SortedSet<Element> members, Content liNav) {
- addNavDetailLink(!members.isEmpty(), liNav);
- }
-
- /**
- * Add the navigation summary link.
- *
- * @param members members to be linked
- * @param visibleMemberMap the visible inherited members map
- * @param liNav the content tree to which the navigation summary link will be added
- */
- protected void addNavSummaryLink(SortedSet<? extends Element> members,
- VisibleMemberMap visibleMemberMap, Content liNav) {
- if (!members.isEmpty()) {
- liNav.addContent(getNavSummaryLink(null, true));
- return;
- }
-
- TypeElement superClass = utils.getSuperClass(typeElement);
- while (superClass != null) {
- if (visibleMemberMap.hasMembers(superClass)) {
- liNav.addContent(getNavSummaryLink(superClass, true));
- return;
- }
- superClass = utils.getSuperClass(superClass);
- }
- liNav.addContent(getNavSummaryLink(null, false));
- }
-
protected void serialWarning(Element e, String key, String a1, String a2) {
if (configuration.serialwarn) {
configuration.messages.warning(e, key, a1, a2);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractModuleIndexWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractModuleIndexWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -37,6 +37,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
@@ -61,6 +63,8 @@
*/
protected SortedMap<ModuleElement, Set<PackageElement>> modules;
+ protected Navigation navBar;
+
/**
* Constructor. Also initializes the modules variable.
*
@@ -71,6 +75,7 @@
DocPath filename) {
super(configuration, filename);
modules = configuration.modulePackages;
+ this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.OVERVIEW, path);
}
/**
@@ -252,18 +257,6 @@
}
/**
- * Returns highlighted "Overview", in the navigation bar as this is the
- * overview page.
- *
- * @return a Content object to be added to the documentation tree
- */
- @Override
- protected Content getNavLinkContents() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.overviewLabel);
- return li;
- }
-
- /**
* Do nothing. This will be overridden in ModuleIndexFrameWriter.
*
* @param div the document tree to which the all classes link will be added
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractPackageIndexWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractPackageIndexWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -33,6 +33,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
@@ -58,6 +60,8 @@
*/
protected SortedSet<PackageElement> packages;
+ protected Navigation navBar;
+
/**
* Constructor. Also initializes the packages variable.
*
@@ -68,6 +72,7 @@
DocPath filename) {
super(configuration, filename);
packages = configuration.packages;
+ this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.OVERVIEW, path);
}
/**
@@ -174,18 +179,6 @@
}
/**
- * Returns highlighted "Overview", in the navigation bar as this is the
- * overview page.
- *
- * @return a Content object to be added to the documentation tree
- */
- @Override
- protected Content getNavLinkContents() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.overviewLabel);
- return li;
- }
-
- /**
* Do nothing. This will be overridden.
*
* @param div the document tree to which the all classes link will be added
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -184,14 +184,4 @@
protected void addPartialInfo(TypeElement typeElement, Content contentTree) {
addPreQualifiedStrongClassLink(LinkInfoImpl.Kind.TREE, typeElement, contentTree);
}
-
- /**
- * Get the tree label for the navigation bar.
- *
- * @return a content tree for the tree label
- */
- protected Content getNavLinkTree() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.treeLabel);
- return li;
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeFieldWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -285,31 +285,6 @@
member, utils.getFullyQualifiedName(member));
}
- /**
- * {@inheritDoc}
- */
- protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
- if (link) {
- return links.createLink(
- SectionName.ANNOTATION_TYPE_FIELD_SUMMARY,
- contents.navField);
- } else {
- return contents.navField;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- protected void addNavDetailLink(boolean link, Content liNav) {
- if (link) {
- liNav.addContent(links.createLink(
- SectionName.ANNOTATION_TYPE_FIELD_DETAIL,
- contents.navField));
- } else {
- liNav.addContent(contents.navField);
- }
- }
private TypeMirror getType(Element member) {
if (utils.isConstructor(member))
return null;
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -35,7 +35,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeOptionalMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -152,18 +152,4 @@
memberTree.addContent(links.createAnchor(
SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY));
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
- if (link) {
- return links.createLink(
- SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY,
- contents.navAnnotationTypeOptionalMember);
- } else {
- return contents.navAnnotationTypeOptionalMember;
- }
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -300,32 +300,6 @@
return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, name);
}
- /**
- * {@inheritDoc}
- */
- protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
- if (link) {
- return links.createLink(
- SectionName.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY,
- contents.navAnnotationTypeRequiredMember);
- } else {
- return contents.navAnnotationTypeRequiredMember;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- protected void addNavDetailLink(boolean link, Content liNav) {
- if (link) {
- liNav.addContent(links.createLink(
- SectionName.ANNOTATION_TYPE_ELEMENT_DETAIL,
- contents.navAnnotationTypeMember));
- } else {
- liNav.addContent(contents.navAnnotationTypeMember);
- }
- }
-
private TypeMirror getType(Element member) {
return utils.isExecutableElement(member)
? utils.getReturnType((ExecutableElement) member)
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -30,21 +30,20 @@
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
/**
@@ -69,6 +68,8 @@
protected TypeElement annotationType;
+ private final Navigation navBar;
+
/**
* @param configuration the configuration
* @param annotationType the annotation type being documented.
@@ -78,55 +79,7 @@
super(configuration, configuration.docPaths.forClass(annotationType));
this.annotationType = annotationType;
configuration.currentTypeElement = annotationType;
- }
-
- /**
- * Get the module link.
- *
- * @return a content tree for the module link
- */
- @Override
- protected Content getNavLinkModule() {
- Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(annotationType),
- contents.moduleLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get this package link.
- *
- * @return a content tree for the package link
- */
- @Override
- protected Content getNavLinkPackage() {
- Content linkContent = links.createLink(DocPaths.PACKAGE_SUMMARY,
- contents.packageLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get the class link.
- *
- * @return a content tree for the class link
- */
- @Override
- protected Content getNavLinkClass() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.classLabel);
- return li;
- }
-
- /**
- * Get the class use link.
- *
- * @return a content tree for the class use link
- */
- @Override
- protected Content getNavLinkClassUse() {
- Content linkContent = links.createLink(DocPaths.CLASS_USE.resolve(filename), contents.useLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
+ this.navBar = new Navigation(annotationType, configuration, fixedNavDiv, PageMode.CLASS, path);
}
/**
@@ -139,7 +92,12 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(annotationType),
+ contents.moduleLabel);
+ navBar.setNavLinkModule(linkContent);
+ navBar.setMemberSummaryBuilder(configuration.getBuilderFactory().getMemberSummaryBuilder(this));
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -195,7 +153,8 @@
Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: contentTree;
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
contentTree.addContent(htmlTree);
@@ -299,123 +258,6 @@
* {@inheritDoc}
*/
@Override
- protected Content getNavLinkTree() {
- Content treeLinkContent = links.createLink(DocPaths.PACKAGE_TREE,
- contents.treeLabel, "", "");
- Content li = HtmlTree.LI(treeLinkContent);
- return li;
- }
-
- /**
- * Add summary details to the navigation bar.
- *
- * @param subDiv the content tree to which the summary detail links will be added
- */
- @Override
- protected void addSummaryDetailLinks(Content subDiv) {
- Content div = HtmlTree.DIV(getNavSummaryLinks());
- div.addContent(getNavDetailLinks());
- subDiv.addContent(div);
- }
-
- /**
- * Get summary links for navigation bar.
- *
- * @return the content tree for the navigation summary links
- */
- protected Content getNavSummaryLinks() {
- Content li = HtmlTree.LI(contents.summaryLabel);
- li.addContent(Contents.SPACE);
- Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
- MemberSummaryBuilder memberSummaryBuilder =
- configuration.getBuilderFactory().getMemberSummaryBuilder(this);
- Content liNavField = new HtmlTree(HtmlTag.LI);
- addNavSummaryLink(memberSummaryBuilder,
- "doclet.navField",
- VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS, liNavField);
- addNavGap(liNavField);
- ulNav.addContent(liNavField);
- Content liNavReq = new HtmlTree(HtmlTag.LI);
- addNavSummaryLink(memberSummaryBuilder,
- "doclet.navAnnotationTypeRequiredMember",
- VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED, liNavReq);
- addNavGap(liNavReq);
- ulNav.addContent(liNavReq);
- Content liNavOpt = new HtmlTree(HtmlTag.LI);
- addNavSummaryLink(memberSummaryBuilder,
- "doclet.navAnnotationTypeOptionalMember",
- VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL, liNavOpt);
- ulNav.addContent(liNavOpt);
- return ulNav;
- }
-
- /**
- * Add the navigation summary link.
- *
- * @param builder builder for the member to be documented
- * @param label the label for the navigation
- * @param type type to be documented
- * @param liNav the content tree to which the navigation summary link will be added
- */
- protected void addNavSummaryLink(MemberSummaryBuilder builder,
- String label, VisibleMemberMap.Kind type, Content liNav) {
- AbstractMemberWriter writer = ((AbstractMemberWriter) builder.
- getMemberSummaryWriter(type));
- if (writer == null) {
- liNav.addContent(contents.getContent(label));
- } else {
- liNav.addContent(writer.getNavSummaryLink(null,
- ! builder.getVisibleMemberMap(type).noVisibleMembers()));
- }
- }
-
- /**
- * Get detail links for the navigation bar.
- *
- * @return the content tree for the detail links
- */
- protected Content getNavDetailLinks() {
- Content li = HtmlTree.LI(contents.detailLabel);
- li.addContent(Contents.SPACE);
- Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
- MemberSummaryBuilder memberSummaryBuilder =
- configuration.getBuilderFactory().getMemberSummaryBuilder(this);
- AbstractMemberWriter writerField =
- ((AbstractMemberWriter) memberSummaryBuilder.
- getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS));
- AbstractMemberWriter writerOptional =
- ((AbstractMemberWriter) memberSummaryBuilder.
- getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL));
- AbstractMemberWriter writerRequired =
- ((AbstractMemberWriter) memberSummaryBuilder.
- getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED));
- Content liNavField = new HtmlTree(HtmlTag.LI);
- if (writerField != null) {
- writerField.addNavDetailLink(!utils.getAnnotationFields(annotationType).isEmpty(), liNavField);
- } else {
- liNavField.addContent(contents.navField);
- }
- addNavGap(liNavField);
- ulNav.addContent(liNavField);
- if (writerOptional != null){
- Content liNavOpt = new HtmlTree(HtmlTag.LI);
- writerOptional.addNavDetailLink(!annotationType.getAnnotationMirrors().isEmpty(), liNavOpt);
- ulNav.addContent(liNavOpt);
- } else if (writerRequired != null){
- Content liNavReq = new HtmlTree(HtmlTag.LI);
- writerRequired.addNavDetailLink(!annotationType.getAnnotationMirrors().isEmpty(), liNavReq);
- ulNav.addContent(liNavReq);
- } else {
- Content liNav = HtmlTree.LI(contents.navAnnotationTypeMember);
- ulNav.addContent(liNav);
- }
- return ulNav;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public TypeElement getAnnotationTypeElement() {
return annotationType;
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -47,7 +47,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
@@ -106,6 +107,7 @@
final String methodUseTableSummary;
final String constructorUseTableSummary;
final String packageUseTableSummary;
+ private final Navigation navBar;
/**
* The HTML tree for main tag.
@@ -178,6 +180,7 @@
resources.getText("doclet.constructors"));
packageUseTableSummary = MessageFormat.format(useTableSummary,
resources.getText("doclet.packages"));
+ this.navBar = new Navigation(typeElement, configuration, fixedNavDiv, PageMode.USE, path);
}
/**
@@ -264,7 +267,8 @@
HtmlTree htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: body;
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(htmlTree);
@@ -476,7 +480,15 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ Content mdleLinkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
+ contents.moduleLabel);
+ navBar.setNavLinkModule(mdleLinkContent);
+ Content classLinkContent = getLink(new LinkInfoImpl(
+ configuration, LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)
+ .label(configuration.getText("doclet.Class")));
+ navBar.setNavLinkClass(classLinkContent);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -494,65 +506,4 @@
}
return bodyTree;
}
-
- /**
- * Get the module link.
- *
- * @return a content tree for the module link
- */
- @Override
- protected Content getNavLinkModule() {
- Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
- contents.moduleLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get this package link.
- *
- * @return a content tree for the package link
- */
- protected Content getNavLinkPackage() {
- Content linkContent =
- links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_SUMMARY), contents.packageLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get class page link.
- *
- * @return a content tree for the class page link
- */
- protected Content getNavLinkClass() {
- Content linkContent = getLink(new LinkInfoImpl(
- configuration, LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)
- .label(configuration.getText("doclet.Class")));
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get the use link.
- *
- * @return a content tree for the use link
- */
- protected Content getNavLinkClassUse() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.useLabel);
- return li;
- }
-
- /**
- * Get the tree link.
- *
- * @return a content tree for the tree link
- */
- protected Content getNavLinkTree() {
- Content linkContent = utils.isEnclosingPackageIncluded(typeElement)
- ? links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_TREE), contents.treeLabel)
- : links.createLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), contents.treeLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -40,6 +40,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -48,11 +50,9 @@
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
-import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.Kind;
/**
* Generate the Class Information Page.
@@ -78,6 +78,8 @@
protected final ClassTree classtree;
+ private final Navigation navBar;
+
/**
* @param configuration the configuration data for the doclet
* @param typeElement the class being documented.
@@ -89,55 +91,7 @@
this.typeElement = typeElement;
configuration.currentTypeElement = typeElement;
this.classtree = classTree;
- }
-
- /**
- * Get the module link.
- *
- * @return a content tree for the module link
- */
- @Override
- protected Content getNavLinkModule() {
- Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
- contents.moduleLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get this package link.
- *
- * @return a content tree for the package link
- */
- @Override
- protected Content getNavLinkPackage() {
- Content linkContent = links.createLink(DocPaths.PACKAGE_SUMMARY,
- contents.packageLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get the class link.
- *
- * @return a content tree for the class link
- */
- @Override
- protected Content getNavLinkClass() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.classLabel);
- return li;
- }
-
- /**
- * Get the class use link.
- *
- * @return a content tree for the class use link
- */
- @Override
- protected Content getNavLinkClassUse() {
- Content linkContent = links.createLink(DocPaths.CLASS_USE.resolve(filename), contents.useLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
+ this.navBar = new Navigation(typeElement, configuration, fixedNavDiv, PageMode.CLASS, path);
}
/**
@@ -150,7 +104,12 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
+ contents.moduleLabel);
+ navBar.setNavLinkModule(linkContent);
+ navBar.setMemberSummaryBuilder(configuration.getBuilderFactory().getMemberSummaryBuilder(this));
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -210,7 +169,8 @@
Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: contentTree;
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
contentTree.addContent(htmlTree);
@@ -609,100 +569,6 @@
}
/**
- * {@inheritDoc}
- */
- @Override
- protected Content getNavLinkTree() {
- Content treeLinkContent = links.createLink(DocPaths.PACKAGE_TREE,
- contents.treeLabel, "", "");
- Content li = HtmlTree.LI(treeLinkContent);
- return li;
- }
-
- /**
- * Add summary details to the navigation bar.
- *
- * @param subDiv the content tree to which the summary detail links will be added
- */
- @Override
- protected void addSummaryDetailLinks(Content subDiv) {
- Content div = HtmlTree.DIV(getNavSummaryLinks());
- div.addContent(getNavDetailLinks());
- subDiv.addContent(div);
- }
-
- /**
- * Get summary links for navigation bar.
- *
- * @return the content tree for the navigation summary links
- */
- protected Content getNavSummaryLinks() {
- Content li = HtmlTree.LI(contents.summaryLabel);
- li.addContent(Contents.SPACE);
- Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
- MemberSummaryBuilder memberSummaryBuilder =
- configuration.getBuilderFactory().getMemberSummaryBuilder(this);
- for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.summarySet) {
- Content liNav = new HtmlTree(HtmlTag.LI);
- if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) {
- continue;
- }
- if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) {
- continue;
- }
- AbstractMemberWriter writer =
- ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind));
- if (writer == null) {
- liNav.addContent(contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
- } else {
- writer.addNavSummaryLink(
- memberSummaryBuilder.members(kind),
- memberSummaryBuilder.getVisibleMemberMap(kind), liNav);
- }
- if (kind != Kind.METHODS) {
- addNavGap(liNav);
- }
- ulNav.addContent(liNav);
- }
- return ulNav;
- }
-
- /**
- * Get detail links for the navigation bar.
- *
- * @return the content tree for the detail links
- */
- protected Content getNavDetailLinks() {
- Content li = HtmlTree.LI(contents.detailLabel);
- li.addContent(Contents.SPACE);
- Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
- MemberSummaryBuilder memberSummaryBuilder =
- configuration.getBuilderFactory().getMemberSummaryBuilder(this);
- for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.detailSet) {
- Content liNav = new HtmlTree(HtmlTag.LI);
- AbstractMemberWriter writer =
- ((AbstractMemberWriter) memberSummaryBuilder.
- getMemberSummaryWriter(kind));
- if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) {
- continue;
- }
- if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) {
- continue;
- }
- if (writer == null) {
- liNav.addContent(contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
- } else {
- writer.addNavDetailLink(memberSummaryBuilder.members(kind), liNav);
- }
- if (kind != Kind.METHODS) {
- addNavGap(liNav);
- }
- ulNav.addContent(liNav);
- }
- return ulNav;
- }
-
- /**
* Return the TypeElement being documented.
*
* @return the TypeElement being documented.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -40,7 +40,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.ConstantsSummaryWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -86,6 +87,8 @@
*/
private HtmlTree summaryTree;
+ private final Navigation navBar;
+
/**
* Construct a ConstantsSummaryWriter.
* @param configuration the configuration used in this run
@@ -98,6 +101,7 @@
configuration.getText("doclet.Constants_Summary"));
constantsTableHeader = new TableHeader(
contents.modifierAndTypeLabel, contents.constantFieldLabel, contents.valueLabel);
+ this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.CONSTANTVALUES, path);
}
/**
@@ -111,7 +115,8 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -341,7 +346,8 @@
Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: contentTree;
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
contentTree.addContent(htmlTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -38,7 +38,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.ConstructorWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -298,33 +298,6 @@
* {@inheritDoc}
*/
@Override
- protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
- if (link) {
- return links.createLink(SectionName.CONSTRUCTOR_SUMMARY,
- contents.navConstructor);
- } else {
- return contents.navConstructor;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void addNavDetailLink(boolean link, Content liNav) {
- if (link) {
- liNav.addContent(links.createLink(
- SectionName.CONSTRUCTOR_DETAIL,
- contents.navConstructor));
- } else {
- liNav.addContent(contents.navConstructor);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
protected void addSummaryType(Element member, Content tdSummaryType) {
if (foundNonPubConstructor) {
Content code = new HtmlTree(HtmlTag.CODE);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -42,6 +42,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DeprecatedAPIListBuilder;
@@ -209,6 +211,8 @@
private HtmlConfiguration configuration;
+ private final Navigation navBar;
+
/**
* Constructor.
*
@@ -219,6 +223,7 @@
public DeprecatedListWriter(HtmlConfiguration configuration, DocPath filename) {
super(configuration, filename);
this.configuration = configuration;
+ this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.DEPRECATED, path);
NestedClassWriterImpl classW = new NestedClassWriterImpl(this);
writerMap = new EnumMap<>(DeprElementKind.class);
for (DeprElementKind kind : DeprElementKind.values()) {
@@ -307,7 +312,8 @@
htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: body;
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(htmlTree);
@@ -378,7 +384,8 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -386,17 +393,6 @@
}
/**
- * Get the deprecated label.
- *
- * @return a content tree for the deprecated label
- */
- @Override
- protected Content getNavLinkDeprecated() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.deprecatedLabel);
- return li;
- }
-
- /**
* Add deprecated information to the documentation tree
*
* @param deprList list of deprecated API elements
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -27,16 +27,15 @@
import com.sun.source.doctree.AttributeTree;
import com.sun.source.doctree.AttributeTree.ValueKind;
-import com.sun.source.doctree.DocRootTree;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.EndElementTree;
-import com.sun.source.doctree.LinkTree;
import com.sun.source.doctree.StartElementTree;
import com.sun.source.doctree.TextTree;
import com.sun.source.util.SimpleDocTreeVisitor;
import com.sun.tools.doclint.HtmlTag;
import com.sun.tools.doclint.HtmlTag.Attr;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.DocFileElement;
import jdk.javadoc.internal.doclets.toolkit.DocFilesHandler;
@@ -51,15 +50,19 @@
import javax.lang.model.element.PackageElement;
import javax.tools.FileObject;
import javax.tools.JavaFileManager.Location;
+
import java.util.Collections;
import java.util.List;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
+
public class DocFilesHandlerImpl implements DocFilesHandler {
public final Element element;
public final Location location;
public final DocPath source;
public final HtmlConfiguration configuration;
+ private Navigation navBar;
/**
* Constructor to construct the DocFilesWriter object.
@@ -171,14 +174,24 @@
String title = getWindowTitle(docletWriter, dfElement).trim();
HtmlTree htmlContent = docletWriter.getBody(true, title);
docletWriter.addTop(htmlContent);
- docletWriter.addNavLinks(true, htmlContent);
+ PackageElement pkg = (PackageElement) element;
+ this.navBar = new Navigation(pkg, configuration, docletWriter.fixedNavDiv,
+ PageMode.DOCFILE, docletWriter.path);
+ Content mdleLinkContent = docletWriter.getModuleLink(utils.elementUtils.getModuleOf(pkg),
+ docletWriter.contents.moduleLabel);
+ navBar.setNavLinkModule(mdleLinkContent);
+ Content pkgLinkContent = docletWriter.getPackageLink(pkg, docletWriter.contents.packageLabel);
+ navBar.setNavLinkPackage(pkgLinkContent);
+ navBar.setUserHeader(docletWriter.getUserHeaderFooter(true));
+ htmlContent.addContent(navBar.getContent(true));
List<? extends DocTree> fullBody = utils.getFullBody(dfElement);
Content bodyContent = docletWriter.commentTagsToContent(null, dfElement, fullBody, false);
docletWriter.addTagsInfo(dfElement, bodyContent);
htmlContent.addContent(bodyContent);
- docletWriter.addNavLinks(false, htmlContent);
+ navBar.setUserFooter(docletWriter.getUserHeaderFooter(false));
+ htmlContent.addContent(navBar.getContent(false));
docletWriter.addBottom(htmlContent);
docletWriter.printHtmlDocument(Collections.emptyList(), false, htmlContent);
return true;
@@ -301,31 +314,5 @@
throw new AssertionError("unsupported element: " + e.getKind());
}
}
-
- /**
- * Get the module link.
- *
- * @return a content tree for the module link
- */
- @Override
- protected Content getNavLinkModule() {
- Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(pkg),
- contents.moduleLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get this package link.
- *
- * @return a content tree for the package link
- */
- @Override
- protected Content getNavLinkPackage() {
- Content linkContent = getPackageLink(pkg,
- contents.packageLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
}
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.EnumConstantWriter;
@@ -273,37 +273,4 @@
String name = utils.getFullyQualifiedName(member) + "." + member.getSimpleName();
return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, name);
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
- if (link) {
- if (typeElement == null) {
- return links.createLink(SectionName.ENUM_CONSTANT_SUMMARY,
- contents.navEnum);
- } else {
- return links.createLink(
- SectionName.ENUM_CONSTANTS_INHERITANCE,
- configuration.getClassName(typeElement), contents.navEnum);
- }
- } else {
- return contents.navEnum;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void addNavDetailLink(boolean link, Content liNav) {
- if (link) {
- liNav.addContent(links.createLink(
- SectionName.ENUM_CONSTANT_DETAIL,
- contents.navEnum));
- } else {
- liNav.addContent(contents.navEnum);
- }
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -39,7 +39,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.FieldWriter;
@@ -302,38 +302,4 @@
String name = utils.getFullyQualifiedName(member) + "." + member.getSimpleName();
return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, name);
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
- if (link) {
- if (typeElement == null) {
- return links.createLink(
- SectionName.FIELD_SUMMARY,
- contents.navField);
- } else {
- return links.createLink(
- SectionName.FIELDS_INHERITANCE,
- configuration.getClassName(typeElement), contents.navField);
- }
- } else {
- return contents.navField;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void addNavDetailLink(boolean link, Content liNav) {
- if (link) {
- liNav.addContent(links.createLink(
- SectionName.FIELD_DETAIL,
- contents.navField));
- } else {
- liNav.addContent(contents.navField);
- }
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -29,6 +29,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
@@ -51,6 +53,8 @@
HtmlTree mainTree = HtmlTree.MAIN();
+ private final Navigation navBar;
+
/**
* Constructor to construct HelpWriter object.
* @param configuration the configuration
@@ -59,6 +63,7 @@
public HelpWriter(HtmlConfiguration configuration,
DocPath filename) {
super(configuration, filename);
+ this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.HELP, path);
}
/**
@@ -88,7 +93,8 @@
? HtmlTree.HEADER()
: body;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
body.addContent(htmlTree);
}
@@ -96,7 +102,8 @@
if (configuration.allowTag(HtmlTag.FOOTER)) {
htmlTree = HtmlTree.FOOTER();
}
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(htmlTree);
@@ -428,15 +435,4 @@
contentTree.addContent(divContent);
}
}
-
- /**
- * Get the help label.
- *
- * @return a content tree for the help label
- */
- @Override
- protected Content getNavLinkHelp() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.helpLabel);
- return li;
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java Tue Apr 10 13:58:47 2018 -0700
@@ -247,11 +247,11 @@
protected Set<Character> tagSearchIndexKeys;
- protected final Contents contents;
+ public final Contents contents;
protected final Messages messages;
- protected DocPaths docPaths;
+ public DocPaths docPaths;
/**
* Creates an object to hold the configuration for a doclet.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -69,13 +69,13 @@
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.DocType;
-import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
import jdk.javadoc.internal.doclets.formats.html.markup.Script;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
@@ -491,261 +491,6 @@
}
/**
- * Adds the navigation bar for the Html page at the top and and the bottom.
- *
- * @param header If true print navigation bar at the top of the page else
- * @param htmlTree the HtmlTree to which the nav links will be added
- */
- protected void addNavLinks(boolean header, Content htmlTree) {
- if (!configuration.nonavbar) {
- Content tree = (configuration.allowTag(HtmlTag.NAV))
- ? HtmlTree.NAV()
- : htmlTree;
- String allClassesId = "allclasses_";
- HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
- fixedNavDiv.setStyle(HtmlStyle.fixedNav);
- Content skipNavLinks = configuration.getContent("doclet.Skip_navigation_links");
- if (header) {
- fixedNavDiv.addContent(HtmlConstants.START_OF_TOP_NAVBAR);
- navDiv.setStyle(HtmlStyle.topNav);
- allClassesId += "navbar_top";
- Content a = links.createAnchor(SectionName.NAVBAR_TOP);
- //WCAG - Hyperlinks should contain text or an image with alt text - for AT tools
- navDiv.addContent(a);
- Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav,
- links.createLink(SectionName.SKIP_NAVBAR_TOP, skipNavLinks,
- skipNavLinks.toString(), ""));
- navDiv.addContent(skipLinkContent);
- } else {
- tree.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
- navDiv.setStyle(HtmlStyle.bottomNav);
- allClassesId += "navbar_bottom";
- Content a = links.createAnchor(SectionName.NAVBAR_BOTTOM);
- navDiv.addContent(a);
- Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav,
- links.createLink(SectionName.SKIP_NAVBAR_BOTTOM, skipNavLinks,
- skipNavLinks.toString(), ""));
- navDiv.addContent(skipLinkContent);
- }
- if (header) {
- navDiv.addContent(links.createAnchor(SectionName.NAVBAR_TOP_FIRSTROW));
- } else {
- navDiv.addContent(links.createAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW));
- }
- HtmlTree navList = new HtmlTree(HtmlTag.UL);
- navList.setStyle(HtmlStyle.navList);
- navList.addAttr(HtmlAttr.TITLE,
- configuration.getText("doclet.Navigation"));
- if (configuration.createoverview) {
- navList.addContent(getNavLinkContents());
- }
- if (configuration.showModules) {
- if (configuration.modules.size() == 1) {
- navList.addContent(getNavLinkModule(configuration.modules.first()));
- } else if (!configuration.modules.isEmpty()) {
- navList.addContent(getNavLinkModule());
- }
- }
- if (configuration.packages.size() == 1) {
- navList.addContent(getNavLinkPackage(configuration.packages.first()));
- } else if (!configuration.packages.isEmpty()) {
- navList.addContent(getNavLinkPackage());
- }
- navList.addContent(getNavLinkClass());
- if(configuration.classuse) {
- navList.addContent(getNavLinkClassUse());
- }
- if(configuration.createtree) {
- navList.addContent(getNavLinkTree());
- }
- if(!(configuration.nodeprecated ||
- configuration.nodeprecatedlist)) {
- navList.addContent(getNavLinkDeprecated());
- }
- if(configuration.createindex) {
- navList.addContent(getNavLinkIndex());
- }
- if (!configuration.nohelp) {
- navList.addContent(getNavLinkHelp());
- }
- navDiv.addContent(navList);
- Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header));
- navDiv.addContent(aboutDiv);
- if (header) {
- fixedNavDiv.addContent(navDiv);
- } else {
- tree.addContent(navDiv);
- }
- HtmlTree subDiv = new HtmlTree(HtmlTag.DIV);
- subDiv.setStyle(HtmlStyle.subNav);
- if (configuration.frames) {
- Content ulFrames = HtmlTree.UL(HtmlStyle.navList,
- getNavShowLists(), getNavHideLists(filename));
- subDiv.addContent(ulFrames);
- }
- HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex());
- ulAllClasses.addAttr(HtmlAttr.ID, allClassesId);
- subDiv.addContent(ulAllClasses);
- if (header && configuration.createindex) {
- String searchValueId = "search";
- String reset = "reset";
- HtmlTree inputText = HtmlTree.INPUT("text", searchValueId, searchValueId);
- HtmlTree inputReset = HtmlTree.INPUT(reset, reset, reset);
- Content searchTxt = configuration.getContent("doclet.search");
- HtmlTree liInput = HtmlTree.LI(HtmlTree.LABEL(searchValueId, searchTxt));
- liInput.addContent(inputText);
- liInput.addContent(inputReset);
- HtmlTree ulSearch = HtmlTree.UL(HtmlStyle.navListSearch, liInput);
- subDiv.addContent(ulSearch);
- }
- subDiv.addContent(getAllClassesLinkScript(allClassesId));
- addSummaryDetailLinks(subDiv);
- if (header) {
- subDiv.addContent(links.createAnchor(SectionName.SKIP_NAVBAR_TOP));
- fixedNavDiv.addContent(subDiv);
- fixedNavDiv.addContent(HtmlConstants.END_OF_TOP_NAVBAR);
- tree.addContent(fixedNavDiv);
- HtmlTree paddingDiv = HtmlTree.DIV(HtmlStyle.navPadding, Contents.SPACE);
- tree.addContent(paddingDiv);
- Script script = new Script(
- "<!--\n"
- + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
- + "//-->\n");
- tree.addContent(script.asContent());
- } else {
- subDiv.addContent(links.createAnchor(SectionName.SKIP_NAVBAR_BOTTOM));
- tree.addContent(subDiv);
- tree.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR);
- }
- if (configuration.allowTag(HtmlTag.NAV)) {
- htmlTree.addContent(tree);
- }
- }
- }
-
- /**
- * Do nothing. This is the default method.
- */
- protected void addSummaryDetailLinks(Content navDiv) {
- }
-
- /**
- * Get link to the "overview-summary.html" page.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkContents() {
- Content linkContent = links.createLink(pathToRoot.resolve(DocPaths.overviewSummary(configuration.frames)),
- contents.overviewLabel, "", "");
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get link to the module summary page for the module passed.
- *
- * @param mdle Module to which link will be generated
- * @return a content tree for the link
- */
- protected Content getNavLinkModule(ModuleElement mdle) {
- Content linkContent = getModuleLink(mdle, contents.moduleLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get the word "Module", to indicate that link is not available here.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkModule() {
- Content li = HtmlTree.LI(contents.moduleLabel);
- return li;
- }
-
- /**
- * Get link to the "package-summary.html" page for the package passed.
- *
- * @param pkg Package to which link will be generated
- * @return a content tree for the link
- */
- protected Content getNavLinkPackage(PackageElement pkg) {
- Content linkContent = getPackageLink(pkg, contents.packageLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get the word "Package" , to indicate that link is not available here.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkPackage() {
- Content li = HtmlTree.LI(contents.packageLabel);
- return li;
- }
-
- /**
- * Get the word "Use", to indicate that link is not available.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkClassUse() {
- Content li = HtmlTree.LI(contents.useLabel);
- return li;
- }
-
- /**
- * Get "FRAMES" link, to switch to the frame version of the output.
- *
- * @param link File to be linked, "index.html"
- * @return a content tree for the link
- */
- protected Content getNavShowLists(DocPath link) {
- DocLink dl = new DocLink(link, path.getPath(), null);
- Content framesContent = links.createLink(dl, contents.framesLabel, "", "_top");
- Content li = HtmlTree.LI(framesContent);
- return li;
- }
-
- /**
- * Get "FRAMES" link, to switch to the frame version of the output.
- *
- * @return a content tree for the link
- */
- protected Content getNavShowLists() {
- return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX));
- }
-
- /**
- * Get "NO FRAMES" link, to switch to the non-frame version of the output.
- *
- * @param link File to be linked
- * @return a content tree for the link
- */
- protected Content getNavHideLists(DocPath link) {
- Content noFramesContent = links.createLink(link, contents.noFramesLabel, "", "_top");
- Content li = HtmlTree.LI(noFramesContent);
- return li;
- }
-
- /**
- * Get "Tree" link in the navigation bar. If there is only one package
- * specified on the command line, then the "Tree" link will be to the
- * only "package-tree.html" file otherwise it will be to the
- * "overview-tree.html" file.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkTree() {
- List<PackageElement> packages = new ArrayList<>(configuration.getSpecifiedPackageElements());
- DocPath docPath = packages.size() == 1 && configuration.getSpecifiedTypeElements().isEmpty()
- ? pathString(packages.get(0), DocPaths.PACKAGE_TREE)
- : pathToRoot.resolve(DocPaths.OVERVIEW_TREE);
- return HtmlTree.LI(links.createLink(docPath, contents.treeLabel, "", ""));
- }
-
- /**
* Get the overview tree link for the main tree.
*
* @param label the label for the link
@@ -759,91 +504,6 @@
}
/**
- * Get the word "Class", to indicate that class link is not available.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkClass() {
- Content li = HtmlTree.LI(contents.classLabel);
- return li;
- }
-
- /**
- * Get "Deprecated" API link in the navigation bar.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkDeprecated() {
- Content linkContent = links.createLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
- contents.deprecatedLabel, "", "");
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get link for generated index. If the user has used "-splitindex"
- * command line option, then link to file "index-files/index-1.html" is
- * generated otherwise link to file "index-all.html" is generated.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkClassIndex() {
- Content allClassesContent = links.createLink(pathToRoot.resolve(
- DocPaths.AllClasses(configuration.frames)),
- contents.allClassesLabel, "", "");
- Content li = HtmlTree.LI(allClassesContent);
- return li;
- }
-
- /**
- * Get link for generated class index.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkIndex() {
- Content linkContent = links.createLink(pathToRoot.resolve(
- (configuration.splitindex
- ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
- : DocPaths.INDEX_ALL)),
- contents.indexLabel, "", "");
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get help file link. If user has provided a help file, then generate a
- * link to the user given file, which is already copied to current or
- * destination directory.
- *
- * @return a content tree for the link
- */
- protected Content getNavLinkHelp() {
- String helpfile = configuration.helpfile;
- DocPath helpfilenm;
- if (helpfile.isEmpty()) {
- helpfilenm = DocPaths.HELP_DOC;
- } else {
- DocFile file = DocFile.createFileForInput(configuration, helpfile);
- helpfilenm = DocPath.create(file.getName());
- }
- Content linkContent = links.createLink(pathToRoot.resolve(helpfilenm),
- contents.helpLabel, "", "");
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Add gap between navigation bar elements.
- *
- * @param liNav the content tree to which the gap will be added
- */
- protected void addNavGap(Content liNav) {
- liNav.addContent(Contents.SPACE);
- liNav.addContent("|");
- liNav.addContent(Contents.SPACE);
- }
-
- /**
* Get table caption.
*
* @param title the content for the caption
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -40,7 +40,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
@@ -424,37 +424,4 @@
htmltree.addContent(Contents.SPACE);
}
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
- if (link) {
- if (typeElement == null) {
- return links.createLink(
- SectionName.METHOD_SUMMARY,
- contents.navMethod);
- } else {
- return links.createLink(
- SectionName.METHODS_INHERITANCE,
- configuration.getClassName(typeElement), contents.navMethod);
- }
- } else {
- return contents.navMethod;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void addNavDetailLink(boolean link, Content liNav) {
- if (link) {
- liNav.addContent(links.createLink(
- SectionName.METHOD_DETAIL, contents.navMethod));
- } else {
- liNav.addContent(contents.navMethod);
- }
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -227,7 +227,8 @@
? HtmlTree.HEADER()
: body;
addTop(tree);
- addNavLinks(true, tree);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ tree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
body.addContent(tree);
}
@@ -244,7 +245,8 @@
Content htmltree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: body;
- addNavLinks(false, htmltree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmltree.addContent(navBar.getContent(false));
addBottom(htmltree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(htmltree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -50,13 +50,14 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.ModuleSummaryWriter;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
/**
* Class to generate file for each module contents in the right-hand frame. This will list all the
@@ -171,6 +172,8 @@
*/
protected HtmlTree sectionTree = HtmlTree.SECTION();
+ private final Navigation navBar;
+
/**
* Constructor to construct ModuleWriter object and to generate "moduleName-summary.html" file.
*
@@ -181,6 +184,7 @@
super(configuration, configuration.docPaths.moduleSummary(mdle));
this.mdle = mdle;
this.moduleMode = configuration.docEnv.getModuleMode();
+ this.navBar = new Navigation(mdle, configuration, fixedNavDiv, PageMode.MODULE, path);
computeModulesData();
}
@@ -196,7 +200,13 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ navBar.setDisplaySummaryModuleDescLink(!utils.getFullBody(mdle).isEmpty() && !configuration.nocomment);
+ navBar.setDisplaySummaryModulesLink(display(requires) || display(indirectModules));
+ navBar.setDisplaySummaryPackagesLink(display(packages) || display(indirectPackages)
+ || display(indirectOpenPackages));
+ navBar.setDisplaySummaryServicesLink(displayServices(uses, usesTrees) || displayServices(provides.keySet(), providesTrees));
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -914,47 +924,6 @@
}
/**
- * Add summary details to the navigation bar.
- *
- * @param subDiv the content tree to which the summary detail links will be added
- */
- @Override
- protected void addSummaryDetailLinks(Content subDiv) {
- Content div = HtmlTree.DIV(getNavSummaryLinks());
- subDiv.addContent(div);
- }
-
- /**
- * Get summary links for navigation bar.
- *
- * @return the content tree for the navigation summary links
- */
- protected Content getNavSummaryLinks() {
- Content li = HtmlTree.LI(contents.moduleSubNavLabel);
- li.addContent(Contents.SPACE);
- Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
- Content liNav = new HtmlTree(HtmlTag.LI);
- liNav.addContent(!utils.getFullBody(mdle).isEmpty() && !configuration.nocomment
- ? links.createLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription)
- : contents.navModuleDescription);
- addNavGap(liNav);
- liNav.addContent((display(requires) || display(indirectModules))
- ? links.createLink(SectionName.MODULES, contents.navModules)
- : contents.navModules);
- addNavGap(liNav);
- liNav.addContent((display(packages)
- || display(indirectPackages) || display(indirectOpenPackages))
- ? links.createLink(SectionName.PACKAGES, contents.navPackages)
- : contents.navPackages);
- addNavGap(liNav);
- liNav.addContent((displayServices(uses, usesTrees) || displayServices(provides.keySet(), providesTrees))
- ? links.createLink(SectionName.SERVICES, contents.navServices)
- : contents.navServices);
- ulNav.addContent(liNav);
- return ulNav;
- }
-
- /**
* {@inheritDoc}
*/
@Override
@@ -975,7 +944,8 @@
Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: contentTree;
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
contentTree.addContent(htmlTree);
@@ -1017,15 +987,4 @@
li.addContent(deprDiv);
}
}
-
- /**
- * Get this module link.
- *
- * @return a content tree for the module link
- */
- @Override
- protected Content getNavLinkModule() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.moduleLabel);
- return li;
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
@@ -205,31 +205,4 @@
protected Content getDeprecatedLink(Element member) {
return writer.getQualifiedClassLink(LinkInfoImpl.Kind.MEMBER, member);
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
- if (link) {
- if (typeElement == null) {
- return links.createLink(
- SectionName.NESTED_CLASS_SUMMARY,
- contents.navNested);
- } else {
- return links.createLink(
- SectionName.NESTED_CLASSES_INHERITANCE,
- utils.getFullyQualifiedName(typeElement), contents.navNested);
- }
- } else {
- return contents.navNested;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void addNavDetailLink(boolean link, Content liNav) {
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -209,7 +209,8 @@
? HtmlTree.HEADER()
: body;
addTop(tree);
- addNavLinks(true, tree);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ tree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
body.addContent(tree);
}
@@ -226,7 +227,8 @@
Content tree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: body;
- addNavLinks(false, tree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ tree.addContent(navBar.getContent(false));
addBottom(tree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(tree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -31,6 +31,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
@@ -57,6 +59,8 @@
*/
protected PackageElement packageElement;
+ private final Navigation navBar;
+
/**
* Constructor.
* @param configuration the configuration
@@ -67,6 +71,7 @@
super(configuration, path,
new ClassTree(configuration.typeElementCatalog.allClasses(packageElement), configuration));
this.packageElement = packageElement;
+ this.navBar = new Navigation(packageElement, configuration, fixedNavDiv, PageMode.TREE, path);
}
/**
@@ -118,7 +123,8 @@
HtmlTree tree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: body;
- addNavLinks(false, tree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ tree.addContent(navBar.getContent(false));
addBottom(tree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(tree);
@@ -139,7 +145,11 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
+ contents.moduleLabel);
+ navBar.setNavLinkModule(linkContent);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -160,30 +170,4 @@
ul.addContent(getNavLinkMainTree(configuration.getText("doclet.All_Packages")));
div.addContent(ul);
}
-
- /**
- * Get the module link.
- *
- * @return a content tree for the module link
- */
- @Override
- protected Content getNavLinkModule() {
- Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
- contents.moduleLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get link to the package summary page for the package of this tree.
- *
- * @return a content tree for the package link
- */
- @Override
- protected Content getNavLinkPackage() {
- Content linkContent = links.createLink(DocPaths.PACKAGE_SUMMARY,
- contents.packageLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -38,7 +38,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper;
@@ -63,6 +64,7 @@
final SortedMap<String, Set<TypeElement>> usingPackageToUsedClasses = new TreeMap<>();
protected HtmlTree mainTree = HtmlTree.MAIN();
final String packageUseTableSummary;
+ private final Navigation navBar;
/**
* Constructor.
@@ -100,6 +102,7 @@
packageUseTableSummary = resources.getText("doclet.Use_Table_Summary",
resources.getText("doclet.packages"));
+ this.navBar = new Navigation(packageElement, configuration, fixedNavDiv, PageMode.USE, path);
}
/**
@@ -140,7 +143,8 @@
HtmlTree tree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: body;
- addNavLinks(false, tree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ tree.addContent(navBar.getContent(false));
addBottom(tree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(tree);
@@ -249,7 +253,11 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
+ contents.moduleLabel);
+ navBar.setNavLinkModule(linkContent);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -267,54 +275,4 @@
}
return bodyTree;
}
-
- /**
- * Get the module link.
- *
- * @return a content tree for the module link
- */
- @Override
- protected Content getNavLinkModule() {
- Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
- contents.moduleLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get this package link.
- *
- * @return a content tree for the package link
- */
- @Override
- protected Content getNavLinkPackage() {
- Content linkContent = links.createLink(DocPaths.PACKAGE_SUMMARY,
- contents.packageLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Get the use link.
- *
- * @return a content tree for the use link
- */
- @Override
- protected Content getNavLinkClassUse() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.useLabel);
- return li;
- }
-
- /**
- * Get the tree link.
- *
- * @return a content tree for the tree link
- */
- @Override
- protected Content getNavLinkTree() {
- Content linkContent = links.createLink(DocPaths.PACKAGE_TREE,
- contents.treeLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -40,12 +40,13 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
/**
@@ -79,6 +80,8 @@
*/
protected HtmlTree sectionTree = HtmlTree.SECTION();
+ private final Navigation navBar;
+
/**
* Constructor to construct PackageWriter object and to generate
* "package-summary.html" file in the respective package directory.
@@ -95,6 +98,7 @@
configuration.docPaths.forPackage(packageElement)
.resolve(DocPaths.PACKAGE_SUMMARY));
this.packageElement = packageElement;
+ this.navBar = new Navigation(packageElement, configuration, fixedNavDiv, PageMode.PACKAGE, path);
}
/**
@@ -107,7 +111,11 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
+ contents.moduleLabel);
+ navBar.setNavLinkModule(linkContent);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -346,7 +354,8 @@
Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: contentTree;
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
contentTree.addContent(htmlTree);
@@ -361,55 +370,4 @@
printHtmlDocument(configuration.metakeywords.getMetaKeywords(packageElement),
true, contentTree);
}
-
- /**
- * Get "Use" link for this pacakge in the navigation bar.
- *
- * @return a content tree for the class use link
- */
- @Override
- protected Content getNavLinkClassUse() {
- Content useLink = links.createLink(DocPaths.PACKAGE_USE,
- contents.useLabel, "", "");
- Content li = HtmlTree.LI(useLink);
- return li;
- }
-
- /**
- * Get "Tree" link in the navigation bar. This will be link to the package
- * tree file.
- *
- * @return a content tree for the tree link
- */
- @Override
- protected Content getNavLinkTree() {
- Content useLink = links.createLink(DocPaths.PACKAGE_TREE,
- contents.treeLabel, "", "");
- Content li = HtmlTree.LI(useLink);
- return li;
- }
-
- /**
- * Get the module link.
- *
- * @return a content tree for the module link
- */
- @Override
- protected Content getNavLinkModule() {
- Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
- contents.moduleLabel);
- Content li = HtmlTree.LI(linkContent);
- return li;
- }
-
- /**
- * Highlight "Package" in the navigation bar, as this is the package page.
- *
- * @return a content tree for the package link
- */
- @Override
- protected Content getNavLinkPackage() {
- Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.packageLabel);
- return li;
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
@@ -324,38 +324,4 @@
return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member,
utils.getFullyQualifiedName(member));
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
- if (link) {
- if (typeElement == null) {
- return links.createLink(
- SectionName.PROPERTY_SUMMARY,
- contents.navProperty);
- } else {
- return links.createLink(
- SectionName.PROPERTIES_INHERITANCE,
- configuration.getClassName(typeElement), contents.navProperty);
- }
- } else {
- return contents.navProperty;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void addNavDetailLink(boolean link, Content liNav) {
- if (link) {
- liNav.addContent(links.createLink(
- SectionName.PROPERTY_DETAIL,
- contents.navProperty));
- } else {
- liNav.addContent(contents.navProperty);
- }
- }
}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java Tue Apr 10 13:58:47 2018 -0700
@@ -33,6 +33,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter;
@@ -59,12 +61,15 @@
*/
private HtmlTree mainTree = HtmlTree.MAIN();
+ private final Navigation navBar;
+
/**
* @param configuration the configuration data for the doclet
*/
public SerializedFormWriterImpl(HtmlConfiguration configuration) {
super(configuration, DocPaths.SERIALIZED_FORM);
visibleClasses = configuration.getIncludedTypeElements();
+ this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.SERIALIZEDFORM, path);
}
/**
@@ -79,7 +84,8 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
@@ -261,7 +267,8 @@
Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
? HtmlTree.FOOTER()
: serializedTree;
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
serializedTree.addContent(htmlTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -97,7 +97,8 @@
? HtmlTree.HEADER()
: body;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
body.addContent(htmlTree);
}
@@ -123,7 +124,8 @@
if (configuration.allowTag(HtmlTag.FOOTER)) {
htmlTree = HtmlTree.FOOTER();
}
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(htmlTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -125,7 +125,8 @@
? HtmlTree.HEADER()
: body;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
body.addContent(htmlTree);
}
@@ -145,7 +146,8 @@
if (configuration.allowTag(HtmlTag.FOOTER)) {
htmlTree = HtmlTree.FOOTER();
}
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(htmlTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java Tue Apr 10 13:58:47 2018 -0700
@@ -33,7 +33,8 @@
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
@@ -68,6 +69,8 @@
*/
private final boolean classesOnly;
+ private final Navigation navBar;
+
/**
* Constructor to construct TreeWriter object.
*
@@ -79,6 +82,7 @@
super(configuration, filename, classtree);
packages = configuration.packages;
classesOnly = packages.isEmpty();
+ this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.TREE, path);
}
/**
@@ -127,7 +131,8 @@
} else {
htmlTree = body;
}
- addNavLinks(false, htmlTree);
+ navBar.setUserFooter(getUserHeaderFooter(false));
+ htmlTree.addContent(navBar.getContent(false));
addBottom(htmlTree);
if (configuration.allowTag(HtmlTag.FOOTER)) {
body.addContent(htmlTree);
@@ -186,7 +191,8 @@
? HtmlTree.HEADER()
: bodyTree;
addTop(htmlTree);
- addNavLinks(true, htmlTree);
+ navBar.setUserHeader(getUserHeaderFooter(true));
+ htmlTree.addContent(navBar.getContent(true));
if (configuration.allowTag(HtmlTag.HEADER)) {
bodyTree.addContent(htmlTree);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Navigation.java Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,1089 @@
+/*
+ * Copyright (c) 2018, 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.javadoc.internal.doclets.formats.html.markup;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+import jdk.javadoc.internal.doclets.formats.html.AbstractMemberWriter;
+import jdk.javadoc.internal.doclets.formats.html.Contents;
+import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
+import jdk.javadoc.internal.doclets.formats.html.SectionName;
+import jdk.javadoc.internal.doclets.toolkit.Content;
+import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder;
+import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
+import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
+import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
+import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
+import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
+
+/**
+ * Factory for navigation bar.
+ *
+ * <p>
+ * <b>This is NOT part of any supported API. If you write code that depends on this, you do so at
+ * your own risk. This code and its internal interfaces are subject to change or deletion without
+ * notice.</b>
+ */
+public class Navigation {
+
+ private final HtmlConfiguration configuration;
+ private final Element element;
+ private final Contents contents;
+ private final DocPath path;
+ private final DocPath pathToRoot;
+ private final Links links;
+ private final HtmlTree fixedNavDiv;
+ private final PageMode documentedPage;
+ private Content navLinkModule;
+ private Content navLinkPackage;
+ private Content navLinkClass;
+ private MemberSummaryBuilder memberSummaryBuilder;
+ private boolean displaySummaryModuleDescLink;
+ private boolean displaySummaryModulesLink;
+ private boolean displaySummaryPackagesLink;
+ private boolean displaySummaryServicesLink;
+ private final Map<Position, Deque<Content>> topBottomNavContents;
+ private Content userHeader;
+ private Content userFooter;
+ private final String rowListTitle;
+ private final Content searchLabel;
+ private static final Script FIXED_NAV_SCRIPT = new Script("<!--\n"
+ + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
+ + "//-->\n");
+
+ public enum PageMode {
+ CLASS,
+ CONSTANTVALUES,
+ DEPRECATED,
+ DOCFILE,
+ HELP,
+ INDEX,
+ MODULE,
+ OVERVIEW,
+ PACKAGE,
+ SERIALIZEDFORM,
+ TREE,
+ USE;
+ }
+
+ enum Position {
+ BOTTOM("allclasses_navbar_bottom", HtmlConstants.START_OF_BOTTOM_NAVBAR, HtmlConstants.END_OF_BOTTOM_NAVBAR),
+ TOP("allclasses_navbar_top", HtmlConstants.START_OF_TOP_NAVBAR, HtmlConstants.END_OF_TOP_NAVBAR);
+
+ final String allClassesLinkId;
+ final Content startOfNav;
+ final Content endOfNav;
+
+ Position(String allClassesLinkId, Content startOfNav, Content endOfNav) {
+ this.allClassesLinkId = allClassesLinkId;
+ this.startOfNav = startOfNav;
+ this.endOfNav = endOfNav;
+ }
+
+ String allClassesLinkId() {
+ return allClassesLinkId;
+ }
+
+ Content startOfNav() {
+ return startOfNav;
+ }
+
+ Content endOfNav() {
+ return endOfNav;
+ }
+
+ Script allClassesLinkScript() {
+ return new Script("<!--\n"
+ + " allClassesLink = document.getElementById(")
+ .appendStringLiteral(allClassesLinkId)
+ .append(");\n"
+ + " if(window==top) {\n"
+ + " allClassesLink.style.display = \"block\";\n"
+ + " }\n"
+ + " else {\n"
+ + " allClassesLink.style.display = \"none\";\n"
+ + " }\n"
+ + " //-->\n");
+ }
+ }
+
+ /**
+ * Creates a {@code Navigation} object for a specific file, to be written in a specific HTML
+ * version.
+ *
+ * @param element element being documented. null if its not an element documentation page
+ * @param configuration the configuration object
+ * @param fixedNavDiv the fixed navigation for the header navigation
+ * @param page the kind of page being documented
+ * @param path the DocPath object
+ */
+ public Navigation(Element element, HtmlConfiguration configuration, HtmlTree fixedNavDiv,
+ PageMode page, DocPath path) {
+ this.configuration = configuration;
+ this.element = element;
+ this.fixedNavDiv = fixedNavDiv;
+ this.contents = configuration.contents;
+ this.documentedPage = page;
+ this.path = path;
+ this.pathToRoot = path.parent().invert();
+ this.links = new Links(path, configuration.htmlVersion);
+ this.topBottomNavContents = new HashMap<>();
+ this.rowListTitle = configuration.getText("doclet.Navigation");
+ this.searchLabel = configuration.getContent("doclet.search");
+ populateNavContents(Position.TOP);
+ populateNavContents(Position.BOTTOM);
+ }
+
+ /**
+ * Populate the navigation contents for top and bottom navigation
+ *
+ * @param position the position of the navigation bar on the page
+ */
+ private void populateNavContents(Position position) {
+ Deque<Content> queue = new ArrayDeque<>();
+ Content skipNavLinks = configuration.getContent("doclet.Skip_navigation_links");
+ switch (position) {
+ case TOP:
+ queue.addLast(links.createAnchor(SectionName.NAVBAR_TOP));
+ queue.addLast(links.createLink(SectionName.SKIP_NAVBAR_TOP, skipNavLinks,
+ skipNavLinks.toString(), ""));
+ queue.addLast(links.createAnchor(SectionName.NAVBAR_TOP_FIRSTROW));
+ queue.addLast(links.createAnchor(SectionName.SKIP_NAVBAR_TOP));
+ topBottomNavContents.put(position, queue);
+ break;
+ case BOTTOM:
+ queue.addLast(links.createAnchor(SectionName.NAVBAR_BOTTOM));
+ queue.addLast(links.createLink(SectionName.SKIP_NAVBAR_BOTTOM, skipNavLinks,
+ skipNavLinks.toString(), ""));
+ queue.addLast(links.createAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW));
+ queue.addLast(links.createAnchor(SectionName.SKIP_NAVBAR_BOTTOM));
+ topBottomNavContents.put(position, queue);
+ break;
+ default:
+ break;
+ }
+ }
+
+ public Navigation setNavLinkModule(Content navLinkModule) {
+ this.navLinkModule = navLinkModule;
+ return this;
+ }
+
+ public Navigation setNavLinkPackage(Content navLinkPackage) {
+ this.navLinkPackage = navLinkPackage;
+ return this;
+ }
+
+ public Navigation setNavLinkClass(Content navLinkClass) {
+ this.navLinkClass = navLinkClass;
+ return this;
+ }
+
+ public Navigation setMemberSummaryBuilder(MemberSummaryBuilder memberSummaryBuilder) {
+ this.memberSummaryBuilder = memberSummaryBuilder;
+ return this;
+ }
+
+ public Navigation setDisplaySummaryModuleDescLink(boolean displaySummaryModuleDescLink) {
+ this.displaySummaryModuleDescLink = displaySummaryModuleDescLink;
+ return this;
+ }
+
+ public Navigation setDisplaySummaryModulesLink(boolean displaySummaryModulesLink) {
+ this.displaySummaryModulesLink = displaySummaryModulesLink;
+ return this;
+ }
+
+ public Navigation setDisplaySummaryPackagesLink(boolean displaySummaryPackagesLink) {
+ this.displaySummaryPackagesLink = displaySummaryPackagesLink;
+ return this;
+ }
+
+ public Navigation setDisplaySummaryServicesLink(boolean displaySummaryServicesLink) {
+ this.displaySummaryServicesLink = displaySummaryServicesLink;
+ return this;
+ }
+
+ public Navigation setUserHeader(Content userHeader) {
+ this.userHeader = userHeader;
+ return this;
+ }
+
+ public Navigation setUserFooter(Content userFooter) {
+ this.userFooter = userFooter;
+ return this;
+ }
+
+ /**
+ * Add the links for the main navigation.
+ *
+ * @param tree the content tree to which the main navigation will added
+ */
+ private void addMainNavLinks(Content tree) {
+ switch (documentedPage) {
+ case OVERVIEW:
+ addActivePageLink(tree, contents.overviewLabel, configuration.createoverview);
+ addModuleLink(tree);
+ addPackageLink(tree);
+ addPageLabel(tree, contents.classLabel, true);
+ addPageLabel(tree, contents.useLabel, configuration.classuse);
+ addTreeLink(tree);
+ addDeprecatedLink(tree);
+ addIndexLink(tree);
+ addHelpLink(tree);
+ break;
+ case MODULE:
+ addOverviewLink(tree);
+ addActivePageLink(tree, contents.moduleLabel, configuration.showModules);
+ addPackageLink(tree);
+ addPageLabel(tree, contents.classLabel, true);
+ addPageLabel(tree, contents.useLabel, configuration.classuse);
+ addTreeLink(tree);
+ addDeprecatedLink(tree);
+ addIndexLink(tree);
+ addHelpLink(tree);
+ break;
+ case PACKAGE:
+ addOverviewLink(tree);
+ addModuleOfElementLink(tree);
+ addActivePageLink(tree, contents.packageLabel, true);
+ addPageLabel(tree, contents.classLabel, true);
+ if (configuration.classuse) {
+ addContentToTree(tree, links.createLink(DocPaths.PACKAGE_USE,
+ contents.useLabel, "", ""));
+ }
+ if (configuration.createtree) {
+ addContentToTree(tree, links.createLink(DocPaths.PACKAGE_TREE,
+ contents.treeLabel, "", ""));
+ }
+ addDeprecatedLink(tree);
+ addIndexLink(tree);
+ addHelpLink(tree);
+ break;
+ case CLASS:
+ addOverviewLink(tree);
+ addModuleOfElementLink(tree);
+ addPackageSummaryLink(tree);
+ addActivePageLink(tree, contents.classLabel, true);
+ if (configuration.classuse) {
+ addContentToTree(tree, links.createLink(DocPaths.CLASS_USE.resolve(path.basename()),
+ contents.useLabel));
+ }
+ if (configuration.createtree) {
+ addContentToTree(tree, links.createLink(DocPaths.PACKAGE_TREE,
+ contents.treeLabel, "", ""));
+ }
+ addDeprecatedLink(tree);
+ addIndexLink(tree);
+ addHelpLink(tree);
+ break;
+ case USE:
+ addOverviewLink(tree);
+ addModuleOfElementLink(tree);
+ if (element instanceof PackageElement) {
+ addPackageSummaryLink(tree);
+ addPageLabel(tree, contents.classLabel, true);
+ } else {
+ addPackageOfElementLink(tree);
+ addContentToTree(tree, navLinkClass);
+ }
+ addActivePageLink(tree, contents.useLabel, configuration.classuse);
+ if (element instanceof PackageElement) {
+ addContentToTree(tree, links.createLink(DocPaths.PACKAGE_TREE, contents.treeLabel));
+ } else {
+ addContentToTree(tree, configuration.utils.isEnclosingPackageIncluded((TypeElement) element)
+ ? links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_TREE), contents.treeLabel)
+ : links.createLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), contents.treeLabel));
+ }
+ addDeprecatedLink(tree);
+ addIndexLink(tree);
+ addHelpLink(tree);
+ break;
+ case TREE:
+ addOverviewLink(tree);
+ if (element == null) {
+ addPageLabel(tree, contents.moduleLabel, configuration.showModules);
+ addPageLabel(tree, contents.packageLabel, true);
+ } else {
+ addModuleOfElementLink(tree);
+ addPackageSummaryLink(tree);
+ }
+ addPageLabel(tree, contents.classLabel, true);
+ addPageLabel(tree, contents.useLabel, configuration.classuse);
+ addActivePageLink(tree, contents.treeLabel, configuration.createtree);
+ addDeprecatedLink(tree);
+ addIndexLink(tree);
+ addHelpLink(tree);
+ break;
+ case DEPRECATED:
+ case INDEX:
+ case HELP:
+ addOverviewLink(tree);
+ addModuleLink(tree);
+ addPackageLink(tree);
+ addPageLabel(tree, contents.classLabel, true);
+ addPageLabel(tree, contents.useLabel, configuration.classuse);
+ addTreeLink(tree);
+ if (documentedPage == PageMode.DEPRECATED) {
+ addActivePageLink(tree, contents.deprecatedLabel, !(configuration.nodeprecated
+ || configuration.nodeprecatedlist));
+ } else {
+ addDeprecatedLink(tree);
+ }
+ if (documentedPage == PageMode.INDEX) {
+ addActivePageLink(tree, contents.indexLabel, configuration.createindex);
+ } else {
+ addIndexLink(tree);
+ }
+ if (documentedPage == PageMode.HELP) {
+ addActivePageLink(tree, contents.helpLabel, !configuration.nohelp);
+ } else {
+ addHelpLink(tree);
+ }
+ break;
+ case CONSTANTVALUES:
+ case SERIALIZEDFORM:
+ addOverviewLink(tree);
+ addModuleLink(tree);
+ addPackageLink(tree);
+ addPageLabel(tree, contents.classLabel, true);
+ addPageLabel(tree, contents.useLabel, configuration.classuse);
+ addTreeLink(tree);
+ addDeprecatedLink(tree);
+ addIndexLink(tree);
+ addHelpLink(tree);
+ break;
+ case DOCFILE:
+ addOverviewLink(tree);
+ addModuleOfElementLink(tree);
+ addContentToTree(tree, navLinkPackage);
+ addPageLabel(tree, contents.classLabel, true);
+ addPageLabel(tree, contents.useLabel, configuration.classuse);
+ addTreeLink(tree);
+ addDeprecatedLink(tree);
+ addIndexLink(tree);
+ addHelpLink(tree);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Add the summary links to the sub-navigation.
+ *
+ * @param tree the content tree to which the sub-navigation will added
+ */
+ private void addSummaryLinks(Content tree) {
+ List<Content> listContents = new ArrayList<>();
+ switch (documentedPage) {
+ case CLASS:
+ if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
+ addAnnotationTypeSummaryLink("doclet.navField",
+ VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS, listContents);
+ addAnnotationTypeSummaryLink("doclet.navAnnotationTypeRequiredMember",
+ VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED, listContents);
+ addAnnotationTypeSummaryLink("doclet.navAnnotationTypeOptionalMember",
+ VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL, listContents);
+ } else {
+ TypeElement typeElement = (TypeElement) element;
+ for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.summarySet) {
+ if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) {
+ continue;
+ }
+ if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && configuration.utils.isEnum(typeElement)) {
+ continue;
+ }
+ AbstractMemberWriter writer
+ = ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind));
+ if (writer == null) {
+ addContentToList(listContents,
+ contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
+ } else {
+ addTypeSummaryLink(memberSummaryBuilder.members(kind),
+ memberSummaryBuilder.getVisibleMemberMap(kind), listContents);
+ }
+ }
+ }
+ if (!listContents.isEmpty()) {
+ Content li = HtmlTree.LI(contents.summaryLabel);
+ li.addContent(Contents.SPACE);
+ tree.addContent(li);
+ addListToNav(listContents, tree);
+ }
+ break;
+ case MODULE:
+ if (displaySummaryModuleDescLink) {
+ addContentToList(listContents,
+ links.createLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription));
+ } else {
+ addContentToList(listContents, contents.navModuleDescription);
+ }
+ if (displaySummaryModulesLink) {
+ addContentToList(listContents,
+ links.createLink(SectionName.MODULES, contents.navModules));
+ } else {
+ addContentToList(listContents, contents.navModules);
+ }
+ if (displaySummaryPackagesLink) {
+ addContentToList(listContents,
+ links.createLink(SectionName.PACKAGES, contents.navPackages));
+ } else {
+ addContentToList(listContents, contents.navPackages);
+ }
+ if (displaySummaryServicesLink) {
+ addContentToList(listContents,
+ links.createLink(SectionName.SERVICES, contents.navServices));
+ } else {
+ addContentToList(listContents, contents.navServices);
+ }
+ if (!listContents.isEmpty()) {
+ Content li = HtmlTree.LI(contents.moduleSubNavLabel);
+ li.addContent(Contents.SPACE);
+ tree.addContent(li);
+ addListToNav(listContents, tree);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Add the navigation summary link.
+ *
+ * @param members members to be linked
+ * @param visibleMemberMap the visible inherited members map
+ * @param listContents the list of contents
+ */
+ private void addTypeSummaryLink(SortedSet<? extends Element> members,
+ VisibleMemberMap visibleMemberMap, List<Content> listContents) {
+ if (!members.isEmpty()) {
+ addTypeSummaryLink(null, visibleMemberMap.kind, true, listContents);
+ return;
+ }
+
+ SortedSet<TypeElement> visibleClasses = visibleMemberMap.getVisibleClasses();
+ for (TypeElement t : visibleClasses) {
+ if (!configuration.getVisibleMemberMap(t, visibleMemberMap.kind).getLeafMembers().isEmpty()) {
+ addTypeSummaryLink(null, visibleMemberMap.kind, true, listContents);
+ return;
+ }
+ }
+ addTypeSummaryLink(null, visibleMemberMap.kind, false, listContents);
+ }
+
+ /**
+ * Add the navigation Type summary link.
+ *
+ * @param typeElement the Type being documented
+ * @param kind the kind of member being documented
+ * @param link true if the members are listed and need to be linked
+ * @param listContents the list of contents to which the summary will be added
+ */
+ private void addTypeSummaryLink(TypeElement typeElement, VisibleMemberMap.Kind kind, boolean link,
+ List<Content> listContents) {
+ switch (kind) {
+ case CONSTRUCTORS:
+ if (link) {
+ addContentToList(listContents, links.createLink(SectionName.CONSTRUCTOR_SUMMARY,
+ contents.navConstructor));
+ } else {
+ addContentToList(listContents, contents.navConstructor);
+ }
+ break;
+ case ENUM_CONSTANTS:
+ if (link) {
+ if (typeElement == null) {
+ addContentToList(listContents, links.createLink(SectionName.ENUM_CONSTANT_SUMMARY,
+ contents.navEnum));
+ } else {
+ addContentToList(listContents, links.createLink(
+ SectionName.ENUM_CONSTANTS_INHERITANCE,
+ configuration.getClassName(typeElement), contents.navEnum));
+ }
+ } else {
+ addContentToList(listContents, contents.navEnum);
+ }
+ break;
+ case FIELDS:
+ if (link) {
+ if (typeElement == null) {
+ addContentToList(listContents,
+ links.createLink(SectionName.FIELD_SUMMARY, contents.navField));
+ } else {
+ addContentToList(listContents, links.createLink(SectionName.FIELDS_INHERITANCE,
+ configuration.getClassName(typeElement), contents.navField));
+ }
+ } else {
+ addContentToList(listContents, contents.navField);
+ }
+ break;
+ case METHODS:
+ if (link) {
+ if (typeElement == null) {
+ addContentToList(listContents,
+ links.createLink(SectionName.METHOD_SUMMARY, contents.navMethod));
+ } else {
+ addContentToList(listContents, links.createLink(SectionName.METHODS_INHERITANCE,
+ configuration.getClassName(typeElement), contents.navMethod));
+ }
+ } else {
+ addContentToList(listContents, contents.navMethod);
+ }
+ break;
+ case INNER_CLASSES:
+ if (link) {
+ if (typeElement == null) {
+ addContentToList(listContents,
+ links.createLink(SectionName.NESTED_CLASS_SUMMARY, contents.navNested));
+ } else {
+ addContentToList(listContents, links.createLink(SectionName.NESTED_CLASSES_INHERITANCE,
+ configuration.utils.getFullyQualifiedName(typeElement), contents.navNested));
+ }
+ } else {
+ addContentToList(listContents, contents.navNested);
+ }
+ break;
+ case PROPERTIES:
+ if (link) {
+ if (typeElement == null) {
+ addContentToList(listContents,
+ links.createLink(SectionName.PROPERTY_SUMMARY, contents.navProperty));
+ } else {
+ addContentToList(listContents, links.createLink(SectionName.PROPERTIES_INHERITANCE,
+ configuration.getClassName(typeElement), contents.navProperty));
+ }
+ } else {
+ addContentToList(listContents, contents.navProperty);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Add the navigation Type summary link.
+ *
+ * @param label the label to be added
+ * @param type the kind of member being documented
+ * @param listContents the list of contents to which the summary will be added
+ */
+ private void addAnnotationTypeSummaryLink(String label, VisibleMemberMap.Kind type, List<Content> listContents) {
+ AbstractMemberWriter writer = ((AbstractMemberWriter) memberSummaryBuilder.
+ getMemberSummaryWriter(type));
+ if (writer == null) {
+ addContentToList(listContents, contents.getContent(label));
+ } else {
+ boolean link = !memberSummaryBuilder.getVisibleMemberMap(type).noVisibleMembers();
+ switch (type) {
+ case ANNOTATION_TYPE_FIELDS:
+ if (link) {
+ addContentToList(listContents, links.createLink(SectionName.ANNOTATION_TYPE_FIELD_SUMMARY,
+ contents.navField));
+ } else {
+ addContentToList(listContents, contents.navField);
+ }
+ break;
+ case ANNOTATION_TYPE_MEMBER_REQUIRED:
+ if (link) {
+ addContentToList(listContents, links.createLink(
+ SectionName.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY,
+ contents.navAnnotationTypeRequiredMember));
+ } else {
+ addContentToList(listContents, contents.navAnnotationTypeRequiredMember);
+ }
+ break;
+ case ANNOTATION_TYPE_MEMBER_OPTIONAL:
+ if (link) {
+ addContentToList(listContents, links.createLink(
+ SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY,
+ contents.navAnnotationTypeOptionalMember));
+ } else {
+ addContentToList(listContents, contents.navAnnotationTypeOptionalMember);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Add the detail links to sub-navigation.
+ *
+ * @param tree the content tree to which the links will be added
+ */
+ private void addDetailLinks(Content tree) {
+ switch (documentedPage) {
+ case CLASS:
+ List<Content> listContents = new ArrayList<>();
+ if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
+ addAnnotationTypeDetailLink(listContents);
+ } else {
+ TypeElement typeElement = (TypeElement) element;
+ for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.detailSet) {
+ AbstractMemberWriter writer
+ = ((AbstractMemberWriter) memberSummaryBuilder.
+ getMemberSummaryWriter(kind));
+ if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) {
+ continue;
+ }
+ if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && configuration.utils.isEnum(typeElement)) {
+ continue;
+ }
+ if (writer == null) {
+ addContentToList(listContents, contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
+ } else {
+ addTypeDetailLink(kind, !memberSummaryBuilder.members(kind).isEmpty(), listContents);
+ }
+ }
+ }
+ if (!listContents.isEmpty()) {
+ Content li = HtmlTree.LI(contents.detailLabel);
+ li.addContent(Contents.SPACE);
+ tree.addContent(li);
+ addListToNav(listContents, tree);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Add the navigation Type detail link.
+ *
+ * @param kind the kind of member being documented
+ * @param link true if the members are listed and need to be linked
+ * @param listContents the list of contents to which the detail will be added.
+ */
+ protected void addTypeDetailLink(VisibleMemberMap.Kind kind, boolean link, List<Content> listContents) {
+ switch (kind) {
+ case CONSTRUCTORS:
+ if (link) {
+ addContentToList(listContents, links.createLink(SectionName.CONSTRUCTOR_DETAIL, contents.navConstructor));
+ } else {
+ addContentToList(listContents, contents.navConstructor);
+ }
+ break;
+ case ENUM_CONSTANTS:
+ if (link) {
+ addContentToList(listContents, links.createLink(SectionName.ENUM_CONSTANT_DETAIL, contents.navEnum));
+ } else {
+ addContentToList(listContents, contents.navEnum);
+ }
+ break;
+ case FIELDS:
+ if (link) {
+ addContentToList(listContents, links.createLink(SectionName.FIELD_DETAIL, contents.navField));
+ } else {
+ addContentToList(listContents, contents.navField);
+ }
+ break;
+ case METHODS:
+ if (link) {
+ addContentToList(listContents, links.createLink(SectionName.METHOD_DETAIL, contents.navMethod));
+ } else {
+ addContentToList(listContents, contents.navMethod);
+ }
+ break;
+ case PROPERTIES:
+ if (link) {
+ addContentToList(listContents, links.createLink(SectionName.PROPERTY_DETAIL, contents.navProperty));
+ } else {
+ addContentToList(listContents, contents.navProperty);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Add the navigation Annotation Type detail link.
+ *
+ * @param listContents the list of contents to which the annotation detail will be added.
+ */
+ protected void addAnnotationTypeDetailLink(List<Content> listContents) {
+ TypeElement annotationType = (TypeElement) element;
+ AbstractMemberWriter writerField
+ = ((AbstractMemberWriter) memberSummaryBuilder.
+ getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS));
+ AbstractMemberWriter writerOptional
+ = ((AbstractMemberWriter) memberSummaryBuilder.
+ getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL));
+ AbstractMemberWriter writerRequired
+ = ((AbstractMemberWriter) memberSummaryBuilder.
+ getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED));
+ if (writerField != null) {
+ addAnnotationTypeDetailLink(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS,
+ !configuration.utils.getAnnotationFields(annotationType).isEmpty(),
+ listContents);
+ } else {
+ addContentToList(listContents, contents.navField);
+ }
+ if (writerOptional != null) {
+ addAnnotationTypeDetailLink(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL,
+ !annotationType.getAnnotationMirrors().isEmpty(), listContents);
+ } else if (writerRequired != null) {
+ addAnnotationTypeDetailLink(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED,
+ !annotationType.getAnnotationMirrors().isEmpty(), listContents);
+ } else {
+ addContentToList(listContents, contents.navAnnotationTypeMember);
+ }
+ }
+
+ /**
+ * Add the navigation Annotation Type detail link.
+ *
+ * @param type the kind of member being documented
+ * @param link true if the member details need to be linked
+ * @param listContents the list of contents to which the annotation detail will be added.
+ */
+ protected void addAnnotationTypeDetailLink(VisibleMemberMap.Kind type, boolean link, List<Content> listContents) {
+ switch (type) {
+ case ANNOTATION_TYPE_FIELDS:
+ if (link) {
+ addContentToList(listContents, links.createLink(SectionName.ANNOTATION_TYPE_FIELD_DETAIL,
+ contents.navField));
+ } else {
+ addContentToList(listContents, contents.navField);
+ }
+ break;
+ case ANNOTATION_TYPE_MEMBER_REQUIRED:
+ case ANNOTATION_TYPE_MEMBER_OPTIONAL:
+ if (link) {
+ addContentToList(listContents, links.createLink(SectionName.ANNOTATION_TYPE_ELEMENT_DETAIL,
+ contents.navAnnotationTypeMember));
+ } else {
+ addContentToList(listContents, contents.navAnnotationTypeMember);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void addContentToList(List<Content> listContents, Content tree) {
+ listContents.add(HtmlTree.LI(tree));
+ }
+
+ private void addContentToTree(Content tree, Content content) {
+ tree.addContent(HtmlTree.LI(content));
+ }
+
+ private void addListToNav(List<Content> listContents, Content tree) {
+ int count = 0;
+ for (Content liContent : listContents) {
+ if (count < listContents.size() - 1) {
+ liContent.addContent(Contents.SPACE);
+ liContent.addContent("|");
+ liContent.addContent(Contents.SPACE);
+ }
+ tree.addContent(liContent);
+ count++;
+ }
+ }
+
+ private void addActivePageLink(Content tree, Content label, boolean display) {
+ if (display) {
+ tree.addContent(HtmlTree.LI(HtmlStyle.navBarCell1Rev, label));
+ }
+ }
+
+ private void addPageLabel(Content tree, Content label, boolean display) {
+ if (display) {
+ tree.addContent(HtmlTree.LI(label));
+ }
+ }
+
+ private void addOverviewLink(Content tree) {
+ if (configuration.createoverview) {
+ tree.addContent(HtmlTree.LI(links.createLink(pathToRoot.resolve(DocPaths.overviewSummary(configuration.frames)),
+ contents.overviewLabel, "", "")));
+ }
+ }
+
+ private void addModuleLink(Content tree) {
+ if (configuration.showModules) {
+ if (configuration.modules.size() == 1) {
+ ModuleElement mdle = configuration.modules.first();
+ boolean included = configuration.utils.isIncluded(mdle);
+ tree.addContent(HtmlTree.LI((included)
+ ? links.createLink(pathToRoot.resolve(configuration.docPaths.moduleSummary(mdle)), contents.moduleLabel, "", "")
+ : contents.moduleLabel));
+ } else if (!configuration.modules.isEmpty()) {
+ addPageLabel(tree, contents.moduleLabel, true);
+ }
+ }
+ }
+
+ private void addModuleOfElementLink(Content tree) {
+ if (configuration.showModules) {
+ tree.addContent(HtmlTree.LI(navLinkModule));
+ }
+ }
+
+ private void addPackageLink(Content tree) {
+ if (configuration.packages.size() == 1) {
+ PackageElement packageElement = configuration.packages.first();
+ boolean included = packageElement != null && configuration.utils.isIncluded(packageElement);
+ if (!included) {
+ for (PackageElement p : configuration.packages) {
+ if (p.equals(packageElement)) {
+ included = true;
+ break;
+ }
+ }
+ }
+ if (included || packageElement == null) {
+ tree.addContent(HtmlTree.LI(links.createLink(
+ pathToRoot.resolve(configuration.docPaths.forPackage(packageElement).resolve(DocPaths.PACKAGE_SUMMARY)),
+ contents.packageLabel)));
+ } else {
+ DocLink crossPkgLink = configuration.extern.getExternalLink(
+ configuration.utils.getPackageName(packageElement), pathToRoot,
+ DocPaths.PACKAGE_SUMMARY.getPath());
+ if (crossPkgLink != null) {
+ tree.addContent(HtmlTree.LI(links.createLink(crossPkgLink, contents.packageLabel)));
+ } else {
+ tree.addContent(HtmlTree.LI(contents.packageLabel));
+ }
+ }
+ } else if (!configuration.packages.isEmpty()) {
+ addPageLabel(tree, contents.packageLabel, true);
+ }
+ }
+
+ private void addPackageOfElementLink(Content tree) {
+ tree.addContent(HtmlTree.LI(links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_SUMMARY),
+ contents.packageLabel)));
+ }
+
+ private void addPackageSummaryLink(Content tree) {
+ tree.addContent(HtmlTree.LI(links.createLink(DocPaths.PACKAGE_SUMMARY, contents.packageLabel)));
+ }
+
+ private void addTreeLink(Content tree) {
+ if (configuration.createtree) {
+ List<PackageElement> packages = new ArrayList<>(configuration.getSpecifiedPackageElements());
+ DocPath docPath = packages.size() == 1 && configuration.getSpecifiedTypeElements().isEmpty()
+ ? pathToRoot.resolve(configuration.docPaths.forPackage(packages.get(0)).resolve(DocPaths.PACKAGE_TREE))
+ : pathToRoot.resolve(DocPaths.OVERVIEW_TREE);
+ tree.addContent(HtmlTree.LI(links.createLink(docPath, contents.treeLabel, "", "")));
+ }
+ }
+
+ private void addDeprecatedLink(Content tree) {
+ if (!(configuration.nodeprecated || configuration.nodeprecatedlist)) {
+ tree.addContent(HtmlTree.LI(links.createLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
+ contents.deprecatedLabel, "", "")));
+ }
+ }
+
+ private void addIndexLink(Content tree) {
+ if (configuration.createindex) {
+ tree.addContent(HtmlTree.LI(links.createLink(pathToRoot.resolve(
+ (configuration.splitindex
+ ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
+ : DocPaths.INDEX_ALL)),
+ contents.indexLabel, "", "")));
+ }
+ }
+
+ private void addHelpLink(Content tree) {
+ if (!configuration.nohelp) {
+ String helpfile = configuration.helpfile;
+ DocPath helpfilenm;
+ if (helpfile.isEmpty()) {
+ helpfilenm = DocPaths.HELP_DOC;
+ } else {
+ DocFile file = DocFile.createFileForInput(configuration, helpfile);
+ helpfilenm = DocPath.create(file.getName());
+ }
+ tree.addContent(HtmlTree.LI(links.createLink(pathToRoot.resolve(helpfilenm),
+ contents.helpLabel, "", "")));
+ }
+ }
+
+ /**
+ * Add "FRAMES" link, to switch to the frame version of the output.
+ *
+ * @param tree the content tree to which the link will be added
+ */
+ private void addNavShowLists(Content tree) {
+ DocLink dl = new DocLink(pathToRoot.resolve(DocPaths.INDEX), path.getPath(), null);
+ Content framesContent = links.createLink(dl, contents.framesLabel, "", "_top");
+ tree.addContent(HtmlTree.LI(framesContent));
+ }
+
+ /**
+ * Add "NO FRAMES" link, to switch to the non-frame version of the output.
+ *
+ * @param tree the content tree to which the link will be added
+ */
+ private void addNavHideLists(Content tree) {
+ Content noFramesContent = links.createLink(path.basename(), contents.noFramesLabel, "", "_top");
+ tree.addContent(HtmlTree.LI(noFramesContent));
+ }
+
+ private void addNavLinkClassIndex(Content tree) {
+ Content allClassesContent = links.createLink(pathToRoot.resolve(
+ DocPaths.AllClasses(configuration.frames)),
+ contents.allClassesLabel, "", "");
+ tree.addContent(HtmlTree.LI(allClassesContent));
+ }
+
+ private void addSearch(Content tree) {
+ String searchValueId = "search";
+ String reset = "reset";
+ HtmlTree inputText = HtmlTree.INPUT("text", searchValueId, searchValueId);
+ HtmlTree inputReset = HtmlTree.INPUT(reset, reset, reset);
+ HtmlTree liInput = HtmlTree.LI(HtmlTree.LABEL(searchValueId, searchLabel));
+ liInput.addContent(inputText);
+ liInput.addContent(inputReset);
+ HtmlTree ulSearch = HtmlTree.UL(HtmlStyle.navListSearch, liInput);
+ tree.addContent(ulSearch);
+ }
+
+ private void addAllClassesLinkScript(Content tree, boolean top) {
+ Content div = HtmlTree.DIV(top
+ ? Position.TOP.allClassesLinkScript().asContent()
+ : Position.BOTTOM.allClassesLinkScript().asContent());
+ Content div_noscript = HtmlTree.DIV(contents.noScriptMessage);
+ Content noScript = HtmlTree.NOSCRIPT(div_noscript);
+ div.addContent(noScript);
+ tree.addContent(div);
+ }
+
+ private void addFixedNavScript(Content tree) {
+ tree.addContent(FIXED_NAV_SCRIPT.asContent());
+ }
+
+ /**
+ * Get the navigation content.
+ *
+ * @param top true if the top navigation bar is to be printed
+ * @return the navigation contents
+ */
+ public Content getContent(boolean top) {
+ Content contentTree = new ContentBuilder();
+ if (!configuration.nonavbar) {
+ Deque<Content> queue;
+ Content tree = (configuration.htmlVersion == HtmlVersion.HTML5)
+ ? HtmlTree.NAV()
+ : contentTree;
+ HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
+ if (top) {
+ queue = topBottomNavContents.get(Position.TOP);
+ fixedNavDiv.addContent(Position.TOP.startOfNav());
+ navDiv.setStyle(HtmlStyle.topNav);
+ } else {
+ queue = topBottomNavContents.get(Position.BOTTOM);
+ tree.addContent(Position.BOTTOM.startOfNav());
+ navDiv.setStyle(HtmlStyle.bottomNav);
+ }
+ navDiv.addContent(queue.poll());
+ HtmlTree skipLinkDiv = HtmlTree.DIV(HtmlStyle.skipNav, queue.poll());
+ navDiv.addContent(skipLinkDiv);
+ navDiv.addContent(queue.poll());
+ HtmlTree navList = new HtmlTree(HtmlTag.UL);
+ navList.setStyle(HtmlStyle.navList);
+ navList.addAttr(HtmlAttr.TITLE, rowListTitle);
+ fixedNavDiv.setStyle(HtmlStyle.fixedNav);
+ addMainNavLinks(navList);
+ navDiv.addContent(navList);
+ Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, top ? userHeader : userFooter);
+ navDiv.addContent(aboutDiv);
+ if (top) {
+ fixedNavDiv.addContent(navDiv);
+ } else {
+ tree.addContent(navDiv);
+ }
+ HtmlTree subDiv = new HtmlTree(HtmlTag.DIV);
+ subDiv.setStyle(HtmlStyle.subNav);
+ HtmlTree ulFrames = new HtmlTree(HtmlTag.UL);
+ ulFrames.setStyle(HtmlStyle.navList);
+ if (!configuration.nonavbar) {
+ if (configuration.frames) {
+ addNavShowLists(ulFrames);
+ addNavHideLists(ulFrames);
+ }
+ }
+ subDiv.addContent(ulFrames);
+ HtmlTree ulAllClasses = new HtmlTree(HtmlTag.UL);
+ ulAllClasses.setStyle(HtmlStyle.navList);
+ ulAllClasses.addAttr(HtmlAttr.ID, top
+ ? Position.TOP.allClassesLinkId()
+ : Position.BOTTOM.allClassesLinkId());
+ addNavLinkClassIndex(ulAllClasses);
+ subDiv.addContent(ulAllClasses);
+ if (top && configuration.createindex) {
+ addSearch(subDiv);
+ }
+ addAllClassesLinkScript(subDiv, top);
+ HtmlTree div = new HtmlTree(HtmlTag.DIV);
+ // Add the summary links if present.
+ HtmlTree ulNavSummary = new HtmlTree(HtmlTag.UL);
+ ulNavSummary.setStyle(HtmlStyle.subNavList);
+ addSummaryLinks(ulNavSummary);
+ div.addContent(ulNavSummary);
+ // Add the detail links if present.
+ HtmlTree ulNavDetail = new HtmlTree(HtmlTag.UL);
+ ulNavDetail.setStyle(HtmlStyle.subNavList);
+ addDetailLinks(ulNavDetail);
+ div.addContent(ulNavDetail);
+ subDiv.addContent(div);
+ subDiv.addContent(queue.poll());
+ if (top) {
+ fixedNavDiv.addContent(subDiv);
+ fixedNavDiv.addContent(Position.TOP.endOfNav());
+ tree.addContent(fixedNavDiv);
+ HtmlTree paddingDiv = HtmlTree.DIV(HtmlStyle.navPadding, Contents.SPACE);
+ tree.addContent(paddingDiv);
+ addFixedNavScript(tree);
+ } else {
+ tree.addContent(subDiv);
+ tree.addContent(Position.BOTTOM.endOfNav());
+ }
+ return tree;
+ }
+ return contentTree;
+ }
+}
--- a/test/TestCommon.gmk Mon Apr 09 08:34:30 2018 -0700
+++ b/test/TestCommon.gmk Tue Apr 10 13:58:47 2018 -0700
@@ -446,7 +446,7 @@
JTREG_BASIC_OPTIONS += -e:JDK8_HOME=${JT_JAVA}
# Give aot tests access to Visual Studio installation
ifneq ($(VS120COMNTOOLS), )
- JTREG_BASIC_OPTIONS += -e:VS120COMNTOOLS=$(shell $(GETMIXEDPATH) "$(VS120COMNTOOLS)")
+ JTREG_BASIC_OPTIONS += -e:VS120COMNTOOLS="$(shell $(GETMIXEDPATH) "$(patsubst %\,%,$(VS120COMNTOOLS))")"
endif
# Set other vm and test options
JTREG_TEST_OPTIONS += $(JAVA_ARGS:%=-javaoptions:%) $(JAVA_VM_ARGS:%=-vmoption:%)
--- a/test/jdk/java/util/Collection/IteratorMicroBenchmark.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/Collection/IteratorMicroBenchmark.java Tue Apr 10 13:58:47 2018 -0700
@@ -36,6 +36,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -55,6 +56,7 @@
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
+import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@@ -75,6 +77,13 @@
public Job(String name) { this.name = name; }
public String name() { return name; }
public abstract void work() throws Throwable;
+ public void run() {
+ try { work(); }
+ catch (Throwable ex) {
+ // current job cannot always be deduced from stacktrace.
+ throw new RuntimeException("Job failed: " + name(), ex);
+ }
+ }
}
final int iterations;
@@ -102,6 +111,7 @@
static void forceFullGc() {
CountDownLatch finalizeDone = new CountDownLatch(1);
WeakReference<?> ref = new WeakReference<Object>(new Object() {
+ @SuppressWarnings("deprecation")
protected void finalize() { finalizeDone.countDown(); }});
try {
for (int i = 0; i < 10; i++) {
@@ -123,7 +133,7 @@
* compiling everything worth compiling.
* Returns array of average times per job per run.
*/
- long[] time0(List<Job> jobs) throws Throwable {
+ long[] time0(List<Job> jobs) {
final int size = jobs.size();
long[] nanoss = new long[size];
for (int i = 0; i < size; i++) {
@@ -132,7 +142,7 @@
long totalTime;
int runs = 0;
long startTime = System.nanoTime();
- do { job.work(); runs++; }
+ do { job.run(); runs++; }
while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
nanoss[i] = totalTime/runs;
}
@@ -211,10 +221,6 @@
System.out.println("the answer");
}
- private static <T> List<T> asSubList(List<T> list) {
- return list.subList(0, list.size());
- }
-
private static <T> Iterable<T> backwards(final List<T> list) {
return new Iterable<T>() {
public Iterator<T> iterator() {
@@ -241,11 +247,32 @@
new IteratorMicroBenchmark(args).run();
}
+ HashMap<Class<?>, String> goodClassName = new HashMap<>();
+
+ String goodClassName(Class<?> klazz) {
+ return goodClassName.computeIfAbsent(
+ klazz,
+ k -> {
+ String simple = k.getSimpleName();
+ return (simple.equals("SubList")) // too simple!
+ ? k.getName().replaceFirst(".*\\.", "")
+ : simple;
+ });
+ }
+
+ static List<Integer> makeSubList(List<Integer> list) {
+ final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ int size = list.size();
+ if (size <= 2) return list.subList(0, size);
+ List<Integer> subList = list.subList(rnd.nextInt(0, 2),
+ size - rnd.nextInt(0, 2));
+ List<Integer> copy = new ArrayList<>(list);
+ subList.clear();
+ subList.addAll(copy);
+ return subList;
+ }
+
void run() throws Throwable {
-// System.out.printf(
-// "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
-// iterations, size, warmupSeconds, nameFilter);
-
final ArrayList<Integer> al = new ArrayList<>(size);
// Populate collections with random data
@@ -265,10 +292,14 @@
ArrayList<Job> jobs = Stream.<Collection<Integer>>of(
al, ad, abq,
+ makeSubList(new ArrayList<>(al)),
new LinkedList<>(al),
+ makeSubList(new LinkedList<>(al)),
new PriorityQueue<>(al),
new Vector<>(al),
+ makeSubList(new Vector<>(al)),
new CopyOnWriteArrayList<>(al),
+ makeSubList(new CopyOnWriteArrayList<>(al)),
new ConcurrentLinkedQueue<>(al),
new ConcurrentLinkedDeque<>(al),
new LinkedBlockingQueue<>(al),
@@ -294,16 +325,25 @@
Stream<Job> jobs(Collection<Integer> x) {
return concatStreams(
collectionJobs(x),
+
(x instanceof Deque)
? dequeJobs((Deque<Integer>)x)
: Stream.empty(),
+
(x instanceof List)
? listJobs((List<Integer>)x)
: Stream.empty());
}
+ Object sneakyAdder(int[] sneakySum) {
+ return new Object() {
+ public int hashCode() { throw new AssertionError(); }
+ public boolean equals(Object z) {
+ sneakySum[0] += (int) z; return false; }};
+ }
+
Stream<Job> collectionJobs(Collection<Integer> x) {
- String klazz = x.getClass().getSimpleName();
+ final String klazz = goodClassName(x.getClass());
return Stream.of(
new Job(klazz + " iterate for loop") {
public void work() throws Throwable {
@@ -345,22 +385,28 @@
new Job(klazz + " contains") {
public void work() throws Throwable {
int[] sum = new int[1];
- Object y = new Object() {
- public boolean equals(Object z) {
- sum[0] += (int) z; return false; }};
+ Object sneakyAdder = sneakyAdder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- if (x.contains(y)) throw new AssertionError();
+ if (x.contains(sneakyAdder)) throw new AssertionError();
+ check.sum(sum[0]);}}},
+ new Job(klazz + " containsAll") {
+ public void work() throws Throwable {
+ int[] sum = new int[1];
+ Collection<Object> sneakyAdderCollection =
+ Collections.singleton(sneakyAdder(sum));
+ for (int i = 0; i < iterations; i++) {
+ sum[0] = 0;
+ if (x.containsAll(sneakyAdderCollection))
+ throw new AssertionError();
check.sum(sum[0]);}}},
new Job(klazz + " remove(Object)") {
public void work() throws Throwable {
int[] sum = new int[1];
- Object y = new Object() {
- public boolean equals(Object z) {
- sum[0] += (int) z; return false; }};
+ Object sneakyAdder = sneakyAdder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- if (x.remove(y)) throw new AssertionError();
+ if (x.remove(sneakyAdder)) throw new AssertionError();
check.sum(sum[0]);}}},
new Job(klazz + " forEach") {
public void work() throws Throwable {
@@ -446,7 +492,7 @@
}
Stream<Job> dequeJobs(Deque<Integer> x) {
- String klazz = x.getClass().getSimpleName();
+ String klazz = goodClassName(x.getClass());
return Stream.of(
new Job(klazz + " descendingIterator() loop") {
public void work() throws Throwable {
@@ -466,48 +512,50 @@
}
Stream<Job> listJobs(List<Integer> x) {
- String klazz = x.getClass().getSimpleName();
+ final String klazz = goodClassName(x.getClass());
return Stream.of(
- new Job(klazz + " subList toArray()") {
+ new Job(klazz + " listIterator forward loop") {
public void work() throws Throwable {
- int size = x.size();
for (int i = 0; i < iterations; i++) {
- int total = Stream.of(x.subList(0, size / 2),
- x.subList(size / 2, size))
- .mapToInt(subList -> {
- int sum = 0;
- for (Object o : subList.toArray())
- sum += (Integer) o;
- return sum; })
- .sum();
- check.sum(total);}}},
- new Job(klazz + " subList toArray(a)") {
+ int sum = 0;
+ ListIterator<Integer> it = x.listIterator();
+ while (it.hasNext())
+ sum += it.next();
+ check.sum(sum);}}},
+ new Job(klazz + " listIterator backward loop") {
public void work() throws Throwable {
- int size = x.size();
+ for (int i = 0; i < iterations; i++) {
+ int sum = 0;
+ ListIterator<Integer> it = x.listIterator(x.size());
+ while (it.hasPrevious())
+ sum += it.previous();
+ check.sum(sum);}}},
+ new Job(klazz + " indexOf") {
+ public void work() throws Throwable {
+ int[] sum = new int[1];
+ Object sneakyAdder = sneakyAdder(sum);
for (int i = 0; i < iterations; i++) {
- int total = Stream.of(x.subList(0, size / 2),
- x.subList(size / 2, size))
- .mapToInt(subList -> {
- int sum = 0;
- Integer[] a = new Integer[subList.size()];
- for (Object o : subList.toArray(a))
- sum += (Integer) o;
- return sum; })
- .sum();
- check.sum(total);}}},
- new Job(klazz + " subList toArray(empty)") {
+ sum[0] = 0;
+ if (x.indexOf(sneakyAdder) != -1)
+ throw new AssertionError();
+ check.sum(sum[0]);}}},
+ new Job(klazz + " lastIndexOf") {
public void work() throws Throwable {
- int size = x.size();
- Integer[] empty = new Integer[0];
+ int[] sum = new int[1];
+ Object sneakyAdder = sneakyAdder(sum);
for (int i = 0; i < iterations; i++) {
- int total = Stream.of(x.subList(0, size / 2),
- x.subList(size / 2, size))
- .mapToInt(subList -> {
- int sum = 0;
- for (Object o : subList.toArray(empty))
- sum += (Integer) o;
- return sum; })
- .sum();
- check.sum(total);}}});
+ sum[0] = 0;
+ if (x.lastIndexOf(sneakyAdder) != -1)
+ throw new AssertionError();
+ check.sum(sum[0]);}}},
+ new Job(klazz + " replaceAll") {
+ public void work() throws Throwable {
+ int[] sum = new int[1];
+ UnaryOperator<Integer> sneakyAdder =
+ x -> { sum[0] += x; return x; };
+ for (int i = 0; i < iterations; i++) {
+ sum[0] = 0;
+ x.replaceAll(sneakyAdder);
+ check.sum(sum[0]);}}});
}
}
--- a/test/jdk/java/util/Collection/RemoveMicroBenchmark.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/Collection/RemoveMicroBenchmark.java Tue Apr 10 13:58:47 2018 -0700
@@ -27,7 +27,7 @@
* @run main RemoveMicroBenchmark iterations=1 size=8 warmup=0
*/
-import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toCollection;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
@@ -35,6 +35,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -47,6 +48,7 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
@@ -55,7 +57,7 @@
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
-import java.util.function.Supplier;
+import java.util.stream.Stream;
/**
* Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
@@ -72,25 +74,38 @@
public Job(String name) { this.name = name; }
public String name() { return name; }
public abstract void work() throws Throwable;
+ public void run() {
+ try { work(); }
+ catch (Throwable ex) {
+ // current job cannot always be deduced from stacktrace.
+ throw new RuntimeException("Job failed: " + name(), ex);
+ }
+ }
}
final int iterations;
final int size; // number of elements in collections
final double warmupSeconds;
final long warmupNanos;
- final Pattern filter; // select subset of Jobs to run
+ final Pattern nameFilter; // select subset of Jobs to run
final boolean reverse; // reverse order of Jobs
final boolean shuffle; // randomize order of Jobs
+ final ArrayList<Integer> elements; // contains size random Integers
+
RemoveMicroBenchmark(String[] args) {
iterations = intArg(args, "iterations", 10_000);
size = intArg(args, "size", 1000);
warmupSeconds = doubleArg(args, "warmup", 7.0);
- filter = patternArg(args, "filter");
+ nameFilter = patternArg(args, "filter");
reverse = booleanArg(args, "reverse");
shuffle = booleanArg(args, "shuffle");
warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
+
+ elements = ThreadLocalRandom.current().ints(size)
+ .mapToObj(x -> x)
+ .collect(toCollection(ArrayList::new));
}
// --------------- GC finalization infrastructure ---------------
@@ -99,6 +114,7 @@
static void forceFullGc() {
CountDownLatch finalizeDone = new CountDownLatch(1);
WeakReference<?> ref = new WeakReference<Object>(new Object() {
+ @SuppressWarnings("deprecation")
protected void finalize() { finalizeDone.countDown(); }});
try {
for (int i = 0; i < 10; i++) {
@@ -120,7 +136,7 @@
* compiling everything worth compiling.
* Returns array of average times per job per run.
*/
- long[] time0(List<Job> jobs) throws Throwable {
+ long[] time0(List<Job> jobs) {
final int size = jobs.size();
long[] nanoss = new long[size];
for (int i = 0; i < size; i++) {
@@ -129,7 +145,7 @@
long totalTime;
int runs = 0;
long startTime = System.nanoTime();
- do { job.work(); runs++; }
+ do { job.run(); runs++; }
while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
nanoss[i] = totalTime/runs;
}
@@ -203,22 +219,11 @@
throw new IllegalArgumentException(val);
}
- private static List<Job> filter(Pattern filter, List<Job> jobs) {
- return (filter == null) ? jobs
- : jobs.stream()
- .filter(job -> filter.matcher(job.name()).find())
- .collect(toList());
- }
-
private static void deoptimize(int sum) {
if (sum == 42)
System.out.println("the answer");
}
- private static <T> List<T> asSubList(List<T> list) {
- return list.subList(0, list.size());
- }
-
private static <T> Iterable<T> backwards(final List<T> list) {
return new Iterable<T>() {
public Iterator<T> iterator() {
@@ -245,66 +250,99 @@
new RemoveMicroBenchmark(args).run();
}
- void run() throws Throwable {
-// System.out.printf(
-// "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
-// iterations, size, warmupSeconds, filter);
+ HashMap<Class<?>, String> goodClassName = new HashMap<>();
- final ArrayList<Integer> al = new ArrayList<>(size);
+ String goodClassName(Class<?> klazz) {
+ return goodClassName.computeIfAbsent(
+ klazz,
+ k -> {
+ String simple = k.getSimpleName();
+ return (simple.equals("SubList")) // too simple!
+ ? k.getName().replaceFirst(".*\\.", "")
+ : simple;
+ });
+ }
- // Populate collections with random data
+ static List<Integer> makeSubList(List<Integer> list) {
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
- for (int i = 0; i < size; i++)
- al.add(rnd.nextInt(size));
+ int size = rnd.nextInt(4);
+ for (int i = size; i--> 0; )
+ list.add(rnd.nextInt());
+ int index = rnd.nextInt(size + 1);
+ return list.subList(index, index);
+ }
- ArrayList<Job> jobs = new ArrayList<>();
+ private static <T> List<T> asSubList(List<T> list) {
+ return list.subList(0, list.size());
+ }
+
+ @SafeVarargs @SuppressWarnings("varargs")
+ private <T> Stream<T> concatStreams(Stream<T> ... streams) {
+ return Stream.of(streams).flatMap(s -> s);
+ }
- List.<Collection<Integer>>of(
- new ArrayList<>(),
- new LinkedList<>(),
- new Vector<>(),
- new ArrayDeque<>(),
- new PriorityQueue<>(),
- new ArrayBlockingQueue<>(al.size()),
- new ConcurrentLinkedQueue<>(),
- new ConcurrentLinkedDeque<>(),
- new LinkedBlockingQueue<>(),
- new LinkedBlockingDeque<>(),
- new LinkedTransferQueue<>(),
- new PriorityBlockingQueue<>()).forEach(
- x -> {
- String klazz = x.getClass().getSimpleName();
- jobs.addAll(collectionJobs(klazz, () -> x, al));
- if (x instanceof Queue) {
- Queue<Integer> queue = (Queue<Integer>) x;
- jobs.addAll(queueJobs(klazz, () -> queue, al));
- }
- if (x instanceof Deque) {
- Deque<Integer> deque = (Deque<Integer>) x;
- jobs.addAll(dequeJobs(klazz, () -> deque, al));
- }
- if (x instanceof BlockingQueue) {
- BlockingQueue<Integer> q = (BlockingQueue<Integer>) x;
- jobs.addAll(blockingQueueJobs(klazz, () -> q, al));
- }
- if (x instanceof BlockingDeque) {
- BlockingDeque<Integer> q = (BlockingDeque<Integer>) x;
- jobs.addAll(blockingDequeJobs(klazz, () -> q, al));
- }
- if (x instanceof List) {
- List<Integer> list = (List<Integer>) x;
- jobs.addAll(
- collectionJobs(
- klazz + " subList",
- () -> list.subList(0, x.size()),
- al));
- }
- });
+ Class<?> topLevelClass(Object x) {
+ for (Class<?> k = x.getClass();; ) {
+ Class<?> enclosing = k.getEnclosingClass();
+ if (enclosing == null)
+ return k;
+ k = enclosing;
+ }
+ }
+
+ void run() throws Throwable {
+ ArrayList<Job> jobs = Stream.<Collection<Integer>>of(
+ new ArrayList<>(),
+ makeSubList(new ArrayList<>()),
+ new LinkedList<>(),
+ makeSubList(new LinkedList<>()),
+ new Vector<>(),
+ makeSubList(new Vector<>()),
+ new CopyOnWriteArrayList<>(),
+ makeSubList(new CopyOnWriteArrayList<>()),
+ new ArrayDeque<>(),
+ new PriorityQueue<>(),
+ new ArrayBlockingQueue<>(elements.size()),
+ new ConcurrentLinkedQueue<>(),
+ new ConcurrentLinkedDeque<>(),
+ new LinkedBlockingQueue<>(),
+ new LinkedBlockingDeque<>(),
+ new LinkedTransferQueue<>(),
+ new PriorityBlockingQueue<>())
+ .flatMap(x -> jobs(x))
+ .filter(job ->
+ nameFilter == null || nameFilter.matcher(job.name()).find())
+ .collect(toCollection(ArrayList::new));
if (reverse) Collections.reverse(jobs);
if (shuffle) Collections.shuffle(jobs);
- time(filter(filter, jobs));
+ time(jobs);
+ }
+
+ Stream<Job> jobs(Collection<Integer> x) {
+ return concatStreams(
+ collectionJobs(x),
+
+ (CopyOnWriteArrayList.class.isAssignableFrom(topLevelClass(x)))
+ ? Stream.empty()
+ : iteratorRemoveJobs(x),
+
+ (x instanceof Queue)
+ ? queueJobs((Queue<Integer>)x)
+ : Stream.empty(),
+
+ (x instanceof Deque)
+ ? dequeJobs((Deque<Integer>)x)
+ : Stream.empty(),
+
+ (x instanceof BlockingQueue)
+ ? blockingQueueJobs((BlockingQueue<Integer>)x)
+ : Stream.empty(),
+
+ (x instanceof BlockingDeque)
+ ? blockingDequeJobs((BlockingDeque<Integer>)x)
+ : Stream.empty());
}
Collection<Integer> universeRecorder(int[] sum) {
@@ -323,75 +361,81 @@
}};
}
- List<Job> collectionJobs(
- String description,
- Supplier<Collection<Integer>> supplier,
- ArrayList<Integer> al) {
- return List.of(
- new Job(description + " removeIf") {
+ Stream<Job> collectionJobs(Collection<Integer> x) {
+ final String klazz = goodClassName(x.getClass());
+ return Stream.of(
+ new Job(klazz + " removeIf") {
public void work() throws Throwable {
- Collection<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
x.removeIf(n -> { sum[0] += n; return true; });
check.sum(sum[0]);}}},
- new Job(description + " removeIf rnd-two-pass") {
+ new Job(klazz + " removeIf rnd-two-pass") {
public void work() throws Throwable {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
- Collection<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
x.removeIf(n -> {
boolean b = rnd.nextBoolean();
if (b) sum[0] += n;
return b; });
x.removeIf(n -> { sum[0] += n; return true; });
check.sum(sum[0]);}}},
- new Job(description + " removeAll") {
+ new Job(klazz + " removeAll") {
public void work() throws Throwable {
- Collection<Integer> x = supplier.get();
int[] sum = new int[1];
Collection<Integer> universe = universeRecorder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
x.removeAll(universe);
check.sum(sum[0]);}}},
- new Job(description + " retainAll") {
+ new Job(klazz + " retainAll") {
public void work() throws Throwable {
- Collection<Integer> x = supplier.get();
int[] sum = new int[1];
Collection<Integer> empty = emptyRecorder(sum);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
x.retainAll(empty);
check.sum(sum[0]);}}},
- new Job(description + " Iterator.remove") {
+ new Job(klazz + " clear") {
public void work() throws Throwable {
- Collection<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
+ x.forEach(e -> sum[0] += e);
+ x.clear();
+ check.sum(sum[0]);}}});
+ }
+
+ Stream<Job> iteratorRemoveJobs(Collection<Integer> x) {
+ final String klazz = goodClassName(x.getClass());
+ return Stream.of(
+ new Job(klazz + " Iterator.remove") {
+ public void work() throws Throwable {
+ int[] sum = new int[1];
+ for (int i = 0; i < iterations; i++) {
+ sum[0] = 0;
+ x.addAll(elements);
Iterator<Integer> it = x.iterator();
while (it.hasNext()) {
sum[0] += it.next();
it.remove();
}
check.sum(sum[0]);}}},
- new Job(description + " Iterator.remove-rnd-two-pass") {
+ new Job(klazz + " Iterator.remove-rnd-two-pass") {
public void work() throws Throwable {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
- Collection<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
for (Iterator<Integer> it = x.iterator();
it.hasNext(); ) {
Integer e = it.next();
@@ -405,129 +449,103 @@
sum[0] += it.next();
it.remove();
}
- check.sum(sum[0]);}}},
- new Job(description + " clear") {
- public void work() throws Throwable {
- Collection<Integer> x = supplier.get();
- int[] sum = new int[1];
- for (int i = 0; i < iterations; i++) {
- sum[0] = 0;
- x.addAll(al);
- x.forEach(e -> sum[0] += e);
- x.clear();
check.sum(sum[0]);}}});
}
- List<Job> queueJobs(
- String description,
- Supplier<Queue<Integer>> supplier,
- ArrayList<Integer> al) {
- return List.of(
- new Job(description + " poll()") {
+ Stream<Job> queueJobs(Queue<Integer> x) {
+ final String klazz = goodClassName(x.getClass());
+ return Stream.of(
+ new Job(klazz + " poll()") {
public void work() throws Throwable {
- Queue<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
for (Integer e; (e = x.poll()) != null; )
sum[0] += e;
check.sum(sum[0]);}}});
}
- List<Job> dequeJobs(
- String description,
- Supplier<Deque<Integer>> supplier,
- ArrayList<Integer> al) {
- return List.of(
- new Job(description + " descendingIterator().remove") {
+ Stream<Job> dequeJobs(Deque<Integer> x) {
+ final String klazz = goodClassName(x.getClass());
+ return Stream.of(
+ new Job(klazz + " descendingIterator().remove") {
public void work() throws Throwable {
- Deque<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
Iterator<Integer> it = x.descendingIterator();
while (it.hasNext()) {
sum[0] += it.next();
it.remove();
}
check.sum(sum[0]);}}},
- new Job(description + " pollFirst()") {
+ new Job(klazz + " pollFirst()") {
public void work() throws Throwable {
- Deque<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
for (Integer e; (e = x.pollFirst()) != null; )
sum[0] += e;
check.sum(sum[0]);}}},
- new Job(description + " pollLast()") {
+ new Job(klazz + " pollLast()") {
public void work() throws Throwable {
- Deque<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
for (Integer e; (e = x.pollLast()) != null; )
sum[0] += e;
check.sum(sum[0]);}}});
}
- List<Job> blockingQueueJobs(
- String description,
- Supplier<BlockingQueue<Integer>> supplier,
- ArrayList<Integer> al) {
- return List.of(
- new Job(description + " drainTo(sink)") {
+ Stream<Job> blockingQueueJobs(BlockingQueue<Integer> x) {
+ final String klazz = goodClassName(x.getClass());
+ return Stream.of(
+ new Job(klazz + " drainTo(sink)") {
public void work() throws Throwable {
- BlockingQueue<Integer> x = supplier.get();
ArrayList<Integer> sink = new ArrayList<>();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
sink.clear();
- x.addAll(al);
+ x.addAll(elements);
x.drainTo(sink);
sink.forEach(e -> sum[0] += e);
check.sum(sum[0]);}}},
- new Job(description + " drainTo(sink, n)") {
+ new Job(klazz + " drainTo(sink, n)") {
public void work() throws Throwable {
- BlockingQueue<Integer> x = supplier.get();
ArrayList<Integer> sink = new ArrayList<>();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
sink.clear();
- x.addAll(al);
- x.drainTo(sink, al.size());
+ x.addAll(elements);
+ x.drainTo(sink, elements.size());
sink.forEach(e -> sum[0] += e);
check.sum(sum[0]);}}});
}
- List<Job> blockingDequeJobs(
- String description,
- Supplier<BlockingDeque<Integer>> supplier,
- ArrayList<Integer> al) {
- return List.of(
- new Job(description + " timed pollFirst()") {
+ Stream<Job> blockingDequeJobs(BlockingDeque<Integer> x) {
+ final String klazz = goodClassName(x.getClass());
+ return Stream.of(
+ new Job(klazz + " timed pollFirst()") {
public void work() throws Throwable {
- BlockingDeque<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
for (Integer e; (e = x.pollFirst(0L, TimeUnit.DAYS)) != null; )
sum[0] += e;
check.sum(sum[0]);}}},
- new Job(description + " timed pollLast()") {
+ new Job(klazz + " timed pollLast()") {
public void work() throws Throwable {
- BlockingDeque<Integer> x = supplier.get();
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
- x.addAll(al);
+ x.addAll(elements);
for (Integer e; (e = x.pollLast(0L, TimeUnit.DAYS)) != null; )
sum[0] += e;
check.sum(sum[0]);}}});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/WhiteBox.java Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,155 @@
+/*
+ * 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 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/
+ */
+
+/*
+ * @test
+ * @modules java.base/java.util.concurrent:open
+ * @run testng WhiteBox
+ * @summary White box tests of implementation details
+ */
+
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadLocalRandom;
+
+@Test
+public class WhiteBox {
+ final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ final VarHandle TABLE, NEXTTABLE, SIZECTL;
+
+ WhiteBox() throws ReflectiveOperationException {
+ Class<?> mClass = ConcurrentHashMap.class;
+ String nodeClassName = mClass.getName() + "$Node";
+ Class<?> nodeClass = Class.forName(nodeClassName);
+ Class<?> nodeArrayClass = Class.forName("[L" + nodeClassName + ";");
+ MethodHandles.Lookup lookup
+ = MethodHandles.privateLookupIn(mClass, MethodHandles.lookup());
+ TABLE = lookup.findVarHandle(mClass, "table", nodeArrayClass);
+ NEXTTABLE = lookup.findVarHandle(mClass, "nextTable", nodeArrayClass);
+ SIZECTL = lookup.findVarHandle(mClass, "sizeCtl", int.class);
+ }
+
+ Object[] table(ConcurrentHashMap m) { return (Object[]) TABLE.getVolatile(m); }
+ Object[] nextTable(ConcurrentHashMap m) { return (Object[]) NEXTTABLE.getVolatile(m); }
+ int sizeCtl(ConcurrentHashMap m) { return (int) SIZECTL.getVolatile(m); }
+
+ @Test
+ public void defaultConstructor() {
+ ConcurrentHashMap m = new ConcurrentHashMap();
+ assertNull(table(m));
+ assertEquals(sizeCtl(m), 0);
+ assertResizeNotInProgress(m);
+ }
+
+ @Test
+ public void shouldNotResizeWhenInitialCapacityProvided() {
+ int initialCapacity = rnd.nextInt(1, 100);
+ Object[] initialTable = null;
+ ConcurrentHashMap m = new ConcurrentHashMap(initialCapacity);
+
+ // table is lazily initialized
+ assertNull(table(m));
+ int expectedInitialTableLength = sizeCtl(m);
+
+ assertInvariants(m);
+ for (int i = 0; i < initialCapacity; i++) {
+ m.put(i * 100 + rnd.nextInt(100), i);
+ if (i == 0)
+ initialTable = table(m);
+ else
+ assertSame(table(m), initialTable);
+ assertInvariants(m);
+ }
+ assertEquals(initialTable.length, expectedInitialTableLength);
+ }
+
+ byte[] serialBytes(Object o) {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(bos);
+ oos.writeObject(o);
+ oos.flush();
+ oos.close();
+ return bos.toByteArray();
+ } catch (Exception fail) {
+ throw new AssertionError(fail);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ <T> T serialClone(T o) {
+ try {
+ ObjectInputStream ois = new ObjectInputStream
+ (new ByteArrayInputStream(serialBytes(o)));
+ T clone = (T) ois.readObject();
+ assertNotSame(o, clone);
+ assertSame(o.getClass(), clone.getClass());
+ return clone;
+ } catch (Exception fail) {
+ throw new AssertionError(fail);
+ }
+ }
+
+ @Test
+ public void testSerialization() {
+ assertInvariants(serialClone(new ConcurrentHashMap()));
+
+ ConcurrentHashMap m = new ConcurrentHashMap(rnd.nextInt(100));
+ m.put(1, 1);
+ ConcurrentHashMap clone = serialClone(m);
+ assertInvariants(clone);
+ assertNotSame(table(m), table(clone));
+ assertEquals(m, clone);
+ assertResizeNotInProgress(m);
+ assertResizeNotInProgress(clone);
+ }
+
+ /** Checks conditions which should always be true. */
+ void assertInvariants(ConcurrentHashMap m) {
+ if (!m.isEmpty())
+ assertNotNull(table(m));
+ }
+
+ void assertResizeNotInProgress(ConcurrentHashMap m) {
+ assertTrue(sizeCtl(m) >= 0);
+ assertNull(nextTable(m));
+ }
+}
--- a/test/jdk/java/util/concurrent/ConcurrentLinkedQueue/WhiteBox.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/ConcurrentLinkedQueue/WhiteBox.java Tue Apr 10 13:58:47 2018 -0700
@@ -338,6 +338,7 @@
}
}
+ @Test
public void testSerialization() {
ConcurrentLinkedQueue q = serialClone(new ConcurrentLinkedQueue());
assertInvariants(q);
--- a/test/jdk/java/util/concurrent/Executors/PrivilegedCallables.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/Executors/PrivilegedCallables.java Tue Apr 10 13:58:47 2018 -0700
@@ -101,8 +101,7 @@
final Policy policy = new Policy();
Policy.setPolicy(policy);
policy.setPermissions(new RuntimePermission("getClassLoader"),
- new RuntimePermission("setContextClassLoader"),
- new RuntimePermission("stopThread"));
+ new RuntimePermission("setContextClassLoader"));
System.setSecurityManager(new SecurityManager());
testPrivileged();
--- a/test/jdk/java/util/concurrent/LinkedTransferQueue/WhiteBox.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/LinkedTransferQueue/WhiteBox.java Tue Apr 10 13:58:47 2018 -0700
@@ -361,6 +361,7 @@
}
}
+ @Test
public void testSerialization() {
LinkedTransferQueue q = serialClone(new LinkedTransferQueue());
assertInvariants(q);
--- a/test/jdk/java/util/concurrent/tck/Collection8Test.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/Collection8Test.java Tue Apr 10 13:58:47 2018 -0700
@@ -35,6 +35,7 @@
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -46,6 +47,7 @@
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Queue;
+import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
@@ -86,8 +88,9 @@
Object bomb() {
return new Object() {
- public boolean equals(Object x) { throw new AssertionError(); }
- public int hashCode() { throw new AssertionError(); }
+ @Override public boolean equals(Object x) { throw new AssertionError(); }
+ @Override public int hashCode() { throw new AssertionError(); }
+ @Override public String toString() { throw new AssertionError(); }
};
}
@@ -119,6 +122,23 @@
assertTrue(c.isEmpty());
assertEquals(0, c.size());
assertEquals("[]", c.toString());
+ if (c instanceof List<?>) {
+ List x = (List) c;
+ assertEquals(1, x.hashCode());
+ assertEquals(x, Collections.emptyList());
+ assertEquals(Collections.emptyList(), x);
+ assertEquals(-1, x.indexOf(impl.makeElement(86)));
+ assertEquals(-1, x.lastIndexOf(impl.makeElement(99)));
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> x.get(0),
+ () -> x.set(0, impl.makeElement(42)));
+ }
+ else if (c instanceof Set<?>) {
+ assertEquals(0, c.hashCode());
+ assertEquals(c, Collections.emptySet());
+ assertEquals(Collections.emptySet(), c);
+ }
{
Object[] a = c.toArray();
assertEquals(0, a.length);
@@ -279,6 +299,16 @@
() -> d.pop(),
() -> d.descendingIterator().next());
}
+ if (c instanceof List) {
+ List x = (List) c;
+ assertThrows(
+ NoSuchElementException.class,
+ () -> x.iterator().next(),
+ () -> x.listIterator().next(),
+ () -> x.listIterator(0).next(),
+ () -> x.listIterator().previous(),
+ () -> x.listIterator(0).previous());
+ }
}
public void testRemoveIf() {
@@ -904,6 +934,31 @@
}
}
+ public void testCollectionCopies() throws Exception {
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ Collection c = impl.emptyCollection();
+ for (int n = rnd.nextInt(4); n--> 0; )
+ c.add(impl.makeElement(rnd.nextInt()));
+ assertEquals(c, c);
+ if (c instanceof List)
+ assertCollectionsEquals(c, new ArrayList(c));
+ else if (c instanceof Set)
+ assertCollectionsEquals(c, new HashSet(c));
+ else if (c instanceof Deque)
+ assertCollectionsEquivalent(c, new ArrayDeque(c));
+
+ Collection clone = cloneableClone(c);
+ if (clone != null) {
+ assertSame(c.getClass(), clone.getClass());
+ assertCollectionsEquivalent(c, clone);
+ }
+ try {
+ Collection serialClone = serialClonePossiblyFailing(c);
+ assertSame(c.getClass(), serialClone.getClass());
+ assertCollectionsEquivalent(c, serialClone);
+ } catch (java.io.NotSerializableException acceptable) {}
+ }
+
// public void testCollection8DebugFail() {
// fail(impl.klazz().getSimpleName());
// }
--- a/test/jdk/java/util/concurrent/tck/CopyOnWriteArrayListTest.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/CopyOnWriteArrayListTest.java Tue Apr 10 13:58:47 2018 -0700
@@ -36,12 +36,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ThreadLocalRandom;
import junit.framework.Test;
@@ -61,7 +62,12 @@
}
class SubListImplementation extends Implementation {
public List emptyCollection() {
- return super.emptyCollection().subList(0, 0);
+ List list = super.emptyCollection();
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ if (rnd.nextBoolean())
+ list.add(makeElement(rnd.nextInt()));
+ int i = rnd.nextInt(list.size() + 1);
+ return list.subList(i, i);
}
}
return newTestSuite(
@@ -70,67 +76,67 @@
CollectionTest.testSuite(new SubListImplementation()));
}
- static CopyOnWriteArrayList<Integer> populatedArray(int n) {
- CopyOnWriteArrayList<Integer> a = new CopyOnWriteArrayList<>();
- assertTrue(a.isEmpty());
+ static CopyOnWriteArrayList<Integer> populatedList(int n) {
+ CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
+ assertTrue(list.isEmpty());
for (int i = 0; i < n; i++)
- a.add(i);
- assertFalse(a.isEmpty());
- assertEquals(n, a.size());
- return a;
+ list.add(i);
+ assertEquals(n <= 0, list.isEmpty());
+ assertEquals(n, list.size());
+ return list;
}
- static CopyOnWriteArrayList<Integer> populatedArray(Integer[] elements) {
- CopyOnWriteArrayList<Integer> a = new CopyOnWriteArrayList<>();
- assertTrue(a.isEmpty());
+ static CopyOnWriteArrayList<Integer> populatedList(Integer[] elements) {
+ CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
+ assertTrue(list.isEmpty());
for (Integer element : elements)
- a.add(element);
- assertFalse(a.isEmpty());
- assertEquals(elements.length, a.size());
- return a;
+ list.add(element);
+ assertFalse(list.isEmpty());
+ assertEquals(elements.length, list.size());
+ return list;
}
/**
* a new list is empty
*/
public void testConstructor() {
- CopyOnWriteArrayList a = new CopyOnWriteArrayList();
- assertTrue(a.isEmpty());
+ List list = new CopyOnWriteArrayList();
+ assertTrue(list.isEmpty());
}
/**
* new list contains all elements of initializing array
*/
public void testConstructor2() {
- Integer[] ints = new Integer[SIZE];
+ Integer[] elts = new Integer[SIZE];
for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
- CopyOnWriteArrayList a = new CopyOnWriteArrayList(ints);
+ elts[i] = i;
+ List list = new CopyOnWriteArrayList(elts);
for (int i = 0; i < SIZE; ++i)
- assertEquals(ints[i], a.get(i));
+ assertEquals(elts[i], list.get(i));
}
/**
* new list contains all elements of initializing collection
*/
public void testConstructor3() {
- Integer[] ints = new Integer[SIZE];
+ Integer[] elts = new Integer[SIZE];
for (int i = 0; i < SIZE - 1; ++i)
- ints[i] = new Integer(i);
- CopyOnWriteArrayList a = new CopyOnWriteArrayList(Arrays.asList(ints));
+ elts[i] = i;
+ List list = new CopyOnWriteArrayList(Arrays.asList(elts));
for (int i = 0; i < SIZE; ++i)
- assertEquals(ints[i], a.get(i));
+ assertEquals(elts[i], list.get(i));
}
/**
* addAll adds each element from the given collection, including duplicates
*/
public void testAddAll() {
- CopyOnWriteArrayList full = populatedArray(3);
- assertTrue(full.addAll(Arrays.asList(three, four, five)));
- assertEquals(6, full.size());
- assertTrue(full.addAll(Arrays.asList(three, four, five)));
- assertEquals(9, full.size());
+ List list = populatedList(3);
+ assertTrue(list.addAll(Arrays.asList(three, four, five)));
+ assertEquals(6, list.size());
+ assertTrue(list.addAll(Arrays.asList(three, four, five)));
+ assertEquals(9, list.size());
}
/**
@@ -138,46 +144,46 @@
* already exist in the List
*/
public void testAddAllAbsent() {
- CopyOnWriteArrayList full = populatedArray(3);
+ CopyOnWriteArrayList list = populatedList(3);
// "one" is duplicate and will not be added
- assertEquals(2, full.addAllAbsent(Arrays.asList(three, four, one)));
- assertEquals(5, full.size());
- assertEquals(0, full.addAllAbsent(Arrays.asList(three, four, one)));
- assertEquals(5, full.size());
+ assertEquals(2, list.addAllAbsent(Arrays.asList(three, four, one)));
+ assertEquals(5, list.size());
+ assertEquals(0, list.addAllAbsent(Arrays.asList(three, four, one)));
+ assertEquals(5, list.size());
}
/**
* addIfAbsent will not add the element if it already exists in the list
*/
public void testAddIfAbsent() {
- CopyOnWriteArrayList full = populatedArray(SIZE);
- full.addIfAbsent(one);
- assertEquals(SIZE, full.size());
+ CopyOnWriteArrayList list = populatedList(SIZE);
+ list.addIfAbsent(one);
+ assertEquals(SIZE, list.size());
}
/**
* addIfAbsent adds the element when it does not exist in the list
*/
public void testAddIfAbsent2() {
- CopyOnWriteArrayList full = populatedArray(SIZE);
- full.addIfAbsent(three);
- assertTrue(full.contains(three));
+ CopyOnWriteArrayList list = populatedList(SIZE);
+ list.addIfAbsent(three);
+ assertTrue(list.contains(three));
}
/**
* clear removes all elements from the list
*/
public void testClear() {
- CopyOnWriteArrayList full = populatedArray(SIZE);
- full.clear();
- assertEquals(0, full.size());
+ List list = populatedList(SIZE);
+ list.clear();
+ assertEquals(0, list.size());
}
/**
* Cloned list is equal
*/
public void testClone() {
- CopyOnWriteArrayList l1 = populatedArray(SIZE);
+ CopyOnWriteArrayList l1 = populatedList(SIZE);
CopyOnWriteArrayList l2 = (CopyOnWriteArrayList)(l1.clone());
assertEquals(l1, l2);
l1.clear();
@@ -188,33 +194,33 @@
* contains is true for added elements
*/
public void testContains() {
- CopyOnWriteArrayList full = populatedArray(3);
- assertTrue(full.contains(one));
- assertFalse(full.contains(five));
+ List list = populatedList(3);
+ assertTrue(list.contains(one));
+ assertFalse(list.contains(five));
}
/**
* adding at an index places it in the indicated index
*/
public void testAddIndex() {
- CopyOnWriteArrayList full = populatedArray(3);
- full.add(0, m1);
- assertEquals(4, full.size());
- assertEquals(m1, full.get(0));
- assertEquals(zero, full.get(1));
+ List list = populatedList(3);
+ list.add(0, m1);
+ assertEquals(4, list.size());
+ assertEquals(m1, list.get(0));
+ assertEquals(zero, list.get(1));
- full.add(2, m2);
- assertEquals(5, full.size());
- assertEquals(m2, full.get(2));
- assertEquals(two, full.get(4));
+ list.add(2, m2);
+ assertEquals(5, list.size());
+ assertEquals(m2, list.get(2));
+ assertEquals(two, list.get(4));
}
/**
* lists with same elements are equal and have same hashCode
*/
public void testEquals() {
- CopyOnWriteArrayList a = populatedArray(3);
- CopyOnWriteArrayList b = populatedArray(3);
+ List a = populatedList(3);
+ List b = populatedList(3);
assertTrue(a.equals(b));
assertTrue(b.equals(a));
assertTrue(a.containsAll(b));
@@ -239,15 +245,15 @@
* containsAll returns true for collections with subset of elements
*/
public void testContainsAll() {
- CopyOnWriteArrayList full = populatedArray(3);
- assertTrue(full.containsAll(Arrays.asList()));
- assertTrue(full.containsAll(Arrays.asList(one)));
- assertTrue(full.containsAll(Arrays.asList(one, two)));
- assertFalse(full.containsAll(Arrays.asList(one, two, six)));
- assertFalse(full.containsAll(Arrays.asList(six)));
+ List list = populatedList(3);
+ assertTrue(list.containsAll(Arrays.asList()));
+ assertTrue(list.containsAll(Arrays.asList(one)));
+ assertTrue(list.containsAll(Arrays.asList(one, two)));
+ assertFalse(list.containsAll(Arrays.asList(one, two, six)));
+ assertFalse(list.containsAll(Arrays.asList(six)));
try {
- full.containsAll(null);
+ list.containsAll(null);
shouldThrow();
} catch (NullPointerException success) {}
}
@@ -256,37 +262,81 @@
* get returns the value at the given index
*/
public void testGet() {
- CopyOnWriteArrayList full = populatedArray(3);
- assertEquals(0, full.get(0));
+ List list = populatedList(3);
+ assertEquals(0, list.get(0));
}
/**
- * indexOf gives the index for the given object
+ * indexOf(Object) returns the index of the first occurrence of the
+ * specified element in this list, or -1 if this list does not
+ * contain the element
*/
public void testIndexOf() {
- CopyOnWriteArrayList full = populatedArray(3);
- assertEquals(1, full.indexOf(one));
- assertEquals(-1, full.indexOf("puppies"));
+ List list = populatedList(3);
+ assertEquals(-1, list.indexOf(-42));
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ assertEquals(i, list.indexOf(i));
+ assertEquals(i, list.subList(0, size).indexOf(i));
+ assertEquals(i, list.subList(0, i + 1).indexOf(i));
+ assertEquals(-1, list.subList(0, i).indexOf(i));
+ assertEquals(0, list.subList(i, size).indexOf(i));
+ assertEquals(-1, list.subList(i + 1, size).indexOf(i));
+ }
+
+ list.add(1);
+ assertEquals(1, list.indexOf(1));
+ assertEquals(1, list.subList(0, size + 1).indexOf(1));
+ assertEquals(0, list.subList(1, size + 1).indexOf(1));
+ assertEquals(size - 2, list.subList(2, size + 1).indexOf(1));
+ assertEquals(0, list.subList(size, size + 1).indexOf(1));
+ assertEquals(-1, list.subList(size + 1, size + 1).indexOf(1));
}
/**
- * indexOf gives the index based on the given index
- * at which to start searching
+ * indexOf(E, int) returns the index of the first occurrence of the
+ * specified element in this list, searching forwards from index,
+ * or returns -1 if the element is not found
*/
public void testIndexOf2() {
- CopyOnWriteArrayList full = populatedArray(3);
- assertEquals(1, full.indexOf(one, 0));
- assertEquals(-1, full.indexOf(one, 2));
+ CopyOnWriteArrayList list = populatedList(3);
+ int size = list.size();
+ assertEquals(-1, list.indexOf(-42, 0));
+
+ // we might expect IOOBE, but spec says otherwise
+ assertEquals(-1, list.indexOf(0, size));
+ assertEquals(-1, list.indexOf(0, Integer.MAX_VALUE));
+
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> list.indexOf(0, -1),
+ () -> list.indexOf(0, Integer.MIN_VALUE));
+
+ for (int i = 0; i < size; i++) {
+ assertEquals(i, list.indexOf(i, 0));
+ assertEquals(i, list.indexOf(i, i));
+ assertEquals(-1, list.indexOf(i, i + 1));
+ }
+
+ list.add(1);
+ assertEquals(1, list.indexOf(1, 0));
+ assertEquals(1, list.indexOf(1, 1));
+ assertEquals(size, list.indexOf(1, 2));
+ assertEquals(size, list.indexOf(1, size));
}
/**
* isEmpty returns true when empty, else false
*/
public void testIsEmpty() {
- CopyOnWriteArrayList empty = new CopyOnWriteArrayList();
- CopyOnWriteArrayList full = populatedArray(SIZE);
+ List empty = new CopyOnWriteArrayList();
assertTrue(empty.isEmpty());
+ assertTrue(empty.subList(0, 0).isEmpty());
+
+ List full = populatedList(SIZE);
assertFalse(full.isEmpty());
+ assertTrue(full.subList(0, 0).isEmpty());
+ assertTrue(full.subList(SIZE, SIZE).isEmpty());
}
/**
@@ -305,7 +355,7 @@
for (int i = 0; i < SIZE; i++)
elements[i] = i;
shuffle(elements);
- Collection<Integer> full = populatedArray(elements);
+ Collection<Integer> full = populatedList(elements);
Iterator it = full.iterator();
for (int j = 0; j < SIZE; j++) {
@@ -327,8 +377,8 @@
* iterator.remove throws UnsupportedOperationException
*/
public void testIteratorRemove() {
- CopyOnWriteArrayList full = populatedArray(SIZE);
- Iterator it = full.iterator();
+ CopyOnWriteArrayList list = populatedList(SIZE);
+ Iterator it = list.iterator();
it.next();
try {
it.remove();
@@ -341,42 +391,78 @@
*/
public void testToString() {
assertEquals("[]", new CopyOnWriteArrayList().toString());
- CopyOnWriteArrayList full = populatedArray(3);
- String s = full.toString();
+ List list = populatedList(3);
+ String s = list.toString();
for (int i = 0; i < 3; ++i)
assertTrue(s.contains(String.valueOf(i)));
- assertEquals(new ArrayList(full).toString(),
- full.toString());
+ assertEquals(new ArrayList(list).toString(),
+ list.toString());
}
/**
- * lastIndexOf returns the index for the given object
+ * lastIndexOf(Object) returns the index of the last occurrence of
+ * the specified element in this list, or -1 if this list does not
+ * contain the element
*/
public void testLastIndexOf1() {
- CopyOnWriteArrayList full = populatedArray(3);
- full.add(one);
- full.add(three);
- assertEquals(3, full.lastIndexOf(one));
- assertEquals(-1, full.lastIndexOf(six));
+ List list = populatedList(3);
+ assertEquals(-1, list.lastIndexOf(-42));
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ assertEquals(i, list.lastIndexOf(i));
+ assertEquals(i, list.subList(0, size).lastIndexOf(i));
+ assertEquals(i, list.subList(0, i + 1).lastIndexOf(i));
+ assertEquals(-1, list.subList(0, i).lastIndexOf(i));
+ assertEquals(0, list.subList(i, size).lastIndexOf(i));
+ assertEquals(-1, list.subList(i + 1, size).lastIndexOf(i));
+ }
+
+ list.add(1);
+ assertEquals(size, list.lastIndexOf(1));
+ assertEquals(size, list.subList(0, size + 1).lastIndexOf(1));
+ assertEquals(1, list.subList(0, size).lastIndexOf(1));
+ assertEquals(0, list.subList(1, 2).lastIndexOf(1));
+ assertEquals(-1, list.subList(0, 1).indexOf(1));
}
/**
- * lastIndexOf returns the index from the given starting point
+ * lastIndexOf(E, int) returns the index of the last occurrence of the
+ * specified element in this list, searching backwards from index, or
+ * returns -1 if the element is not found
*/
public void testLastIndexOf2() {
- CopyOnWriteArrayList full = populatedArray(3);
- full.add(one);
- full.add(three);
- assertEquals(3, full.lastIndexOf(one, 4));
- assertEquals(-1, full.lastIndexOf(three, 3));
+ CopyOnWriteArrayList list = populatedList(3);
+
+ // we might expect IOOBE, but spec says otherwise
+ assertEquals(-1, list.lastIndexOf(0, -1));
+
+ int size = list.size();
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> list.lastIndexOf(0, size),
+ () -> list.lastIndexOf(0, Integer.MAX_VALUE));
+
+ for (int i = 0; i < size; i++) {
+ assertEquals(i, list.lastIndexOf(i, i));
+ assertEquals(list.indexOf(i), list.lastIndexOf(i, i));
+ if (i > 0)
+ assertEquals(-1, list.lastIndexOf(i, i - 1));
+ }
+ list.add(one);
+ list.add(three);
+ assertEquals(1, list.lastIndexOf(one, 1));
+ assertEquals(1, list.lastIndexOf(one, 2));
+ assertEquals(3, list.lastIndexOf(one, 3));
+ assertEquals(3, list.lastIndexOf(one, 4));
+ assertEquals(-1, list.lastIndexOf(three, 3));
}
/**
* listIterator traverses all elements
*/
public void testListIterator1() {
- CopyOnWriteArrayList full = populatedArray(SIZE);
- ListIterator i = full.listIterator();
+ List list = populatedList(SIZE);
+ ListIterator i = list.listIterator();
int j;
for (j = 0; i.hasNext(); j++)
assertEquals(j, i.next());
@@ -387,8 +473,8 @@
* listIterator only returns those elements after the given index
*/
public void testListIterator2() {
- CopyOnWriteArrayList full = populatedArray(3);
- ListIterator i = full.listIterator(1);
+ List list = populatedList(3);
+ ListIterator i = list.listIterator(1);
int j;
for (j = 0; i.hasNext(); j++)
assertEquals(j + 1, i.next());
@@ -401,10 +487,10 @@
public void testRemove_int() {
int SIZE = 3;
for (int i = 0; i < SIZE; i++) {
- CopyOnWriteArrayList full = populatedArray(SIZE);
- assertEquals(i, full.remove(i));
- assertEquals(SIZE - 1, full.size());
- assertFalse(full.contains(new Integer(i)));
+ List list = populatedList(SIZE);
+ assertEquals(i, list.remove(i));
+ assertEquals(SIZE - 1, list.size());
+ assertFalse(list.contains(new Integer(i)));
}
}
@@ -414,11 +500,11 @@
public void testRemove_Object() {
int SIZE = 3;
for (int i = 0; i < SIZE; i++) {
- CopyOnWriteArrayList full = populatedArray(SIZE);
- assertFalse(full.remove(new Integer(-42)));
- assertTrue(full.remove(new Integer(i)));
- assertEquals(SIZE - 1, full.size());
- assertFalse(full.contains(new Integer(i)));
+ List list = populatedList(SIZE);
+ assertFalse(list.remove(new Integer(-42)));
+ assertTrue(list.remove(new Integer(i)));
+ assertEquals(SIZE - 1, list.size());
+ assertFalse(list.contains(new Integer(i)));
}
CopyOnWriteArrayList x = new CopyOnWriteArrayList(Arrays.asList(4, 5, 6));
assertTrue(x.remove(new Integer(6)));
@@ -434,30 +520,34 @@
* removeAll removes all elements from the given collection
*/
public void testRemoveAll() {
- CopyOnWriteArrayList full = populatedArray(3);
- assertTrue(full.removeAll(Arrays.asList(one, two)));
- assertEquals(1, full.size());
- assertFalse(full.removeAll(Arrays.asList(one, two)));
- assertEquals(1, full.size());
+ List list = populatedList(3);
+ assertTrue(list.removeAll(Arrays.asList(one, two)));
+ assertEquals(1, list.size());
+ assertFalse(list.removeAll(Arrays.asList(one, two)));
+ assertEquals(1, list.size());
}
/**
* set changes the element at the given index
*/
public void testSet() {
- CopyOnWriteArrayList full = populatedArray(3);
- assertEquals(2, full.set(2, four));
- assertEquals(4, full.get(2));
+ List list = populatedList(3);
+ assertEquals(2, list.set(2, four));
+ assertEquals(4, list.get(2));
}
/**
* size returns the number of elements
*/
public void testSize() {
- CopyOnWriteArrayList empty = new CopyOnWriteArrayList();
- CopyOnWriteArrayList full = populatedArray(SIZE);
+ List empty = new CopyOnWriteArrayList();
+ assertEquals(0, empty.size());
+ assertEquals(0, empty.subList(0, 0).size());
+
+ List full = populatedList(SIZE);
assertEquals(SIZE, full.size());
- assertEquals(0, empty.size());
+ assertEquals(0, full.subList(0, 0).size());
+ assertEquals(0, full.subList(SIZE, SIZE).size());
}
/**
@@ -473,7 +563,7 @@
for (int i = 0; i < SIZE; i++)
elements[i] = i;
shuffle(elements);
- Collection<Integer> full = populatedArray(elements);
+ Collection<Integer> full = populatedList(elements);
assertTrue(Arrays.equals(elements, full.toArray()));
assertSame(Object[].class, full.toArray().getClass());
@@ -501,7 +591,7 @@
for (int i = 0; i < SIZE; i++)
elements[i] = i;
shuffle(elements);
- Collection<Integer> full = populatedArray(elements);
+ Collection<Integer> full = populatedList(elements);
Arrays.fill(a, 42);
assertTrue(Arrays.equals(elements, full.toArray(a)));
@@ -527,7 +617,7 @@
* sublists contains elements at indexes offset from their base
*/
public void testSubList() {
- CopyOnWriteArrayList a = populatedArray(10);
+ List a = populatedList(10);
assertTrue(a.subList(1,1).isEmpty());
for (int j = 0; j < 9; ++j) {
for (int i = j ; i < 10; ++i) {
@@ -544,6 +634,11 @@
assertEquals(a.get(4), m1);
s.clear();
assertEquals(7, a.size());
+
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> s.get(0),
+ () -> s.set(0, 42));
}
// Exception tests
@@ -553,231 +648,72 @@
* can not store the objects inside the list
*/
public void testToArray_ArrayStoreException() {
- CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- c.add("zfasdfsdf");
- c.add("asdadasd");
- try {
- c.toArray(new Long[5]);
- shouldThrow();
- } catch (ArrayStoreException success) {}
- }
-
- /**
- * get throws an IndexOutOfBoundsException on a negative index
- */
- public void testGet1_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.get(-1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * get throws an IndexOutOfBoundsException on a too high index
- */
- public void testGet2_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.get(list.size());
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * set throws an IndexOutOfBoundsException on a negative index
- */
- public void testSet1_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.set(-1, "qwerty");
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
+ List list = new CopyOnWriteArrayList();
+ // Integers are not auto-converted to Longs
+ list.add(86);
+ list.add(99);
+ assertThrows(
+ ArrayStoreException.class,
+ () -> list.toArray(new Long[0]),
+ () -> list.toArray(new Long[5]));
}
- /**
- * set throws an IndexOutOfBoundsException on a too high index
- */
- public void testSet2() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.set(list.size(), "qwerty");
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
+ void testIndexOutOfBoundsException(List list) {
+ int size = list.size();
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> list.get(-1),
+ () -> list.get(size),
+ () -> list.set(-1, "qwerty"),
+ () -> list.set(size, "qwerty"),
+ () -> list.add(-1, "qwerty"),
+ () -> list.add(size + 1, "qwerty"),
+ () -> list.remove(-1),
+ () -> list.remove(size),
+ () -> list.addAll(-1, Collections.emptyList()),
+ () -> list.addAll(size + 1, Collections.emptyList()),
+ () -> list.listIterator(-1),
+ () -> list.listIterator(size + 1),
+ () -> list.subList(-1, size),
+ () -> list.subList(0, size + 1));
- /**
- * add throws an IndexOutOfBoundsException on a negative index
- */
- public void testAdd1_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.add(-1, "qwerty");
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * add throws an IndexOutOfBoundsException on a too high index
- */
- public void testAdd2_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.add(list.size() + 1, "qwerty");
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * remove throws an IndexOutOfBoundsException on a negative index
- */
- public void testRemove1_IndexOutOfBounds() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.remove(-1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
+ // Conversely, operations that must not throw
+ list.addAll(0, Collections.emptyList());
+ list.addAll(size, Collections.emptyList());
+ list.add(0, "qwerty");
+ list.add(list.size(), "qwerty");
+ list.get(0);
+ list.get(list.size() - 1);
+ list.set(0, "azerty");
+ list.set(list.size() - 1, "azerty");
+ list.listIterator(0);
+ list.listIterator(list.size());
+ list.subList(0, list.size());
+ list.remove(list.size() - 1);
}
/**
- * remove throws an IndexOutOfBoundsException on a too high index
- */
- public void testRemove2_IndexOutOfBounds() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.remove(list.size());
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * addAll throws an IndexOutOfBoundsException on a negative index
+ * IndexOutOfBoundsException is thrown when specified
*/
- public void testAddAll1_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.addAll(-1, new LinkedList());
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * addAll throws an IndexOutOfBoundsException on a too high index
- */
- public void testAddAll2_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.addAll(list.size() + 1, new LinkedList());
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * listIterator throws an IndexOutOfBoundsException on a negative index
- */
- public void testListIterator1_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.listIterator(-1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
+ public void testIndexOutOfBoundsException() {
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ List x = populatedList(rnd.nextInt(5));
+ testIndexOutOfBoundsException(x);
- /**
- * listIterator throws an IndexOutOfBoundsException on a too high index
- */
- public void testListIterator2_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.listIterator(list.size() + 1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * subList throws an IndexOutOfBoundsException on a negative index
- */
- public void testSubList1_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.subList(-1, list.size());
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * subList throws an IndexOutOfBoundsException on a too high index
- */
- public void testSubList2_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.subList(0, list.size() + 1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
- }
-
- /**
- * subList throws IndexOutOfBoundsException when the second index
- * is lower then the first
- */
- public void testSubList3_IndexOutOfBoundsException() {
- CopyOnWriteArrayList c = populatedArray(5);
- List[] lists = { c, c.subList(1, c.size() - 1) };
- for (List list : lists) {
- try {
- list.subList(list.size() - 1, 1);
- shouldThrow();
- } catch (IndexOutOfBoundsException success) {}
- }
+ int start = rnd.nextInt(x.size() + 1);
+ int end = rnd.nextInt(start, x.size() + 1);
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> x.subList(start, start - 1));
+ List subList = x.subList(start, end);
+ testIndexOutOfBoundsException(x);
}
/**
* a deserialized/reserialized list equals original
*/
public void testSerialization() throws Exception {
- List x = populatedArray(SIZE);
+ List x = populatedList(SIZE);
List y = serialClone(x);
assertNotSame(x, y);
--- a/test/jdk/java/util/concurrent/tck/CopyOnWriteArraySetTest.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/CopyOnWriteArraySetTest.java Tue Apr 10 13:58:47 2018 -0700
@@ -49,7 +49,16 @@
main(suite(), args);
}
public static Test suite() {
- return new TestSuite(CopyOnWriteArraySetTest.class);
+ class Implementation implements CollectionImplementation {
+ public Class<?> klazz() { return CopyOnWriteArraySet.class; }
+ public Set emptyCollection() { return new CopyOnWriteArraySet(); }
+ public Object makeElement(int i) { return i; }
+ public boolean isConcurrent() { return true; }
+ public boolean permitsNulls() { return true; }
+ }
+ return newTestSuite(
+ CopyOnWriteArraySetTest.class,
+ CollectionTest.testSuite(new Implementation()));
}
static CopyOnWriteArraySet<Integer> populatedSet(int n) {
--- a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java Tue Apr 10 13:58:47 2018 -0700
@@ -93,11 +93,14 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+import java.util.Deque;
import java.util.Enumeration;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.PropertyPermission;
+import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
@@ -475,6 +478,7 @@
public static boolean atLeastJava8() { return JAVA_CLASS_VERSION >= 52.0; }
public static boolean atLeastJava9() { return JAVA_CLASS_VERSION >= 53.0; }
public static boolean atLeastJava10() { return JAVA_CLASS_VERSION >= 54.0; }
+ public static boolean atLeastJava11() { return JAVA_CLASS_VERSION >= 55.0; }
/**
* Collects all JSR166 unit tests as one suite.
@@ -1473,26 +1477,6 @@
}
}
- public abstract class RunnableShouldThrow implements Runnable {
- protected abstract void realRun() throws Throwable;
-
- final Class<?> exceptionClass;
-
- <T extends Throwable> RunnableShouldThrow(Class<T> exceptionClass) {
- this.exceptionClass = exceptionClass;
- }
-
- public final void run() {
- try {
- realRun();
- threadShouldThrow(exceptionClass.getSimpleName());
- } catch (Throwable t) {
- if (! exceptionClass.isInstance(t))
- threadUnexpectedException(t);
- }
- }
- }
-
public abstract class ThreadShouldThrow extends Thread {
protected abstract void realRun() throws Throwable;
@@ -2098,4 +2082,42 @@
assertEquals(savedCompletedTaskCount, p.getCompletedTaskCount());
assertEquals(savedQueueSize, p.getQueue().size());
}
+
+ void assertCollectionsEquals(Collection<?> x, Collection<?> y) {
+ assertEquals(x, y);
+ assertEquals(y, x);
+ assertEquals(x.isEmpty(), y.isEmpty());
+ assertEquals(x.size(), y.size());
+ if (x instanceof List) {
+ assertEquals(x.toString(), y.toString());
+ }
+ if (x instanceof List || x instanceof Set) {
+ assertEquals(x.hashCode(), y.hashCode());
+ }
+ if (x instanceof List || x instanceof Deque) {
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ assertTrue(Arrays.equals(x.toArray(new Object[0]),
+ y.toArray(new Object[0])));
+ }
+ }
+
+ /**
+ * A weaker form of assertCollectionsEquals which does not insist
+ * that the two collections satisfy Object#equals(Object), since
+ * they may use identity semantics as Deques do.
+ */
+ void assertCollectionsEquivalent(Collection<?> x, Collection<?> y) {
+ if (x instanceof List || x instanceof Set)
+ assertCollectionsEquals(x, y);
+ else {
+ assertEquals(x.isEmpty(), y.isEmpty());
+ assertEquals(x.size(), y.size());
+ assertEquals(new HashSet(x), new HashSet(y));
+ if (x instanceof Deque) {
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ assertTrue(Arrays.equals(x.toArray(new Object[0]),
+ y.toArray(new Object[0])));
+ }
+ }
+ }
}
--- a/test/jdk/java/util/concurrent/tck/LinkedListTest.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/LinkedListTest.java Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,9 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
+import java.util.List;
import java.util.NoSuchElementException;
+import java.util.concurrent.ThreadLocalRandom;
import junit.framework.Test;
@@ -49,14 +51,19 @@
public static Test suite() {
class Implementation implements CollectionImplementation {
public Class<?> klazz() { return LinkedList.class; }
- public Collection emptyCollection() { return new LinkedList(); }
+ public List emptyCollection() { return new LinkedList(); }
public Object makeElement(int i) { return i; }
public boolean isConcurrent() { return false; }
public boolean permitsNulls() { return true; }
}
class SubListImplementation extends Implementation {
- public Collection emptyCollection() {
- return new LinkedList().subList(0, 0);
+ public List emptyCollection() {
+ List list = super.emptyCollection();
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ if (rnd.nextBoolean())
+ list.add(makeElement(rnd.nextInt()));
+ int i = rnd.nextInt(list.size() + 1);
+ return list.subList(i, i);
}
}
return newTestSuite(
--- a/test/jdk/java/util/concurrent/tck/VectorTest.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/VectorTest.java Tue Apr 10 13:58:47 2018 -0700
@@ -32,8 +32,13 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import java.util.Vector;
-import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
import junit.framework.Test;
@@ -52,7 +57,12 @@
}
class SubListImplementation extends Implementation {
public List emptyCollection() {
- return super.emptyCollection().subList(0, 0);
+ List list = super.emptyCollection();
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ if (rnd.nextBoolean())
+ list.add(makeElement(rnd.nextInt()));
+ int i = rnd.nextInt(list.size() + 1);
+ return list.subList(i, i);
}
}
return newTestSuite(
@@ -61,6 +71,393 @@
CollectionTest.testSuite(new SubListImplementation()));
}
+ static Vector<Integer> populatedList(int n) {
+ Vector<Integer> list = new Vector<>();
+ assertTrue(list.isEmpty());
+ for (int i = 0; i < n; i++)
+ list.add(i);
+ assertEquals(n <= 0, list.isEmpty());
+ assertEquals(n, list.size());
+ return list;
+ }
+
+ /**
+ * addAll adds each element from the given collection, including duplicates
+ */
+ public void testAddAll() {
+ List list = populatedList(3);
+ assertTrue(list.addAll(Arrays.asList(three, four, five)));
+ assertEquals(6, list.size());
+ assertTrue(list.addAll(Arrays.asList(three, four, five)));
+ assertEquals(9, list.size());
+ }
+
+ /**
+ * clear removes all elements from the list
+ */
+ public void testClear() {
+ List list = populatedList(SIZE);
+ list.clear();
+ assertEquals(0, list.size());
+ }
+
+ /**
+ * Cloned list is equal
+ */
+ public void testClone() {
+ Vector l1 = populatedList(SIZE);
+ Vector l2 = (Vector)(l1.clone());
+ assertEquals(l1, l2);
+ l1.clear();
+ assertFalse(l1.equals(l2));
+ }
+
+ /**
+ * contains is true for added elements
+ */
+ public void testContains() {
+ List list = populatedList(3);
+ assertTrue(list.contains(one));
+ assertFalse(list.contains(five));
+ }
+
+ /**
+ * adding at an index places it in the indicated index
+ */
+ public void testAddIndex() {
+ List list = populatedList(3);
+ list.add(0, m1);
+ assertEquals(4, list.size());
+ assertEquals(m1, list.get(0));
+ assertEquals(zero, list.get(1));
+
+ list.add(2, m2);
+ assertEquals(5, list.size());
+ assertEquals(m2, list.get(2));
+ assertEquals(two, list.get(4));
+ }
+
+ /**
+ * lists with same elements are equal and have same hashCode
+ */
+ public void testEquals() {
+ List a = populatedList(3);
+ List b = populatedList(3);
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ assertTrue(a.containsAll(b));
+ assertTrue(b.containsAll(a));
+ assertEquals(a.hashCode(), b.hashCode());
+ a.add(m1);
+ assertFalse(a.equals(b));
+ assertFalse(b.equals(a));
+ assertTrue(a.containsAll(b));
+ assertFalse(b.containsAll(a));
+ b.add(m1);
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ assertTrue(a.containsAll(b));
+ assertTrue(b.containsAll(a));
+ assertEquals(a.hashCode(), b.hashCode());
+
+ assertFalse(a.equals(null));
+ }
+
+ /**
+ * containsAll returns true for collections with subset of elements
+ */
+ public void testContainsAll() {
+ List list = populatedList(3);
+ assertTrue(list.containsAll(Arrays.asList()));
+ assertTrue(list.containsAll(Arrays.asList(one)));
+ assertTrue(list.containsAll(Arrays.asList(one, two)));
+ assertFalse(list.containsAll(Arrays.asList(one, two, six)));
+ assertFalse(list.containsAll(Arrays.asList(six)));
+
+ try {
+ list.containsAll(null);
+ shouldThrow();
+ } catch (NullPointerException success) {}
+ }
+
+ /**
+ * get returns the value at the given index
+ */
+ public void testGet() {
+ List list = populatedList(3);
+ assertEquals(0, list.get(0));
+ }
+
+ /**
+ * indexOf(Object) returns the index of the first occurrence of the
+ * specified element in this list, or -1 if this list does not
+ * contain the element
+ */
+ public void testIndexOf() {
+ List list = populatedList(3);
+ assertEquals(-1, list.indexOf(-42));
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ assertEquals(i, list.indexOf(i));
+ assertEquals(i, list.subList(0, size).indexOf(i));
+ assertEquals(i, list.subList(0, i + 1).indexOf(i));
+ assertEquals(-1, list.subList(0, i).indexOf(i));
+ assertEquals(0, list.subList(i, size).indexOf(i));
+ assertEquals(-1, list.subList(i + 1, size).indexOf(i));
+ }
+
+ list.add(1);
+ assertEquals(1, list.indexOf(1));
+ assertEquals(1, list.subList(0, size + 1).indexOf(1));
+ assertEquals(0, list.subList(1, size + 1).indexOf(1));
+ assertEquals(size - 2, list.subList(2, size + 1).indexOf(1));
+ assertEquals(0, list.subList(size, size + 1).indexOf(1));
+ assertEquals(-1, list.subList(size + 1, size + 1).indexOf(1));
+ }
+
+ /**
+ * indexOf(E, int) returns the index of the first occurrence of the
+ * specified element in this list, searching forwards from index,
+ * or returns -1 if the element is not found
+ */
+ public void testIndexOf2() {
+ Vector list = populatedList(3);
+ int size = list.size();
+ assertEquals(-1, list.indexOf(-42, 0));
+
+ // we might expect IOOBE, but spec says otherwise
+ assertEquals(-1, list.indexOf(0, size));
+ assertEquals(-1, list.indexOf(0, Integer.MAX_VALUE));
+
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> list.indexOf(0, -1),
+ () -> list.indexOf(0, Integer.MIN_VALUE));
+
+ for (int i = 0; i < size; i++) {
+ assertEquals(i, list.indexOf(i, 0));
+ assertEquals(i, list.indexOf(i, i));
+ assertEquals(-1, list.indexOf(i, i + 1));
+ }
+
+ list.add(1);
+ assertEquals(1, list.indexOf(1, 0));
+ assertEquals(1, list.indexOf(1, 1));
+ assertEquals(size, list.indexOf(1, 2));
+ assertEquals(size, list.indexOf(1, size));
+ }
+
+ /**
+ * isEmpty returns true when empty, else false
+ */
+ public void testIsEmpty() {
+ List empty = new Vector();
+ assertTrue(empty.isEmpty());
+ assertTrue(empty.subList(0, 0).isEmpty());
+
+ List full = populatedList(SIZE);
+ assertFalse(full.isEmpty());
+ assertTrue(full.subList(0, 0).isEmpty());
+ assertTrue(full.subList(SIZE, SIZE).isEmpty());
+ }
+
+ /**
+ * iterator of empty collection has no elements
+ */
+ public void testEmptyIterator() {
+ Collection c = new Vector();
+ assertIteratorExhausted(c.iterator());
+ }
+
+ /**
+ * lastIndexOf(Object) returns the index of the last occurrence of
+ * the specified element in this list, or -1 if this list does not
+ * contain the element
+ */
+ public void testLastIndexOf1() {
+ List list = populatedList(3);
+ assertEquals(-1, list.lastIndexOf(-42));
+ int size = list.size();
+ for (int i = 0; i < size; i++) {
+ assertEquals(i, list.lastIndexOf(i));
+ assertEquals(i, list.subList(0, size).lastIndexOf(i));
+ assertEquals(i, list.subList(0, i + 1).lastIndexOf(i));
+ assertEquals(-1, list.subList(0, i).lastIndexOf(i));
+ assertEquals(0, list.subList(i, size).lastIndexOf(i));
+ assertEquals(-1, list.subList(i + 1, size).lastIndexOf(i));
+ }
+
+ list.add(1);
+ assertEquals(size, list.lastIndexOf(1));
+ assertEquals(size, list.subList(0, size + 1).lastIndexOf(1));
+ assertEquals(1, list.subList(0, size).lastIndexOf(1));
+ assertEquals(0, list.subList(1, 2).lastIndexOf(1));
+ assertEquals(-1, list.subList(0, 1).indexOf(1));
+ }
+
+ /**
+ * lastIndexOf(E, int) returns the index of the last occurrence of the
+ * specified element in this list, searching backwards from index, or
+ * returns -1 if the element is not found
+ */
+ public void testLastIndexOf2() {
+ Vector list = populatedList(3);
+
+ // we might expect IOOBE, but spec says otherwise
+ assertEquals(-1, list.lastIndexOf(0, -1));
+
+ int size = list.size();
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> list.lastIndexOf(0, size),
+ () -> list.lastIndexOf(0, Integer.MAX_VALUE));
+
+ for (int i = 0; i < size; i++) {
+ assertEquals(i, list.lastIndexOf(i, i));
+ assertEquals(list.indexOf(i), list.lastIndexOf(i, i));
+ if (i > 0)
+ assertEquals(-1, list.lastIndexOf(i, i - 1));
+ }
+ list.add(one);
+ list.add(three);
+ assertEquals(1, list.lastIndexOf(one, 1));
+ assertEquals(1, list.lastIndexOf(one, 2));
+ assertEquals(3, list.lastIndexOf(one, 3));
+ assertEquals(3, list.lastIndexOf(one, 4));
+ assertEquals(-1, list.lastIndexOf(three, 3));
+ }
+
+ /**
+ * size returns the number of elements
+ */
+ public void testSize() {
+ List empty = new Vector();
+ assertEquals(0, empty.size());
+ assertEquals(0, empty.subList(0, 0).size());
+
+ List full = populatedList(SIZE);
+ assertEquals(SIZE, full.size());
+ assertEquals(0, full.subList(0, 0).size());
+ assertEquals(0, full.subList(SIZE, SIZE).size());
+ }
+
+ /**
+ * sublists contains elements at indexes offset from their base
+ */
+ public void testSubList() {
+ List a = populatedList(10);
+ assertTrue(a.subList(1,1).isEmpty());
+ for (int j = 0; j < 9; ++j) {
+ for (int i = j ; i < 10; ++i) {
+ List b = a.subList(j,i);
+ for (int k = j; k < i; ++k) {
+ assertEquals(new Integer(k), b.get(k-j));
+ }
+ }
+ }
+
+ List s = a.subList(2, 5);
+ assertEquals(3, s.size());
+ s.set(2, m1);
+ assertEquals(a.get(4), m1);
+ s.clear();
+ assertEquals(7, a.size());
+
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> s.get(0),
+ () -> s.set(0, 42));
+ }
+
+ /**
+ * toArray throws an ArrayStoreException when the given array
+ * can not store the objects inside the list
+ */
+ public void testToArray_ArrayStoreException() {
+ List list = new Vector();
+ // Integers are not auto-converted to Longs
+ list.add(86);
+ list.add(99);
+ assertThrows(
+ ArrayStoreException.class,
+ () -> list.toArray(new Long[0]),
+ () -> list.toArray(new Long[5]));
+ }
+
+ void testIndexOutOfBoundsException(List list) {
+ int size = list.size();
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> list.get(-1),
+ () -> list.get(size),
+ () -> list.set(-1, "qwerty"),
+ () -> list.set(size, "qwerty"),
+ () -> list.add(-1, "qwerty"),
+ () -> list.add(size + 1, "qwerty"),
+ () -> list.remove(-1),
+ () -> list.remove(size),
+ () -> list.addAll(-1, Collections.emptyList()),
+ () -> list.addAll(size + 1, Collections.emptyList()),
+ () -> list.listIterator(-1),
+ () -> list.listIterator(size + 1),
+ () -> list.subList(-1, size),
+ () -> list.subList(0, size + 1));
+
+ // Conversely, operations that must not throw
+ list.addAll(0, Collections.emptyList());
+ list.addAll(size, Collections.emptyList());
+ list.add(0, "qwerty");
+ list.add(list.size(), "qwerty");
+ list.get(0);
+ list.get(list.size() - 1);
+ list.set(0, "azerty");
+ list.set(list.size() - 1, "azerty");
+ list.listIterator(0);
+ list.listIterator(list.size());
+ list.subList(0, list.size());
+ list.remove(list.size() - 1);
+ }
+
+ /**
+ * IndexOutOfBoundsException is thrown when specified
+ */
+ public void testIndexOutOfBoundsException() {
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+ List x = populatedList(rnd.nextInt(5));
+ testIndexOutOfBoundsException(x);
+
+ int start = rnd.nextInt(x.size() + 1);
+ int end = rnd.nextInt(start, x.size() + 1);
+
+ // Vector#subList spec deviates slightly from List#subList spec
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> x.subList(start, start - 1));
+
+ List subList = x.subList(start, end);
+ testIndexOutOfBoundsException(x);
+ }
+
+ /**
+ * a deserialized/reserialized list equals original
+ */
+ public void testSerialization() throws Exception {
+ List x = populatedList(SIZE);
+ List y = serialClone(x);
+
+ assertNotSame(x, y);
+ assertEquals(x.size(), y.size());
+ assertEquals(x.toString(), y.toString());
+ assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+ assertEquals(x, y);
+ assertEquals(y, x);
+ while (!x.isEmpty()) {
+ assertFalse(y.isEmpty());
+ assertEquals(x.remove(0), y.remove(0));
+ }
+ assertTrue(y.isEmpty());
+ }
+
/**
* tests for setSize()
*/
--- a/test/jdk/java/util/regex/RegExTest.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/regex/RegExTest.java Tue Apr 10 13:58:47 2018 -0700
@@ -4683,6 +4683,9 @@
if (p.test("1234")) {
failCount++;
}
+ if (!p.test("word1234")) {
+ failCount++;
+ }
report("Pattern.asPredicate");
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/krb5/auto/NonAscii.java Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, 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 8200152
+ * @summary KerberosString should use UTF-8 by default
+ * @library /test/lib
+ * @compile -XDignore.symbol.file NonAscii.java
+ * @run main jdk.test.lib.FileInstaller TestHosts TestHosts
+ * @run main/othervm -Djdk.net.hosts.file=TestHosts NonAscii
+ * @run main/othervm/fail -Djdk.net.hosts.file=TestHosts
+ * -Dsun.security.krb5.msinterop.kstring=false
+ * NonAscii
+ * @run main/othervm/fail -Djdk.net.hosts.file=TestHosts
+ * -Dsun.security.krb5.msinterop.kstring=no
+ * NonAscii
+ */
+
+public class NonAscii {
+ public static void main(String[] args) throws Exception {
+ String name = "ab\u00e7";
+ char[] password = "password".toCharArray();
+ new OneKDC(null).addPrincipal(name, password);
+ Context.fromUserPass(name, password, false);
+ }
+}
--- a/test/langtools/jdk/javadoc/doclet/testModules/TestModuleServicesLink.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModuleServicesLink.java Tue Apr 10 13:58:47 2018 -0700
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8185151
+ * @bug 8185151 8196200
* @summary test that navigation summary links are not linked when there are no dependencies
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
@@ -69,10 +69,10 @@
checkExit(Exit.OK);
checkOutput("m/module-summary.html", true,
- "<a href=\"#module.description\">Description</a> |"
- + " Modules |"
- + " <a href=\"#packages.summary\">Packages</a> |"
- + " <a href=\"#services.summary\">Services</a>");
+ "<li><a href=\"#module.description\">Description</a> | </li>\n"
+ + "<li>Modules | </li>\n"
+ + "<li><a href=\"#packages.summary\">Packages</a> | </li>\n"
+ + "<li><a href=\"#services.summary\">Services</a></li>");
}
@@ -93,10 +93,10 @@
checkExit(Exit.OK);
checkOutput("m/module-summary.html", true,
- "<a href=\"#module.description\">Description</a> |"
- + " Modules |"
- + " <a href=\"#packages.summary\">Packages</a> |"
- + " <a href=\"#services.summary\">Services</a>");
+ "<li><a href=\"#module.description\">Description</a> | </li>\n"
+ + "<li>Modules | </li>\n"
+ + "<li><a href=\"#packages.summary\">Packages</a> | </li>\n"
+ + "<li><a href=\"#services.summary\">Services</a></li>");
}
@@ -115,9 +115,10 @@
checkExit(Exit.OK);
checkOutput("m/module-summary.html", true,
- "Description | Modules |"
- + " <a href=\"#packages.summary\">Packages</a> |"
- + " Services");
+ "<li>Description | </li>\n"
+ + "<li>Modules | </li>\n"
+ + "<li><a href=\"#packages.summary\">Packages</a> | </li>\n"
+ + "<li>Services</li>");
}
}
--- a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java Tue Apr 10 13:58:47 2018 -0700
@@ -26,7 +26,7 @@
* @bug 8154119 8154262 8156077 8157987 8154261 8154817 8135291 8155995 8162363
* 8168766 8168688 8162674 8160196 8175799 8174974 8176778 8177562 8175218
* 8175823 8166306 8178043 8181622 8183511 8169819 8074407 8183037 8191464
- 8164407 8192007 8182765
+ 8164407 8192007 8182765 8196200
* @summary Test modules support in javadoc.
* @author bpatel
* @library ../lib
@@ -940,9 +940,10 @@
checkOutput("moduleA/module-summary.html", true,
"<ul class=\"subNavList\">\n"
+ "<li>Module: </li>\n"
- + "<li><a href=\"#module.description\">Description</a> | <a "
- + "href=\"#modules.summary\">Modules</a> | <a href=\"#packages.summary\">"
- + "Packages</a> | Services</li>\n"
+ + "<li><a href=\"#module.description\">Description</a> | </li>\n"
+ + "<li><a href=\"#modules.summary\">Modules</a> | </li>\n"
+ + "<li><a href=\"#packages.summary\">Packages</a> | </li>\n"
+ + "<li>Services</li>\n"
+ "</ul>",
"<!-- ============ MODULES SUMMARY =========== -->\n"
+ "<a id=\"modules.summary\">\n"
@@ -964,9 +965,10 @@
+ "</td>\n"
+ "</tr>");
checkOutput("moduleB/module-summary.html", true,
- "<li><a href=\"#module.description\">Description</a> | Modules | "
- + "<a href=\"#packages.summary\">Packages</a> | <a href=\"#services.summary\">"
- + "Services</a></li>",
+ "<li><a href=\"#module.description\">Description</a> | </li>\n"
+ + "<li>Modules | </li>\n"
+ + "<li><a href=\"#packages.summary\">Packages</a> | </li>\n"
+ + "<li><a href=\"#services.summary\">Services</a></li>",
"<!-- ============ PACKAGES SUMMARY =========== -->\n"
+ "<a id=\"packages.summary\">\n"
+ "<!-- -->\n"
@@ -1180,8 +1182,10 @@
+ " Package Link: <a href=\"moduletags/testpkgmdltags/package-summary.html\"><code>testpkgmdltags</code></a>.<br></div>\n"
+ "</td>");
checkOutput("moduleA/module-summary.html", true,
- "<li><a href=\"#module.description\">Description</a> | <a href=\"#modules.summary\">"
- + "Modules</a> | <a href=\"#packages.summary\">Packages</a> | Services</li>",
+ "<li><a href=\"#module.description\">Description</a> | </li>\n"
+ + "<li><a href=\"#modules.summary\">Modules</a> | </li>\n"
+ + "<li><a href=\"#packages.summary\">Packages</a> | </li>\n"
+ + "<li>Services</li>",
"<th class=\"colFirst\" scope=\"row\"><a href=\"../moduleB/module-summary.html\">moduleB</a></th>\n"
+ "<td class=\"colLast\"><a href=\"../moduleB/testpkgmdlB/package-summary.html\">testpkgmdlB</a></td>\n");
checkOutput("moduleB/module-summary.html", true,
@@ -1189,8 +1193,10 @@
+ "<td class=\"colLast\">\n"
+ "<div class=\"block\">With a test description for uses.</div>\n</td>\n");
checkOutput("moduletags/module-summary.html", true,
- "<li><a href=\"#module.description\">Description</a> | <a href=\"#modules.summary\">Modules"
- + "</a> | <a href=\"#packages.summary\">Packages</a> | Services</li>",
+ "<li><a href=\"#module.description\">Description</a> | </li>\n"
+ + "<li><a href=\"#modules.summary\">Modules</a> | </li>\n"
+ + "<li><a href=\"#packages.summary\">Packages</a> | </li>\n"
+ + "<li>Services</li>",
"<table class=\"requiresSummary\">\n"
+ "<caption><span>Indirect Requires</span><span class=\"tabEnd\"> </span></caption>",
"<td class=\"colFirst\">transitive</td>\n"
@@ -1267,8 +1273,10 @@
"<th class=\"colFirst\" scope=\"row\"><a href=\"testpkgmdlA/package-summary.html\">testpkgmdlA</a></th>\n"
+ "<td class=\"colLast\"> </td>");
checkOutput("moduleB/module-summary.html", found,
- "<li><a href=\"#module.description\">Description</a> | Modules | "
- + "<a href=\"#packages.summary\">Packages</a> | <a href=\"#services.summary\">Services</a></li>",
+ "<li><a href=\"#module.description\">Description</a> | </li>\n"
+ + "<li>Modules | </li>\n"
+ + "<li><a href=\"#packages.summary\">Packages</a> | </li>\n"
+ + "<li><a href=\"#services.summary\">Services</a></li>",
"<th class=\"colFirst\" scope=\"row\"><a href=\"testpkgmdlB/package-summary.html\">testpkgmdlB</a></th>\n"
+ "<td class=\"colLast\"> </td>",
"<table class=\"packagesSummary\">\n"
@@ -1329,8 +1337,10 @@
+ "<td class=\"colSecond\">None</td>\n"
+ "<td class=\"colLast\"> </td>");
checkOutput("moduleB/module-summary.html", found,
- "<li><a href=\"#module.description\">Description</a> | <a href=\"#modules.summary\">"
- + "Modules</a> | <a href=\"#packages.summary\">Packages</a> | <a href=\"#services.summary\">Services</a></li>",
+ "<li><a href=\"#module.description\">Description</a> | </li>\n"
+ + "<li><a href=\"#modules.summary\">Modules</a> | </li>\n"
+ + "<li><a href=\"#packages.summary\">Packages</a> | </li>\n"
+ + "<li><a href=\"#services.summary\">Services</a></li>",
"<th class=\"colFirst\" scope=\"row\"><a href=\"testpkgmdlB/package-summary.html\">testpkgmdlB</a></th>\n"
+ "<td class=\"colSecond\">None</td>\n"
+ "<td class=\"colSecond\">All Modules</td>\n"
--- a/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java Mon Apr 09 08:34:30 2018 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java Tue Apr 10 13:58:47 2018 -0700
@@ -24,24 +24,36 @@
/*
* @test
* @bug 4131628 4664607 7025314 8023700 7198273 8025633 8026567 8081854 8150188 8151743 8196027 8182765
+ * 8196200
* @summary Make sure the Next/Prev Class links iterate through all types.
* Make sure the navagation is 2 columns, not 3.
* @author jamieh
- * @library ../lib
+ * @library /tools/lib ../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
- * @build JavadocTester
+ * @build toolbox.ToolBox JavadocTester
* @run main TestNavigation
*/
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import toolbox.*;
+
public class TestNavigation extends JavadocTester {
+ public final ToolBox tb;
public static void main(String... args) throws Exception {
TestNavigation tester = new TestNavigation();
- tester.runTests();
+ tester.runTests(m -> new Object[] { Paths.get(m.getName()) });
+ }
+
+ public TestNavigation() {
+ tb = new ToolBox();
}
@Test
- void test() {
+ void test(Path ignore) {
javadoc("-d", "out",
"-overview", testSrc("overview.html"),
"-sourcepath", testSrc,
@@ -96,7 +108,7 @@
}
@Test
- void test_html4() {
+ void test_html4(Path ignore) {
javadoc("-d", "out-html4",
"-html4",
"-overview", testSrc("overview.html"),
@@ -135,7 +147,7 @@
// Test for checking additional padding to offset the fixed navigation bar in HTML5.
@Test
- void test1() {
+ void test1(Path ignore) {
javadoc("-d", "out-1",
"-html5",
"-sourcepath", testSrc,
@@ -167,7 +179,7 @@
// Test to make sure that no extra padding for nav bar gets generated if -nonavbar is specified for HTML4.
@Test
- void test2() {
+ void test2(Path ignore) {
javadoc("-d", "out-2",
"-nonavbar",
"-sourcepath", testSrc,
@@ -197,7 +209,7 @@
// Test to make sure that no extra padding for nav bar gets generated if -nonavbar is specified for HTML5.
@Test
- void test3() {
+ void test3(Path ignore) {
javadoc("-d", "out-3",
"-html5",
"-nonavbar",
@@ -227,4 +239,89 @@
+ "</script>\n"
+ "</nav>");
}
+
+ @Test
+ void test4(Path base) throws IOException {
+ Path src = base.resolve("src");
+ tb.writeJavaFiles(src,
+ "package pkg1; public class A {\n"
+ + " /**\n"
+ + " * Class with members.\n"
+ + " */\n"
+ + " public static class X {\n"
+ + " /**\n"
+ + " * A ctor\n"
+ + " */\n"
+ + " public X() {\n"
+ + " }\n"
+ + " /**\n"
+ + " * A field\n"
+ + " */\n"
+ + " public int field;\n"
+ + " /**\n"
+ + " * A method\n"
+ + " */\n"
+ + " public void method() {\n"
+ + " }\n"
+ + " /**\n"
+ + " * An inner class\n"
+ + " */\n"
+ + " public static class IC {\n"
+ + " }\n"
+ + " }\n"
+ + " /**\n"
+ + " * Class with all inherited members.\n"
+ + " */\n"
+ + " public static class Y extends X {\n"
+ + " }\n"
+ + "}");
+
+ tb.writeJavaFiles(src,
+ "package pkg1; public class C {\n"
+ + "}");
+
+ tb.writeJavaFiles(src,
+ "package pkg1; public interface InterfaceWithNoMembers {\n"
+ + "}");
+
+ javadoc("-d", "out-4",
+ "-sourcepath", src.toString(),
+ "pkg1");
+ checkExit(Exit.OK);
+
+ checkOrder("pkg1/A.X.html",
+ "Summary",
+ "<li><a href=\"#nested.class.summary\">Nested</a> | </li>",
+ "<li><a href=\"#field.summary\">Field</a> | </li>",
+ "<li><a href=\"#constructor.summary\">Constr</a> | </li>",
+ "<li><a href=\"#method.summary\">Method</a></li>");
+
+ checkOrder("pkg1/A.Y.html",
+ "Summary",
+ "<li><a href=\"#nested.class.summary\">Nested</a> | </li>",
+ "<li><a href=\"#field.summary\">Field</a> | </li>",
+ "<li><a href=\"#constructor.summary\">Constr</a> | </li>",
+ "<li><a href=\"#method.summary\">Method</a></li>");
+
+ checkOrder("pkg1/A.X.IC.html",
+ "Summary",
+ "<li>Nested | </li>",
+ "<li>Field | </li>",
+ "<li><a href=\"#constructor.summary\">Constr</a> | </li>",
+ "<li><a href=\"#method.summary\">Method</a></li>");
+
+ checkOrder("pkg1/C.html",
+ "Summary",
+ "<li>Nested | </li>",
+ "<li>Field | </li>",
+ "<li><a href=\"#constructor.summary\">Constr</a> | </li>",
+ "<li><a href=\"#method.summary\">Method</a></li>");
+
+ checkOrder("pkg1/InterfaceWithNoMembers.html",
+ "Summary",
+ "<li>Nested | </li>",
+ "<li>Field | </li>",
+ "<li>Constr | </li>",
+ "<li>Method</li>");
+ }
}