diff --git a/closed/openjdk-tag.gmk b/closed/openjdk-tag.gmk index 7080825ca25..7384f05b3fa 100644 --- a/closed/openjdk-tag.gmk +++ b/closed/openjdk-tag.gmk @@ -1 +1 @@ -OPENJDK_TAG := jdk-11.0.5+10 +OPENJDK_TAG := jdk-11.0.6+2 diff --git a/make/Help.gmk b/make/Help.gmk index 461d3431a62..e58f54862af 100644 --- a/make/Help.gmk +++ b/make/Help.gmk @@ -119,7 +119,7 @@ print-configurations: run-test-prebuilt: @( cd $(topdir) && \ $(MAKE) --no-print-directory -r -R -I make/common/ -f make/RunTestsPrebuilt.gmk \ - run-test-prebuilt TEST="$(TEST)" ) + run-test-prebuilt CUSTOM_MAKE_DIR=$(CUSTOM_MAKE_DIR) TEST="$(TEST)" ) ALL_GLOBAL_TARGETS := help print-configurations run-test-prebuilt diff --git a/make/Main.gmk b/make/Main.gmk index f4757f3a946..ce234ef382f 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -637,6 +637,7 @@ else # Declare dependencies between hotspot-* targets $(foreach v, $(JVM_VARIANTS), \ $(eval hotspot-$v: hotspot-$v-gensrc hotspot-$v-libs) \ + $(eval hotspot-$v-gensrc: java.base-copy) \ $(eval hotspot-$v-libs: hotspot-$v-gensrc java.base-copy) \ ) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index af958831be7..782d8fed564 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -82,8 +82,8 @@ ifneq ($(TEST_VM_OPTS), ) endif $(eval $(call ParseKeywordVariable, TEST_OPTS, \ - KEYWORDS := JOBS TIMEOUT, \ - STRING_KEYWORDS := VM_OPTIONS, \ + SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR, \ + STRING_KEYWORDS := VM_OPTIONS JAVA_OPTIONS, \ )) # Helper function to propagate TEST_OPTS values. @@ -102,10 +102,14 @@ ifeq ($(OPENJDK_TARGET_OS), windows) ifndef _NT_SYMBOL_PATH # Can't use PathList here as it adds quotes around the value. _NT_SYMBOL_PATH := \ - $(subst $(SPACE),;, $(foreach p, $(sort $(dir $(wildcard \ - $(addprefix $(SYMBOLS_IMAGE_DIR)/bin/, *.pdb */*.pdb)))), $(call FixPath, $p))) + $(subst $(SPACE),;,$(strip \ + $(foreach p, $(sort $(dir $(wildcard \ + $(addprefix $(SYMBOLS_IMAGE_DIR)/bin/, *.pdb */*.pdb)))), \ + $(call FixPath, $p) \ + ) \ + )) export _NT_SYMBOL_PATH - $(info _NT_SYMBOL_PATH $(_NT_SYMBOL_PATH)) + $(info _NT_SYMBOL_PATH=$(_NT_SYMBOL_PATH)) endif endif @@ -140,6 +144,31 @@ endif GTEST_LAUNCHER_DIRS := $(patsubst %/gtestLauncher, %, $(wildcard $(TEST_IMAGE_DIR)/hotspot/gtest/*/gtestLauncher)) GTEST_VARIANTS := $(strip $(patsubst $(TEST_IMAGE_DIR)/hotspot/gtest/%, %, $(GTEST_LAUNCHER_DIRS))) +################################################################################ +# Setup global test running parameters +################################################################################ + +# Each factor variable comes in 3 variants. The first one is reserved for users +# to use on command line. The other two are for predifined configurations in JDL +# and for machine specific configurations respectively. +TEST_JOBS_FACTOR ?= 1 +TEST_JOBS_FACTOR_JDL ?= 1 +TEST_JOBS_FACTOR_MACHINE ?= 1 + +ifeq ($(TEST_JOBS), 0) + # Concurrency based on min(cores / 2, 12) * TEST_JOBS_FACTOR + TEST_JOBS := $(shell $(AWK) \ + 'BEGIN { \ + c = $(NUM_CORES) / 2; \ + if (c > 12) c = 12; \ + c = c * $(TEST_JOBS_FACTOR); \ + c = c * $(TEST_JOBS_FACTOR_JDL); \ + c = c * $(TEST_JOBS_FACTOR_MACHINE); \ + if (c < 1) c = 1; \ + printf "%.0f", c; \ + }') +endif + ################################################################################ # Parse control variables ################################################################################ @@ -147,16 +176,19 @@ GTEST_VARIANTS := $(strip $(patsubst $(TEST_IMAGE_DIR)/hotspot/gtest/%, %, $(GTE ifneq ($(TEST_OPTS), ) # Inform the user $(info Running tests using TEST_OPTS control variable '$(TEST_OPTS)') +endif - $(eval $(call SetTestOpt,VM_OPTIONS,JTREG)) - $(eval $(call SetTestOpt,VM_OPTIONS,GTEST)) +$(eval $(call SetTestOpt,VM_OPTIONS,JTREG)) +$(eval $(call SetTestOpt,JAVA_OPTIONS,JTREG)) +$(eval $(call SetTestOpt,VM_OPTIONS,GTEST)) +$(eval $(call SetTestOpt,JAVA_OPTIONS,GTEST)) - $(eval $(call SetTestOpt,JOBS,JTREG)) - $(eval $(call SetTestOpt,TIMEOUT,JTREG)) -endif +$(eval $(call SetTestOpt,JOBS,JTREG)) +$(eval $(call SetTestOpt,TIMEOUT_FACTOR,JTREG)) $(eval $(call ParseKeywordVariable, JTREG, \ - KEYWORDS := JOBS TIMEOUT TEST_MODE ASSERT VERBOSE RETAIN MAX_MEM, \ + SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR TEST_MODE ASSERT VERBOSE RETAIN MAX_MEM \ + EXTRA_PROBLEM_LISTS KEYWORDS, \ STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS, \ )) @@ -166,8 +198,8 @@ ifneq ($(JTREG), ) endif $(eval $(call ParseKeywordVariable, GTEST, \ - KEYWORDS := REPEAT, \ - STRING_KEYWORDS := OPTIONS VM_OPTIONS, \ + SINGLE_KEYWORDS := REPEAT, \ + STRING_KEYWORDS := OPTIONS VM_OPTIONS JAVA_OPTIONS, \ )) ifneq ($(GTEST), ) @@ -396,15 +428,16 @@ define SetupRunGtestTestBody $1_GTEST_REPEAT :=--gtest_repeat=$$(GTEST_REPEAT) endif - run-test-$1: + run-test-$1: $(TEST_PREREQS) $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, \ $$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/$$($1_VARIANT)/gtestLauncher \ - -jdk $(JDK_IMAGE_DIR) $$($1_GTEST_FILTER) \ - --gtest_output=xml:$$($1_TEST_RESULTS_DIR)/gtest.xml \ - $$($1_GTEST_REPEAT) $$(GTEST_OPTIONS) $$(GTEST_VM_OPTIONS) \ + -jdk $(JDK_IMAGE_DIR) $$($1_GTEST_FILTER) \ + --gtest_output=xml:$$($1_TEST_RESULTS_DIR)/gtest.xml \ + $$($1_GTEST_REPEAT) $$(GTEST_OPTIONS) $$(GTEST_VM_OPTIONS) \ + $$($1_GTEST_JAVA_OPTIONS) \ > >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \ && $$(ECHO) $$$$? > $$($1_EXITCODE) \ || $$(ECHO) $$$$? > $$($1_EXITCODE) \ @@ -475,12 +508,11 @@ define SetupRunJtregTestBody $1_TEST_NAME := $$(strip $$(patsubst jtreg:%, %, $$($1_TEST))) - $1_COMPONENT := \ + $1_TEST_ROOT := \ $$(strip $$(foreach root, $$(JTREG_TESTROOTS), \ - $$(if $$(filter $$(root)%, $$(JTREG_TOPDIR)/$$($1_TEST_NAME)), \ - $$(lastword $$(subst /, $$(SPACE), $$(root))) \ - ) \ + $$(if $$(filter $$(root)%, $$(JTREG_TOPDIR)/$$($1_TEST_NAME)), $$(root)) \ )) + $1_COMPONENT := $$(lastword $$(subst /, $$(SPACE), $$($1_TEST_ROOT))) # This will work only as long as just hotspot has the additional "jtreg" directory ifeq ($$($1_COMPONENT), jtreg) $1_COMPONENT := hotspot @@ -503,6 +535,9 @@ define SetupRunJtregTestBody $$(eval $$(call SetJtregValue,$1,JTREG_BASIC_OPTIONS)) $$(eval $$(call SetJtregValue,$1,JTREG_PROBLEM_LIST)) + # Only the problem list for the current test root should be used. + $1_JTREG_PROBLEM_LIST := $$(filter $$($1_TEST_ROOT)%, $$($1_JTREG_PROBLEM_LIST)) + ifneq ($(TEST_JOBS), 0) $$(eval $$(call SetJtregValue,$1,JTREG_JOBS,$$(TEST_JOBS))) else @@ -515,9 +550,9 @@ define SetupRunJtregTestBody # SPARC is in general slower per core so need to scale up timeouts a bit. ifeq ($(OPENJDK_TARGET_CPU_ARCH), sparc) - JTREG_TIMEOUT ?= 8 + JTREG_TIMEOUT_FACTOR ?= 8 else - JTREG_TIMEOUT ?= 4 + JTREG_TIMEOUT_FACTOR ?= 4 endif JTREG_VERBOSE ?= fail,error,summary JTREG_RETAIN ?= fail,error @@ -529,10 +564,10 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += -$$($1_JTREG_TEST_MODE) \ -verbose:$$(JTREG_VERBOSE) -retain:$$(JTREG_RETAIN) \ - -concurrency:$$($1_JTREG_JOBS) -timeoutFactor:$$(JTREG_TIMEOUT) \ + -concurrency:$$($1_JTREG_JOBS) -timeoutFactor:$$(JTREG_TIMEOUT_FACTOR) \ -vmoption:-XX:MaxRAMPercentage=$$($1_JTREG_MAX_RAM_PERCENTAGE) - $1_JTREG_BASIC_OPTIONS += -automatic -keywords:\!ignore -ignore:quiet + $1_JTREG_BASIC_OPTIONS += -automatic -ignore:quiet # Make it possible to specify the JIB_DATA_DIR for tests using the # JIB Artifact resolver @@ -562,8 +597,16 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += $$(addprefix -exclude:, $$($1_JTREG_PROBLEM_LIST)) endif - ifneq ($$(JIB_JAR), ) - $1_JTREG_BASIC_OPTIONS += -cpa:$$(JIB_JAR) + ifneq ($$(JTREG_EXTRA_PROBLEM_LISTS), ) + # Accept both absolute paths as well as relative to the current test root. + $1_JTREG_BASIC_OPTIONS += $$(addprefix -exclude:, $$(wildcard \ + $$(JTREG_EXTRA_PROBLEM_LISTS) \ + $$(addprefix $$($1_TEST_ROOT)/, $$(JTREG_EXTRA_PROBLEM_LISTS)) \ + )) + endif + + ifneq ($$(JIB_HOME), ) + $1_JTREG_BASIC_OPTIONS += -e:JIB_HOME=$$(JIB_HOME) endif $1_JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_GRAAL_DIR=${TEST_IMAGE_DIR}/hotspot/jtreg/graal @@ -572,10 +615,21 @@ define SetupRunJtregTestBody $1_JTREG_LAUNCHER_OPTIONS += -Djava.library.path="$(JTREG_FAILURE_HANDLER_DIR)" endif + ifneq ($$(JTREG_KEYWORDS), ) + # The keywords string may contain problematic characters and may be quoted + # already when it arrives here. Remove any existing quotes and replace them + # with one set of single quotes. + $1_JTREG_KEYWORDS := \ + $$(strip $$(subst $$(SQUOTE),,$$(subst $$(DQUOTE),,$$(JTREG_KEYWORDS)))) + ifneq ($$($1_JTREG_KEYWORDS), ) + $1_JTREG_BASIC_OPTIONS += -k:'$$($1_JTREG_KEYWORDS)' + endif + endif + clean-workdir-$1: $$(RM) -r $$($1_TEST_SUPPORT_DIR) - run-test-$1: clean-workdir-$1 + run-test-$1: clean-workdir-$1 $(TEST_PREREQS) $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) @@ -662,7 +716,7 @@ define SetupRunSpecialTestBody $$(error Invalid special test specification: $$($1_TEST_NAME)) endif - run-test-$1: + run-test-$1: $(TEST_PREREQS) $$(call LogWarn) $$(call LogWarn, Running test '$$($1_TEST)') $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR)) diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk index 888393a141b..b781832fad2 100644 --- a/make/RunTestsPrebuilt.gmk +++ b/make/RunTestsPrebuilt.gmk @@ -49,10 +49,11 @@ TOPDIR := $(strip $(patsubst %/make/, %, $(dir $(makefile_path)))) # given. # Note: No spaces are allowed around the arguments. # -# $1: The name of the argument +# $1: The name of the variable # $2: The default value, if any, or OPTIONAL (do not provide a default but # do not exit if it is missing) # $3: If NO_CHECK, disable checking for target file/directory existence +# If MKDIR, create the default directory define SetupVariable ifeq ($$($1), ) ifeq ($2, ) @@ -75,10 +76,17 @@ define SetupVariable endif # If $1 has a value (is not optional), and $3 is not set (to NO_CHECK), # and if wildcard is empty, then complain that the file is missing. - ifeq ($$(strip $$(if $$($1), , OPTIONAL) $$(wildcard $$($1)) $3), ) - $$(info Error: Prebuilt variable $1 points to missing file/directory:) - $$(info '$$($1)') - $$(error Cannot continue.) + ifeq ($3, MKDIR) + ifneq ($$(findstring $$(LOG), info debug trace), ) + $$(info Creating directory for $1) + endif + $$(shell mkdir -p $$($1)) + else ifneq ($3, NO_CHECK) + ifeq ($$(strip $$(if $$($1), , OPTIONAL) $$(wildcard $$($1))), ) + $$(info Error: Prebuilt variable $1 points to missing file/directory:) + $$(info '$$($1)') + $$(error Cannot continue.) + endif endif endef @@ -106,14 +114,14 @@ endef # Verify that user has given correct additional input. # These variables are absolutely necessary -$(eval $(call SetupVariable,OUTPUTDIR)) +$(eval $(call SetupVariable,OUTPUTDIR,$(TOPDIR)/build/run-test-prebuilt,MKDIR)) $(eval $(call SetupVariable,BOOT_JDK)) $(eval $(call SetupVariable,JT_HOME)) # These can have default values based on the ones above $(eval $(call SetupVariable,JDK_IMAGE_DIR,$(OUTPUTDIR)/images/jdk)) $(eval $(call SetupVariable,TEST_IMAGE_DIR,$(OUTPUTDIR)/images/test)) -$(eval $(call SetupVariable,SYMBOLS_IMAGE_DIR,$(OUTPUTDIR)/images/symbols)) +$(eval $(call SetupVariable,SYMBOLS_IMAGE_DIR,$(OUTPUTDIR)/images/symbols,NO_CHECK)) # Provide default values for tools that we need $(eval $(call SetupVariable,MAKE,make,NO_CHECK)) @@ -202,8 +210,8 @@ endif ifeq ($(OPENJDK_TARGET_OS), windows) ifeq ($(wildcard $(TEST_IMAGE_DIR)/bin/fixpath.exe), ) - $$(info Error: fixpath is missing from test image '$(TEST_IMAGE_DIR)') - $$(error Cannot continue.) + $(info Error: fixpath is missing from test image '$(TEST_IMAGE_DIR)') + $(error Cannot continue.) endif FIXPATH := $(TEST_IMAGE_DIR)/bin/fixpath.exe -c PATH_SEP:=; @@ -214,27 +222,32 @@ endif # Check number of cores and memory in MB ifeq ($(OPENJDK_TARGET_OS), linux) - NUM_CORES := $(shell $(CAT) /proc/cpuinfo | $(GREP) -c processor) - MEMORY_SIZE := $(shell \ + NUM_CORES := $(shell $(CAT) /proc/cpuinfo | $(GREP) -c processor) + MEMORY_SIZE := $(shell \ $(EXPR) `$(CAT) /proc/meminfo | $(GREP) MemTotal | $(AWK) '{print $$2}'` / 1024 \ - ) + ) else ifeq ($(OPENJDK_TARGET_OS), macosx) - NUM_CORES := $(shell /usr/sbin/sysctl -n hw.ncpu) - MEMORY_SIZE := $(shell $(EXPR) `/usr/sbin/sysctl -n hw.memsize` / 1024 / 1024) + NUM_CORES := $(shell /usr/sbin/sysctl -n hw.ncpu) + MEMORY_SIZE := $(shell $(EXPR) `/usr/sbin/sysctl -n hw.memsize` / 1024 / 1024) else ifeq ($(OPENJDK_TARGET_OS), solaris) - NUM_CORES := $(shell LC_MESSAGES=C /usr/sbin/psrinfo -v | $(GREP) -c on-line) - MEMORY_SIZE := $(shell \ + NUM_CORES := $(shell LC_MESSAGES=C /usr/sbin/psrinfo -v | $(GREP) -c on-line) + MEMORY_SIZE := $(shell \ /usr/sbin/prtconf 2> /dev/null | $(GREP) "^Memory [Ss]ize" | $(AWK) '{print $$3}' \ - ) + ) else ifeq ($(OPENJDK_TARGET_OS), windows) - NUM_CORES := $(NUMBER_OF_PROCESSORS) - MEMORY_SIZE := $(shell \ + NUM_CORES := $(NUMBER_OF_PROCESSORS) + MEMORY_SIZE := $(shell \ $(EXPR) `wmic computersystem get totalphysicalmemory -value | $(GREP) = \ | $(CUT) -d "=" -f 2-` / 1024 / 1024 \ - ) -else - NUM_CORES := 1 - MEMORY_SIZE := 1024 + ) +endif +ifeq ($(NUM_CORES), ) + $(warn Could not find number of CPUs, assuming 1) + NUM_CORES := 1 +endif +ifeq ($(MEMORY_SIZE), ) + $(warn Could not find memory size, assuming 1024 MB) + MEMORY_SIZE := 1024 endif ################################################################################ @@ -289,9 +302,6 @@ run-test-prebuilt: @$(RM) -f $(MAKESUPPORT_OUTPUTDIR)/exit-with-error @cd $(TOPDIR) && $(MAKE) $(MAKE_ARGS) -f make/RunTests.gmk run-test \ TEST="$(TEST)" - @if test -f $(MAKESUPPORT_OUTPUTDIR)/exit-with-error ; then \ - exit 1 ; \ - fi all: run-test-prebuilt diff --git a/make/RunTestsPrebuiltSpec.gmk b/make/RunTestsPrebuiltSpec.gmk index fd76562e7e1..8564a1f7ddd 100644 --- a/make/RunTestsPrebuiltSpec.gmk +++ b/make/RunTestsPrebuiltSpec.gmk @@ -124,7 +124,7 @@ JLINK := $(FIXPATH) $(JLINK_CMD) JMOD := $(FIXPATH) $(JMOD_CMD) JARSIGNER := $(FIXPATH) $(JARSIGNER_CMD) -BUILD_JAVA := $(JAVA) +BUILD_JAVA := $(JDK_IMAGE_DIR)/bin/JAVA ################################################################################ # Some common tools. Assume most common name and no path. AWK := awk @@ -172,3 +172,17 @@ UNZIP := unzip EXPR := expr FILE := file HG := hg + +# On Solaris gnu versions of some tools are required. +ifeq ($(OPENJDK_BUILD_OS), solaris) + AWK := gawk + GREP := ggrep + EGREP := ggrep -E + FGREP := grep -F + SED := gsed + TAR := gtar +endif + +ifeq ($(OPENJDK_BUILD_OS), windows) + CYGPATH := cygpath +endif diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4 index 1ffc437268e..5e2243c0a31 100644 --- a/make/autoconf/flags.m4 +++ b/make/autoconf/flags.m4 @@ -162,6 +162,10 @@ AC_DEFUN_ONCE([FLAGS_SETUP_USER_SUPPLIED_FLAGS], AC_MSG_WARN([Ignoring LDFLAGS($LDFLAGS) found in environment. Use --with-extra-ldflags]) fi + if test "x$ASFLAGS" != "x"; then + AC_MSG_WARN([Ignoring ASFLAGS($ASFLAGS) found in environment. Use --with-extra-asflags]) + fi + AC_ARG_WITH(extra-cflags, [AS_HELP_STRING([--with-extra-cflags], [extra flags to be used when compiling jdk c-files])]) @@ -171,9 +175,13 @@ AC_DEFUN_ONCE([FLAGS_SETUP_USER_SUPPLIED_FLAGS], AC_ARG_WITH(extra-ldflags, [AS_HELP_STRING([--with-extra-ldflags], [extra flags to be used when linking jdk])]) + AC_ARG_WITH(extra-asflags, [AS_HELP_STRING([--with-extra-asflags], + [extra flags to be passed to the assembler])]) + USER_CFLAGS="$with_extra_cflags" USER_CXXFLAGS="$with_extra_cxxflags" USER_LDFLAGS="$with_extra_ldflags" + USER_ASFLAGS="$with_extra_asflags" ]) # Setup the sysroot flags and add them to global CFLAGS and LDFLAGS so @@ -265,10 +273,12 @@ AC_DEFUN_ONCE([FLAGS_PRE_TOOLCHAIN], EXTRA_CFLAGS="$MACHINE_FLAG $USER_CFLAGS" EXTRA_CXXFLAGS="$MACHINE_FLAG $USER_CXXFLAGS" EXTRA_LDFLAGS="$MACHINE_FLAG $USER_LDFLAGS" + EXTRA_ASFLAGS="$USER_ASFLAGS" AC_SUBST(EXTRA_CFLAGS) AC_SUBST(EXTRA_CXXFLAGS) AC_SUBST(EXTRA_LDFLAGS) + AC_SUBST(EXTRA_ASFLAGS) # For autoconf testing to work, the global flags must also be stored in the # "unnamed" CFLAGS etc. diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index 390b9d6f412..a458e99a020 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -462,6 +462,7 @@ JVM_RCFLAGS := @JVM_RCFLAGS@ EXTRA_CFLAGS = @EXTRA_CFLAGS@ EXTRA_CXXFLAGS = @EXTRA_CXXFLAGS@ EXTRA_LDFLAGS = @EXTRA_LDFLAGS@ +EXTRA_ASFLAGS = @EXTRA_ASFLAGS@ CXX:=@FIXPATH@ @CCACHE@ @ICECC@ @CXX@ @@ -731,7 +732,7 @@ SETFILE:=@SETFILE@ XATTR:=@XATTR@ JT_HOME:=@JT_HOME@ JTREGEXE:=@JTREGEXE@ -JIB_JAR:=@JIB_JAR@ +JIB_HOME:=@JIB_HOME@ XCODEBUILD=@XCODEBUILD@ DTRACE := @DTRACE@ FIXPATH:=@FIXPATH@ diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 91fabcd4f49..a0b49a48057 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -1144,5 +1144,5 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_JIB], fi fi - AC_SUBST(JIB_JAR) + AC_SUBST(JIB_HOME) ]) diff --git a/make/autoconf/version-numbers b/make/autoconf/version-numbers index fec9997e75a..4a63f2dac0c 100644 --- a/make/autoconf/version-numbers +++ b/make/autoconf/version-numbers @@ -27,12 +27,12 @@ DEFAULT_VERSION_FEATURE=11 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=5 +DEFAULT_VERSION_UPDATE=6 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2019-10-15 +DEFAULT_VERSION_DATE=2020-01-14 DEFAULT_VERSION_CLASSFILE_MAJOR=55 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_ACCEPTABLE_BOOT_VERSIONS="10 11" diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk index d511836f097..170c3ed0da0 100644 --- a/make/common/MakeBase.gmk +++ b/make/common/MakeBase.gmk @@ -842,7 +842,7 @@ endef # Parameter 1 is the name of the rule, and is also the name of the variable. # # Remaining parameters are named arguments. These include: -# KEYWORDS A list of valid keywords +# SINGLE_KEYWORDS A list of valid keywords with single string values # STRING_KEYWORDS A list of valid keywords, processed as string. This means # that '%20' will be replaced by ' ' to allow for multi-word strings. # @@ -856,7 +856,7 @@ define ParseKeywordVariableBody $$(eval mangled_part_eval := $$(call DoubleDollar, $$(mangled_part))) \ $$(eval part := $$$$(subst ||||,$$$$(SPACE),$$$$(mangled_part_eval))) \ $$(eval $1_NO_MATCH := true) \ - $$(foreach keyword, $$($1_KEYWORDS), \ + $$(foreach keyword, $$($1_SINGLE_KEYWORDS), \ $$(eval keyword_eval := $$(call DoubleDollar, $$(keyword))) \ $$(if $$(filter $$(keyword)=%, $$(part)), \ $$(eval $(strip $1)_$$$$(keyword_eval) := $$$$(strip $$$$(patsubst $$$$(keyword_eval)=%, %, $$$$(part)))) \ @@ -871,11 +871,11 @@ define ParseKeywordVariableBody ) \ ) \ $$(if $$($1_NO_MATCH), \ - $$(if $$(filter $$(part), $$($1_KEYWORDS) $$($1_STRING_KEYWORDS)), \ + $$(if $$(filter $$(part), $$($1_SINGLE_KEYWORDS) $$($1_STRING_KEYWORDS)), \ $$(info Keyword $$(part) for $1 needs to be assigned a value.) \ , \ $$(info $$(part) is not a valid keyword for $1.) \ - $$(info Valid keywords: $$($1_KEYWORDS) $$($1_STRING_KEYWORDS).) \ + $$(info Valid keywords: $$($1_SINGLE_KEYWORDS) $$($1_STRING_KEYWORDS).) \ ) \ $$(error Cannot continue) \ ) \ diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 20a92a1b923..04d5d70df87 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -747,16 +747,15 @@ var getJibProfilesProfiles = function (input, common, data) { "run-test-prebuilt": { target_os: input.build_os, target_cpu: input.build_cpu, - src: "src.conf", dependencies: [ "jtreg", "gnumake", "boot_jdk", "jib", testedProfile + ".jdk", - testedProfile + ".test", "src.full" + testedProfile + ".test" ], - work_dir: input.get("src.full", "install_path") + "/test", + src: "src.conf", + make_args: [ "run-test-prebuilt", "LOG_CMDLINES=true" ], environment: { - "JT_JAVA": common.boot_jdk_home, - "PRODUCT_HOME": input.get(testedProfile + ".jdk", "home_path"), - "TEST_IMAGE_DIR": input.get(testedProfile + ".test", "home_path"), - "TEST_OUTPUT_DIR": input.src_top_dir + "BOOT_JDK": common.boot_jdk_home, + "JDK_IMAGE_DIR": input.get(testedProfile + ".jdk", "home_path"), + "TEST_IMAGE_DIR": input.get(testedProfile + ".test", "home_path") }, labels: "test" } @@ -794,13 +793,34 @@ var getJibProfilesProfiles = function (input, common, data) { windowsRunTestPrebuiltExtra = { dependencies: [ testedProfile + ".jdk_symbols" ], environment: { - "PRODUCT_SYMBOLS_HOME": input.get(testedProfile + ".jdk_symbols", "home_path"), + "SYMBOLS_IMAGE_DIR": input.get(testedProfile + ".jdk_symbols", "home_path"), } }; profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"], windowsRunTestPrebuiltExtra); } + // The profile run-test-prebuilt defines src.conf as the src bundle. When + // running in Mach 5, this reduces the time it takes to populate the + // considerably. But with just src.conf, we cannot actually run any tests, + // so if running from a workspace with just src.conf in it, we need to also + // get src.full as a dependency, and define the work_dir (where make gets + // run) to be in the src.full install path. By running in the install path, + // the same cached installation of the full src can be reused for multiple + // test tasks. Care must however be taken not to polute that work dir by + // setting the appropriate make variables to control output directories. + // + // Use the existance of the top level README as indication of if this is + // the full source or just src.conf. + if (!new java.io.File(__DIR__, "../../README").exists()) { + var runTestPrebuiltSrcFullExtra = { + dependencies: "src.full", + work_dir: input.get("src.full", "install_path"), + } + profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"], + runTestPrebuiltSrcFullExtra); + } + // Generate the missing platform attributes profiles = generatePlatformAttributes(profiles); profiles = generateDefaultMakeTargetsConfigureArg(common, profiles); @@ -827,7 +847,7 @@ var getJibProfilesDependencies = function (input, common) { : "gcc7.3.0-Fedora27+1.0"), linux_arm: (input.profile != null && input.profile.indexOf("hflt") >= 0 ? "gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux+1.0" - : (input.profile.indexOf("arm32") >= 0 + : (input.profile != null && input.profile.indexOf("arm32") >= 0 ? "gcc7.3.0-Fedora27+1.0" : "arm-linaro-4.7+1.0" ) @@ -941,9 +961,9 @@ var getJibProfilesDependencies = function (input, common) { ext: "zip", classifier: "distribution", revision: "3.0-SNAPSHOT", - environment_name: "JIB_JAR", + environment_name: "JIB_HOME", environment_value: input.get("jib", "install_path") - + "/jib-3.0-SNAPSHOT-distribution/lib/jib-3.0-SNAPSHOT.jar" + + "/jib-3.0-SNAPSHOT-distribution" }, ant: { diff --git a/make/hotspot/gensrc/GensrcDtrace.gmk b/make/hotspot/gensrc/GensrcDtrace.gmk index 3a013c71808..9b279e8200c 100644 --- a/make/hotspot/gensrc/GensrcDtrace.gmk +++ b/make/hotspot/gensrc/GensrcDtrace.gmk @@ -64,8 +64,9 @@ ifeq ($(call check-jvm-feature, dtrace), true) include lib/JvmFeatures.gmk include lib/JvmFlags.gmk - # We cannot compile until the JVMTI gensrc has finished + # We cannot compile until the JVMTI and JFR gensrc has finished JVMTI_H := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.h + JFR_FILES := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jfrfiles/jfrEventClasses.hpp $(eval $(call SetupNativeCompilation, BUILD_DTRACE_GEN_OFFSETS, \ NAME := dtraceGenOffsets, \ @@ -74,7 +75,7 @@ ifeq ($(call check-jvm-feature, dtrace), true) TOOLCHAIN := $(TOOLCHAIN_BUILD), \ LDFLAGS := -m64, \ CFLAGS := -m64 $(JVM_CFLAGS), \ - EXTRA_DEPS := $(JVMTI_H), \ + EXTRA_DEPS := $(JVMTI_H) $(JFR_FILES), \ OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \ OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \ )) diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index a4b67f09fd5..297c106b71c 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -47,6 +47,8 @@ JVM_LDFLAGS += \ $(EXTRA_LDFLAGS) \ # +JVM_ASFLAGS += $(EXTRA_ASFLAGS) + JVM_LIBS += \ $(JVM_LIBS_FEATURES) \ # diff --git a/make/launcher/Launcher-jdk.jfr.gmk b/make/launcher/Launcher-jdk.jfr.gmk new file mode 100644 index 00000000000..f2d504ac373 --- /dev/null +++ b/make/launcher/Launcher-jdk.jfr.gmk @@ -0,0 +1,31 @@ +# +# 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. +# + +include LauncherCommon.gmk + +$(eval $(call SetupBuildLauncher, jfr, \ + MAIN_CLASS := jdk.jfr.internal.tool.Main, \ + CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \ +)) diff --git a/make/lib/Lib-jdk.jdwp.agent.gmk b/make/lib/Lib-jdk.jdwp.agent.gmk index 0bc93e0d352..f00f0760fb6 100644 --- a/make/lib/Lib-jdk.jdwp.agent.gmk +++ b/make/lib/Lib-jdk.jdwp.agent.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJDWP, \ LIBS_solaris := $(LIBDL), \ LIBS_macosx := -liconv, \ LIBS_aix := -liconv, \ + LIBS_windows := $(WIN_JAVA_LIB), \ )) $(BUILD_LIBJDWP): $(call FindLib, java.base, java) diff --git a/src/hotspot/os/windows/include/jvm_md.h b/src/hotspot/os/windows/include/jvm_md.h index e047137c783..4baba320855 100644 --- a/src/hotspot/os/windows/include/jvm_md.h +++ b/src/hotspot/os/windows/include/jvm_md.h @@ -63,7 +63,7 @@ typedef struct { #include /* For uintptr_t */ #include -#define JVM_MAXPATHLEN _MAX_PATH +#define JVM_MAXPATHLEN 1024 #define JVM_R_OK 4 #define JVM_W_OK 2 diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java b/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java index c154ff56476..cfd83963b2b 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -79,10 +79,26 @@ List getMountEntries(String fstab) { ArrayList entries = new ArrayList<>(); try { long fp = setmntent(Util.toBytes(fstab), Util.toBytes("r")); + int maxLineSize = 1024; + try { + for (;;) { + int lineSize = getlinelen(fp); + if (lineSize == -1) + break; + if (lineSize > maxLineSize) + maxLineSize = lineSize; + } + } catch (UnixException x) { + // nothing we need to do + } finally { + rewind(fp); + } + try { for (;;) { UnixMountEntry entry = new UnixMountEntry(); - int res = getmntent(fp, entry); + // count in NUL character at the end + int res = getmntent(fp, entry, maxLineSize + 1); if (res < 0) break; entries.add(entry); diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxNativeDispatcher.java b/src/java.base/linux/classes/sun/nio/fs/LinuxNativeDispatcher.java index 5dbb331631f..1fa359b3f06 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxNativeDispatcher.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxNativeDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -54,7 +54,17 @@ private static native long setmntent0(long pathAddress, long typeAddress) /** * int getmntent(FILE *fp, struct mnttab *mp, int len); */ - static native int getmntent(long fp, UnixMountEntry entry) + + static int getmntent(long fp, UnixMountEntry entry, int buflen) throws UnixException { + NativeBuffer buffer = NativeBuffers.getNativeBuffer(buflen); + try { + return getmntent0(fp, entry, buffer.address(), buflen); + } finally { + buffer.release(); + } + } + + static native int getmntent0(long fp, UnixMountEntry entry, long buffer, int bufLen) throws UnixException; /** diff --git a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c index c8500db5c87..48df9b7c197 100644 --- a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c +++ b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -169,12 +169,11 @@ Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong } JNIEXPORT jint JNICALL -Java_sun_nio_fs_LinuxNativeDispatcher_getmntent(JNIEnv* env, jclass this, - jlong value, jobject entry) +Java_sun_nio_fs_LinuxNativeDispatcher_getmntent0(JNIEnv* env, jclass this, + jlong value, jobject entry, jlong buffer, jint bufLen) { struct mntent ent; - char buf[1024]; - int buflen = sizeof(buf); + char * buf = (char*)jlong_to_ptr(buffer); struct mntent* m; FILE* fp = jlong_to_ptr(value); jsize len; @@ -184,7 +183,7 @@ Java_sun_nio_fs_LinuxNativeDispatcher_getmntent(JNIEnv* env, jclass this, char* fstype; char* options; - m = getmntent_r(fp, &ent, (char*)&buf, buflen); + m = getmntent_r(fp, &ent, buf, (int)bufLen); if (m == NULL) return -1; name = m->mnt_fsname; diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m index c9ddeefe3e6..6c35dbf2b10 100644 --- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m +++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m @@ -581,13 +581,15 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore) cssmPerror("_addItemToKeychain: SecKeychainItemImport", err); } - (*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT); - if (createdItems != NULL) { CFRelease(createdItems); } errOut: + if (rawData) { + (*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT); + } + if (passwordStrRef) CFRelease(passwordStrRef); if (passwordChars) { // clear the password and release diff --git a/src/java.base/share/classes/java/io/BufferedReader.java b/src/java.base/share/classes/java/io/BufferedReader.java index 8cb4f73e597..9e909734d16 100644 --- a/src/java.base/share/classes/java/io/BufferedReader.java +++ b/src/java.base/share/classes/java/io/BufferedReader.java @@ -312,7 +312,7 @@ public int read(char cbuf[], int off, int len) throws IOException { * @exception IOException If an I/O error occurs */ String readLine(boolean ignoreLF) throws IOException { - StringBuffer s = null; + StringBuilder s = null; int startChar; synchronized (lock) { @@ -368,7 +368,7 @@ String readLine(boolean ignoreLF) throws IOException { } if (s == null) - s = new StringBuffer(defaultExpectedLineLength); + s = new StringBuilder(defaultExpectedLineLength); s.append(cb, startChar, i - startChar); } } diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index 6bf3fe708aa..617082896d6 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -182,11 +182,13 @@ private static enum PathStatus { INVALID, CHECKED }; * @return true if the file path is invalid. */ final boolean isInvalid() { - if (status == null) { - status = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKED - : PathStatus.INVALID; + PathStatus s = status; + if (s == null) { + s = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKED + : PathStatus.INVALID; + status = s; } - return status == PathStatus.INVALID; + return s == PathStatus.INVALID; } /** diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 959a434e969..43cd0f3e6a4 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -997,7 +997,8 @@ public static Integer valueOf(String s) throws NumberFormatException { private static class IntegerCache { static final int low = -128; static final int high; - static final Integer cache[]; + static final Integer[] cache; + static Integer[] archivedCache; static { // high value may be configured by property @@ -1016,11 +1017,19 @@ private static class IntegerCache { } high = h; - cache = new Integer[(high - low) + 1]; - int j = low; - for(int k = 0; k < cache.length; k++) - cache[k] = new Integer(j++); - + // Load IntegerCache.archivedCache from archive, if possible + VM.initializeFromArchive(IntegerCache.class); + int size = (high - low) + 1; + + // Use the archived cache if it exists and is large enough + if (archivedCache == null || size > archivedCache.length) { + Integer[] c = new Integer[size]; + int j = low; + for(int k = 0; k < c.length; k++) + c[k] = new Integer(j++); + archivedCache = c; + } + cache = archivedCache; // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java index 2f942816ab5..6d474b1ad5c 100644 --- a/src/java.base/share/classes/java/lang/Module.java +++ b/src/java.base/share/classes/java/lang/Module.java @@ -40,7 +40,6 @@ import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -1123,7 +1122,7 @@ static Map defineModules(Configuration cf, Set reads = new HashSet<>(); // name -> source Module when in parent layer - Map nameToSource = Collections.emptyMap(); + Map nameToSource = Map.of(); for (ResolvedModule other : resolvedModule.reads()) { Module m2 = null; diff --git a/src/java.base/share/classes/java/lang/ModuleLayer.java b/src/java.base/share/classes/java/lang/ModuleLayer.java index f4ea6553e52..213358712db 100644 --- a/src/java.base/share/classes/java/lang/ModuleLayer.java +++ b/src/java.base/share/classes/java/lang/ModuleLayer.java @@ -173,7 +173,7 @@ private ModuleLayer(Configuration cf, Map map; if (parents.isEmpty()) { - map = Collections.emptyMap(); + map = Map.of(); } else { map = Module.defineModules(cf, clf, this); } @@ -811,8 +811,7 @@ Stream layers() { public Set modules() { Set modules = this.modules; if (modules == null) { - this.modules = modules = - Collections.unmodifiableSet(new HashSet<>(nameToModule.values())); + this.modules = modules = Set.copyOf(nameToModule.values()); } return modules; } diff --git a/src/java.base/share/classes/java/lang/StackFrameInfo.java b/src/java.base/share/classes/java/lang/StackFrameInfo.java index 10a6989d3c7..6ebcf9735b3 100644 --- a/src/java.base/share/classes/java/lang/StackFrameInfo.java +++ b/src/java.base/share/classes/java/lang/StackFrameInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -32,23 +32,23 @@ import java.lang.invoke.MethodType; class StackFrameInfo implements StackFrame { - private final byte RETAIN_CLASS_REF = 0x01; - private final static JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess(); - private final byte flags; - private final Object memberName; - private final short bci; + private final boolean retainClassRef; + private final Object memberName; // MemberName initialized by VM + private int bci; // initialized by VM to >= 0 private volatile StackTraceElement ste; /* - * Create StackFrameInfo for StackFrameTraverser and LiveStackFrameTraverser - * to use + * Construct an empty StackFrameInfo object that will be filled by the VM + * during stack walking. + * + * @see StackStreamFactory.AbstractStackWalker#callStackWalk + * @see StackStreamFactory.AbstractStackWalker#fetchStackFrames */ StackFrameInfo(StackWalker walker) { - this.flags = walker.retainClassRef ? RETAIN_CLASS_REF : 0; - this.bci = -1; + this.retainClassRef = walker.retainClassRef; this.memberName = JLIA.newMemberName(); } @@ -136,7 +136,7 @@ public StackTraceElement toStackTraceElement() { } private void ensureRetainClassRefEnabled() { - if ((flags & RETAIN_CLASS_REF) == 0) { + if (!retainClassRef) { throw new UnsupportedOperationException("No access to RETAIN_CLASS_REFERENCE"); } } diff --git a/src/java.base/share/classes/java/lang/module/Configuration.java b/src/java.base/share/classes/java/lang/module/Configuration.java index 24bf3349b85..288c12cb5f9 100644 --- a/src/java.base/share/classes/java/lang/module/Configuration.java +++ b/src/java.base/share/classes/java/lang/module/Configuration.java @@ -31,7 +31,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Deque; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -42,8 +41,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.internal.misc.VM; import jdk.internal.module.ModuleReferenceImpl; import jdk.internal.module.ModuleTarget; +import jdk.internal.vm.annotation.Stable; /** * A configuration that is the result of @@ -104,7 +105,17 @@ public final class Configuration { // @see Configuration#empty() - private static final Configuration EMPTY_CONFIGURATION = new Configuration(); + // EMPTY_CONFIGURATION may be initialized from the CDS archive. + private static @Stable Configuration EMPTY_CONFIGURATION; + + static { + // Initialize EMPTY_CONFIGURATION from the archive. + VM.initializeFromArchive(Configuration.class); + // Create a new empty Configuration if there is no archived version. + if (EMPTY_CONFIGURATION == null) { + EMPTY_CONFIGURATION = new Configuration(); + } + } // parent configurations, in search order private final List parents; @@ -119,10 +130,10 @@ public final class Configuration { String targetPlatform() { return targetPlatform; } private Configuration() { - this.parents = Collections.emptyList(); - this.graph = Collections.emptyMap(); - this.modules = Collections.emptySet(); - this.nameToModule = Collections.emptyMap(); + this.parents = List.of(); + this.graph = Map.of(); + this.modules = Set.of(); + this.nameToModule = Map.of(); this.targetPlatform = null; } @@ -140,7 +151,7 @@ private Configuration(List parents, Resolver resolver) { i++; } - this.parents = Collections.unmodifiableList(parents); + this.parents = List.copyOf(parents); this.graph = g; this.modules = Set.of(moduleArray); this.nameToModule = Map.ofEntries(nameEntries); @@ -554,7 +565,7 @@ public Optional findModule(String name) { Set descriptors() { if (modules.isEmpty()) { - return Collections.emptySet(); + return Set.of(); } else { return modules.stream() .map(ResolvedModule::reference) @@ -596,7 +607,7 @@ Stream configurations() { } } } - this.allConfigurations = Collections.unmodifiableList(allConfigurations); + this.allConfigurations = allConfigurations; // no need to do defensive copy } return allConfigurations.stream(); } diff --git a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java index cb578423cba..fa359348f6c 100644 --- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java +++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -102,7 +102,7 @@ public class ModuleDescriptor * @since 9 * @spec JPMS */ - public static enum Modifier { + public enum Modifier { /** * An open module. An open module does not declare any open packages * but the resulting module is treated as if all packages are open. @@ -149,7 +149,7 @@ public final static class Requires * @since 9 * @spec JPMS */ - public static enum Modifier { + public enum Modifier { /** * The dependence causes any module which depends on the current @@ -185,12 +185,7 @@ public static enum Modifier { private Requires(Set ms, String mn, Version v, String vs) { assert v == null || vs == null; - if (ms.isEmpty()) { - ms = Collections.emptySet(); - } else { - ms = Collections.unmodifiableSet(EnumSet.copyOf(ms)); - } - this.mods = ms; + this.mods = Set.copyOf(ms); this.name = mn; this.compiledVersion = v; this.rawCompiledVersion = vs; @@ -384,7 +379,7 @@ public final static class Exports * @since 9 * @spec JPMS */ - public static enum Modifier { + public enum Modifier { /** * The export was not explicitly or implicitly declared in the @@ -408,14 +403,9 @@ public static enum Modifier { * Constructs an export */ private Exports(Set ms, String source, Set targets) { - if (ms.isEmpty()) { - ms = Collections.emptySet(); - } else { - ms = Collections.unmodifiableSet(EnumSet.copyOf(ms)); - } - this.mods = ms; + this.mods = Set.copyOf(ms); this.source = source; - this.targets = emptyOrUnmodifiableSet(targets); + this.targets = Set.copyOf(targets); } private Exports(Set ms, @@ -596,7 +586,7 @@ public final static class Opens * @since 9 * @spec JPMS */ - public static enum Modifier { + public enum Modifier { /** * The open package was not explicitly or implicitly declared in @@ -620,14 +610,9 @@ public static enum Modifier { * Constructs an Opens */ private Opens(Set ms, String source, Set targets) { - if (ms.isEmpty()) { - ms = Collections.emptySet(); - } else { - ms = Collections.unmodifiableSet(EnumSet.copyOf(ms)); - } - this.mods = ms; + this.mods = Set.copyOf(ms); this.source = source; - this.targets = emptyOrUnmodifiableSet(targets); + this.targets = Set.copyOf(targets); } private Opens(Set ms, @@ -800,7 +785,7 @@ public final static class Provides private Provides(String service, List providers) { this.service = service; - this.providers = Collections.unmodifiableList(providers); + this.providers = List.copyOf(providers); } private Provides(String service, List providers, boolean unused) { @@ -1264,18 +1249,18 @@ private ModuleDescriptor(String name, this.name = name; this.version = version; this.rawVersionString = rawVersionString; - this.modifiers = emptyOrUnmodifiableSet(modifiers); + this.modifiers = Set.copyOf(modifiers); this.open = modifiers.contains(Modifier.OPEN); this.automatic = modifiers.contains(Modifier.AUTOMATIC); assert (requires.stream().map(Requires::name).distinct().count() == requires.size()); - this.requires = emptyOrUnmodifiableSet(requires); - this.exports = emptyOrUnmodifiableSet(exports); - this.opens = emptyOrUnmodifiableSet(opens); - this.uses = emptyOrUnmodifiableSet(uses); - this.provides = emptyOrUnmodifiableSet(provides); + this.requires = Set.copyOf(requires); + this.exports = Set.copyOf(exports); + this.opens = Set.copyOf(opens); + this.uses = Set.copyOf(uses); + this.provides = Set.copyOf(provides); - this.packages = emptyOrUnmodifiableSet(packages); + this.packages = Set.copyOf(packages); this.mainClass = mainClass; } @@ -1734,16 +1719,14 @@ public Builder exports(Set ms, String pn, Set targets) { - Exports e = new Exports(ms, pn, targets); - - // check targets - targets = e.targets(); + targets = new HashSet<>(targets); if (targets.isEmpty()) throw new IllegalArgumentException("Empty target set"); if (strict) { - requirePackageName(e.source()); + requirePackageName(pn); targets.forEach(Checks::requireModuleName); } + Exports e = new Exports(ms, pn, targets); return exports(e); } @@ -1769,7 +1752,7 @@ public Builder exports(Set ms, String pn) { if (strict) { requirePackageName(pn); } - Exports e = new Exports(ms, pn, Collections.emptySet()); + Exports e = new Exports(ms, pn, Set.of()); return exports(e); } @@ -1794,7 +1777,7 @@ public Builder exports(Set ms, String pn) { * or this builder is for an automatic module */ public Builder exports(String pn, Set targets) { - return exports(Collections.emptySet(), pn, targets); + return exports(Set.of(), pn, targets); } /** @@ -1813,7 +1796,7 @@ public Builder exports(String pn, Set targets) { * or this builder is for an automatic module */ public Builder exports(String pn) { - return exports(Collections.emptySet(), pn); + return exports(Set.of(), pn); } /** @@ -1870,16 +1853,14 @@ public Builder opens(Set ms, String pn, Set targets) { - Opens opens = new Opens(ms, pn, targets); - - // check targets - targets = opens.targets(); + targets = new HashSet<>(targets); if (targets.isEmpty()) throw new IllegalArgumentException("Empty target set"); if (strict) { - requirePackageName(opens.source()); + requirePackageName(pn); targets.forEach(Checks::requireModuleName); } + Opens opens = new Opens(ms, pn, targets); return opens(opens); } @@ -1905,7 +1886,7 @@ public Builder opens(Set ms, String pn) { if (strict) { requirePackageName(pn); } - Opens e = new Opens(ms, pn, Collections.emptySet()); + Opens e = new Opens(ms, pn, Set.of()); return opens(e); } @@ -1929,7 +1910,7 @@ public Builder opens(Set ms, String pn) { * builder for an open module or automatic module */ public Builder opens(String pn, Set targets) { - return opens(Collections.emptySet(), pn, targets); + return opens(Set.of(), pn, targets); } /** @@ -1948,7 +1929,7 @@ public Builder opens(String pn, Set targets) { * builder for an open module or automatic module */ public Builder opens(String pn) { - return opens(Collections.emptySet(), pn); + return opens(Set.of(), pn); } /** @@ -2021,15 +2002,12 @@ public Builder provides(Provides p) { * declared */ public Builder provides(String service, List providers) { - Provides p = new Provides(service, providers); - - // check providers after the set has been copied. - List providerNames = p.providers(); - if (providerNames.isEmpty()) + providers = new ArrayList<>(providers); + if (providers.isEmpty()) throw new IllegalArgumentException("Empty providers set"); if (strict) { - requireServiceTypeName(p.service()); - providerNames.forEach(Checks::requireServiceProviderName); + requireServiceTypeName(service); + providers.forEach(Checks::requireServiceProviderName); } else { // Disallow service/providers in unnamed package String pn = packageName(service); @@ -2037,7 +2015,7 @@ public Builder provides(String service, List providers) { throw new IllegalArgumentException(service + ": unnamed package"); } - for (String name : providerNames) { + for (String name : providers) { pn = packageName(name); if (pn.isEmpty()) { throw new IllegalArgumentException(name @@ -2045,6 +2023,7 @@ public Builder provides(String service, List providers) { } } } + Provides p = new Provides(service, providers); return provides(p); } @@ -2574,27 +2553,6 @@ public static ModuleDescriptor read(ByteBuffer bb) { return ModuleInfo.read(bb, null).descriptor(); } - private static Map emptyOrUnmodifiableMap(Map map) { - if (map.isEmpty()) { - return Collections.emptyMap(); - } else if (map.size() == 1) { - Map.Entry entry = map.entrySet().iterator().next(); - return Collections.singletonMap(entry.getKey(), entry.getValue()); - } else { - return Collections.unmodifiableMap(map); - } - } - - private static Set emptyOrUnmodifiableSet(Set set) { - if (set.isEmpty()) { - return Collections.emptySet(); - } else if (set.size() == 1) { - return Collections.singleton(set.iterator().next()); - } else { - return Collections.unmodifiableSet(set); - } - } - private static String packageName(String cn) { int index = cn.lastIndexOf('.'); return (index == -1) ? "" : cn.substring(0, index); @@ -2674,7 +2632,7 @@ public Requires newRequires(Set ms, String mn, Version v) { @Override public Exports newExports(Set ms, String source) { - return new Exports(ms, source, Collections.emptySet(), true); + return new Exports(ms, source, Set.of(), true); } @Override @@ -2693,7 +2651,7 @@ public Opens newOpens(Set ms, @Override public Opens newOpens(Set ms, String source) { - return new Opens(ms, source, Collections.emptySet(), true); + return new Opens(ms, source, Set.of(), true); } @Override diff --git a/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/src/java.base/share/classes/java/lang/module/ModuleFinder.java index b85b2e179da..c556390aa88 100644 --- a/src/java.base/share/classes/java/lang/module/ModuleFinder.java +++ b/src/java.base/share/classes/java/lang/module/ModuleFinder.java @@ -306,7 +306,7 @@ public Optional find(String name) { @Override public Set findAll() { - return Collections.emptySet(); + return Set.of(); } }; } diff --git a/src/java.base/share/classes/java/util/EnumSet.java b/src/java.base/share/classes/java/util/EnumSet.java index 70da034a8b3..69da1680de6 100644 --- a/src/java.base/share/classes/java/util/EnumSet.java +++ b/src/java.base/share/classes/java/util/EnumSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -76,20 +76,26 @@ * @since 1.5 * @see EnumMap */ -@SuppressWarnings("serial") // No serialVersionUID due to usage of - // serial proxy pattern +@SuppressWarnings("serial") // No serialVersionUID declared public abstract class EnumSet> extends AbstractSet implements Cloneable, java.io.Serializable { + // The following must be present in order to preserve the same computed + // serialVersionUID value as JDK 8, and to prevent the appearance of + // the fields in the Serialized Form documentation. See JDK-8227368. + static Enum[] access$000() { return null; } + private static final java.io.ObjectStreamField[] serialPersistentFields + = new java.io.ObjectStreamField[0]; + /** * The class of all the elements of this set. */ - final transient Class elementType; + final Class elementType; /** * All of the values comprising E. (Cached for performance.) */ - final transient Enum[] universe; + final Enum[] universe; EnumSet(ClasselementType, Enum[] universe) { this.elementType = elementType; diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index 1b8c4acce71..0f11c741f0f 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -36,6 +36,7 @@ import java.util.function.Predicate; import java.util.function.UnaryOperator; import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.VM; import jdk.internal.vm.annotation.Stable; /** @@ -409,7 +410,15 @@ private Object writeReplace() { static final class ListN extends AbstractImmutableList implements Serializable { - static final List EMPTY_LIST = new ListN<>(); + // EMPTY_LIST may be initialized from the CDS archive. + static @Stable List EMPTY_LIST; + + static { + VM.initializeFromArchive(ListN.class); + if (EMPTY_LIST == null) { + EMPTY_LIST = new ListN<>(); + } + } @Stable private final E[] elements; @@ -567,7 +576,15 @@ private Object writeReplace() { static final class SetN extends AbstractImmutableSet implements Serializable { - static final Set EMPTY_SET = new SetN<>(); + // EMPTY_SET may be initialized from the CDS archive. + static @Stable Set EMPTY_SET; + + static { + VM.initializeFromArchive(SetN.class); + if (EMPTY_SET == null) { + EMPTY_SET = new SetN<>(); + } + } @Stable final E[] elements; @@ -777,7 +794,15 @@ public int hashCode() { */ static final class MapN extends AbstractImmutableMap { - static final Map EMPTY_MAP = new MapN<>(); + // EMPTY_MAP may be initialized from the CDS archive. + static @Stable Map EMPTY_MAP; + + static { + VM.initializeFromArchive(MapN.class); + if (EMPTY_MAP == null) { + EMPTY_MAP = new MapN<>(); + } + } @Stable final Object[] table; // pairs of key, value diff --git a/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java b/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java index 35b4d09718b..e433d85c5b7 100644 --- a/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java +++ b/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java @@ -25,6 +25,7 @@ package jdk.internal.module; +import java.lang.module.Configuration; import java.lang.module.ModuleFinder; import java.util.Objects; import jdk.internal.misc.VM; @@ -36,13 +37,18 @@ final class ArchivedModuleGraph { private static String archivedMainModule; private static SystemModules archivedSystemModules; private static ModuleFinder archivedModuleFinder; + private static Configuration archivedConfiguration; private final SystemModules systemModules; private final ModuleFinder finder; + private final Configuration configuration; - private ArchivedModuleGraph(SystemModules modules, ModuleFinder finder) { + private ArchivedModuleGraph(SystemModules modules, + ModuleFinder finder, + Configuration configuration) { this.systemModules = modules; this.finder = finder; + this.configuration = configuration; } SystemModules systemModules() { @@ -53,27 +59,36 @@ ModuleFinder finder() { return finder; } + Configuration configuration() { + return configuration; + } + // A factory method that ModuleBootstrap can use to obtain the // ArchivedModuleGraph. static ArchivedModuleGraph get(String mainModule) { if (Objects.equals(mainModule, archivedMainModule) && archivedSystemModules != null - && archivedModuleFinder != null) { + && archivedModuleFinder != null + && archivedConfiguration != null) { return new ArchivedModuleGraph(archivedSystemModules, - archivedModuleFinder); + archivedModuleFinder, + archivedConfiguration); } else { return null; } } // Used at CDS dump time - static void archive(String mainModule, SystemModules systemModules, - ModuleFinder finder) { + static void archive(String mainModule, + SystemModules systemModules, + ModuleFinder finder, + Configuration configuration) { if (archivedMainModule != null) throw new UnsupportedOperationException(); archivedMainModule = mainModule; archivedSystemModules = systemModules; archivedModuleFinder = finder; + archivedConfiguration = configuration; } static { diff --git a/src/java.base/share/classes/jdk/internal/module/Builder.java b/src/java.base/share/classes/jdk/internal/module/Builder.java index 2792ccca19f..fa6fe24ba2f 100644 --- a/src/java.base/share/classes/jdk/internal/module/Builder.java +++ b/src/java.base/share/classes/jdk/internal/module/Builder.java @@ -30,7 +30,6 @@ import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Version; -import java.util.Collections; import java.util.List; import java.util.Set; @@ -148,11 +147,11 @@ public static Provides newProvides(String st, List pcs) { Builder(String name) { this.name = name; - this.requires = Collections.emptySet(); - this.exports = Collections.emptySet(); - this.opens = Collections.emptySet(); - this.provides = Collections.emptySet(); - this.uses = Collections.emptySet(); + this.requires = Set.of(); + this.exports = Set.of(); + this.opens = Set.of(); + this.provides = Set.of(); + this.uses = Set.of(); } Builder open(boolean value) { @@ -253,7 +252,7 @@ private Set modifiers() { if (synthetic) n++; if (mandated) n++; if (n == 0) { - return Collections.emptySet(); + return Set.of(); } else { ModuleDescriptor.Modifier[] mods = new ModuleDescriptor.Modifier[n]; if (open) mods[--n] = ModuleDescriptor.Modifier.OPEN; diff --git a/src/java.base/share/classes/jdk/internal/module/ExplodedSystemModules.java b/src/java.base/share/classes/jdk/internal/module/ExplodedSystemModules.java index b424b9c0ec1..5f241913e70 100644 --- a/src/java.base/share/classes/jdk/internal/module/ExplodedSystemModules.java +++ b/src/java.base/share/classes/jdk/internal/module/ExplodedSystemModules.java @@ -26,7 +26,6 @@ package jdk.internal.module; import java.lang.module.ModuleDescriptor; -import java.util.Collections; import java.util.Map; import java.util.Set; @@ -72,11 +71,11 @@ public Map> moduleReads() { @Override public Map> concealedPackagesToOpen() { - return Collections.emptyMap(); + return Map.of(); } @Override public Map> exportedPackagesToOpen() { - return Collections.emptyMap(); + return Map.of(); } } diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index 9534bc3cfc2..fa8594663da 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -178,6 +178,7 @@ public static ModuleLayer boot() throws Exception { boolean haveModulePath = (appModulePath != null || upgradeModulePath != null); boolean needResolution = true; + boolean canArchive = false; // If the java heap was archived at CDS dump time and the environment // at dump time matches the current environment then use the archived @@ -192,7 +193,6 @@ public static ModuleLayer boot() throws Exception { systemModuleFinder = archivedModuleGraph.finder(); needResolution = (traceOutput != null); } else { - boolean canArchive = false; if (!haveModulePath && addModules.isEmpty() && limitModules.isEmpty()) { systemModules = SystemModuleFinders.systemModules(mainModule); if (systemModules != null && !isPatched) { @@ -212,12 +212,6 @@ public static ModuleLayer boot() throws Exception { systemModules = new ExplodedSystemModules(); systemModuleFinder = SystemModuleFinders.ofSystem(); } - - // Module graph can be archived at CDS dump time. Only allow the - // unnamed module case for now. - if (canArchive && (mainModule == null)) { - ArchivedModuleGraph.archive(mainModule, systemModules, systemModuleFinder); - } } Counters.add("jdk.module.boot.1.systemModulesTime", t1); @@ -359,8 +353,12 @@ public static ModuleLayer boot() throws Exception { if (needResolution) { cf = JLMA.resolveAndBind(finder, roots, traceOutput); } else { - Map> map = systemModules.moduleReads(); - cf = JLMA.newConfiguration(systemModuleFinder, map); + if (archivedModuleGraph != null) { + cf = archivedModuleGraph.configuration(); + } else { + Map> map = systemModules.moduleReads(); + cf = JLMA.newConfiguration(systemModuleFinder, map); + } } // check that modules specified to --patch-module are resolved @@ -373,6 +371,7 @@ public static ModuleLayer boot() throws Exception { Counters.add("jdk.module.boot.4.resolveTime", t4); + // Step 5: Map the modules in the configuration to class loaders. // The static configuration provides the mapping of standard and JDK // modules to the boot and platform loaders. All other modules (JDK @@ -446,6 +445,13 @@ public static ModuleLayer boot() throws Exception { ((BuiltinClassLoader)platformLoader).initializeSharedClassesSupport(); //OpenJ9-shared_classes_misc ((BuiltinClassLoader)appLoader).initializeSharedClassesSupport(); //OpenJ9-shared_classes_misc + // Module graph can be archived at CDS dump time. Only allow the + // unnamed module case for now. + if (canArchive && (mainModule == null)) { + ArchivedModuleGraph.archive(mainModule, systemModules, + systemModuleFinder, cf); + } + // total time to initialize Counters.add("jdk.module.boot.totalTime", t0); Counters.publish(); @@ -578,7 +584,7 @@ private static Set addModules() { // the system property is removed after decoding String value = getAndRemoveProperty(prefix + index); if (value == null) { - return Collections.emptySet(); + return Set.of(); } else { Set modules = new HashSet<>(); while (value != null) { @@ -599,7 +605,7 @@ private static Set addModules() { private static Set limitModules() { String value = getAndRemoveProperty("jdk.module.limitmods"); if (value == null) { - return Collections.emptySet(); + return Set.of(); } else { Set names = new HashSet<>(); for (String name : value.split(",")) { @@ -851,7 +857,7 @@ private static Map> decode(String prefix, // the system property is removed after decoding String value = getAndRemoveProperty(prefix + index); if (value == null) - return Collections.emptyMap(); + return Map.of(); Map> map = new HashMap<>(); diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java b/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java index 230695206f0..33e5b33f963 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java @@ -40,7 +40,6 @@ import java.nio.ByteBuffer; import java.nio.BufferUnderflowException; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -374,7 +373,7 @@ private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major) int requires_flags = in.readUnsignedShort(); Set mods; if (requires_flags == 0) { - mods = Collections.emptySet(); + mods = Set.of(); } else { mods = new HashSet<>(); if ((requires_flags & ACC_TRANSITIVE) != 0) @@ -430,7 +429,7 @@ private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major) Set mods; int exports_flags = in.readUnsignedShort(); if (exports_flags == 0) { - mods = Collections.emptySet(); + mods = Set.of(); } else { mods = new HashSet<>(); if ((exports_flags & ACC_SYNTHETIC) != 0) @@ -470,7 +469,7 @@ private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major) Set mods; int opens_flags = in.readUnsignedShort(); if (opens_flags == 0) { - mods = Collections.emptySet(); + mods = Set.of(); } else { mods = new HashSet<>(); if ((opens_flags & ACC_SYNTHETIC) != 0) diff --git a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java index 8b50e12dec6..e37e5cf3437 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java +++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -42,7 +42,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -78,7 +77,7 @@ public final class ModulePatcher { */ public ModulePatcher(Map> input) { if (input.isEmpty()) { - this.map = Collections.emptyMap(); + this.map = Map.of(); } else { Map> map = new HashMap<>(); for (Map.Entry> e : input.entrySet()) { diff --git a/src/java.base/share/classes/jdk/internal/module/ModulePath.java b/src/java.base/share/classes/jdk/internal/module/ModulePath.java index 2e5918627b5..0718336093b 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModulePath.java +++ b/src/java.base/share/classes/jdk/internal/module/ModulePath.java @@ -45,7 +45,6 @@ import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -217,7 +216,7 @@ private Map scan(Path entry) { try { attrs = Files.readAttributes(entry, BasicFileAttributes.class); } catch (NoSuchFileException e) { - return Collections.emptyMap(); + return Map.of(); } catch (IOException ioe) { throw new FindException(ioe); } @@ -236,7 +235,7 @@ private Map scan(Path entry) { ModuleReference mref = readModule(entry, attrs); if (mref != null) { String name = mref.descriptor().name(); - return Collections.singletonMap(name, mref); + return Map.of(name, mref); } // not recognized diff --git a/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java b/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java index f0d7126adc8..9e39e5ee479 100644 --- a/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java +++ b/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java @@ -28,7 +28,6 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Provides; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -147,7 +146,7 @@ public void addProvider(Module module, Class service, Class impl) { * the given service type. */ public List findServices(String service) { - return map.getOrDefault(service, Collections.emptyList()); + return map.getOrDefault(service, List.of()); } /** @@ -175,4 +174,4 @@ public static ServicesCatalog getServicesCatalog(ClassLoader loader) { // the ServicesCatalog registered to a class loader private static final ClassLoaderValue CLV = new ClassLoaderValue<>(); -} \ No newline at end of file +} diff --git a/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java b/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java index 9ed3b54c01c..4775e719cd0 100644 --- a/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java +++ b/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java @@ -282,8 +282,8 @@ private static class SystemModuleFinder implements ModuleFinder { SystemModuleFinder(Set mrefs, Map nameToModule) { - this.mrefs = Collections.unmodifiableSet(mrefs); - this.nameToModule = Collections.unmodifiableMap(nameToModule); + this.mrefs = Set.copyOf(mrefs); + this.nameToModule = Map.copyOf(nameToModule); } @Override @@ -353,7 +353,7 @@ static Map generateNameToHash(ModuleHashes[] recordedHashes) { } } } - return (nameToHash != null) ? nameToHash : Collections.emptyMap(); + return (nameToHash != null) ? nameToHash : Map.of(); } /** diff --git a/src/java.base/share/classes/sun/security/jca/ProviderConfig.java b/src/java.base/share/classes/sun/security/jca/ProviderConfig.java index ffa06f51fb5..a07d6fea8b8 100644 --- a/src/java.base/share/classes/sun/security/jca/ProviderConfig.java +++ b/src/java.base/share/classes/sun/security/jca/ProviderConfig.java @@ -179,7 +179,11 @@ synchronized Provider getProvider() { } else if (provName.equals("SunJCE") || provName.equals("com.sun.crypto.provider.SunJCE")) { p = new com.sun.crypto.provider.SunJCE(); } else if (provName.equals("SunJSSE") || provName.equals("com.sun.net.ssl.internal.ssl.Provider")) { - p = new com.sun.net.ssl.internal.ssl.Provider(); + if (hasArgument()) { + p = new com.sun.net.ssl.internal.ssl.Provider(argument); + } else { + p = new com.sun.net.ssl.internal.ssl.Provider(); + } } else if (provName.equals("Apple") || provName.equals("apple.security.AppleProvider")) { // need to use reflection since this class only exists on MacOsx p = AccessController.doPrivileged(new PrivilegedAction() { diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHello.java b/src/java.base/share/classes/sun/security/ssl/ClientHello.java index 6fbac3103e5..53b74223bfb 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -519,7 +519,7 @@ public byte[] produce(ConnectionContext context) throws IOException { if (session != null && identityAlg != null) { String sessionIdentityAlg = session.getIdentificationProtocol(); - if (!Objects.equals(identityAlg, sessionIdentityAlg)) { + if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest("Can't resume, endpoint id" + @@ -1036,7 +1036,7 @@ public void consume(ConnectionContext context, if (resumingSession && identityAlg != null) { String sessionIdentityAlg = previous.getIdentificationProtocol(); - if (!Objects.equals(identityAlg, sessionIdentityAlg)) { + if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { SSLLogger.finest("Can't resume, endpoint id" + diff --git a/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java b/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java index 7e7731f27a8..9b485a5269f 100644 --- a/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java +++ b/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java @@ -518,10 +518,10 @@ static final class T12HandshakeHash implements TranscriptHash { JsseJce.getMessageDigest(cipherSuite.hashAlg.name); if (md instanceof Cloneable) { transcriptHash = new CloneableHash(md); - this.baos = null; + this.baos = new ByteArrayOutputStream(); } else { transcriptHash = new NonCloneableHash(md); - this.baos = new ByteArrayOutputStream(); + this.baos = null; } } @@ -550,26 +550,20 @@ public byte[] archived() { static final class T13HandshakeHash implements TranscriptHash { private final TranscriptHash transcriptHash; - private final ByteArrayOutputStream baos; T13HandshakeHash(CipherSuite cipherSuite) { MessageDigest md = JsseJce.getMessageDigest(cipherSuite.hashAlg.name); if (md instanceof Cloneable) { transcriptHash = new CloneableHash(md); - this.baos = null; } else { transcriptHash = new NonCloneableHash(md); - this.baos = new ByteArrayOutputStream(); } } @Override public void update(byte[] input, int offset, int length) { transcriptHash.update(input, offset, length); - if (baos != null) { - baos.write(input, offset, length); - } } @Override @@ -579,13 +573,9 @@ public byte[] digest() { @Override public byte[] archived() { - if (baos != null) { - return baos.toByteArray(); - } else { - return transcriptHash.archived(); - } - - // throw new UnsupportedOperationException("Not supported yet."); + // This method is not necessary in T13 + throw new UnsupportedOperationException( + "TLS 1.3 does not require archived."); } } diff --git a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java index de485e23d89..1f0a957e2f9 100644 --- a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -458,7 +458,7 @@ private static boolean canRejoin(ClientHelloMessage clientHello, String identityAlg = shc.sslConfig.identificationProtocol; if (result && identityAlg != null) { String sessionIdentityAlg = s.getIdentificationProtocol(); - if (!Objects.equals(identityAlg, sessionIdentityAlg)) { + if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index e4afe9e3ceb..dd261418787 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -474,6 +474,31 @@ networkaddress.cache.negative.ttl=10 # krb5.kdc.bad.policy = tryLast +# +# Kerberos cross-realm referrals (RFC 6806) +# +# OpenJDK's Kerberos client supports cross-realm referrals as defined in +# RFC 6806. This allows to setup more dynamic environments in which clients +# do not need to know in advance how to reach the realm of a target principal +# (either a user or service). +# +# When a client issues an AS or a TGS request, the "canonicalize" option +# is set to announce support of this feature. A KDC server may fulfill the +# request or reply referring the client to a different one. If referred, +# the client will issue a new request and the cycle repeats. +# +# In addition to referrals, the "canonicalize" option allows the KDC server +# to change the client name in response to an AS request. For security reasons, +# RFC 6806 (section 11) FAST scheme is enforced. +# +# Disable Kerberos cross-realm referrals. Value may be overwritten with a +# System property (-Dsun.security.krb5.disableReferrals). +sun.security.krb5.disableReferrals=false + +# Maximum number of AS or TGS referrals to avoid infinite loops. Value may +# be overwritten with a System property (-Dsun.security.krb5.maxReferrals). +sun.security.krb5.maxReferrals=5 + # # Algorithm restrictions for certification path (CertPath) processing # diff --git a/src/java.base/share/native/libzip/Deflater.c b/src/java.base/share/native/libzip/Deflater.c index 2a5791ec62d..78de361cba3 100644 --- a/src/java.base/share/native/libzip/Deflater.c +++ b/src/java.base/share/native/libzip/Deflater.c @@ -257,7 +257,7 @@ Java_java_util_zip_Deflater_deflateBufferBytes(JNIEnv *env, jobject this, jlong res = doDeflate(env, addr, input, inputLen, output + outputOff, outputLen, flush, params); - (*env)->ReleasePrimitiveArrayCritical(env, outputArray, input, 0); + (*env)->ReleasePrimitiveArrayCritical(env, outputArray, output, 0); retVal = checkDeflateStatus(env, addr, inputLen, outputLen, params, res); return retVal; diff --git a/src/java.base/share/native/libzip/zip_util.c b/src/java.base/share/native/libzip/zip_util.c index 76c40747bb2..f129e4548e5 100644 --- a/src/java.base/share/native/libzip/zip_util.c +++ b/src/java.base/share/native/libzip/zip_util.c @@ -100,6 +100,9 @@ DEF_STATIC_JNI_OnLoad static ZFILE ZFILE_Open(const char *fname, int flags) { #ifdef WIN32 + WCHAR *wfname, *wprefixed_fname; + size_t converted_chars, fname_length; + jlong fhandle; const DWORD access = (flags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) : (flags & O_WRONLY) ? GENERIC_WRITE : @@ -121,14 +124,37 @@ ZFILE_Open(const char *fname, int flags) { FILE_ATTRIBUTE_NORMAL; const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose; - return (jlong) CreateFile( - fname, /* Wide char path name */ - access, /* Read and/or write permission */ - sharing, /* File sharing flags */ - NULL, /* Security attributes */ - disposition, /* creation disposition */ - flagsAndAttributes, /* flags and attributes */ - NULL); + fname_length = strlen(fname); + if (fname_length < MAX_PATH) { + return (jlong)CreateFile( + fname, /* path name in multibyte char */ + access, /* Read and/or write permission */ + sharing, /* File sharing flags */ + NULL, /* Security attributes */ + disposition, /* creation disposition */ + flagsAndAttributes, /* flags and attributes */ + NULL); + } else { + if ((wfname = (WCHAR*)malloc((fname_length + 1) * sizeof(WCHAR))) == NULL) + return (jlong)INVALID_HANDLE_VALUE; + + if (mbstowcs_s(&converted_chars, wfname, fname_length + 1, fname, fname_length) != 0) { + free(wfname); + return (jlong)INVALID_HANDLE_VALUE; + } + wprefixed_fname = getPrefixed(wfname, (int)fname_length); + fhandle = (jlong)CreateFileW( + wprefixed_fname, /* Wide char path name */ + access, /* Read and/or write permission */ + sharing, /* File sharing flags */ + NULL, /* Security attributes */ + disposition, /* creation disposition */ + flagsAndAttributes, /* flags and attributes */ + NULL); + free(wfname); + free(wprefixed_fname); + return fhandle; + } #else return open(fname, flags, 0); #endif diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java index fe2d0f3f1a5..9f59063d357 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -121,6 +121,16 @@ private static native long fopen0(long pathAddress, long modeAddress) */ static native void fclose(long stream) throws UnixException; + /** + * void rewind(FILE* stream); + */ + static native void rewind(long stream) throws UnixException; + + /** + * ssize_t getline(char **lineptr, size_t *n, FILE *stream); + */ + static native int getlinelen(long stream) throws UnixException; + /** * link(const char* existing, const char* new) */ diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c index ed93bd1ff11..cfa3864ba73 100644 --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -238,6 +238,7 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0 ifs = enumInterfaces(env); if (ifs == NULL) { + (*env)->ReleaseStringUTFChars(env, name, name_utf); return NULL; } diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 472de82490b..aa6ff9b1061 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, 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 @@ -390,6 +390,51 @@ Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stre } } +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_rewind(JNIEnv* env, jclass this, jlong stream) +{ + FILE* fp = jlong_to_ptr(stream); + int saved_errno; + + errno = 0; + rewind(fp); + saved_errno = errno; + if (ferror(fp)) { + throwUnixException(env, saved_errno); + } +} + +/** + * This function returns line length without NUL terminator or -1 on EOF. + */ +JNIEXPORT jint JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_getlinelen(JNIEnv* env, jclass this, jlong stream) +{ + FILE* fp = jlong_to_ptr(stream); + size_t lineSize = 0; + char * lineBuffer = NULL; + int saved_errno; + + ssize_t res = getline(&lineBuffer, &lineSize, fp); + saved_errno = errno; + + /* Should free lineBuffer no matter result, according to man page */ + if (lineBuffer != NULL) + free(lineBuffer); + + if (feof(fp)) + return -1; + + /* On successfull return res >= 0, otherwise res is -1 */ + if (res == -1) + throwUnixException(env, saved_errno); + + if (res > INT_MAX) + throwUnixException(env, EOVERFLOW); + + return (jint)res; +} + JNIEXPORT jint JNICALL Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this, jlong pathAddress, jint oflags, jint mode) diff --git a/src/java.base/windows/native/libjava/canonicalize_md.c b/src/java.base/windows/native/libjava/canonicalize_md.c index ba0d08624e3..b51919e77e4 100644 --- a/src/java.base/windows/native/libjava/canonicalize_md.c +++ b/src/java.base/windows/native/libjava/canonicalize_md.c @@ -225,6 +225,8 @@ lastErrorReportable() return 1; } +int wcanonicalize(WCHAR *orig_path, WCHAR *result, int size); + /* Convert a pathname to canonical form. The input orig_path is assumed to have been converted to native form already, via JVM_NativePath(). This is necessary because _fullpath() rejects duplicate separator characters on @@ -237,6 +239,38 @@ canonicalize(char *orig_path, char *result, int size) HANDLE h; char path[1024]; /* Working copy of path */ char *src, *dst, *dend; + wchar_t *worig_path, *wresult; + size_t converted_chars = 0; + + /* handle long path with length >= MAX_PATH */ + if (strlen(orig_path) >= MAX_PATH) { + if ((worig_path = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL) + return -1; + + if (mbstowcs_s(&converted_chars, worig_path, (size_t)size, orig_path, (size_t)(size - 1)) != 0) { + free(worig_path); + return -1; + } + + if ((wresult = (WCHAR*)malloc(size * sizeof(WCHAR))) == NULL) + return -1; + + if (wcanonicalize(worig_path, wresult, size) != 0) { + free(worig_path); + free(wresult); + return -1; + } + + if (wcstombs_s(&converted_chars, result, (size_t)size, wresult, (size_t)(size - 1)) != 0) { + free(worig_path); + free(wresult); + return -1; + } + + free(worig_path); + free(wresult); + return 0; + } /* Reject paths that contain wildcards */ if (wild(orig_path)) { @@ -245,15 +279,15 @@ canonicalize(char *orig_path, char *result, int size) } /* Collapse instances of "foo\.." and ensure absoluteness. Note that - contrary to the documentation, the _fullpath procedure does not require - the drive to be available. It also does not reliably change all - occurrences of '/' to '\\' on Win95, so now JVM_NativePath does that. */ - if(!_fullpath(path, orig_path, sizeof(path))) { + contrary to the documentation, the _fullpath procedure does not require + the drive to be available. It also does not reliably change all + occurrences of '/' to '\\' on Win95, so now JVM_NativePath does that. */ + if (!_fullpath(path, orig_path, sizeof(path))) { return -1; } /* Correction for Win95: _fullpath may leave a trailing "\\" - on a UNC pathname */ + on a UNC pathname */ if ((path[0] == '\\') && (path[1] == '\\')) { char *p = path + strlen(path); if ((p[-1] == '\\') && !islb(p[-2])) { @@ -281,16 +315,16 @@ canonicalize(char *orig_path, char *result, int size) char *p; p = nextsep(src + 2); /* Skip past host name */ if (!*p) { - /* A UNC pathname must begin with "\\\\host\\share", - so reject this path as invalid if there is no share name */ + /* A UNC pathname must begin with "\\\\host\\share", + so reject this path as invalid if there is no share name */ errno = EINVAL; return -1; - } - p = nextsep(p + 1); /* Skip past share name */ - if (!(dst = cp(dst, dend, '\0', src, p))) { - return -1; - } - src = p; + } + p = nextsep(p + 1); /* Skip past share name */ + if (!(dst = cp(dst, dend, '\0', src, p))) { + return -1; + } + src = p; } else { /* Invalid path */ errno = EINVAL; @@ -309,11 +343,11 @@ canonicalize(char *orig_path, char *result, int size) } /* At this point we have copied either a drive specifier ("z:") or a UNC - prefix ("\\\\host\\share") to the result buffer, and src points to the - first byte of the remainder of the path. We now scan through the rest - of the path, looking up each prefix in order to find the true name of - the last element of each prefix, thereby computing the full true name of - the original path. */ + prefix ("\\\\host\\share") to the result buffer, and src points to the + first byte of the remainder of the path. We now scan through the rest + of the path, looking up each prefix in order to find the true name of + the last element of each prefix, thereby computing the full true name of + the original path. */ while (*src) { char *p = nextsep(src + 1); /* Find next separator */ char c = *p; @@ -325,8 +359,8 @@ canonicalize(char *orig_path, char *result, int size) /* Lookup succeeded; append true name to result and continue */ FindClose(h); if (!(dst = cp(dst, dend, '\\', - fd.cFileName, - fd.cFileName + strlen(fd.cFileName)))) { + fd.cFileName, + fd.cFileName + strlen(fd.cFileName)))) { return -1; } src = p; @@ -344,8 +378,8 @@ canonicalize(char *orig_path, char *result, int size) } if (dst >= dend) { - errno = ENAMETOOLONG; - return -1; + errno = ENAMETOOLONG; + return -1; } *dst = '\0'; return 0; @@ -587,7 +621,7 @@ wcanonicalizeWithPrefix(WCHAR *canonicalPrefix, WCHAR *pathWithCanonicalPrefix, */ /* copy \\?\ or \\?\UNC\ to the front of path*/ -WCHAR* +__declspec(dllexport) WCHAR* getPrefixed(const WCHAR* path, int pathlen) { WCHAR* pathbuf = (WCHAR*)malloc((pathlen + 10) * sizeof (WCHAR)); if (pathbuf != 0) { diff --git a/src/java.base/windows/native/libjava/io_util_md.h b/src/java.base/windows/native/libjava/io_util_md.h index 66f9ab5b214..b1a272ac0fd 100644 --- a/src/java.base/windows/native/libjava/io_util_md.h +++ b/src/java.base/windows/native/libjava/io_util_md.h @@ -38,7 +38,7 @@ */ WCHAR* pathToNTPath(JNIEnv *env, jstring path, jboolean throwFNFE); WCHAR* fileToNTPath(JNIEnv *env, jobject file, jfieldID id); -WCHAR* getPrefixed(const WCHAR* path, int pathlen); +__declspec(dllexport) WCHAR* getPrefixed(const WCHAR* path, int pathlen); WCHAR* currentDir(int di); int currentDirLength(const WCHAR* path, int pathlen); int handleAvailable(FD fd, jlong *pbytes); diff --git a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c index 3b26bacc4ea..85b052b5f58 100644 --- a/src/java.base/windows/native/libnet/NetworkInterface_winXP.c +++ b/src/java.base/windows/native/libnet/NetworkInterface_winXP.c @@ -41,7 +41,7 @@ void printnif (netif *nif) { #ifdef _WIN64 printf ("nif:0x%I64x name:%s\n", (UINT_PTR)nif, nif->name); #else - printf ("nif:0x%x name:%s\n", nif, nif->name); + printf ("nif:0x%x name:%s\n", (UINT_PTR)nif, nif->name); #endif if (nif->dNameIsUnicode) { printf ("dName:%S index:%d ", (unsigned short *)nif->displayName, diff --git a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java index 2eb9048e71e..bebc9b5fc2c 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java +++ b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLSurfaceData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,8 +48,9 @@ public abstract class CGLSurfaceData extends OGLSurfaceData { native void validate(int xoff, int yoff, int width, int height, boolean isOpaque); - private native void initOps(long pConfigInfo, long pPeerData, long layerPtr, - int xoff, int yoff, boolean isOpaque); + private native void initOps(OGLGraphicsConfig gc, long pConfigInfo, + long pPeerData, long layerPtr, int xoff, + int yoff, boolean isOpaque); protected CGLSurfaceData(CGLGraphicsConfig gc, ColorModel cm, int type, int width, int height) { @@ -74,7 +75,7 @@ protected CGLSurfaceData(CPlatformView pView, CGLGraphicsConfig gc, pPeerData = pView.getAWTView(); isOpaque = pView.isOpaque(); } - initOps(pConfigInfo, pPeerData, 0, 0, 0, isOpaque); + initOps(gc, pConfigInfo, pPeerData, 0, 0, 0, isOpaque); } protected CGLSurfaceData(CGLLayer layer, CGLGraphicsConfig gc, @@ -90,7 +91,7 @@ protected CGLSurfaceData(CGLLayer layer, CGLGraphicsConfig gc, layerPtr = layer.getPointer(); isOpaque = layer.isOpaque(); } - initOps(pConfigInfo, 0, layerPtr, 0, 0, isOpaque); + initOps(gc, pConfigInfo, 0, layerPtr, 0, 0, isOpaque); } @Override //SurfaceData diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m index c394854a5c6..b06b8de6905 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m @@ -301,7 +301,7 @@ static void PostMouseEvent(const CGPoint point, CGMouseButton button, // create a graphics context around the Java int array CGColorSpaceRef picColorSpace = CGColorSpaceCreateWithName( - kCGColorSpaceGenericRGB); + kCGColorSpaceSRGB); CGContextRef jPicContextRef = CGBitmapContextCreate( jPixelData, picWidth, picHeight, diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.m index 328721843a3..981009176e6 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl/CGLSurfaceData.m @@ -130,31 +130,6 @@ extern CGLError CGLTexImageIOSurface2D( JNF_COCOA_EXIT(env); } -/** - * Returns a pointer (as a jlong) to the native CGLGraphicsConfigInfo - * associated with the given OGLSDOps. This method can be called from - * shared code to retrieve the native GraphicsConfig data in a platform- - * independent manner. - */ -jlong -OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo) -{ - J2dTraceLn(J2D_TRACE_INFO, "OGLSD_GetNativeConfigInfo"); - - if (oglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_GetNativeConfigInfo: ops are null"); - return 0L; - } - - CGLSDOps *cglsdo = (CGLSDOps *)oglsdo->privOps; - if (cglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, "OGLSD_GetNativeConfigInfo: cgl ops are null"); - return 0L; - } - - return ptr_to_jlong(cglsdo->configInfo); -} - /** * Makes the given GraphicsConfig's context current to its associated * "scratch" surface. If there is a problem making the context current, @@ -376,7 +351,7 @@ extern CGLError CGLTexImageIOSurface2D( JNIEXPORT void JNICALL Java_sun_java2d_opengl_CGLSurfaceData_initOps - (JNIEnv *env, jobject cglsd, + (JNIEnv *env, jobject cglsd, jobject gc, jlong pConfigInfo, jlong pPeerData, jlong layerPtr, jint xoff, jint yoff, jboolean isOpaque) { @@ -384,8 +359,22 @@ extern CGLError CGLTexImageIOSurface2D( J2dTraceLn1(J2D_TRACE_INFO, " pPeerData=%p", jlong_to_ptr(pPeerData)); J2dTraceLn2(J2D_TRACE_INFO, " xoff=%d, yoff=%d", (int)xoff, (int)yoff); + gc = (*env)->NewGlobalRef(env, gc); + if (gc == NULL) { + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); + return; + } + OGLSDOps *oglsdo = (OGLSDOps *) SurfaceData_InitOps(env, cglsd, sizeof(OGLSDOps)); + if (oglsdo == NULL) { + (*env)->DeleteGlobalRef(env, gc); + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); + return; + } + // later the graphicsConfig will be used for deallocation of oglsdo + oglsdo->graphicsConfig = gc; + CGLSDOps *cglsdo = (CGLSDOps *)malloc(sizeof(CGLSDOps)); if (cglsdo == NULL) { JNU_ThrowOutOfMemoryError(env, "creating native cgl ops"); diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java index 3bd0585c94a..ec05b6aced5 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java @@ -702,6 +702,7 @@ protected void modelChanged() { Document doc = editor.getDocument(); Element elem = doc.getDefaultRootElement(); setView(f.create(elem)); + rootViewNeedsLayout = false; } /** @@ -947,11 +948,10 @@ public Dimension getPreferredSize(JComponent c) { if ((d.width > (i.left + i.right + caretMargin)) && (d.height > (i.top + i.bottom))) { rootView.setSize(d.width - i.left - i.right - caretMargin, d.height - i.top - i.bottom); - } - else if (!rootViewInitialized && (d.width <= 0 || d.height <= 0)) { + } if (!rootViewNeedsLayout) { // Probably haven't been layed out yet, force some sort of // initial sizing. - rootViewInitialized = true; + rootViewNeedsLayout = true; rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE); } d.width = (int) Math.min((long) rootView.getPreferredSpan(View.X_AXIS) + @@ -1403,7 +1403,7 @@ static class BasicCursor extends Cursor implements UIResource { private static final Position.Bias[] discardBias = new Position.Bias[1]; private DefaultCaret dropCaret; private int caretMargin; - private boolean rootViewInitialized; + private boolean rootViewNeedsLayout; /** * Root view that acts as a gateway between the component @@ -1966,6 +1966,7 @@ public final void insertUpdate(DocumentEvent e) { // normal insert update Rectangle alloc = (painted) ? getVisibleEditorRect() : null; rootView.insertUpdate(e, alloc, rootView.getViewFactory()); + rootViewNeedsLayout = false; } /** @@ -1981,6 +1982,7 @@ public final void insertUpdate(DocumentEvent e) { public final void removeUpdate(DocumentEvent e) { Rectangle alloc = (painted) ? getVisibleEditorRect() : null; rootView.removeUpdate(e, alloc, rootView.getViewFactory()); + rootViewNeedsLayout = false; } /** @@ -1996,6 +1998,7 @@ public final void removeUpdate(DocumentEvent e) { public final void changedUpdate(DocumentEvent e) { Rectangle alloc = (painted) ? getVisibleEditorRect() : null; rootView.changedUpdate(e, alloc, rootView.getViewFactory()); + rootViewNeedsLayout = false; } // --- LayoutManager2 methods -------------------------------- diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java b/src/java.desktop/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java index f3d44e3ba92..66858dfdd5a 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java @@ -246,7 +246,8 @@ private double userSpaceLineWidth(AffineTransform at, double lw) { widthScale = 1.0d; } else if ((at.getType() & (AffineTransform.TYPE_GENERAL_TRANSFORM | AffineTransform.TYPE_GENERAL_SCALE)) != 0) { - widthScale = Math.sqrt(at.getDeterminant()); + // Determinant may be negative (flip), use its absolute value: + widthScale = Math.sqrt(Math.abs(at.getDeterminant())); } else { // First calculate the "maximum scale" of this transform. double A = at.getScaleX(); // m00 diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java b/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java index a3baed14378..3bba4c194b2 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java @@ -245,7 +245,8 @@ private float userSpaceLineWidth(AffineTransform at, float lw) { widthScale = 1.0f; } else if ((at.getType() & (AffineTransform.TYPE_GENERAL_TRANSFORM | AffineTransform.TYPE_GENERAL_SCALE)) != 0) { - widthScale = (float)Math.sqrt(at.getDeterminant()); + // Determinant may be negative (flip), use its absolute value: + widthScale = (float)Math.sqrt(Math.abs(at.getDeterminant())); } else { // First calculate the "maximum scale" of this transform. double A = at.getScaleX(); // m00 diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/Version.java b/src/java.desktop/share/classes/sun/java2d/marlin/Version.java index e7e94ffe397..0155b049fab 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/Version.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/Version.java @@ -27,7 +27,7 @@ public final class Version { - private static final String VERSION = "marlin-0.9.1.2-Unsafe-OpenJDK"; + private static final String VERSION = "marlin-0.9.1.3-Unsafe-OpenJDK"; public static String getVersion() { return VERSION; diff --git a/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java b/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java index 5e6f802da14..02302ceb8f1 100644 --- a/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java +++ b/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java @@ -27,6 +27,7 @@ import java.awt.AlphaComposite; import java.awt.Composite; +import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import java.awt.Transparency; @@ -578,16 +579,16 @@ public void flush() { * (referenced by the pData parameter). This method is invoked from * the native Dispose() method from the Disposer thread when the * Java-level OGLSurfaceData object is about to go away. Note that we - * also pass a reference to the native GLX/WGLGraphicsConfigInfo - * (pConfigInfo) for the purposes of making a context current. + * also pass a reference to the OGLGraphicsConfig + * for the purposes of making a context current. */ - static void dispose(long pData, long pConfigInfo) { + static void dispose(long pData, OGLGraphicsConfig gc) { OGLRenderQueue rq = OGLRenderQueue.getInstance(); rq.lock(); try { // make sure we have a current context before // disposing the native resources (e.g. texture object) - OGLContext.setScratchSurface(pConfigInfo); + OGLContext.setScratchSurface(gc); RenderBuffer buf = rq.getBuffer(); rq.ensureCapacityAndAlignment(12, 4); diff --git a/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.c b/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.c index d12ab19d87d..59773ec666d 100644 --- a/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.c +++ b/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,6 @@ * The following methods are implemented in the windowing system (i.e. GLX * and WGL) source files. */ -extern jlong OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo); extern jboolean OGLSD_InitOGLWindow(JNIEnv *env, OGLSDOps *oglsdo); extern void OGLSD_DestroyOGLSurface(JNIEnv *env, OGLSDOps *oglsdo); @@ -593,11 +592,14 @@ void OGLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops) { OGLSDOps *oglsdo = (OGLSDOps *)ops; - jlong pConfigInfo = OGLSD_GetNativeConfigInfo(oglsdo); + jobject graphicsConfig = oglsdo->graphicsConfig; JNU_CallStaticMethodByName(env, NULL, "sun/java2d/opengl/OGLSurfaceData", - "dispose", "(JJ)V", - ptr_to_jlong(ops), pConfigInfo); + "dispose", + "(JLsun/java2d/opengl/OGLGraphicsConfig;)V", + ptr_to_jlong(ops), graphicsConfig); + (*env)->DeleteGlobalRef(env, graphicsConfig); + oglsdo->graphicsConfig = NULL; } /** diff --git a/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.h b/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.h index e5ce1604fbe..353a2a2b649 100644 --- a/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.h +++ b/src/java.desktop/share/native/common/java2d/opengl/OGLSurfaceData.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,6 +85,9 @@ typedef struct { * Pointer to native-specific (GLX, WGL, etc.) SurfaceData info, such as the * native Drawable handle and GraphicsConfig data. * + * jobject graphicsConfig;; + * Strong reference to the OGLGraphicsConfig used by this OGLSurfaceData. + * * jint drawableType; * The surface type; can be any one of the surface type constants defined * below (OGLSD_WINDOW, OGLSD_TEXTURE, etc). @@ -162,6 +165,7 @@ typedef struct { struct _OGLSDOps { SurfaceDataOps sdOps; void *privOps; + jobject graphicsConfig; jint drawableType; GLenum activeBuffer; jboolean isOpaque; diff --git a/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c b/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c index b53b2e379c7..c15795203a1 100644 --- a/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c +++ b/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, 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 @@ -351,6 +351,7 @@ static ColorData *BufImg_SetupICM(JNIEnv *env, cData->img_clr_tbl = initCubemap(pRgb, bisdo->lutsize, 32); if (cData->img_clr_tbl == NULL) { + (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray, pRgb, JNI_ABORT); free(cData); return (ColorData*)NULL; } diff --git a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c index 014074b050b..e61a4e7de0a 100644 --- a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c +++ b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c @@ -29,7 +29,10 @@ #include "sunfontids.h" #include "sun_font_FreetypeFontScaler.h" -#include +#include +#if !defined(_WIN32) && !defined(__APPLE_) +#include +#endif #include #include "ft2build.h" #include FT_FREETYPE_H @@ -38,6 +41,8 @@ #include FT_SIZES_H #include FT_OUTLINE_H #include FT_SYNTHESIS_H +#include FT_LCD_FILTER_H +#include FT_MODULE_H #include "fontscaler.h" @@ -246,6 +251,52 @@ static unsigned long ReadTTFontFileFunc(FT_Stream stream, } } +typedef FT_Error (*FT_Prop_Set_Func)(FT_Library library, + const FT_String* module_name, + const FT_String* property_name, + const void* value ); + +/** + * Prefer the older v35 freetype byte code interpreter. + */ +static void setInterpreterVersion(FT_Library library) { + + char* props = getenv("FREETYPE_PROPERTIES"); + int version = 35; + const char* module = "truetype"; + const char* property = "interpreter-version"; + + /* If some one is setting this, don't override it */ + if (props != NULL && strstr(property, props)) { + return; + } + /* + * FT_Property_Set was introduced in 2.4.11. + * Some older supported Linux OSes may not include it so look + * this up dynamically. + * And if its not available it doesn't matter, since the reason + * we need it dates from 2.7. + * On Windows & Mac the library is always bundled so it is safe + * to use directly in those cases. + */ +#if defined(_WIN32) || defined(__APPLE__) + FT_Property_Set(library, module, property, (void*)(&version)); +#else + void *lib = dlopen("libfreetype.so", RTLD_LOCAL|RTLD_LAZY); + if (lib == NULL) { + lib = dlopen("libfreetype.so.6", RTLD_LOCAL|RTLD_LAZY); + if (lib == NULL) { + return; + } + } + FT_Prop_Set_Func func = (FT_Prop_Set_Func)dlsym(lib, "FT_Property_Set"); + if (func != NULL) { + func(library, module, property, (void*)(&version)); + } + dlclose(lib); +#endif +} + /* * Class: sun_font_FreetypeFontScaler * Method: initNativeScaler @@ -285,6 +336,7 @@ Java_sun_font_FreetypeFontScaler_initNativeScaler( free(scalerInfo); return 0; } + setInterpreterVersion(scalerInfo->library); #define TYPE1_FROM_JAVA 2 @@ -439,6 +491,8 @@ static int setupFTContext(JNIEnv *env, if (errCode == 0) { errCode = FT_Activate_Size(scalerInfo->face->size); } + + FT_Library_SetLcdFilter(scalerInfo->library, FT_LCD_FILTER_DEFAULT); } return errCode; diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index 2b8f26da5c9..65cb46ccfdf 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -2554,14 +2554,16 @@ private void processXkbChanges(XEvent ev) { //System.out.println("XkbNewKeyboard:"+(xke.get_new_kbd())); break; case XConstants.XkbMapNotify : - //TODO: provide a simple unit test. - XlibWrapper.XkbGetUpdatedMap(getDisplay(), - XConstants.XkbKeyTypesMask | - XConstants.XkbKeySymsMask | - XConstants.XkbModifierMapMask | - XConstants.XkbVirtualModsMask, - awt_XKBDescPtr); - //System.out.println("XkbMap:"+(xke.get_map())); + if (awt_XKBDescPtr != 0) { + //TODO: provide a simple unit test. + XlibWrapper.XkbGetUpdatedMap(getDisplay(), + XConstants.XkbKeyTypesMask | + XConstants.XkbKeySymsMask | + XConstants.XkbModifierMapMask | + XConstants.XkbVirtualModsMask, + awt_XKBDescPtr); + } + //System.out.println("XkbMap:"+(xke.get_map())); break; case XConstants.XkbStateNotify : // May use it later e.g. to obtain an effective group etc. diff --git a/src/java.desktop/unix/classes/sun/java2d/opengl/GLXSurfaceData.java b/src/java.desktop/unix/classes/sun/java2d/opengl/GLXSurfaceData.java index bfe9a26426e..790a0c38f0c 100644 --- a/src/java.desktop/unix/classes/sun/java2d/opengl/GLXSurfaceData.java +++ b/src/java.desktop/unix/classes/sun/java2d/opengl/GLXSurfaceData.java @@ -40,7 +40,8 @@ public abstract class GLXSurfaceData extends OGLSurfaceData { protected X11ComponentPeer peer; private GLXGraphicsConfig graphicsConfig; - private native void initOps(X11ComponentPeer peer, long aData); + private native void initOps(OGLGraphicsConfig gc, X11ComponentPeer peer, + long aData); protected GLXSurfaceData(X11ComponentPeer peer, GLXGraphicsConfig gc, ColorModel cm, int type) @@ -48,7 +49,7 @@ protected GLXSurfaceData(X11ComponentPeer peer, GLXGraphicsConfig gc, super(gc, cm, type); this.peer = peer; this.graphicsConfig = gc; - initOps(peer, graphicsConfig.getAData()); + initOps(gc, peer, graphicsConfig.getAData()); } public GraphicsConfiguration getDeviceConfiguration() { diff --git a/src/java.desktop/unix/native/common/awt/fontpath.c b/src/java.desktop/unix/native/common/awt/fontpath.c index 66ac6dff304..ab287555964 100644 --- a/src/java.desktop/unix/native/common/awt/fontpath.c +++ b/src/java.desktop/unix/native/common/awt/fontpath.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -887,9 +887,9 @@ Java_sun_font_FontConfigManager_getFontConfigAASettings locale = (*env)->GetStringUTFChars(env, localeStr, 0); if ((libfontconfig = openFontConfig()) == NULL) { - (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName); + (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName); if (locale) { - (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale); + (*env)->ReleaseStringUTFChars(env, localeStr,(const char*)locale); } return -1; } @@ -918,9 +918,9 @@ Java_sun_font_FontConfigManager_getFontConfigAASettings FcPatternGetInteger == NULL || FcPatternDestroy == NULL) { /* problem with the library: return. */ - (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName); + (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName); if (locale) { - (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale); + (*env)->ReleaseStringUTFChars(env, localeStr,(const char*)locale); } closeFontConfig(libfontconfig, JNI_FALSE); return -1; @@ -945,9 +945,9 @@ Java_sun_font_FontConfigManager_getFontConfigAASettings } (*FcPatternDestroy)(pattern); - (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName); + (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName); if (locale) { - (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale); + (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale); } closeFontConfig(libfontconfig, JNI_TRUE); @@ -1179,6 +1179,9 @@ Java_sun_font_FontConfigManager_getFontConfig (*env)->DeleteLocalRef(env, fcNameStr); if (pattern == NULL) { closeFontConfig(libfontconfig, JNI_FALSE); + if (locale) { + (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale); + } return; } @@ -1196,6 +1199,9 @@ Java_sun_font_FontConfigManager_getFontConfig if (fontset == NULL) { (*FcPatternDestroy)(pattern); closeFontConfig(libfontconfig, JNI_FALSE); + if (locale) { + (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale); + } return; } @@ -1227,6 +1233,9 @@ Java_sun_font_FontConfigManager_getFontConfig (*FcPatternDestroy)(pattern); (*FcFontSetDestroy)(fontset); closeFontConfig(libfontconfig, JNI_FALSE); + if (locale) { + (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale); + } return; } fontCount = 0; @@ -1269,6 +1278,9 @@ Java_sun_font_FontConfigManager_getFontConfig (*FcPatternDestroy)(pattern); (*FcFontSetDestroy)(fontset); closeFontConfig(libfontconfig, JNI_FALSE); + if (locale) { + (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale); + } return; } @@ -1323,6 +1335,9 @@ Java_sun_font_FontConfigManager_getFontConfig (*FcPatternDestroy)(pattern); (*FcFontSetDestroy)(fontset); closeFontConfig(libfontconfig, JNI_FALSE); + if (locale) { + (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale); + } return; } (*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr); @@ -1384,7 +1399,7 @@ Java_sun_font_FontConfigManager_getFontConfig /* release resources and close the ".so" */ if (locale) { - (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale); + (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale); } closeFontConfig(libfontconfig, JNI_TRUE); } diff --git a/src/java.desktop/unix/native/common/java2d/opengl/GLXSurfaceData.c b/src/java.desktop/unix/native/common/java2d/opengl/GLXSurfaceData.c index 9ea366e46fd..c48b38fa1f3 100644 --- a/src/java.desktop/unix/native/common/java2d/opengl/GLXSurfaceData.c +++ b/src/java.desktop/unix/native/common/java2d/opengl/GLXSurfaceData.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -54,23 +54,32 @@ jboolean surfaceCreationFailed = JNI_FALSE; JNIEXPORT void JNICALL Java_sun_java2d_opengl_GLXSurfaceData_initOps(JNIEnv *env, jobject glxsd, + jobject gc, jobject peer, jlong aData) { #ifndef HEADLESS - GLXSDOps *glxsdo = (GLXSDOps *)malloc(sizeof(GLXSDOps)); - - if (glxsdo == NULL) { - JNU_ThrowOutOfMemoryError(env, "creating native GLX ops"); + gc = (*env)->NewGlobalRef(env, gc); + if (gc == NULL) { + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); return; } OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, glxsd, sizeof(OGLSDOps)); if (oglsdo == NULL) { - free(glxsdo); + (*env)->DeleteGlobalRef(env, gc); JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); return; } + // later the graphicsConfig will be used for deallocation of oglsdo + oglsdo->graphicsConfig = gc; + + GLXSDOps *glxsdo = (GLXSDOps *)malloc(sizeof(GLXSDOps)); + + if (glxsdo == NULL) { + JNU_ThrowOutOfMemoryError(env, "creating native GLX ops"); + return; + } J2dTraceLn(J2D_TRACE_INFO, "GLXSurfaceData_initOps"); @@ -152,39 +161,6 @@ GLXSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc) return JNI_TRUE; } -/** - * Returns a pointer (as a jlong) to the native GLXGraphicsConfigInfo - * associated with the given OGLSDOps. This method can be called from - * shared code to retrieve the native GraphicsConfig data in a platform- - * independent manner. - */ -jlong -OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo) -{ - GLXSDOps *glxsdo; - - if (oglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "OGLSD_GetNativeConfigInfo: ops are null"); - return 0L; - } - - glxsdo = (GLXSDOps *)oglsdo->privOps; - if (glxsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "OGLSD_GetNativeConfigInfo: glx ops are null"); - return 0L; - } - - if (glxsdo->configData == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "OGLSD_GetNativeConfigInfo: config data is null"); - return 0L; - } - - return ptr_to_jlong(glxsdo->configData->glxInfo); -} - /** * Makes the given GraphicsConfig's context current to its associated * "scratch" surface. If there is a problem making the context current, diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c b/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c index ecd592e2848..b3fea02b2a1 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c @@ -123,7 +123,15 @@ static char *x11GraphicsConfigClassName = "sun/awt/X11GraphicsConfig"; */ #define MAXFRAMEBUFFERS 16 -#if defined(__linux__) || defined(MACOSX) +#if defined(__solaris__) +typedef Status XineramaGetInfoFunc(Display* display, int screen_number, + XRectangle* framebuffer_rects, unsigned char* framebuffer_hints, + int* num_framebuffers); +typedef Status XineramaGetCenterHintFunc(Display* display, int screen_number, + int* x, int* y); + +XineramaGetCenterHintFunc* XineramaSolarisCenterFunc = NULL; +#else /* Linux, Mac, AIX */ typedef struct { int screen_number; short x_org; @@ -133,15 +141,6 @@ typedef struct { } XineramaScreenInfo; typedef XineramaScreenInfo* XineramaQueryScreensFunc(Display*, int*); - -#else /* SOLARIS */ -typedef Status XineramaGetInfoFunc(Display* display, int screen_number, - XRectangle* framebuffer_rects, unsigned char* framebuffer_hints, - int* num_framebuffers); -typedef Status XineramaGetCenterHintFunc(Display* display, int screen_number, - int* x, int* y); - -XineramaGetCenterHintFunc* XineramaSolarisCenterFunc = NULL; #endif Bool usingXinerama = False; @@ -442,6 +441,7 @@ getAllConfigs (JNIEnv *env, int screen, AwtScreenDataPtr screenDataPtr) { if (XQueryExtension(awt_display, "RENDER", &major_opcode, &first_event, &first_error)) { + DTRACE_PRINTLN("RENDER extension available"); xrenderLibHandle = dlopen("libXrender.so.1", RTLD_LAZY | RTLD_GLOBAL); #ifdef MACOSX @@ -455,18 +455,30 @@ getAllConfigs (JNIEnv *env, int screen, AwtScreenDataPtr screenDataPtr) { RTLD_LAZY | RTLD_GLOBAL); } -#ifndef __linux__ /* SOLARIS */ +#if defined(__solaris__) if (xrenderLibHandle == NULL) { xrenderLibHandle = dlopen("/usr/lib/libXrender.so.1", RTLD_LAZY | RTLD_GLOBAL); } +#elif defined(_AIX) + if (xrenderLibHandle == NULL) { + xrenderLibHandle = dlopen("libXrender.a(libXrender.so.0)", + RTLD_MEMBER | RTLD_LAZY | RTLD_GLOBAL); + } #endif - if (xrenderLibHandle != NULL) { + DTRACE_PRINTLN("Loaded libXrender"); xrenderFindVisualFormat = (XRenderFindVisualFormatFunc*)dlsym(xrenderLibHandle, "XRenderFindVisualFormat"); + if (xrenderFindVisualFormat == NULL) { + DTRACE_PRINTLN1("Can't find 'XRenderFindVisualFormat' in libXrender (%s)", dlerror()); + } + } else { + DTRACE_PRINTLN1("Can't load libXrender (%s)", dlerror()); } + } else { + DTRACE_PRINTLN("RENDER extension NOT available"); } for (i = 0; i < nTrue; i++) { @@ -482,18 +494,23 @@ getAllConfigs (JNIEnv *env, int screen, AwtScreenDataPtr screenDataPtr) { graphicsConfigs [ind]->awt_depth = pVITrue [i].depth; memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVITrue [i], sizeof (XVisualInfo)); - if (xrenderFindVisualFormat != NULL) { + if (xrenderFindVisualFormat != NULL) { XRenderPictFormat *format = xrenderFindVisualFormat (awt_display, - pVITrue [i].visual); + pVITrue [i].visual); if (format && format->type == PictTypeDirect && format->direct.alphaMask) { + DTRACE_PRINTLN1("GraphicsConfig[%d] supports Translucency", ind); graphicsConfigs [ind]->isTranslucencySupported = 1; memcpy(&graphicsConfigs [ind]->renderPictFormat, format, sizeof(*format)); + } else { + DTRACE_PRINTLN1(format ? + "GraphicsConfig[%d] has no Translucency support" : + "Error calling 'XRenderFindVisualFormat'", ind); } - } + } } if (xrenderLibHandle != NULL) { @@ -599,7 +616,7 @@ getAllConfigs (JNIEnv *env, int screen, AwtScreenDataPtr screenDataPtr) { } #ifndef HEADLESS -#if defined(__linux__) || defined(MACOSX) +#if defined(__linux__) || defined(MACOSX) || defined(_AIX) static void xinerama_init_linux() { void* libHandle = NULL; @@ -612,14 +629,18 @@ static void xinerama_init_linux() libHandle = dlopen(VERSIONED_JNI_LIB_NAME("Xinerama", "1"), RTLD_LAZY | RTLD_GLOBAL); if (libHandle == NULL) { +#if defined(_AIX) + libHandle = dlopen("libXext.a(shr_64.o)", RTLD_MEMBER | RTLD_LAZY | RTLD_GLOBAL); +#else libHandle = dlopen(JNI_LIB_NAME("Xinerama"), RTLD_LAZY | RTLD_GLOBAL); +#endif } if (libHandle != NULL) { XineramaQueryScreens = (XineramaQueryScreensFunc*) dlsym(libHandle, XineramaQueryScreensName); if (XineramaQueryScreens != NULL) { - DTRACE_PRINTLN("calling XineramaQueryScreens func on Linux"); + DTRACE_PRINTLN("calling XineramaQueryScreens func"); xinInfo = (*XineramaQueryScreens)(awt_display, &locNumScr); if (xinInfo != NULL && locNumScr > XScreenCount(awt_display)) { int32_t idx; @@ -639,7 +660,10 @@ static void xinerama_init_linux() fbrects[idx].y = xinInfo[idx].y_org; } } else { - DTRACE_PRINTLN("calling XineramaQueryScreens didn't work"); + DTRACE_PRINTLN((xinInfo == NULL) ? + "calling XineramaQueryScreens didn't work" : + "XineramaQueryScreens <= XScreenCount" + ); } } else { DTRACE_PRINTLN("couldn't load XineramaQueryScreens symbol"); @@ -649,8 +673,7 @@ static void xinerama_init_linux() DTRACE_PRINTLN1("\ncouldn't open shared library: %s\n", dlerror()); } } -#endif -#if !defined(__linux__) && !defined(MACOSX) /* Solaris */ +#elif defined(__solaris__) static void xinerama_init_solaris() { void* libHandle = NULL; @@ -710,11 +733,11 @@ static void xineramaInit(void) { } DTRACE_PRINTLN("Xinerama extension is available"); -#if defined(__linux__) || defined(MACOSX) - xinerama_init_linux(); -#else /* Solaris */ +#if defined(__solaris__) xinerama_init_solaris(); -#endif /* __linux__ || MACOSX */ +#else /* Linux, Mac, AIX */ + xinerama_init_linux(); +#endif } #endif /* HEADLESS */ @@ -1615,7 +1638,7 @@ Java_sun_awt_X11GraphicsEnvironment_getXineramaCenterPoint(JNIEnv *env, { jobject point = NULL; #ifndef HEADLESS /* return NULL in HEADLESS, Linux */ -#if !defined(__linux__) && !defined(MACOSX) +#if defined(__solaris__) int x,y; AWT_LOCK(); @@ -1628,7 +1651,7 @@ Java_sun_awt_X11GraphicsEnvironment_getXineramaCenterPoint(JNIEnv *env, DTRACE_PRINTLN("unable to call XineramaSolarisCenterFunc: symbol is null"); } AWT_FLUSH_UNLOCK(); -#endif /* __linux __ || MACOSX */ +#endif /* __solaris__ */ #endif /* HEADLESS */ return point; } diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c index 800af14d67a..41ee56fcd4f 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, 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 @@ -2451,14 +2451,14 @@ static jobject get_string_property(JNIEnv *env, GtkSettings* settings, const gch static jobject get_integer_property(JNIEnv *env, GtkSettings* settings, const gchar* key) { - gint intval = NULL; + gint intval = 0; (*fp_g_object_get)(settings, key, &intval, NULL); return create_Integer(env, intval); } static jobject get_boolean_property(JNIEnv *env, GtkSettings* settings, const gchar* key) { - gint intval = NULL; + gint intval = 0; (*fp_g_object_get)(settings, key, &intval, NULL); return create_Boolean(env, intval); } diff --git a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java index 79eff60b2f8..fa4cb6a3cc2 100644 --- a/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java +++ b/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java @@ -46,8 +46,8 @@ public abstract class WGLSurfaceData extends OGLSurfaceData { protected double scaleX = 1; protected double scaleY = 1; - private native void initOps(long pConfigInfo, WComponentPeer peer, - long hwnd); + private native void initOps(OGLGraphicsConfig gc, long pConfigInfo, + WComponentPeer peer, long hwnd); protected WGLSurfaceData(WComponentPeer peer, WGLGraphicsConfig gc, ColorModel cm, int type) @@ -62,7 +62,7 @@ protected WGLSurfaceData(WComponentPeer peer, WGLGraphicsConfig gc, long pConfigInfo = gc.getNativeConfigInfo(); long hwnd = peer != null ? peer.getHWnd() : 0L; - initOps(pConfigInfo, peer, hwnd); + initOps(gc, pConfigInfo, peer, hwnd); } @Override diff --git a/src/java.desktop/windows/native/common/awt/systemscale/systemScale.cpp b/src/java.desktop/windows/native/common/awt/systemscale/systemScale.cpp index f8ea087883c..ceca5d9ed4b 100644 --- a/src/java.desktop/windows/native/common/awt/systemscale/systemScale.cpp +++ b/src/java.desktop/windows/native/common/awt/systemscale/systemScale.cpp @@ -24,7 +24,6 @@ */ #include "systemScale.h" #include -#pragma comment(lib, "d2d1") #include #ifndef MDT_EFFECTIVE_DPI #define MDT_EFFECTIVE_DPI 0 @@ -53,6 +52,9 @@ void GetScreenDpi(HMONITOR hmon, float *dpiX, float *dpiY) return; } + typedef HRESULT(WINAPI D2D1CreateFactoryFunc) + (D2D1_FACTORY_TYPE, REFIID, + CONST D2D1_FACTORY_OPTIONS*, ID2D1Factory**); typedef HRESULT(WINAPI GetDpiForMonitorFunc)(HMONITOR, int, UINT*, UINT*); static HMODULE hLibSHCoreDll = NULL; static GetDpiForMonitorFunc *lpGetDpiForMonitor = NULL; @@ -73,12 +75,27 @@ void GetScreenDpi(HMONITOR hmon, float *dpiX, float *dpiY) *dpiY = static_cast(y); } } else { - ID2D1Factory* m_pDirect2dFactory; - HRESULT res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, - &m_pDirect2dFactory); - if (res == S_OK) { - m_pDirect2dFactory->GetDesktopDpi(dpiX, dpiY); - m_pDirect2dFactory->Release(); + static HMODULE d2dDll = NULL; + static BOOL loadAttempted = FALSE; + static D2D1CreateFactoryFunc *lpD2D1CreateFactory = NULL; + if (!loadAttempted && d2dDll == NULL) { + loadAttempted = TRUE; + d2dDll = JDK_LoadSystemLibrary("d2d1.dll"); + } + if (d2dDll != NULL && lpD2D1CreateFactory == NULL) { + lpD2D1CreateFactory = (D2D1CreateFactoryFunc*)GetProcAddress( + d2dDll, "D2D1CreateFactory"); + } + if (lpD2D1CreateFactory != NULL) { + ID2D1Factory* m_pDirect2dFactory; + HRESULT res = lpD2D1CreateFactory + (D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory), NULL, + &m_pDirect2dFactory); + if (res == S_OK) { + m_pDirect2dFactory->GetDesktopDpi(dpiX, dpiY); + m_pDirect2dFactory->Release(); + } } } return; diff --git a/src/java.desktop/windows/native/libawt/java2d/opengl/WGLSurfaceData.c b/src/java.desktop/windows/native/libawt/java2d/opengl/WGLSurfaceData.c index 3496252553b..76bbb89c526 100644 --- a/src/java.desktop/windows/native/libawt/java2d/opengl/WGLSurfaceData.c +++ b/src/java.desktop/windows/native/libawt/java2d/opengl/WGLSurfaceData.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, 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 @@ -58,11 +58,25 @@ extern void JNIEXPORT void JNICALL Java_sun_java2d_opengl_WGLSurfaceData_initOps(JNIEnv *env, jobject wglsd, - jlong pConfigInfo, + jobject gc, jlong pConfigInfo, jobject peer, jlong hwnd) { + gc = (*env)->NewGlobalRef(env, gc); + if (gc == NULL) { + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); + return; + } + OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, wglsd, sizeof(OGLSDOps)); + if (oglsdo == NULL) { + (*env)->DeleteGlobalRef(env, gc); + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); + return; + } + // later the graphicsConfig will be used for deallocation of oglsdo + oglsdo->graphicsConfig = gc; + WGLSDOps *wglsdo = (WGLSDOps *)malloc(sizeof(WGLSDOps)); J2dTraceLn(J2D_TRACE_INFO, "WGLSurfaceData_initOps"); @@ -144,33 +158,6 @@ WGLSD_MakeCurrentToScratch(JNIEnv *env, OGLContext *oglc) return JNI_TRUE; } -/** - * Returns a pointer (as a jlong) to the native WGLGraphicsConfigInfo - * associated with the given OGLSDOps. This method can be called from - * shared code to retrieve the native GraphicsConfig data in a platform- - * independent manner. - */ -jlong -OGLSD_GetNativeConfigInfo(OGLSDOps *oglsdo) -{ - WGLSDOps *wglsdo; - - if (oglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "OGLSD_GetNativeConfigInfo: ops are null"); - return 0L; - } - - wglsdo = (WGLSDOps *)oglsdo->privOps; - if (wglsdo == NULL) { - J2dRlsTraceLn(J2D_TRACE_ERROR, - "OGLSD_GetNativeConfigInfo: wgl ops are null"); - return 0L; - } - - return ptr_to_jlong(wglsdo->configInfo); -} - /** * Makes the given GraphicsConfig's context current to its associated * "scratch" surface. If there is a problem making the context current, diff --git a/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp b/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp index 6315fdf56cb..6e6d5bd0210 100644 --- a/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp +++ b/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -1130,6 +1130,9 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource const char *pLibName = env->GetStringUTFChars(libName, NULL); JNU_CHECK_EXCEPTION_RETURN(env, 0); HINSTANCE libHandle = (HINSTANCE)JDK_LoadSystemLibrary(pLibName); + if (pLibName != NULL) { + env->ReleaseStringUTFChars(libName, pLibName); + } if (libHandle != NULL) { UINT fuLoad = (useVGAColors && !IS_WINXP) ? LR_VGACOLOR : 0; return ptr_to_jlong(LoadImage(libHandle, MAKEINTRESOURCE(iconID), diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp index dcc5ee99335..258b2906f92 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp @@ -49,8 +49,6 @@ #include "dither.h" #include "img_util_md.h" #include "Devices.h" -#include -#pragma comment(lib, "d2d1") #include "systemScale.h" uns_ordered_dither_array img_oda_alpha; diff --git a/src/java.instrument/share/classes/java/lang/instrument/package-info.java b/src/java.instrument/share/classes/java/lang/instrument/package-info.java index 9519bf21948..550d3b7b64c 100644 --- a/src/java.instrument/share/classes/java/lang/instrument/package-info.java +++ b/src/java.instrument/share/classes/java/lang/instrument/package-info.java @@ -5,7 +5,7 @@ * 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 + * 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 diff --git a/src/java.instrument/share/native/libinstrument/JPLISAgent.c b/src/java.instrument/share/native/libinstrument/JPLISAgent.c index 3ca1d32cf0b..da73cca25d1 100644 --- a/src/java.instrument/share/native/libinstrument/JPLISAgent.c +++ b/src/java.instrument/share/native/libinstrument/JPLISAgent.c @@ -1486,6 +1486,7 @@ appendToClassLoaderSearch(JNIEnv * jnienv, JPLISAgent * agent, jstring jarFile, platformLen = convertUft8ToPlatformString((char*)utf8Chars, utf8Len, platformChars, MAXPATHLEN); if (platformLen < 0) { createAndThrowInternalError(jnienv); + (*jnienv)->ReleaseStringUTFChars(jnienv, jarFile, utf8Chars); return; } diff --git a/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c b/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c index 4740a7f7f0f..84ff5863333 100644 --- a/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c +++ b/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 diff --git a/src/java.instrument/windows/native/libinstrument/FileSystemSupport_md.c b/src/java.instrument/windows/native/libinstrument/FileSystemSupport_md.c index f1900675ccf..c93b7b6342f 100644 --- a/src/java.instrument/windows/native/libinstrument/FileSystemSupport_md.c +++ b/src/java.instrument/windows/native/libinstrument/FileSystemSupport_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java index 743cfc5afdb..6a07e584c14 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java @@ -33,8 +33,10 @@ import java.net.URISyntaxException; import java.net.URLPermission; import java.security.AccessControlContext; +import java.time.Duration; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Function; @@ -125,6 +127,10 @@ public HttpRequestImpl request() { return request; } + public Optional remainingConnectTimeout() { + return multi.remainingConnectTimeout(); + } + HttpClientImpl client() { return client; } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index 109dd8c4ebf..942502d806f 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -158,7 +158,7 @@ public void execute(Runnable command) { private final CookieHandler cookieHandler; private final Duration connectTimeout; private final Redirect followRedirects; - private final Optional userProxySelector; + private final ProxySelector userProxySelector; private final ProxySelector proxySelector; private final Authenticator authenticator; private final Version version; @@ -284,12 +284,12 @@ private HttpClientImpl(HttpClientBuilderImpl builder, connectTimeout = builder.connectTimeout; followRedirects = builder.followRedirects == null ? Redirect.NEVER : builder.followRedirects; - this.userProxySelector = Optional.ofNullable(builder.proxy); - this.proxySelector = userProxySelector + this.userProxySelector = builder.proxy; + this.proxySelector = Optional.ofNullable(userProxySelector) .orElseGet(HttpClientImpl::getDefaultProxySelector); if (debug.on()) debug.log("proxySelector is %s (user-supplied=%s)", - this.proxySelector, userProxySelector.isPresent()); + this.proxySelector, userProxySelector != null); authenticator = builder.authenticator; if (builder.version == null) { version = HttpClient.Version.HTTP_2; @@ -1138,7 +1138,7 @@ public Optional connectTimeout() { @Override public Optional proxy() { - return this.userProxySelector; + return Optional.ofNullable(userProxySelector); } // Return the effective proxy that this client uses. diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java index 9b8ab1d3ab8..76bb3c0a606 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java @@ -317,14 +317,13 @@ private static HttpConnection getPlainConnection(InetSocketAddress addr, void closeOrReturnToCache(HttpHeaders hdrs) { if (hdrs == null) { // the connection was closed by server, eof + Log.logTrace("Cannot return connection to pool: closing {0}", this); close(); return; } - if (!isOpen()) { - return; - } HttpClientImpl client = client(); if (client == null) { + Log.logTrace("Client released: closing {0}", this); close(); return; } @@ -333,10 +332,12 @@ void closeOrReturnToCache(HttpHeaders hdrs) { .map((s) -> !s.equalsIgnoreCase("close")) .orElse(true); - if (keepAlive) { + if (keepAlive && isOpen()) { Log.logTrace("Returning connection to the pool: {0}", this); pool.returnToPool(this); } else { + Log.logTrace("Closing connection (keepAlive={0}, isOpen={1}): {2}", + keepAlive, isOpen(), this); close(); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java index 4dcf3be0c88..0b92f112cd9 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java @@ -26,12 +26,14 @@ package jdk.internal.net.http; import java.io.IOException; -import java.io.UncheckedIOException; import java.net.ConnectException; import java.net.http.HttpConnectTimeoutException; +import java.time.Duration; import java.util.Iterator; import java.util.LinkedList; import java.security.AccessControlContext; +import java.util.Objects; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.CompletionException; @@ -39,6 +41,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Flow; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import java.net.http.HttpClient; @@ -71,6 +74,7 @@ class MultiExchange { private final HttpRequest userRequest; // the user request private final HttpRequestImpl request; // a copy of the user request + private final ConnectTimeoutTracker connectTimeout; // null if no timeout final AccessControlContext acc; final HttpClientImpl client; final HttpResponse.BodyHandler responseHandler; @@ -107,6 +111,38 @@ class MultiExchange { // RedirectHandler volatile int numberOfRedirects = 0; + // This class is used to keep track of the connection timeout + // across retries, when a ConnectException causes a retry. + // In that case - we will retry the connect, but we don't + // want to double the timeout by starting a new timer with + // the full connectTimeout again. + // Instead we use the ConnectTimeoutTracker to return a new + // duration that takes into account the time spent in the + // first connect attempt. + // If however, the connection gets connected, but we later + // retry the whole operation, then we reset the timer before + // retrying (since the connection used for the second request + // will not necessarily be the same: it could be a new + // unconnected connection) - see getExceptionalCF(). + private static final class ConnectTimeoutTracker { + final Duration max; + final AtomicLong startTime = new AtomicLong(); + ConnectTimeoutTracker(Duration connectTimeout) { + this.max = Objects.requireNonNull(connectTimeout); + } + + Duration getRemaining() { + long now = System.nanoTime(); + long previous = startTime.compareAndExchange(0, now); + if (previous == 0 || max.isZero()) return max; + Duration remaining = max.minus(Duration.ofNanos(now - previous)); + assert remaining.compareTo(max) <= 0; + return remaining.isNegative() ? Duration.ZERO : remaining; + } + + void reset() { startTime.set(0); } + } + /** * MultiExchange with one final response. */ @@ -135,7 +171,8 @@ class MultiExchange { } else { pushGroup = null; } - + this.connectTimeout = client.connectTimeout() + .map(ConnectTimeoutTracker::new).orElse(null); this.exchange = new Exchange<>(request, this); } @@ -161,6 +198,11 @@ private synchronized void setExchange(Exchange exchange) { this.exchange = exchange; } + public Optional remainingConnectTimeout() { + return Optional.ofNullable(connectTimeout) + .map(ConnectTimeoutTracker::getRemaining); + } + private void cancelTimer() { if (responseTimerEvent != null) { client.cancelTimer(responseTimerEvent); @@ -354,7 +396,7 @@ private static boolean retryPostValue() { return s.isEmpty() ? true : Boolean.parseBoolean(s); } - private static boolean retryConnect() { + private static boolean disableRetryConnect() { String s = Utils.getNetProperty("jdk.httpclient.disableRetryConnect"); if (s == null) return false; @@ -364,7 +406,7 @@ private static boolean retryConnect() { /** True if ALL ( even non-idempotent ) requests can be automatic retried. */ private static final boolean RETRY_ALWAYS = retryPostValue(); /** True if ConnectException should cause a retry. Enabled by default */ - private static final boolean RETRY_CONNECT = retryConnect(); + private static final boolean RETRY_CONNECT = !disableRetryConnect(); /** Returns true is given request has an idempotent method. */ private static boolean isIdempotentRequest(HttpRequest request) { @@ -415,10 +457,13 @@ private CompletableFuture getExceptionalCF(Throwable t) { Throwable cause = retryCause(t); if (!(t instanceof ConnectException)) { + // we may need to start a new connection, and if so + // we want to start with a fresh connect timeout again. + if (connectTimeout != null) connectTimeout.reset(); if (!canRetryRequest(currentreq)) { return failedFuture(cause); // fails with original cause } - } + } // ConnectException: retry, but don't reset the connectTimeout. // allow the retry mechanism to do its work retryCause = cause; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java index d9db165bcea..3256e3c6d36 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -65,7 +65,7 @@ class PlainHttpConnection extends HttpConnection { */ private ConnectTimerEvent newConnectTimer(Exchange exchange, CompletableFuture cf) { - Duration duration = client().connectTimeout().orElse(null); + Duration duration = exchange.remainingConnectTimeout().orElse(null); if (duration != null) { ConnectTimerEvent cte = new ConnectTimerEvent(duration, exchange, cf); return cte; diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java index edfce9f13dc..dcdbce3c506 100644 --- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java +++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosPrincipal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -80,6 +80,11 @@ public final class KerberosPrincipal public static final int KRB_NT_UID = 5; + /** + * Enterprise name (alias) + */ + public static final int KRB_NT_ENTERPRISE = 10; + private transient String fullName; private transient String realm; diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java b/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java index 027b125d9fd..687ff3d79b4 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -218,7 +218,7 @@ boolean isEqual(Checksum cksum) throws KdcErrException { * @exception IOException if an I/O error occurs while reading encoded data. * */ - private Checksum(DerValue encoding) throws Asn1Exception, IOException { + public Checksum(DerValue encoding) throws Asn1Exception, IOException { DerValue der; if (encoding.getTag() != DerValue.tag_Sequence) { throw new Asn1Exception(Krb5.ASN1_BAD_ID); diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/Config.java b/src/java.security.jgss/share/classes/sun/security/krb5/Config.java index 05fcb63345a..f3fda25767b 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/Config.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Config.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ import sun.net.dns.ResolverConfiguration; import sun.security.krb5.internal.crypto.EType; import sun.security.krb5.internal.Krb5; +import sun.security.util.SecurityProperties; /** * This class maintains key-value pairs of Kerberos configurable constants @@ -55,6 +56,41 @@ public class Config { + /** + * {@systemProperty sun.security.krb5.disableReferrals} property + * indicating whether or not cross-realm referrals (RFC 6806) are + * enabled. + */ + public static final boolean DISABLE_REFERRALS; + + /** + * {@systemProperty sun.security.krb5.maxReferrals} property + * indicating the maximum number of cross-realm referral + * hops allowed. + */ + public static final int MAX_REFERRALS; + + static { + String disableReferralsProp = + SecurityProperties.privilegedGetOverridable( + "sun.security.krb5.disableReferrals"); + if (disableReferralsProp != null) { + DISABLE_REFERRALS = "true".equalsIgnoreCase(disableReferralsProp); + } else { + DISABLE_REFERRALS = false; + } + + int maxReferralsValue = 5; + String maxReferralsProp = + SecurityProperties.privilegedGetOverridable( + "sun.security.krb5.maxReferrals"); + try { + maxReferralsValue = Integer.parseInt(maxReferralsProp); + } catch (NumberFormatException e) { + } + MAX_REFERRALS = maxReferralsValue; + } + /* * Only allow a single instance of Config. */ diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java index 1d5febdf41d..d647b82ab16 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsRep.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -155,11 +155,11 @@ private void decrypt(EncryptionKey dkey, KrbAsReq asReq) rep.encKDCRepPart = enc_part; ASReq req = asReq.getMessage(); - check(true, req, rep); + check(true, req, rep, dkey); creds = new Credentials( rep.ticket, - req.reqBody.cname, + rep.cname, enc_part.sname, enc_part.key, enc_part.flags, diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReq.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReq.java index 01fdb9bbb33..19e3ef61076 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReq.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReq.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import sun.security.krb5.internal.crypto.KeyUsage; import java.io.IOException; import java.time.Instant; +import java.util.Arrays; /** * This class encapsulates the KRB-AS-REQ message that the client @@ -58,7 +59,8 @@ public KrbAsReq(EncryptionKey pakey, // ok KerberosTime till, // ok, will use KerberosTime rtime, // ok int[] eTypes, // NO - HostAddresses addresses // ok + HostAddresses addresses, // ok + PAData[] extraPAs // ok ) throws KrbException, IOException { @@ -93,6 +95,15 @@ public KrbAsReq(EncryptionKey pakey, // ok paData[0] = new PAData( Krb5.PA_ENC_TIMESTAMP, encTs.asn1Encode()); } + if (extraPAs != null && extraPAs.length > 0) { + if (paData == null) { + paData = new PAData[extraPAs.length]; + } else { + paData = Arrays.copyOf(paData, paData.length + extraPAs.length); + } + System.arraycopy(extraPAs, 0, paData, + paData.length - extraPAs.length, extraPAs.length); + } if (cname.getRealm() == null) { throw new RealmException(Krb5.REALM_NULL, diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java index 953bb557041..5c434b54efa 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAsReqBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2019, 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 @@ -262,7 +262,9 @@ public void setAddresses(HostAddresses addresses) { * @throws KrbException * @throws IOException */ - private KrbAsReq build(EncryptionKey key) throws KrbException, IOException { + private KrbAsReq build(EncryptionKey key, ReferralsState referralsState) + throws KrbException, IOException { + PAData[] extraPAs = null; int[] eTypes; if (password != null) { eTypes = EType.getDefaults("default_tkt_enctypes"); @@ -272,6 +274,14 @@ private KrbAsReq build(EncryptionKey key) throws KrbException, IOException { ks); for (EncryptionKey k: ks) k.destroy(); } + options = (options == null) ? new KDCOptions() : options; + if (referralsState.isEnabled()) { + options.set(KDCOptions.CANONICALIZE, true); + extraPAs = new PAData[]{ new PAData(Krb5.PA_REQ_ENC_PA_REP, + new byte[]{}) }; + } else { + options.set(KDCOptions.CANONICALIZE, false); + } return new KrbAsReq(key, options, cname, @@ -280,7 +290,8 @@ private KrbAsReq build(EncryptionKey key) throws KrbException, IOException { till, rtime, eTypes, - addresses); + addresses, + extraPAs); } /** @@ -318,11 +329,15 @@ private KrbAsReqBuilder resolve() */ private KrbAsReqBuilder send() throws KrbException, IOException { boolean preAuthFailedOnce = false; - KdcComm comm = new KdcComm(cname.getRealmAsString()); + KdcComm comm = null; EncryptionKey pakey = null; + ReferralsState referralsState = new ReferralsState(); while (true) { + if (referralsState.refreshComm()) { + comm = new KdcComm(cname.getRealmAsString()); + } try { - req = build(pakey); + req = build(pakey, referralsState); rep = new KrbAsRep(comm.send(req.encoding())); return this; } catch (KrbException ke) { @@ -351,12 +366,69 @@ private KrbAsReqBuilder send() throws KrbException, IOException { } paList = kerr.getPA(); // Update current paList } else { + if (referralsState.handleError(ke)) { + continue; + } throw ke; } } } } + private final class ReferralsState { + private boolean enabled; + private int count; + private boolean refreshComm; + + ReferralsState() throws KrbException { + if (Config.DISABLE_REFERRALS) { + if (cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) { + throw new KrbException("NT-ENTERPRISE principals only allowed" + + " when referrals are enabled."); + } + enabled = false; + } else { + enabled = true; + } + refreshComm = true; + } + + boolean handleError(KrbException ke) throws RealmException { + if (enabled) { + if (ke.returnCode() == Krb5.KRB_ERR_WRONG_REALM) { + Realm referredRealm = ke.getError().getClientRealm(); + if (req.getMessage().reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) && + referredRealm != null && referredRealm.toString().length() > 0 && + count < Config.MAX_REFERRALS) { + cname = new PrincipalName(cname.getNameType(), + cname.getNameStrings(), referredRealm); + refreshComm = true; + count++; + return true; + } + } + if (count < Config.MAX_REFERRALS && + cname.getNameType() != PrincipalName.KRB_NT_ENTERPRISE) { + // Server may raise an error if CANONICALIZE is true. + // Try CANONICALIZE false. + enabled = false; + return true; + } + } + return false; + } + + boolean refreshComm() { + boolean retRefreshComm = refreshComm; + refreshComm = false; + return retRefreshComm; + } + + boolean isEnabled() { + return enabled; + } + } + /** * Performs AS-REQ send and AS-REP receive. * Maybe a state is needed here, to divide prepare process and getCreds. diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java index c4a04b1d86c..4f91c2ef3ef 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java @@ -31,23 +31,41 @@ package sun.security.krb5; import sun.security.krb5.internal.*; +import sun.security.krb5.internal.crypto.KeyUsage; +import sun.security.util.DerInputStream; abstract class KrbKdcRep { static void check( boolean isAsReq, KDCReq req, - KDCRep rep + KDCRep rep, + EncryptionKey replyKey ) throws KrbApErrException { - if (isAsReq && !req.reqBody.cname.equals(rep.cname)) { + // cname change in AS-REP is allowed only if the client + // sent CANONICALIZE and the server supports RFC 6806 - Section 11 + // FAST scheme (ENC-PA-REP flag). + if (isAsReq && !req.reqBody.cname.equals(rep.cname) && + (!req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) || + !rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP))) { rep.encKDCRepPart.key.destroy(); throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); } + // sname change in TGS-REP is allowed only if client + // sent CANONICALIZE and new sname is a referral of + // the form krbtgt/TO-REALM.COM@FROM-REALM.COM. if (!req.reqBody.sname.equals(rep.encKDCRepPart.sname)) { - rep.encKDCRepPart.key.destroy(); - throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); + String[] snameStrings = rep.encKDCRepPart.sname.getNameStrings(); + if (isAsReq || !req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) || + snameStrings == null || snameStrings.length != 2 || + !snameStrings[0].equals(PrincipalName.TGS_DEFAULT_SRV_NAME) || + !rep.encKDCRepPart.sname.getRealmString().equals( + req.reqBody.sname.getRealmString())) { + rep.encKDCRepPart.key.destroy(); + throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); + } } if (req.reqBody.getNonce() != rep.encKDCRepPart.nonce) { @@ -118,5 +136,45 @@ static void check( } } } + + // RFC 6806 - Section 11 mechanism check + if (rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP) && + req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE)) { + boolean reqPaReqEncPaRep = false; + boolean repPaReqEncPaRepValid = false; + + // PA_REQ_ENC_PA_REP only required for AS requests + for (PAData pa : req.pAData) { + if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) { + reqPaReqEncPaRep = true; + break; + } + } + + if (rep.encKDCRepPart.pAData != null) { + for (PAData pa : rep.encKDCRepPart.pAData) { + if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) { + try { + Checksum repCksum = new Checksum( + new DerInputStream( + pa.getValue()).getDerValue()); + repPaReqEncPaRepValid = + repCksum.verifyKeyedChecksum( + req.asn1Encode(), replyKey, + KeyUsage.KU_AS_REQ); + } catch (Exception e) { + if (Krb5.DEBUG) { + e.printStackTrace(); + } + } + break; + } + } + } + + if (reqPaReqEncPaRep && !repPaReqEncPaRepValid) { + throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); + } + } } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsRep.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsRep.java index c0e6ef8f0fe..d1f469d37ab 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsRep.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsRep.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -84,7 +84,7 @@ public class KrbTgsRep extends KrbKdcRep { EncTGSRepPart enc_part = new EncTGSRepPart(ref); rep.encKDCRepPart = enc_part; - check(false, req, rep); + check(false, req, rep, tgsReq.tgsReqKey); this.creds = new Credentials(rep.ticket, rep.cname, diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java index 191eb8cd592..02d14a9e39f 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import java.io.IOException; import java.net.UnknownHostException; import java.time.Instant; +import java.util.Arrays; /** * This class encapsulates a Kerberos TGS-REQ that is sent from the @@ -57,59 +58,23 @@ public class KrbTgsReq { private byte[] ibuf; // Used in CredentialsUtil - public KrbTgsReq(Credentials asCreds, - PrincipalName sname) + public KrbTgsReq(KDCOptions options, Credentials asCreds, + PrincipalName cname, PrincipalName sname, + Ticket[] additionalTickets, PAData[] extraPAs) throws KrbException, IOException { - this(new KDCOptions(), - asCreds, - sname, - null, // KerberosTime from - null, // KerberosTime till - null, // KerberosTime rtime - null, // eTypes, // null, // int[] eTypes - null, // HostAddresses addresses - null, // AuthorizationData authorizationData - null, // Ticket[] additionalTickets - null); // EncryptionKey subSessionKey - } - - // S4U2proxy - public KrbTgsReq(Credentials asCreds, - Ticket second, - PrincipalName sname) - throws KrbException, IOException { - this(KDCOptions.with(KDCOptions.CNAME_IN_ADDL_TKT, - KDCOptions.FORWARDABLE), - asCreds, - sname, - null, - null, - null, - null, - null, - null, - new Ticket[] {second}, // the service ticket - null); - } - - // S4U2user - public KrbTgsReq(Credentials asCreds, - PrincipalName sname, - PAData extraPA) - throws KrbException, IOException { - this(KDCOptions.with(KDCOptions.FORWARDABLE), - asCreds, - asCreds.getClient(), - sname, - null, - null, - null, - null, - null, - null, - null, - null, - extraPA); // the PA-FOR-USER + this(options, + asCreds, + cname, + sname, + null, // KerberosTime from + null, // KerberosTime till + null, // KerberosTime rtime + null, // int[] eTypes + null, // HostAddresses addresses + null, // AuthorizationData authorizationData + additionalTickets, + null, // EncryptionKey subKey + extraPAs); } // Called by Credentials, KrbCred @@ -143,7 +108,7 @@ private KrbTgsReq( AuthorizationData authorizationData, Ticket[] additionalTickets, EncryptionKey subKey, - PAData extraPA) throws KrbException, IOException { + PAData[] extraPAs) throws KrbException, IOException { princName = cname; servName = sname; @@ -216,7 +181,7 @@ private KrbTgsReq( authorizationData, additionalTickets, subKey, - extraPA); + extraPAs); obuf = tgsReqMessg.asn1Encode(); // XXX We need to revisit this to see if can't move it @@ -282,7 +247,7 @@ private TGSReq createRequest( AuthorizationData authorizationData, Ticket[] additionalTickets, EncryptionKey subKey, - PAData extraPA) + PAData[] extraPAs) throws IOException, KrbException, UnknownHostException { KerberosTime req_till = null; if (till == null) { @@ -382,11 +347,14 @@ private TGSReq createRequest( null).getMessage(); PAData tgsPAData = new PAData(Krb5.PA_TGS_REQ, tgs_ap_req); - return new TGSReq( - extraPA != null ? - new PAData[] {extraPA, tgsPAData } : - new PAData[] {tgsPAData}, - reqBody); + PAData[] pa; + if (extraPAs != null) { + pa = Arrays.copyOf(extraPAs, extraPAs.length + 1); + pa[extraPAs.length] = tgsPAData; + } else { + pa = new PAData[] {tgsPAData}; + } + return new TGSReq(pa, reqBody); } TGSReq getMessage() { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java b/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java index b3a0e8bea38..577c5e4633e 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -90,6 +90,11 @@ public class PrincipalName implements Cloneable { */ public static final int KRB_NT_UID = 5; + /** + * Enterprise name (alias) + */ + public static final int KRB_NT_ENTERPRISE = 10; + /** * TGS Name */ @@ -454,6 +459,7 @@ public PrincipalName(String name, int type, String realm) case KRB_NT_SRV_INST: case KRB_NT_SRV_XHST: case KRB_NT_UID: + case KRB_NT_ENTERPRISE: nameStrings = nameParts; nameType = type; if (realm != null) { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java index 14620e94483..25e29387a2f 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,8 @@ import sun.security.krb5.*; import java.io.IOException; +import java.util.LinkedList; +import java.util.List; /** * This class is a utility that contains much of the TGS-Exchange @@ -61,13 +63,11 @@ public static Credentials acquireS4U2selfCreds(PrincipalName client, if (!ccreds.isForwardable()) { throw new KrbException("S4U2self needs a FORWARDABLE ticket"); } - KrbTgsReq req = new KrbTgsReq( - ccreds, - ccreds.getClient(), - new PAData(Krb5.PA_FOR_USER, - new PAForUserEnc(client, - ccreds.getSessionKey()).asn1Encode())); - Credentials creds = req.sendAndGetCreds(); + Credentials creds = serviceCreds(KDCOptions.with(KDCOptions.FORWARDABLE), + ccreds, ccreds.getClient(), ccreds.getClient(), null, + new PAData[] {new PAData(Krb5.PA_FOR_USER, + new PAForUserEnc(client, + ccreds.getSessionKey()).asn1Encode())}); if (!creds.getClient().equals(client)) { throw new KrbException("S4U2self request not honored by KDC"); } @@ -89,11 +89,10 @@ public static Credentials acquireS4U2proxyCreds( String backend, Ticket second, PrincipalName client, Credentials ccreds) throws KrbException, IOException { - KrbTgsReq req = new KrbTgsReq( - ccreds, - second, - new PrincipalName(backend)); - Credentials creds = req.sendAndGetCreds(); + Credentials creds = serviceCreds(KDCOptions.with( + KDCOptions.CNAME_IN_ADDL_TKT, KDCOptions.FORWARDABLE), + ccreds, ccreds.getClient(), new PrincipalName(backend), + new Ticket[] {second}, null); if (!creds.getClient().equals(client)) { throw new KrbException("S4U2proxy request not honored by KDC"); } @@ -114,53 +113,9 @@ public static Credentials acquireS4U2proxyCreds( public static Credentials acquireServiceCreds( String service, Credentials ccreds) throws KrbException, IOException { - PrincipalName sname = new PrincipalName(service); - String serviceRealm = sname.getRealmString(); - String localRealm = ccreds.getClient().getRealmString(); - - if (localRealm.equals(serviceRealm)) { - if (DEBUG) { - System.out.println( - ">>> Credentials acquireServiceCreds: same realm"); - } - return serviceCreds(sname, ccreds); - } - Credentials theCreds = null; - - boolean[] okAsDelegate = new boolean[1]; - Credentials theTgt = getTGTforRealm(localRealm, serviceRealm, - ccreds, okAsDelegate); - if (theTgt != null) { - if (DEBUG) { - System.out.println(">>> Credentials acquireServiceCreds: " - + "got right tgt"); - System.out.println(">>> Credentials acquireServiceCreds: " - + "obtaining service creds for " + sname); - } - - try { - theCreds = serviceCreds(sname, theTgt); - } catch (Exception exc) { - if (DEBUG) { - System.out.println(exc); - } - theCreds = null; - } - } - - if (theCreds != null) { - if (DEBUG) { - System.out.println(">>> Credentials acquireServiceCreds: " - + "returning creds:"); - Credentials.printDebug(theCreds); - } - if (!okAsDelegate[0]) { - theCreds.resetDelegate(); - } - return theCreds; - } - throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED, - "No service creds"); + PrincipalName sname = new PrincipalName(service, + PrincipalName.KRB_NT_SRV_HST); + return serviceCreds(sname, ccreds); } /** @@ -305,6 +260,148 @@ private static Credentials getTGTforRealm(String localRealm, private static Credentials serviceCreds( PrincipalName service, Credentials ccreds) throws KrbException, IOException { - return new KrbTgsReq(ccreds, service).sendAndGetCreds(); + return serviceCreds(new KDCOptions(), ccreds, + ccreds.getClient(), service, null, null); + } + + /* + * Obtains credentials for a service (TGS). + * Cross-realm referrals are handled if enabled. A fallback scheme + * without cross-realm referrals supports is used in case of server + * error to maintain backward compatibility. + */ + private static Credentials serviceCreds( + KDCOptions options, Credentials asCreds, + PrincipalName cname, PrincipalName sname, + Ticket[] additionalTickets, PAData[] extraPAs) + throws KrbException, IOException { + if (!Config.DISABLE_REFERRALS) { + try { + return serviceCredsReferrals(options, asCreds, + cname, sname, additionalTickets, extraPAs); + } catch (KrbException e) { + // Server may raise an error if CANONICALIZE is true. + // Try CANONICALIZE false. + } + } + return serviceCredsSingle(options, asCreds, + cname, sname, additionalTickets, extraPAs); + } + + /* + * Obtains credentials for a service (TGS). + * May handle and follow cross-realm referrals as defined by RFC 6806. + */ + private static Credentials serviceCredsReferrals( + KDCOptions options, Credentials asCreds, + PrincipalName cname, PrincipalName sname, + Ticket[] additionalTickets, PAData[] extraPAs) + throws KrbException, IOException { + options = new KDCOptions(options.toBooleanArray()); + options.set(KDCOptions.CANONICALIZE, true); + PrincipalName cSname = sname; + Credentials creds = null; + boolean isReferral = false; + List referrals = new LinkedList<>(); + while (referrals.size() <= Config.MAX_REFERRALS) { + ReferralsCache.ReferralCacheEntry ref = + ReferralsCache.get(sname, cSname.getRealmString()); + String toRealm = null; + if (ref == null) { + creds = serviceCredsSingle(options, asCreds, + cname, cSname, additionalTickets, extraPAs); + PrincipalName server = creds.getServer(); + if (!cSname.equals(server)) { + String[] serverNameStrings = server.getNameStrings(); + if (serverNameStrings.length == 2 && + serverNameStrings[0].equals( + PrincipalName.TGS_DEFAULT_SRV_NAME) && + !cSname.getRealmAsString().equals(serverNameStrings[1])) { + // Server Name (sname) has the following format: + // krbtgt/TO-REALM.COM@FROM-REALM.COM + ReferralsCache.put(sname, server.getRealmString(), + serverNameStrings[1], creds); + toRealm = serverNameStrings[1]; + isReferral = true; + asCreds = creds; + } + } + } else { + toRealm = ref.getToRealm(); + asCreds = ref.getCreds(); + isReferral = true; + } + if (isReferral) { + if (referrals.contains(toRealm)) { + // Referrals loop detected + return null; + } + cSname = new PrincipalName(cSname.getNameString(), + cSname.getNameType(), toRealm); + referrals.add(toRealm); + isReferral = false; + continue; + } + break; + } + return creds; + } + + /* + * Obtains credentials for a service (TGS). + * If the service realm is different than the one in the TGT, a new TGT for + * the service realm is obtained first (see getTGTforRealm call). This is + * not expected when following cross-realm referrals because the referral + * TGT realm matches the service realm. + */ + private static Credentials serviceCredsSingle( + KDCOptions options, Credentials asCreds, + PrincipalName cname, PrincipalName sname, + Ticket[] additionalTickets, PAData[] extraPAs) + throws KrbException, IOException { + Credentials theCreds = null; + boolean[] okAsDelegate = new boolean[]{true}; + String[] serverAsCredsNames = asCreds.getServer().getNameStrings(); + String tgtRealm = serverAsCredsNames[1]; + String serviceRealm = sname.getRealmString(); + if (!serviceRealm.equals(tgtRealm)) { + // This is a cross-realm service request + if (DEBUG) { + System.out.println(">>> serviceCredsSingle:" + + " cross-realm authentication"); + System.out.println(">>> serviceCredsSingle:" + + " obtaining credentials from " + tgtRealm + + " to " + serviceRealm); + } + Credentials newTgt = getTGTforRealm(tgtRealm, serviceRealm, + asCreds, okAsDelegate); + if (newTgt == null) { + throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED, + "No service creds"); + } + if (DEBUG) { + System.out.println(">>> Cross-realm TGT Credentials" + + " serviceCredsSingle: "); + Credentials.printDebug(newTgt); + } + asCreds = newTgt; + cname = asCreds.getClient(); + } else if (DEBUG) { + System.out.println(">>> Credentials serviceCredsSingle:" + + " same realm"); + } + KrbTgsReq req = new KrbTgsReq(options, asCreds, + cname, sname, additionalTickets, extraPAs); + theCreds = req.sendAndGetCreds(); + if (theCreds != null) { + if (DEBUG) { + System.out.println(">>> TGS credentials serviceCredsSingle:"); + Credentials.printDebug(theCreds); + } + if (!okAsDelegate[0]) { + theCreds.resetDelegate(); + } + } + return theCreds; } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncASRepPart.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncASRepPart.java index 7e5d037de5d..ff9382e83f4 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncASRepPart.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncASRepPart.java @@ -47,7 +47,8 @@ public EncASRepPart( KerberosTime new_endtime, KerberosTime new_renewTill, PrincipalName new_sname, - HostAddresses new_caddr) { + HostAddresses new_caddr, + PAData[] new_pAData) { super( new_key, new_lastReq, @@ -60,6 +61,7 @@ public EncASRepPart( new_renewTill, new_sname, new_caddr, + new_pAData, Krb5.KRB_ENC_AS_REP_PART ); //may need to use Krb5.KRB_ENC_TGS_REP_PART to mimic diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKDCRepPart.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKDCRepPart.java index 19d26b725db..9db87e27bfb 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKDCRepPart.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKDCRepPart.java @@ -31,7 +31,6 @@ package sun.security.krb5.internal; import sun.security.krb5.*; -import sun.security.krb5.EncryptionKey; import sun.security.util.*; import java.util.Vector; import java.io.IOException; @@ -41,19 +40,20 @@ * Implements the ASN.1 EncKDCRepPart type. * *
{@code
- * EncKDCRepPart        ::= SEQUENCE {
- *      key             [0] EncryptionKey,
- *      last-req        [1] LastReq,
- *      nonce           [2] UInt32,
- *      key-expiration  [3] KerberosTime OPTIONAL,
- *      flags           [4] TicketFlags,
- *      authtime        [5] KerberosTime,
- *      starttime       [6] KerberosTime OPTIONAL,
- *      endtime         [7] KerberosTime,
- *      renew-till      [8] KerberosTime OPTIONAL,
- *      srealm          [9] Realm,
- *      sname           [10] PrincipalName,
- *      caddr           [11] HostAddresses OPTIONAL
+ * EncKDCRepPart          ::= SEQUENCE {
+ *      key               [0] EncryptionKey,
+ *      last-req          [1] LastReq,
+ *      nonce             [2] UInt32,
+ *      key-expiration    [3] KerberosTime OPTIONAL,
+ *      flags             [4] TicketFlags,
+ *      authtime          [5] KerberosTime,
+ *      starttime         [6] KerberosTime OPTIONAL,
+ *      endtime           [7] KerberosTime,
+ *      renew-till        [8] KerberosTime OPTIONAL,
+ *      srealm            [9] Realm,
+ *      sname             [10] PrincipalName,
+ *      caddr             [11] HostAddresses OPTIONAL,
+ *      encrypted-pa-data [12] SEQUENCE OF PA-DATA OPTIONAL
  * }
  * }
* @@ -76,6 +76,7 @@ public class EncKDCRepPart { public KerberosTime renewTill; //optional public PrincipalName sname; public HostAddresses caddr; //optional + public PAData[] pAData; //optional public int msgType; //not included in sequence public EncKDCRepPart( @@ -90,6 +91,7 @@ public EncKDCRepPart( KerberosTime new_renewTill, PrincipalName new_sname, HostAddresses new_caddr, + PAData[] new_pAData, int new_msgType) { key = new_key; lastReq = new_lastReq; @@ -102,6 +104,7 @@ public EncKDCRepPart( renewTill = new_renewTill; sname = new_sname; caddr = new_caddr; + pAData = new_pAData; msgType = new_msgType; } @@ -160,6 +163,9 @@ protected void init(DerValue encoding, int rep_type) if (der.getData().available() > 0) { caddr = HostAddresses.parse(der.getData(), (byte) 0x0B, true); } + if (der.getData().available() > 0) { + pAData = PAData.parseSequence(der.getData(), (byte) 0x0C, true); + } // We observe extra data from MSAD /*if (der.getData().available() > 0) { throw new Asn1Exception(Krb5.ASN1_BAD_ID); @@ -175,47 +181,58 @@ protected void init(DerValue encoding, int rep_type) */ public byte[] asn1Encode(int rep_type) throws Asn1Exception, IOException { + DerOutputStream bytes; DerOutputStream temp = new DerOutputStream(); - DerOutputStream bytes = new DerOutputStream(); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + DerOutputStream out = new DerOutputStream(); + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x00), key.asn1Encode()); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x01), lastReq.asn1Encode()); temp.putInteger(BigInteger.valueOf(nonce)); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x02), temp); if (keyExpiration != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x03), keyExpiration.asn1Encode()); } - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x04), flags.asn1Encode()); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x05), authtime.asn1Encode()); if (starttime != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x06), starttime.asn1Encode()); } - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x07), endtime.asn1Encode()); if (renewTill != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x08), renewTill.asn1Encode()); } - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x09), sname.getRealm().asn1Encode()); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x0A), sname.asn1Encode()); if (caddr != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x0B), caddr.asn1Encode()); } + if (pAData != null && pAData.length > 0) { + temp = new DerOutputStream(); + for (int i = 0; i < pAData.length; i++) { + temp.write(pAData[i].asn1Encode()); + } + bytes = new DerOutputStream(); + bytes.write(DerValue.tag_SequenceOf, temp); + out.write(DerValue.createTag(DerValue.TAG_CONTEXT, + true, (byte) 0x0C), bytes); + } //should use the rep_type to build the encoding //but other implementations do not; it is ignored and //the cached msgType is used instead temp = new DerOutputStream(); - temp.write(DerValue.tag_Sequence, bytes); + temp.write(DerValue.tag_Sequence, out); bytes = new DerOutputStream(); bytes.write(DerValue.createTag(DerValue.TAG_APPLICATION, true, (byte) msgType), temp); diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncTGSRepPart.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncTGSRepPart.java index cdca881ebe4..b1f192e72e4 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncTGSRepPart.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncTGSRepPart.java @@ -46,7 +46,8 @@ public EncTGSRepPart( KerberosTime new_endtime, KerberosTime new_renewTill, PrincipalName new_sname, - HostAddresses new_caddr) { + HostAddresses new_caddr, + PAData[] new_pAData) { super( new_key, new_lastReq, @@ -59,6 +60,7 @@ public EncTGSRepPart( new_renewTill, new_sname, new_caddr, + new_pAData, Krb5.KRB_ENC_TGS_REP_PART); } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCOptions.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCOptions.java index 7cd666390f8..76a71cb603c 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCOptions.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCOptions.java @@ -140,6 +140,7 @@ public class KDCOptions extends KerberosFlags { public static final int UNUSED10 = 10; public static final int UNUSED11 = 11; public static final int CNAME_IN_ADDL_TKT = 14; + public static final int CANONICALIZE = 15; public static final int RENEWABLE_OK = 27; public static final int ENC_TKT_IN_SKEY = 28; public static final int RENEW = 30; @@ -160,7 +161,8 @@ public class KDCOptions extends KerberosFlags { "UNUSED11", //11; null,null, "CNAME_IN_ADDL_TKT",//14; - null,null,null,null,null,null,null,null,null,null,null,null, + "CANONICALIZE", //15; + null,null,null,null,null,null,null,null,null,null,null, "RENEWABLE_OK", //27; "ENC_TKT_IN_SKEY", //28; null, diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReq.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReq.java index 1aeab385e6e..39e226a8de2 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReq.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReq.java @@ -59,9 +59,9 @@ public class KDCReq { public KDCReqBody reqBody; + public PAData[] pAData = null; //optional private int pvno; private int msgType; - private PAData[] pAData = null; //optional public KDCReq(PAData[] new_pAData, KDCReqBody new_reqBody, int req_type) throws IOException { @@ -144,23 +144,7 @@ protected void init(DerValue encoding, int req_type) throws Asn1Exception, } else { throw new Asn1Exception(Krb5.ASN1_BAD_ID); } - if ((der.getData().peekByte() & 0x1F) == 0x03) { - subDer = der.getData().getDerValue(); - DerValue subsubDer = subDer.getData().getDerValue(); - if (subsubDer.getTag() != DerValue.tag_SequenceOf) { - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - Vector v = new Vector<>(); - while (subsubDer.getData().available() > 0) { - v.addElement(new PAData(subsubDer.getData().getDerValue())); - } - if (v.size() > 0) { - pAData = new PAData[v.size()]; - v.copyInto(pAData); - } - } else { - pAData = null; - } + pAData = PAData.parseSequence(der.getData(), (byte) 0x03, true); subDer = der.getData().getDerValue(); if ((subDer.getTag() & 0x01F) == 0x04) { DerValue subsubDer = subDer.getData().getDerValue(); diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java index 2a885e4f591..ba43305fccb 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -90,6 +90,7 @@ public class KRBError implements java.io.Serializable { private KerberosTime sTime; private Integer suSec; private int errorCode; + private Realm crealm; //optional private PrincipalName cname; //optional private PrincipalName sname; private String eText; //optional @@ -138,6 +139,7 @@ public KRBError( sTime = new_sTime; suSec = new_suSec; errorCode = new_errorCode; + crealm = new_cname.getRealm(); cname = new_cname; sname = new_sname; eText = new_eText; @@ -166,6 +168,7 @@ public KRBError( sTime = new_sTime; suSec = new_suSec; errorCode = new_errorCode; + crealm = new_cname.getRealm(); cname = new_cname; sname = new_sname; eText = new_eText; @@ -262,6 +265,10 @@ private void parsePAData(byte[] data) pa = paList.toArray(new PAData[paList.size()]); } + public final Realm getClientRealm() { + return crealm; + } + public final KerberosTime getServerTime() { return sTime; } @@ -349,7 +356,7 @@ private void init(DerValue encoding) throws Asn1Exception, errorCode = subDer.getData().getBigInteger().intValue(); } else throw new Asn1Exception(Krb5.ASN1_BAD_ID); - Realm crealm = Realm.parse(der.getData(), (byte)0x07, true); + crealm = Realm.parse(der.getData(), (byte)0x07, true); cname = PrincipalName.parse(der.getData(), (byte)0x08, true, crealm); Realm realm = Realm.parse(der.getData(), (byte)0x09, false); sname = PrincipalName.parse(der.getData(), (byte)0x0A, false, realm); @@ -393,6 +400,9 @@ private void showDebug() { System.out.println("\t suSec is " + suSec); System.out.println("\t error code is " + errorCode); System.out.println("\t error Message is " + Krb5.getErrorMessage(errorCode)); + if (crealm != null) { + System.out.println("\t crealm is " + crealm.toString()); + } if (cname != null) { System.out.println("\t cname is " + cname.toString()); } @@ -442,8 +452,10 @@ public byte[] asn1Encode() throws Asn1Exception, IOException { temp.putInteger(BigInteger.valueOf(errorCode)); bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x06), temp); + if (crealm != null) { + bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x07), crealm.asn1Encode()); + } if (cname != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x07), cname.getRealm().asn1Encode()); bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x08), cname.asn1Encode()); } @@ -488,6 +500,7 @@ public byte[] asn1Encode() throws Asn1Exception, IOException { isEqual(sTime, other.sTime) && isEqual(suSec, other.suSec) && errorCode == other.errorCode && + isEqual(crealm, other.crealm) && isEqual(cname, other.cname) && isEqual(sname, other.sname) && isEqual(eText, other.eText) && @@ -508,6 +521,7 @@ private static boolean isEqual(Object a, Object b) { if (sTime != null) result = 37 * result + sTime.hashCode(); if (suSec != null) result = 37 * result + suSec.hashCode(); result = 37 * result + errorCode; + if (crealm != null) result = 37 * result + crealm.hashCode(); if (cname != null) result = 37 * result + cname.hashCode(); if (sname != null) result = 37 * result + sname.hashCode(); if (eText != null) result = 37 * result + eText.hashCode(); diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java index 0b9a12240a8..87861883b57 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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 @@ -70,6 +70,7 @@ public class Krb5 { public static final int TKT_OPTS_PRE_AUTHENT = 10; public static final int TKT_OPTS_HW_AUTHENT = 11; public static final int TKT_OPTS_DELEGATE = 13; + public static final int TKT_OPTS_ENC_PA_REP = 15; public static final int TKT_OPTS_MAX = 31; // KDC Options @@ -163,6 +164,9 @@ public class Krb5 { // S4U2user info public static final int PA_FOR_USER = 129; + // FAST (RFC 6806) + public static final int PA_REQ_ENC_PA_REP = 149; + //-------------------------------+------------- //authorization data type |ad-type value //-------------------------------+------------- @@ -265,6 +269,7 @@ public class Krb5 { public static final int KRB_ERR_RESPONSE_TOO_BIG = 52; //Response too big for UDP, retry with TCP public static final int KRB_ERR_GENERIC = 60; //Generic error (description in e-text) public static final int KRB_ERR_FIELD_TOOLONG = 61; //Field is too long for this implementation + public static final int KRB_ERR_WRONG_REALM = 68; //Wrong realm public static final int KRB_CRYPTO_NOT_SUPPORT = 100; //Client does not support this crypto type public static final int KRB_AP_ERR_NOREALM = 62; public static final int KRB_AP_ERR_GEN_CRED = 63; diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java index 55bc6f26220..830e1929b5e 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/PAData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019 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 @@ -35,6 +35,8 @@ import sun.security.util.*; import sun.security.krb5.Asn1Exception; import java.io.IOException; +import java.util.Vector; + import sun.security.krb5.internal.util.KerberosString; /** @@ -139,6 +141,41 @@ public byte[] getValue() { return ((pADataValue == null) ? null : pADataValue.clone()); } + /** + * Parse (unmarshal) a PAData from a DER input stream. This form + * parsing might be used when expanding a value which is part of + * a constructed sequence and uses explicitly tagged type. + * + * @exception Asn1Exception if an Asn1Exception occurs. + * @param data the Der input stream value, which contains one or more + * marshaled values. + * @param explicitTag tag number. + * @param optional indicates if this data field is optional. + * @return an array of PAData. + */ + public static PAData[] parseSequence(DerInputStream data, + byte explicitTag, boolean optional) + throws Asn1Exception, IOException { + if ((optional) && + (((byte)data.peekByte() & (byte)0x1F) != explicitTag)) + return null; + DerValue subDer = data.getDerValue(); + DerValue subsubDer = subDer.getData().getDerValue(); + if (subsubDer.getTag() != DerValue.tag_SequenceOf) { + throw new Asn1Exception(Krb5.ASN1_BAD_ID); + } + Vector v = new Vector<>(); + while (subsubDer.getData().available() > 0) { + v.addElement(new PAData(subsubDer.getData().getDerValue())); + } + if (v.size() > 0) { + PAData[] pas = new PAData[v.size()]; + v.copyInto(pas); + return pas; + } + return null; + } + /** * Gets the preferred etype from the PAData array. *
    diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/ReferralsCache.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ReferralsCache.java new file mode 100644 index 00000000000..d2118160005 --- /dev/null +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/ReferralsCache.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. + * 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 sun.security.krb5.internal; + +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import sun.security.krb5.Credentials; +import sun.security.krb5.PrincipalName; + +/* + * ReferralsCache class implements a cache scheme for referral TGTs as + * described in RFC 6806 - 10. Caching Information. The goal is to optimize + * resources (such as network traffic) when a client requests credentials for a + * service principal to a given KDC. If a referral TGT was previously received, + * cached information is used instead of issuing a new query. Once a referral + * TGT expires, the corresponding referral entry in the cache is removed. + */ +final class ReferralsCache { + + private static Map> referralsMap = + new HashMap<>(); + + static final class ReferralCacheEntry { + private final Credentials creds; + private final String toRealm; + ReferralCacheEntry(Credentials creds, String toRealm) { + this.creds = creds; + this.toRealm = toRealm; + } + Credentials getCreds() { + return creds; + } + String getToRealm() { + return toRealm; + } + } + + /* + * Add a new referral entry to the cache, including: service principal, + * source KDC realm, destination KDC realm and referral TGT. + * + * If a loop is generated when adding the new referral, the first hop is + * automatically removed. For example, let's assume that adding a + * REALM-3.COM -> REALM-1.COM referral generates the following loop: + * REALM-1.COM -> REALM-2.COM -> REALM-3.COM -> REALM-1.COM. Then, + * REALM-1.COM -> REALM-2.COM referral entry is removed from the cache. + */ + static synchronized void put(PrincipalName service, + String fromRealm, String toRealm, Credentials creds) { + pruneExpired(service); + if (creds.getEndTime().before(new Date())) { + return; + } + Map entries = referralsMap.get(service); + if (entries == null) { + entries = new HashMap(); + referralsMap.put(service, entries); + } + entries.remove(fromRealm); + ReferralCacheEntry newEntry = new ReferralCacheEntry(creds, toRealm); + entries.put(fromRealm, newEntry); + + // Remove loops within the cache + ReferralCacheEntry current = newEntry; + List seen = new LinkedList<>(); + while (current != null) { + if (seen.contains(current)) { + // Loop found. Remove the first referral to cut the loop. + entries.remove(newEntry.getToRealm()); + break; + } + seen.add(current); + current = entries.get(current.getToRealm()); + } + } + + /* + * Obtain a referral entry from the cache given a service principal and a + * source KDC realm. + */ + static synchronized ReferralCacheEntry get(PrincipalName service, + String fromRealm) { + pruneExpired(service); + Map entries = referralsMap.get(service); + if (entries != null) { + ReferralCacheEntry toRef = entries.get(fromRealm); + if (toRef != null) { + return toRef; + } + } + return null; + } + + /* + * Remove referral entries from the cache when referral TGTs expire. + */ + private static void pruneExpired(PrincipalName service) { + Date now = new Date(); + Map entries = referralsMap.get(service); + if (entries != null) { + for (Entry mapEntry : + entries.entrySet()) { + if (mapEntry.getValue().getCreds().getEndTime().before(now)) { + entries.remove(mapEntry.getKey()); + } + } + } + } +} diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/TicketFlags.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/TicketFlags.java index 48961fac317..468796ae27c 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/TicketFlags.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/TicketFlags.java @@ -51,7 +51,8 @@ * renewable(8), * initial(9), * pre-authent(10), - * hw-authent(11) + * hw-authent(11), + * enc-pa-rep(15) * } */ public class TicketFlags extends KerberosFlags { @@ -178,6 +179,9 @@ public String toString() { case 11: sb.append("HW-AUTHENT;"); break; + case 15: + sb.append("ENC-PA-REP;"); + break; } } } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java index f9be46c9beb..5179f520024 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/KeyUsage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, 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 @@ -56,6 +56,7 @@ private KeyUsage() { public static final int KU_KRB_SAFE_CKSUM = 15; // KrbSafe public static final int KU_PA_FOR_USER_ENC_CKSUM = 17; // S4U2user public static final int KU_AD_KDC_ISSUED_CKSUM = 19; + public static final int KU_AS_REQ = 56; public static final boolean isValid(int usage) { return usage >= 0; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/CoreDocumentImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/CoreDocumentImpl.java index 94a83e5e2bd..05de2aff9b4 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/CoreDocumentImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/CoreDocumentImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -83,7 +83,7 @@ * @author Andy Clark, IBM * @author Ralf Pfeiffer, IBM * @since PR-DOM-Level-1-19980818. - * @LastModified: Nov 2018 + * @LastModified: Sept 2019 */ public class CoreDocumentImpl extends ParentNode implements Document { @@ -862,6 +862,9 @@ public String getEncoding() { * the version number of this document. */ public void setXmlVersion(String value) { + if (value == null) { + return; + } if(value.equals("1.0") || value.equals("1.1")){ //we need to change the flag value only -- // when the version set is different than already set. diff --git a/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c b/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c index bf0b21138f9..a21ce9fa73b 100644 --- a/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c +++ b/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c @@ -457,12 +457,11 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue if (pCode == NULL) { JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed"); VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE); + (*env)->ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT); return; } WriteProcessMemory( hProcess, (LPVOID)pCode, (LPCVOID)stubCode, (SIZE_T)stubLen, NULL ); - if (isCopy) { - (*env)->ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT); - } + (*env)->ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT); /* * Create thread in target process to execute code diff --git a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c index fe05a1d23cc..cfcd1394dfc 100644 --- a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c +++ b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c @@ -109,6 +109,7 @@ JNIEXPORT void JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect exceptionMessage = (char *) malloc(sizeof(char) * (strlen(systemErrorMessage) + strlen(libraryNameStr) + 1)); if (exceptionMessage == NULL) { throwOutOfMemoryError(env, 0); + (*env)->ReleaseStringUTFChars(env, jPkcs11ModulePath, libraryNameStr); return; } strcpy(exceptionMessage, systemErrorMessage); diff --git a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java index b40e67ee931..3f7b5917999 100644 --- a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java +++ b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java index 5fb37e25b04..e6163b0a074 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java @@ -40,6 +40,7 @@ import com.sun.jdi.connect.*; import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; import java.io.*; public class TTY implements EventNotifier { @@ -48,7 +49,7 @@ public class TTY implements EventNotifier { /** * List of Strings to execute at each stop. */ - private List monitorCommands = new ArrayList(); + private List monitorCommands = new CopyOnWriteArrayList<>(); private int monitorCount = 0; /** diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c index 07c38e6694e..625427b3bb5 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -1673,7 +1673,7 @@ setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue) /* Create jstrings for property name and value */ nameString = JNI_FUNC_PTR(env,NewStringUTF)(env, propertyName); if (nameString != NULL) { - valueString = JNI_FUNC_PTR(env,NewStringUTF)(env, propertyValue); + valueString = JNU_NewStringPlatform(env, propertyValue); if (valueString != NULL) { /* invoke Properties.setProperty */ JNI_FUNC_PTR(env,CallObjectMethod) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java b/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java index ca4b24839c4..d5ecca9464c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java @@ -291,7 +291,7 @@ public List getFields() { if (type.isSimpleType()) { return Collections.emptyList(); } - return Collections.unmodifiableList(type.getFields()); + return type.getFields(); } // package private diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java index 96319e2f4b4..ee6e00d6ecd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java @@ -53,7 +53,7 @@ final class ChunkParser { private final TimeConverter timeConverter; public ChunkParser(RecordingInput input) throws IOException { - this(new ChunkHeader(input)); + this(new ChunkHeader(input)); } private ChunkParser(ChunkHeader header) throws IOException { @@ -61,7 +61,7 @@ private ChunkParser(ChunkHeader header) throws IOException { this.chunkHeader = header; this.metadata = header.readMetadata(); this.absoluteChunkEnd = header.getEnd(); - this.timeConverter = new TimeConverter(chunkHeader); + this.timeConverter = new TimeConverter(chunkHeader, metadata.getGMTOffset()); ParserFactory factory = new ParserFactory(metadata, timeConverter); LongMap constantPools = factory.getConstantPools(); @@ -114,9 +114,7 @@ private void fillConstantPools(LongMap typeParser, LongMap boolean flush = input.readBoolean(); int poolCount = input.readInt(); Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, () -> { - return "New constant pool: startPosition=" + position + - ", size=" + size + ", deltaToNext=" + delta + - ", flush=" + flush + ", poolCount=" + poolCount; + return "New constant pool: startPosition=" + position + ", size=" + size + ", deltaToNext=" + delta + ", flush=" + flush + ", poolCount=" + poolCount; }); for (int i = 0; i < poolCount; i++) { @@ -155,7 +153,7 @@ private void fillConstantPools(LongMap typeParser, LongMap private String getName(long id) { Type type = typeMap.get(id); - return type == null ? ("unknown(" + id +")") : type.getName(); + return type == null ? ("unknown(" + id + ")") : type.getName(); } public Collection getTypes() { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java index bbcda7afc93..19691302b8c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java @@ -41,7 +41,8 @@ public final class RecordedEvent extends RecordedObject { private final EventType eventType; private final long startTime; - private final long endTime; + // package private needed for efficient sorting + final long endTime; // package private RecordedEvent(EventType type, List vds, Object[] values, long startTime, long endTime, TimeConverter timeConverter) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java index df1cc224228..5633c6068ce 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java @@ -25,11 +25,11 @@ package jdk.jfr.consumer; -import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.time.Duration; import java.time.Instant; +import java.time.OffsetDateTime; import java.util.List; import java.util.Objects; @@ -37,7 +37,7 @@ import jdk.jfr.Timestamp; import jdk.jfr.ValueDescriptor; import jdk.jfr.internal.PrivateAccess; -import jdk.jfr.internal.cmd.PrettyWriter; +import jdk.jfr.internal.tool.PrettyWriter; /** * A complex data type that consists of one or more fields. @@ -878,20 +878,25 @@ public final RecordedThread getThread(String name) { final public String toString() { StringWriter s = new StringWriter(); PrettyWriter p = new PrettyWriter(new PrintWriter(s)); - try { - if (this instanceof RecordedEvent) { - p.print((RecordedEvent) this); - } else { - p.print(this, ""); - } - - } catch (IOException e) { - // Ignore, should not happen with StringWriter + p.setStackDepth(5); + if (this instanceof RecordedEvent) { + p.print((RecordedEvent) this); + } else { + p.print(this, ""); } - p.flush(); + p.flush(true); return s.toString(); } + // package private for now. Used by EventWriter + OffsetDateTime getOffsetDateTime(String name) { + Instant instant = getInstant(name); + if (instant.equals(Instant.MIN)) { + return OffsetDateTime.MIN; + } + return OffsetDateTime.ofInstant(getInstant(name), timeConverter.getZoneOffset()); + } + private static IllegalArgumentException newIllegalArgumentException(String name, String typeName) { return new IllegalArgumentException("Attempt to get field \"" + name + "\" with illegal data type conversion " + typeName); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java index dde93ed81d8..901f2534a13 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java @@ -32,13 +32,16 @@ import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import jdk.jfr.EventType; import jdk.jfr.internal.MetadataDescriptor; +import jdk.jfr.internal.Type; import jdk.jfr.internal.consumer.ChunkHeader; import jdk.jfr.internal.consumer.RecordingInput; +import jdk.jfr.internal.consumer.RecordingInternals; /** * A recording file. @@ -59,7 +62,29 @@ * @since 9 */ public final class RecordingFile implements Closeable { + static{ + RecordingInternals.INSTANCE = new RecordingInternals() { + public List readTypes(RecordingFile file) throws IOException { + return file.readTypes(); + } + + public boolean isLastEventInChunk(RecordingFile file) { + return file.isLastEventInChunk; + } + + @Override + public Object getOffsetDataTime(RecordedObject event, String name) { + return event.getOffsetDateTime(name); + } + + @Override + public void sort(List events) { + Collections.sort(events, (e1, e2) -> Long.compare(e1.endTime, e2.endTime)); + } + }; + } + private boolean isLastEventInChunk; private final File file; private RecordingInput input; private ChunkParser chunkParser; @@ -98,9 +123,11 @@ public RecordedEvent readEvent() throws IOException { ensureOpen(); throw new EOFException(); } + isLastEventInChunk = false; RecordedEvent event = nextEvent; nextEvent = chunkParser.readEvent(); if (nextEvent == null) { + isLastEventInChunk = true; findNext(); } return event; @@ -129,6 +156,21 @@ public List readEventTypes() throws IOException { ensureOpen(); List types = new ArrayList<>(); HashSet foundIds = new HashSet<>(); + try (RecordingInput ri = new RecordingInput(file)) { + ChunkHeader ch = new ChunkHeader(ri); + aggregateEventTypeForChunk(ch, types, foundIds); + while (!ch.isLastChunk()) { + ch = ch.nextHeader(); + aggregateEventTypeForChunk(ch, types, foundIds); + } + } + return types; + } + + List readTypes() throws IOException { + ensureOpen(); + List types = new ArrayList<>(); + HashSet foundIds = new HashSet<>(); try (RecordingInput ri = new RecordingInput(file)) { ChunkHeader ch = new ChunkHeader(ri); aggregateTypeForChunk(ch, types, foundIds); @@ -140,7 +182,17 @@ public List readEventTypes() throws IOException { return types; } - private static void aggregateTypeForChunk(ChunkHeader ch, List types, HashSet foundIds) throws IOException { + private void aggregateTypeForChunk(ChunkHeader ch, List types, HashSet foundIds) throws IOException { + MetadataDescriptor m = ch.readMetadata(); + for (Type t : m.getTypes()) { + if (!foundIds.contains(t.getId())) { + types.add(t); + foundIds.add(t.getId()); + } + } + } + + private static void aggregateEventTypeForChunk(ChunkHeader ch, List types, HashSet foundIds) throws IOException { MetadataDescriptor m = ch.readMetadata(); for (EventType t : m.getEventTypes()) { if (!foundIds.contains(t.getId())) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java index b3b625eb1b4..0397f8a6858 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java @@ -25,6 +25,12 @@ package jdk.jfr.consumer; +import java.time.DateTimeException; +import java.time.ZoneOffset; + +import jdk.jfr.internal.LogLevel; +import jdk.jfr.internal.LogTag; +import jdk.jfr.internal.Logger; import jdk.jfr.internal.consumer.ChunkHeader; /** @@ -34,11 +40,22 @@ final class TimeConverter { private final long startTicks; private final long startNanos; private final double divisor; + private final ZoneOffset zoneOffet; - TimeConverter(ChunkHeader chunkHeader) { + TimeConverter(ChunkHeader chunkHeader, int rawOffset) { this.startTicks = chunkHeader.getStartTicks(); this.startNanos = chunkHeader.getStartNanos(); this.divisor = chunkHeader.getTicksPerSecond() / 1000_000_000L; + this.zoneOffet = zoneOfSet(rawOffset); + } + + private ZoneOffset zoneOfSet(int rawOffset) { + try { + return ZoneOffset.ofTotalSeconds(rawOffset / 1000); + } catch (DateTimeException dte) { + Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Could not create ZoneOffset from raw offset " + rawOffset); + } + return ZoneOffset.UTC; } public long convertTimestamp(long ticks) { @@ -48,4 +65,8 @@ public long convertTimestamp(long ticks) { public long convertTimespan(long ticks) { return (long) (ticks / divisor); } + + public ZoneOffset getZoneOffset() { + return zoneOffet; + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java index 51e3efc71f8..8ef5355fd32 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/OldObjectSample.java @@ -24,7 +24,7 @@ public final class OldObjectSample { private static final String OLD_OBJECT_CUTOFF = EVENT_NAME + "#" + Cutoff.NAME; private static final String OLD_OBJECT_ENABLED = EVENT_NAME + "#" + Enabled.NAME; - // Emit if old object is enabled in recoding with cutoff for that recording + // Emit if old object is enabled in recording with cutoff for that recording public static void emit(PlatformRecording recording) { if (isEnabled(recording)) { long nanos = CutoffSetting.parseValueSafe(recording.getSettings().get(OLD_OBJECT_CUTOFF)); @@ -34,7 +34,7 @@ public static void emit(PlatformRecording recording) { } // Emit if old object is enabled for at least one recording, and use the largest - // cutoff for an enabled recoding + // cutoff for an enabled recording public static void emit(List recordings, Boolean pathToGcRoots) { boolean enabled = false; long cutoffNanos = Boolean.TRUE.equals(pathToGcRoots) ? Long.MAX_VALUE : 0L; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java index 7c48fc26624..5ec29d1015b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java @@ -315,7 +315,7 @@ synchronized void stop(PlatformRecording recording) { private void dumpMemoryToDestination(PlatformRecording recording) { WriteableUserPath dest = recording.getDestination(); if (dest != null) { - MetadataRepository.getInstance().setOutput(dest.getText()); + MetadataRepository.getInstance().setOutput(dest.getRealPathText()); recording.clearDestination(); } } @@ -406,7 +406,7 @@ private void writeMetaEvents() { event.id = r.getId(); event.name = r.getName(); WriteableUserPath p = r.getDestination(); - event.destination = p == null ? null : p.getText(); + event.destination = p == null ? null : p.getRealPathText(); Duration d = r.getDuration(); event.recordingDuration = d == null ? Long.MAX_VALUE : d.toMillis(); Duration age = r.getMaxAge(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java index e460430b459..96a259b10fa 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java @@ -132,7 +132,7 @@ public void start() { options.add("duration=" + Utils.formatTimespan(duration, "")); } if (destination != null) { - options.add("filename=" + destination.getText()); + options.add("filename=" + destination.getRealPathText()); } String optionText = options.toString(); if (optionText.length() != 0) { @@ -165,7 +165,7 @@ public boolean stop(String reason) { if (dest != null) { try { dumpStopped(dest); - Logger.log(LogTag.JFR, LogLevel.INFO, "Wrote recording \"" + getName() + "\" (" + getId() + ") to " + dest.getText()); + Logger.log(LogTag.JFR, LogLevel.INFO, "Wrote recording \"" + getName() + "\" (" + getId() + ") to " + dest.getRealPathText()); notifyIfStateChanged(newState, oldState); close(); // remove if copied out } catch(IOException e) { @@ -365,11 +365,17 @@ public void setMaxSize(long maxSize) { } public void setDestination(WriteableUserPath userSuppliedPath) throws IOException { + synchronized (recorder) { + checkSetDestination(userSuppliedPath); + this.destination = userSuppliedPath; + } + } + + public void checkSetDestination(WriteableUserPath userSuppliedPath) throws IOException { synchronized (recorder) { if (Utils.isState(getState(), RecordingState.STOPPED, RecordingState.CLOSED)) { throw new IllegalStateException("Destination can't be set on a recording that has been stopped/closed"); } - this.destination = userSuppliedPath; } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java index 967e7e28274..fafd4e7ce09 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -71,7 +72,7 @@ public class Type implements Comparable { private final String name; private final String superType; private final boolean constantPool; - private final ArrayList fields = new ArrayList<>(); + private List fields = new ArrayList<>(); private Boolean simpleType; // calculated lazy private boolean remove = true; private long id; @@ -183,6 +184,10 @@ public String getLogName() { } public List getFields() { + if (fields instanceof ArrayList) { + ((ArrayList) fields).trimToSize(); + fields = Collections.unmodifiableList(fields); + } return fields; } @@ -216,7 +221,7 @@ public void add(ValueDescriptor valueDescriptor) { } void trimFields() { - fields.trimToSize(); + getFields(); } void setAnnotations(List annotations) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/WriteableUserPath.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/WriteableUserPath.java index 37a5a5a8141..d802b3b8c37 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/WriteableUserPath.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/WriteableUserPath.java @@ -50,7 +50,8 @@ public final class WriteableUserPath { private final AccessControlContext controlContext; private final Path original; private final Path real; - private final String text; + private final String realPathText; + private final String originalText; // Not to ensure security, but to help // against programming errors @@ -68,8 +69,9 @@ public WriteableUserPath(Path path) throws IOException { BufferedWriter fw = Files.newBufferedWriter(path); fw.close(); this.original = path; + this.originalText = path.toString(); this.real = path.toRealPath(); - this.text = real.toString(); + this.realPathText = real.toString(); } /** @@ -85,14 +87,24 @@ public Path getPotentiallyMaliciousOriginal() { } /** - * Returns a string representation of the path. + * Returns a string representation of the real path. * * @return path as text */ - public String getText() { - return text; + public String getRealPathText() { + return realPathText; } + /** + * Returns a string representation of the original path. + * + * @return path as text + */ + public String getOriginalText() { + return originalText; + } + + /** * Returns a potentially malicious path where the user may have implemented * their own version of Path. This method should never be called in an diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Command.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Command.java deleted file mode 100644 index e9baa02b833..00000000000 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Command.java +++ /dev/null @@ -1,150 +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. - */ - -package jdk.jfr.internal.cmd; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Deque; -import java.util.List; - -abstract class Command { - - private final static Command HELP = new HelpCommand(); - private final static List COMMANDS = createCommands(); - - static void displayHelp() { - System.out.println("Usage: java " + Execute.class.getName() + " []"); - System.out.println(); - displayAvailableCommands(); - } - - static void displayAvailableCommands() { - System.out.println("Available commands are:"); - System.out.println(); - boolean first = true; - for (Command c : Command.COMMANDS) { - if (!first) { - System.out.println(); - } - System.out.println(" " + c.getName() + " " + c.getOptionSyntax()); - System.out.println(" " + c.getDescription()); - first = false; - } - } - - public static List getCommands() { - return COMMANDS; - } - - public static Command valueOf(String commandName) { - for (Command command : COMMANDS) { - if (command.getName().equals(commandName)) { - return command; - } - } - return null; - } - - abstract public String getOptionSyntax(); - - abstract public String getName(); - - abstract public String getDescription(); - - abstract public void displayOptionUsage(); - - abstract public void execute(Deque options); - - final protected void userFailed(String message) { - println(); - println(message); - displayUsage(); - throw new IllegalArgumentException(message); - } - - final protected void ensureMaxArgumentCount(Deque options, int maxCount) { - if (options.size() > maxCount) { - userFailed("Too many arguments"); - } - } - - final protected void ensureMinArgumentCount(Deque options, int minCount) { - if (options.size() < minCount) { - userFailed("Too few arguments"); - } - } - - final protected void ensureFileExist(Path file) { - if (!Files.exists(file)) { - userFailed("Could not find file " + file); - } - } - - final protected Path ensureFileDoesNotExist(Path file) { - if (Files.exists(file)) { - userFailed("File " + file + " already exists"); - } - return file; - } - - final protected void ensureJFRFile(Path path) { - if (!path.toString().endsWith(".jfr")) { - userFailed("Filename must end with .jfr"); - } - } - - final protected void displayUsage() { - String javaText = "java " + Execute.class.getName(); - println(); - println("Usage: " + javaText + " " + getName() + " " + getOptionSyntax()); - println(); - displayOptionUsage(); - } - - final protected void println() { - System.out.println(); - } - - final protected void print(String text) { - System.out.print(text); - } - - final protected void println(String text) { - System.out.println(text); - } - - private static List createCommands() { - List commands = new ArrayList<>(); - commands.add(new PrintCommand()); - commands.add(new SummaryCommand()); - commands.add(new ReconstructCommand()); - commands.add(new SplitCommand()); - commands.add(HELP); - return Collections.unmodifiableList(commands); - } -} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Execute.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Execute.java deleted file mode 100644 index 800c589f2c1..00000000000 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/Execute.java +++ /dev/null @@ -1,65 +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. - */ - -package jdk.jfr.internal.cmd; - -import java.util.Arrays; -import java.util.Deque; -import java.util.LinkedList; - -/** - * Launcher class for JFR tools - * - */ -public final class Execute { - - public static void main(String... args) { - Deque argList = new LinkedList<>(Arrays.asList(args)); - if (argList.isEmpty()) { - System.out.println(); - Command.displayHelp(); - return; - } - String command = argList.remove(); - for (Command c : Command.getCommands()) { - if (c.getName().equals(command)) { - try { - c.execute(argList); - } catch (IllegalArgumentException iae) { - return; // already handled by command - } catch (Throwable e) { - System.out.println(); - System.out.println(e.getMessage()); - System.out.println(); - } - return; - } - } - System.out.println(); - System.out.println("Unknown command " + command + "."); - System.out.println(); - Command.displayHelp(); - } -} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrettyWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrettyWriter.java deleted file mode 100644 index 0cdfbf58fbb..00000000000 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrettyWriter.java +++ /dev/null @@ -1,236 +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. - */ - -package jdk.jfr.internal.cmd; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.StringJoiner; - -import jdk.jfr.AnnotationElement; -import jdk.jfr.ValueDescriptor; -import jdk.jfr.consumer.RecordedEvent; -import jdk.jfr.consumer.RecordedObject; -import jdk.jfr.consumer.RecordingFile; -import jdk.jfr.internal.PrivateAccess; -import jdk.jfr.internal.Type; -import jdk.jfr.internal.consumer.ChunkHeader; -import jdk.jfr.internal.consumer.RecordingInput; - -public final class PrettyWriter extends StructuredWriter { - - public PrettyWriter(PrintWriter destination) { - super(destination); - } - - void print(Path source) throws FileNotFoundException, IOException { - try (RecordingInput input = new RecordingInput(source.toFile())) { - HashSet typeSet = new HashSet<>(); - for (ChunkHeader ch = new ChunkHeader(input); !ch.isLastChunk(); ch = ch.nextHeader()) { - typeSet.addAll(ch.readMetadata().getTypes()); - } - List types = new ArrayList<>(typeSet); - Collections.sort(types, (c1, c2) -> Long.compare(c1.getId(), c2.getId())); - for (Type t : types) { - printType(t); - } - flush(); - } - - try (RecordingFile es = new RecordingFile(source)) { - while (es.hasMoreEvents()) { - print(es.readEvent()); - flush(); - } - } - flush(); - } - - public void printType(Type t) throws IOException { - print("// id: "); - println(String.valueOf(t.getId())); - int commentIndex = t.getName().length() + 10; - String typeName = t.getName(); - int index = typeName.lastIndexOf("."); - if (index != -1) { - println("package " + typeName.substring(0, index) + ";"); - } - printAnnotations(commentIndex, t.getAnnotationElements()); - print("class " + typeName.substring(index + 1)); - String superType = t.getSuperType(); - if (superType != null) { - print(" extends " + superType); - } - println(" {"); - indent(); - for (ValueDescriptor v : t.getFields()) { - printField(commentIndex, v); - } - retract(); - println("}"); - println(); - } - - private void printField(int commentIndex, ValueDescriptor v) throws IOException { - println(); - printAnnotations(commentIndex, v.getAnnotationElements()); - printIndent(); - Type vType = PrivateAccess.getInstance().getType(v); - if (Type.SUPER_TYPE_SETTING.equals(vType.getSuperType())) { - print("static "); - } - print(makeSimpleType(v.getTypeName())); - if (v.isArray()) { - print("[]"); - } - print(" "); - print(v.getName()); - print(";"); - printCommentRef(commentIndex, v.getTypeId()); - } - - private void printCommentRef(int commentIndex, long typeId) throws IOException { - int column = getColumn(); - if (column > commentIndex) { - print(" "); - } else { - while (column < commentIndex) { - print(" "); - column++; - } - } - println(" // id=" + typeId); - } - - private void printAnnotations(int commentIndex, List annotations) throws IOException { - for (AnnotationElement a : annotations) { - printIndent(); - print("@"); - print(makeSimpleType(a.getTypeName())); - List vs = a.getValueDescriptors(); - if (!vs.isEmpty()) { - printAnnotation(a); - printCommentRef(commentIndex, a.getTypeId()); - } else { - println(); - } - } - } - - private void printAnnotation(AnnotationElement a) throws IOException { - StringJoiner sj = new StringJoiner(", ", "(", ")"); - List vs = a.getValueDescriptors(); - for (ValueDescriptor v : vs) { - Object o = a.getValue(v.getName()); - if (vs.size() == 1 && v.getName().equals("value")) { - sj.add(textify(o)); - } else { - sj.add(v.getName() + "=" + textify(o)); - } - } - print(sj.toString()); - } - - private String textify(Object o) { - if (o.getClass().isArray()) { - Object[] array = (Object[]) o; - if (array.length == 1) { - return quoteIfNeeded(array[0]); - } - StringJoiner s = new StringJoiner(", ", "{", "}") ; - for (Object ob : array) { - s.add(quoteIfNeeded(ob)); - } - return s.toString(); - } else { - return quoteIfNeeded(o); - } - } - - private String quoteIfNeeded(Object o) { - if (o instanceof String) { - return "\"" + o + "\""; - } else { - return String.valueOf(o); - } - } - - private String makeSimpleType(String typeName) { - int index = typeName.lastIndexOf("."); - return typeName.substring(index + 1); - } - - public void print(RecordedEvent event) throws IOException { - print(makeSimpleType(event.getEventType().getName()), " "); - print((RecordedObject) event, ""); - } - - public void print(RecordedObject struct, String postFix) throws IOException { - println("{"); - indent(); - for (ValueDescriptor v : struct.getFields()) { - printIndent(); - print(v.getName(), " = "); - printValue(struct.getValue(v.getName()), ""); - } - retract(); - printIndent(); - println("}" + postFix); - } - - private void printArray(Object[] array) throws IOException { - println("["); - indent(); - for (int i = 0; i < array.length; i++) { - printIndent(); - printValue(array[i], i + 1 < array.length ? ", " : ""); - } - retract(); - printIndent(); - println("]"); - } - - private void printValue(Object value, String postFix) throws IOException { - if (value == null) { - println("null" + postFix); - } else if (value instanceof RecordedObject) { - print((RecordedObject) value, postFix); - } else if (value.getClass().isArray()) { - printArray((Object[]) value); - } else { - String text = String.valueOf(value); - if (value instanceof String) { - text = "\"" + text + "\""; - } - println(text); - } - } -} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrintCommand.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrintCommand.java deleted file mode 100644 index 5bea4667ddb..00000000000 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/PrintCommand.java +++ /dev/null @@ -1,100 +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. - */ - -package jdk.jfr.internal.cmd; - -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Deque; - -final class PrintCommand extends Command { - @Override - public String getName() { - return "print"; - } - - @Override - public String getOptionSyntax() { - return "[--xml|--json] "; - } - - @Override - public String getDescription() { - return "Print contents of a recording file (.jfr)"; - } - - @Override - public void displayOptionUsage() { - println(" --xml Print a recording in XML format"); - println(); - println(" --json Print a recording in JSON format"); - println(); - println(" Location of the recording file (.jfr) to print"); - } - - @Override - public void execute(Deque options) { - if (options.isEmpty()) { - userFailed("Missing file"); - } - ensureMaxArgumentCount(options, 2); - - Path file = Paths.get(options.removeLast()); - - ensureFileExist(file); - ensureJFRFile(file); - ensureMaxArgumentCount(options, 1); - - String format = "--pretty"; - if (!options.isEmpty()) { - format = options.remove(); - } - try (PrintWriter pw = new PrintWriter(System.out)) { - try { - switch (format) { - case "--pretty": - PrettyWriter prettyWriter = new PrettyWriter(pw); - prettyWriter.print(file); - break; - case "--xml": - XMLWriter xmlPrinter = new XMLWriter(pw); - xmlPrinter.print(file); - break; - case "--json": - JSONWriter jsonWriter = new JSONWriter(pw); - jsonWriter.print(file); - break; - default: - userFailed("Unknown option " + format); - break; - } - } catch (IOException ioe) { - userFailed("Could not read recording at " + file.toAbsolutePath() + ". " + ioe.getMessage()); - } - } - } -} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SplitCommand.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SplitCommand.java deleted file mode 100644 index fa13a947baf..00000000000 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SplitCommand.java +++ /dev/null @@ -1,195 +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. - */ - -package jdk.jfr.internal.cmd; - -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Deque; -import java.util.List; - -import jdk.jfr.internal.consumer.ChunkHeader; -import jdk.jfr.internal.consumer.RecordingInput; - -final class SplitCommand extends Command { - - @Override - public String getOptionSyntax() { - return "[--maxchunks ] "; - } - - @Override - public void displayOptionUsage() { - println(" --maxchunks Maximum number of chunks per splitted file (default 5)."); - println(" The chunk size varies, but is typically around 15 MB."); - println(); - println(" Location of recording file (.jfr) to split"); - } - - @Override - public String getName() { - return "split"; - } - - @Override - public String getDescription() { - return "Splits a recording file into smaller files"; - } - - @Override - public void execute(Deque options) { - if (options.isEmpty()) { - userFailed("Missing file"); - } - ensureMaxArgumentCount(options, 3); - Path file = Paths.get(options.removeLast()); - ensureFileExist(file); - ensureJFRFile(file); - int maxchunks = 5; - if (!options.isEmpty()) { - String option = options.pop(); - if (!"--maxchunks".equals(option)) { - userFailed("Unknown option " + option); - } - if (options.isEmpty()) { - userFailed("Missing value for --maxChunks"); - } - String value = options.pop(); - try { - maxchunks = Integer.parseInt(value); - if (maxchunks < 1) { - userFailed("Must be at least one chunk per file."); - } - } catch (NumberFormatException nfe) { - userFailed("Not a valid value for --maxchunks."); - } - } - ensureMaxArgumentCount(options, 0); - println(); - println("Examining recording " + file + " ..."); - List sizes; - - try { - sizes = findChunkSizes(file); - } catch (IOException e) { - throw new IllegalStateException("Unexpected error. " + e.getMessage()); - } - if (sizes.size() <= maxchunks) { - throw new IllegalStateException("Number of chunks in recording (" + sizes.size() + ") doesn't exceed max chunks (" + maxchunks + ")"); - } - println(); - - println(); - if (sizes.size() > 0) { - print("File consists of " + sizes.size() + " chunks. The recording will be split into "); - sizes = combineChunkSizes(sizes, maxchunks); - println(sizes.size() + " files with at most " + maxchunks + " chunks per file."); - println(); - - try { - splitFile(file, sizes); - } catch (IOException e) { - throw new IllegalStateException("Unexpected error. " + e.getMessage()); - } - } else { - println("No JFR chunks found in file. "); - } - } - - private List findChunkSizes(Path p) throws IOException { - try (RecordingInput input = new RecordingInput(p.toFile())) { - List sizes = new ArrayList<>(); - ChunkHeader ch = new ChunkHeader(input); - sizes.add(ch.getSize()); - while (!ch.isLastChunk()) { - ch = ch.nextHeader(); - sizes.add(ch.getSize()); - } - return sizes; - } - } - - private List combineChunkSizes(List sizes, int chunksPerFile) { - List reduced = new ArrayList(); - long size = sizes.get(0); - for (int n = 1; n < sizes.size(); n++) { - if (n % chunksPerFile == 0) { - reduced.add(size); - size = 0; - } - size += sizes.get(n); - } - reduced.add(size); - return reduced; - } - - private void splitFile(Path file, List splitPositions) throws IOException { - - int padAmountZeros = String.valueOf(splitPositions.size() - 1).length(); - String fileName = file.toString(); - String fileFormatter = fileName.subSequence(0, fileName.length() - 4) + "_%0" + padAmountZeros + "d.jfr"; - for (int i = 0; i < splitPositions.size(); i++) { - Path p = Paths.get(String.format(fileFormatter, i)); - if (Files.exists(p)) { - throw new IllegalStateException("Can't create split file " + p + ", a file with that name already exist"); - } - } - DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(file.toFile()))); - - for (int i = 0; i < splitPositions.size(); i++) { - Long l = splitPositions.get(i); - byte[] bytes = readBytes(stream, l.intValue()); - Path p = Paths.get(String.format(fileFormatter, i)); - File splittedFile = p.toFile(); - println("Writing " + splittedFile + " ..."); - FileOutputStream fos = new FileOutputStream(splittedFile); - fos.write(bytes); - fos.close(); - } - stream.close(); - } - - private byte[] readBytes(InputStream stream, int count) throws IOException { - byte[] data = new byte[count]; - int totalRead = 0; - while (totalRead < data.length) { - int read = stream.read(data, totalRead, data.length - totalRead); - if (read == -1) { - throw new IOException("Unexpected end of data."); - } - totalRead += read; - } - return data; - } -} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java index 9ab1e02297c..fcdf14adf01 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java @@ -161,7 +161,7 @@ public long getSize() { return chunkSize; } - public long getDuration() { + public long getDurationNanos() { return durationNanos; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInternals.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInternals.java new file mode 100644 index 00000000000..34be20f8a09 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInternals.java @@ -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. 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.jfr.internal.consumer; + +import java.io.IOException; +import java.util.List; + +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedObject; +import jdk.jfr.consumer.RecordingFile; +import jdk.jfr.internal.Type; + +public abstract class RecordingInternals { + + public static RecordingInternals INSTANCE; + + public abstract boolean isLastEventInChunk(RecordingFile file); + + public abstract Object getOffsetDataTime(RecordedObject event, String name); + + public abstract List readTypes(RecordingFile file) throws IOException; + + public abstract void sort(List events); + +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java index d3e83ca39db..15088b986e5 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java @@ -158,7 +158,7 @@ public void dump(PlatformRecorder recorder, Recording recording, String name, St wup = new WriteableUserPath(safe.toPath()); } r.dumpStopped(wup); - reportOperationComplete("Dumped", name, new SafePath(wup.getText())); + reportOperationComplete("Dumped", name, new SafePath(wup.getRealPathText())); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java index 0be1165b8af..7618e403026 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java @@ -24,6 +24,7 @@ */ package jdk.jfr.internal.dcmd; +import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.InvalidPathException; @@ -105,13 +106,17 @@ public String execute(String name, String[] settings, Long delay, Long duration, if (duration == null && Boolean.FALSE.equals(dumpOnExit) && path != null) { throw new DCmdException("Filename can only be set for a time bound recording or if dumponexit=true. Set duration/dumponexit or omit filename."); } - + if (settings.length == 1 && settings[0].length() == 0) { + throw new DCmdException("No settings specified. Use settings=none to start without any settings"); + } Map s = new HashMap<>(); for (String configName : settings) { try { s.putAll(JFC.createKnown(configName).getSettings()); + } catch(FileNotFoundException e) { + throw new DCmdException("Could not find settings file'" + configName + "'", e); } catch (IOException | ParseException e) { - throw new DCmdException("Could not parse setting " + settings[0], e); + throw new DCmdException("Could not parse settings file '" + settings[0] + "'", e); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java index 3ca5465734b..83cb63097cb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/JFC.java @@ -127,7 +127,11 @@ private static String nullSafeFileName(Path file) throws IOException { public static String nameFromPath(Path file) throws IOException { String f = nullSafeFileName(file); - return f.substring(0, f.length() - JFCParser.FILE_EXTENSION.length()); + if (f.endsWith(JFCParser.FILE_EXTENSION)) { + return f.substring(0, f.length() - JFCParser.FILE_EXTENSION.length()); + } else { + return f; + } } // Invoked by DCmdStart diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ManagementSupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ManagementSupport.java index ccbdd1a78d7..efe4accdcd1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ManagementSupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/management/ManagementSupport.java @@ -25,18 +25,24 @@ package jdk.jfr.internal.management; +import java.io.IOException; +import java.nio.file.Paths; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; import jdk.jfr.EventType; +import jdk.jfr.Recording; import jdk.jfr.internal.JVMSupport; import jdk.jfr.internal.LogLevel; import jdk.jfr.internal.LogTag; import jdk.jfr.internal.Logger; import jdk.jfr.internal.MetadataRepository; +import jdk.jfr.internal.PlatformRecording; +import jdk.jfr.internal.PrivateAccess; import jdk.jfr.internal.Utils; +import jdk.jfr.internal.WriteableUserPath; import jdk.jfr.internal.instrument.JDKEvents; /** @@ -86,4 +92,20 @@ public static final String formatTimespan(Duration dValue, String separation) { public static void logError(String message) { Logger.log(LogTag.JFR, LogLevel.ERROR, message); } + + // Get the textual representation when the destination was set, which + // requires access to jdk.jfr.internal.PlatformRecording + public static String getDestinationOriginalText(Recording recording) { + PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording); + WriteableUserPath wup = pr.getDestination(); + return wup == null ? null : wup.getOriginalText(); + } + + public static void checkSetDestination(Recording recording, String destination) throws IOException{ + PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording); + if(destination != null){ + WriteableUserPath wup = new WriteableUserPath(Paths.get(destination)); + pr.checkSetDestination(wup); + } + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/ReconstructCommand.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java similarity index 64% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/ReconstructCommand.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java index cac6d057578..44a834d9f86 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/ReconstructCommand.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java @@ -23,76 +23,72 @@ * questions. */ -package jdk.jfr.internal.cmd; +package jdk.jfr.internal.tool; import java.io.FileOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.nio.channels.FileChannel; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.Deque; import java.util.List; -final class ReconstructCommand extends Command { +final class Assemble extends Command { @Override - public String getOptionSyntax() { - return " "; + public String getName() { + return "assemble"; } @Override - public String getName() { - return "reconstruct"; + public List getOptionSyntax() { + return Collections.singletonList(" "); } @Override public String getDescription() { - return "Assemble leftover chunks, from a disk repository, into a recording file (.jfr)"; + return "Assemble leftover chunks from a disk repository into a recording file"; } @Override - public void displayOptionUsage() { - println(" Directory where the repository is located"); - println(); - println(" Name of the recording file (.jfr) to create"); + public void displayOptionUsage(PrintStream stream) { + stream.println(" Directory where the repository is located"); + stream.println(); + stream.println(" Name of the recording file (.jfr) to create"); } @Override - public void execute(Deque options) { + public void execute(Deque options) throws UserSyntaxException, UserDataException { ensureMinArgumentCount(options, 2); ensureMaxArgumentCount(options, 2); + Path repository = getDirectory(options.pop()); - Path repository = Paths.get(options.pop()).toAbsolutePath(); - if (!Files.exists(repository)) { - userFailed("Could not find disk repository at " + repository); - } - if (!Files.isDirectory(repository)) { - userFailed("Must specify a directory as disk repository"); - } - Path output = Paths.get(options.pop()); - ensureFileDoesNotExist(output); - ensureJFRFile(output); + Path file = Paths.get(options.pop()); + ensureFileDoesNotExist(file); + ensureJFRFile(file); - try (FileOutputStream fos = new FileOutputStream(output.toFile())) { + try (FileOutputStream fos = new FileOutputStream(file.toFile())) { List files = listJFRFiles(repository); if (files.isEmpty()) { - throw new IllegalStateException("No *.jfr files found at " + repository); + throw new UserDataException("no *.jfr files found at " + repository); } println(); - println("Combining files... "); + println("Assembling files... "); println(); - transferTo(files, output, fos.getChannel()); + transferTo(files, file, fos.getChannel()); println(); - println("Reconstruction complete."); + println("Finished."); } catch (IOException e) { - userFailed("Could not open destination file " + output + ". " + e.getMessage()); + throw new UserDataException("could not open destination file " + file + ". " + e.getMessage()); } } - private List listJFRFiles(Path path) throws IOException { + private List listJFRFiles(Path path) throws UserDataException { try { List files = new ArrayList<>(); if (Files.isDirectory(path)) { @@ -107,11 +103,11 @@ private List listJFRFiles(Path path) throws IOException { files.sort((u, v) -> u.getFileName().compareTo(v.getFileName())); return files; } catch (IOException ioe) { - throw new IllegalStateException("Could not list *.jfr for directory " + path + ". " + ioe.getMessage()); + throw new UserDataException("could not list *.jfr for directory " + path + ". " + ioe.getMessage()); } } - private void transferTo(List sourceFiles, Path output, FileChannel out) { + private void transferTo(List sourceFiles, Path output, FileChannel out) throws UserDataException { long pos = 0; for (Path p : sourceFiles) { println(" " + p.toString()); @@ -124,7 +120,7 @@ private void transferTo(List sourceFiles, Path output, FileChannel out) { rem -= w; } } catch (IOException ioe) { - throw new IllegalStateException("Could not copy recording chunk " + p + " to new file. " + ioe.getMessage()); + throw new UserDataException("could not copy recording chunk " + p + " to new file. " + ioe.getMessage()); } } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java new file mode 100644 index 00000000000..a7013579938 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Command.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2016, 2019, 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.jfr.internal.tool; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOError; +import java.io.IOException; +import java.io.PrintStream; +import java.io.RandomAccessFile; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.List; + +abstract class Command { + public final static String title = "Tool for working with Flight Recorder files (.jfr)"; + private final static Command HELP = new Help(); + private final static List COMMANDS = createCommands(); + + private static List createCommands() { + List commands = new ArrayList<>(); + commands.add(new Print()); + commands.add(new Metadata()); + commands.add(new Summary()); + commands.add(new Assemble()); + commands.add(new Disassemble()); + commands.add(new Version()); + commands.add(HELP); + return Collections.unmodifiableList(commands); + } + + static void displayHelp() { + System.out.println(title); + System.out.println(); + displayAvailableCommands(System.out); + } + + abstract public String getName(); + + abstract public String getDescription(); + + abstract public void execute(Deque argList) throws UserSyntaxException, UserDataException; + + protected String getTitle() { + return getDescription(); + } + + static void displayAvailableCommands(PrintStream stream) { + boolean first = true; + for (Command c : Command.COMMANDS) { + if (!first) { + System.out.println(); + } + displayCommand(stream, c); + stream.println(" " + c.getDescription()); + first = false; + } + } + + protected static void displayCommand(PrintStream stream, Command c) { + boolean firstSyntax = true; + String alias = buildAlias(c); + String initial = " jfr " + c.getName(); + for (String syntaxLine : c.getOptionSyntax()) { + if (firstSyntax) { + if (syntaxLine.length() != 0) { + stream.println(initial + " " + syntaxLine + alias); + } else { + stream.println(initial + alias); + } + } else { + for (int i = 0; i < initial.length(); i++) { + stream.print(" "); + } + stream.println(" " + syntaxLine); + } + firstSyntax = false; + } + } + + private static String buildAlias(Command c) { + List aliases = c.getAliases(); + if (aliases.isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + if (aliases.size() == 1) { + sb.append(" (alias "); + sb.append(aliases.get(0)); + sb.append(")"); + return sb.toString(); + } + sb.append(" (aliases "); + for (int i = 0; i< aliases.size(); i ++ ) { + sb.append(aliases.get(i)); + if (i < aliases.size() -1) { + sb.append(", "); + } + } + sb.append(")"); + return sb.toString(); + } + + public static List getCommands() { + return COMMANDS; + } + + public static Command valueOf(String commandName) { + for (Command command : COMMANDS) { + if (command.getName().equals(commandName)) { + return command; + } + } + return null; + } + + public List getOptionSyntax() { + return Collections.singletonList(""); + } + + public void displayOptionUsage(PrintStream stream) { + } + + protected boolean acceptOption(Deque options, String expected) throws UserSyntaxException { + if (expected.equals(options.peek())) { + if (options.size() < 2) { + throw new UserSyntaxException("missing value for " + options.peek()); + } + options.remove(); + return true; + } + return false; + } + + protected void warnForWildcardExpansion(String option, String filter) throws UserDataException { + // Users should quote their wildcards to avoid expansion by the shell + try { + if (!filter.contains(File.pathSeparator)) { + Path p = Path.of(".", filter); + if (!Files.exists(p)) { + return; + } + } + throw new UserDataException("wildcards should be quoted, for example " + option + " \"Foo*\""); + } catch (InvalidPathException ipe) { + // ignore + } + } + + protected boolean acceptFilterOption(Deque options, String expected) throws UserSyntaxException { + if (!acceptOption(options, expected)) { + return false; + } + if (options.isEmpty()) { + throw new UserSyntaxException("missing filter after " + expected); + } + String filter = options.peek(); + if (filter.startsWith("--")) { + throw new UserSyntaxException("missing filter after " + expected); + } + return true; + } + + final protected void ensureMaxArgumentCount(Deque options, int maxCount) throws UserSyntaxException { + if (options.size() > maxCount) { + throw new UserSyntaxException("too many arguments"); + } + } + + final protected void ensureMinArgumentCount(Deque options, int minCount) throws UserSyntaxException { + if (options.size() < minCount) { + throw new UserSyntaxException("too few arguments"); + } + } + + final protected Path getDirectory(String pathText) throws UserDataException { + try { + Path path = Paths.get(pathText).toAbsolutePath(); + if (!Files.exists((path))) { + throw new UserDataException("directory does not exist, " + pathText); + } + if (!Files.isDirectory(path)) { + throw new UserDataException("path must be directory, " + pathText); + } + return path; + } catch (InvalidPathException ipe) { + throw new UserDataException("invalid path '" + pathText + "'"); + } + } + + final protected Path getJFRInputFile(Deque options) throws UserSyntaxException, UserDataException { + if (options.isEmpty()) { + throw new UserSyntaxException("missing file"); + } + String file = options.removeLast(); + if (file.startsWith("--")) { + throw new UserSyntaxException("missing file"); + } + try { + Path path = Paths.get(file).toAbsolutePath(); + ensureAccess(path); + ensureJFRFile(path); + return path; + } catch (IOError ioe) { + throw new UserDataException("i/o error reading file '" + file + "', " + ioe.getMessage()); + } catch (InvalidPathException ipe) { + throw new UserDataException("invalid path '" + file + "'"); + } + } + + private void ensureAccess(Path path) throws UserDataException { + try (RandomAccessFile rad = new RandomAccessFile(path.toFile(), "r")) { + if (rad.length() == 0) { + throw new UserDataException("file is empty '" + path + "'"); + } + rad.read(); // try to read 1 byte + } catch (FileNotFoundException e) { + throw new UserDataException("could not open file " + e.getMessage()); + } catch (IOException e) { + throw new UserDataException("i/o error reading file '" + path + "', " + e.getMessage()); + } + } + + final protected void couldNotReadError(Path p, IOException e) throws UserDataException { + throw new UserDataException("could not read recording at " + p.toAbsolutePath() + ". " + e.getMessage()); + } + + final protected Path ensureFileDoesNotExist(Path file) throws UserDataException { + if (Files.exists(file)) { + throw new UserDataException("file '" + file + "' already exists"); + } + return file; + } + + final protected void ensureJFRFile(Path path) throws UserDataException { + if (!path.toString().endsWith(".jfr")) { + throw new UserDataException("filename must end with '.jfr'"); + } + } + + protected void displayUsage(PrintStream stream) { + displayCommand(stream, this); + stream.println(); + displayOptionUsage(stream); + } + + final protected void println() { + System.out.println(); + } + + final protected void print(String text) { + System.out.print(text); + } + + final protected void println(String text) { + System.out.println(text); + } + + final protected boolean matches(String command) { + for (String s : getNames()) { + if (s.equals(command)) { + return true; + } + } + return false; + } + + protected List getAliases() { + return Collections.emptyList(); + } + + public List getNames() { + List names = new ArrayList<>(); + names.add(getName()); + names.addAll(getAliases()); + return names; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Disassemble.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Disassemble.java new file mode 100644 index 00000000000..17ad5d176f1 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Disassemble.java @@ -0,0 +1,250 @@ +/* + * 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. + */ + +package jdk.jfr.internal.tool; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +import jdk.jfr.internal.consumer.ChunkHeader; +import jdk.jfr.internal.consumer.RecordingInput; + +final class Disassemble extends Command { + + @Override + public String getName() { + return "disassemble"; + } + + @Override + public List getOptionSyntax() { + List list = new ArrayList<>(); + list.add("[--output ]"); + list.add("[--max-chunks ]"); + list.add("[--max-size ]"); + list.add(""); + return list; + } + + @Override + public void displayOptionUsage(PrintStream stream) { + stream.println(" --output The location to write the disassembled file,"); + stream.println(" by default the current directory"); + stream.println(""); + stream.println(" --max-chunks Maximum number of chunks per disassembled file,"); + stream.println(" by default 5. The chunk size varies, but is "); + stream.println(" typically around 15 MB."); + stream.println(""); + stream.println(" --max-size Maximum number of bytes per file."); + stream.println(""); + stream.println(" Location of the recording file (.jfr)"); + } + + @Override + public String getDescription() { + return "Disassamble a recording file into smaller files/chunks"; + } + + @Override + public void execute(Deque options) throws UserSyntaxException, UserDataException { + if (options.isEmpty()) { + throw new UserSyntaxException("missing file"); + } + Path file = getJFRInputFile(options); + int maxChunks = Integer.MAX_VALUE; + int maxsize = Integer.MAX_VALUE; + String output = System.getProperty("user.dir"); + int optionCount = options.size(); + while (optionCount > 0) { + if (acceptOption(options, "--output")) { + output = options.pop(); + } + if (acceptOption(options, "--max-size")) { + String value = options.pop(); + try { + maxsize = Integer.parseInt(value); + if (maxsize < 1) { + throw new UserDataException("max size must be at least 1"); + } + } catch (NumberFormatException nfe) { + throw new UserDataException("not a valid value for --max-size."); + } + } + if (acceptOption(options, "--max-chunks")) { + String value = options.pop(); + try { + maxChunks = Integer.parseInt(value); + if (maxChunks < 1) { + throw new UserDataException("max chunks must be at least 1."); + } + } catch (NumberFormatException nfe) { + throw new UserDataException("not a valid value for --max-size."); + } + } + if (optionCount == options.size()) { + // No progress made + throw new UserSyntaxException("unknown option " + options.peek()); + } + optionCount = options.size(); + } + Path outputPath = getDirectory(output); + + println(); + println("Examining recording " + file + " ..."); + List sizes; + if (maxsize != Integer.MAX_VALUE && maxChunks == Integer.MAX_VALUE) { + try { + long fileSize = Files.size(file); + if (maxsize >=fileSize) { + println(); + println("File size (" + fileSize +") does not exceed max size (" + maxsize + ")"); + return; + } + } catch (IOException e) { + throw new UserDataException("unexpected i/o error when determining file size" + e.getMessage()); + } + } + if (maxsize == Integer.MAX_VALUE && maxChunks == Integer.MAX_VALUE) { + maxChunks = 5; + } + + try { + sizes = findChunkSizes(file); + } catch (IOException e) { + throw new UserDataException("unexpected i/o error. " + e.getMessage()); + } + if (maxsize == Integer.MAX_VALUE == sizes.size() <= maxChunks) { + throw new UserDataException("number of chunks in recording (" + sizes.size() + ") doesn't exceed max chunks (" + maxChunks + ")"); + } + println(); + if (sizes.size() > 0) { + List combinedSizes = combineChunkSizes(sizes, maxChunks, maxsize); + print("File consists of " + sizes.size() + " chunks. The recording will be split into "); + println(combinedSizes.size() + " files"); + println(); + splitFile(outputPath, file, combinedSizes); + } else { + throw new UserDataException("no JFR chunks found in file."); + } + } + + private List findChunkSizes(Path p) throws IOException { + try (RecordingInput input = new RecordingInput(p.toFile())) { + List sizes = new ArrayList<>(); + ChunkHeader ch = new ChunkHeader(input); + sizes.add(ch.getSize()); + while (!ch.isLastChunk()) { + ch = ch.nextHeader(); + sizes.add(ch.getSize()); + } + return sizes; + } + } + + private List combineChunkSizes(List sizes, int maxChunks, long maxSize) { + List reduced = new ArrayList(); + int chunks = 1; + long fileSize = sizes.get(0); + for (int i = 1; i < sizes.size(); i++) { + long size = sizes.get(i); + if (fileSize + size > maxSize) { + reduced.add(fileSize); + chunks = 1; + fileSize = size; + continue; + } + fileSize += size; + if (chunks == maxChunks) { + reduced.add(fileSize); + fileSize = 0; + chunks = 1; + continue; + } + chunks++; + } + if (fileSize != 0) { + reduced.add(fileSize); + } + return reduced; + } + + private void splitFile(Path directory, Path file, List splitPositions) throws UserDataException { + int padAmountZeros = String.valueOf(splitPositions.size() - 1).length(); + String fileName = file.getFileName().toString(); + String fileFormatter = fileName.subSequence(0, fileName.length() - 4) + "_%0" + padAmountZeros + "d.jfr"; + for (int i = 0; i < splitPositions.size(); i++) { + String formattedFilename = String.format(fileFormatter, i); + try { + Path p = directory.resolve(formattedFilename); + if (Files.exists(p)) { + throw new UserDataException("can't create disassembled file " + p + ", a file with that name already exist"); + } + } catch (InvalidPathException ipe) { + throw new UserDataException("can't construct path with filename" + formattedFilename); + } + } + + try (DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(file.toFile())))) { + for (int i = 0; i < splitPositions.size(); i++) { + Long l = splitPositions.get(i); + byte[] bytes = readBytes(stream, l.intValue()); + String formattedFilename = String.format(fileFormatter, i); + Path p = directory.resolve(formattedFilename); + File splittedFile = p.toFile(); + println("Writing " + splittedFile + " ... " + bytes.length); + FileOutputStream fos = new FileOutputStream(splittedFile); + fos.write(bytes); + fos.close(); + } + } catch (IOException ioe) { + throw new UserDataException("i/o error writing file " + file); + } + } + + private byte[] readBytes(InputStream stream, int count) throws UserDataException, IOException { + byte[] data = new byte[count]; + int totalRead = 0; + while (totalRead < data.length) { + int read = stream.read(data, totalRead, data.length - totalRead); + if (read == -1) { + throw new UserDataException("unexpected end of data"); + } + totalRead += read; + } + return data; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/EventPrintWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/EventPrintWriter.java new file mode 100644 index 00000000000..546f48117d7 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/EventPrintWriter.java @@ -0,0 +1,139 @@ +/* + * 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.jfr.internal.tool; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +import jdk.jfr.EventType; +import jdk.jfr.Timespan; +import jdk.jfr.Timestamp; +import jdk.jfr.ValueDescriptor; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedObject; +import jdk.jfr.consumer.RecordingFile; +import jdk.jfr.internal.consumer.RecordingInternals; + +abstract class EventPrintWriter extends StructuredWriter { + + enum ValueType { + TIMESPAN, TIMESTAMP, OTHER + } + + protected static final String STACK_TRACE_FIELD = "stackTrace"; + protected static final String EVENT_THREAD_FIELD = "eventThread"; + + private Predicate eventFilter = x -> true; + private int stackDepth; + + // cach that will speed up annotation lookup + private Map typeOfValues = new HashMap<>(); + + EventPrintWriter(PrintWriter p) { + super(p); + } + + abstract protected void print(List events); + + void print(Path source) throws FileNotFoundException, IOException { + List events = new ArrayList<>(500_000); + printBegin(); + try (RecordingFile file = new RecordingFile(source)) { + while (file.hasMoreEvents()) { + RecordedEvent event = file.readEvent(); + if (acceptEvent(event)) { + events.add(event); + } + if (RecordingInternals.INSTANCE.isLastEventInChunk(file)) { + RecordingInternals.INSTANCE.sort(events); + print(events); + events.clear(); + } + } + } + printEnd(); + flush(true); + } + + protected void printEnd() { + } + + protected void printBegin() { + } + + public final void setEventFilter(Predicate eventFilter) { + this.eventFilter = eventFilter; + } + + protected final boolean acceptEvent(RecordedEvent event) { + return eventFilter.test(event.getEventType()); + } + + protected final int getStackDepth() { + return stackDepth; + } + + protected final boolean isLateField(String name) { + return name.equals(EVENT_THREAD_FIELD) || name.equals(STACK_TRACE_FIELD); + } + + public void setStackDepth(int stackDepth) { + this.stackDepth = stackDepth; + } + + protected Object getValue(RecordedObject object, ValueDescriptor v) { + ValueType valueType = typeOfValues.get(v); + if (valueType == null) { + valueType = determineValueType(v); + typeOfValues.put(v, valueType); + } + switch (valueType) { + case TIMESPAN: + return object.getDuration(v.getName()); + case TIMESTAMP: + return RecordingInternals.INSTANCE.getOffsetDataTime(object, v.getName()); + default: + return object.getValue(v.getName()); + } + } + // It's expensive t check + private ValueType determineValueType(ValueDescriptor v) { + if (v.getAnnotation(Timespan.class) != null) { + return ValueType.TIMESPAN; + } + if (v.getAnnotation(Timestamp.class) != null) { + return ValueType.TIMESTAMP; + } + return ValueType.OTHER; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/HelpCommand.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Help.java similarity index 62% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/HelpCommand.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Help.java index 44abd5b8801..42e840e8b8a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/HelpCommand.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Help.java @@ -23,46 +23,53 @@ * questions. */ -package jdk.jfr.internal.cmd; +package jdk.jfr.internal.tool; +import java.io.PrintStream; +import java.util.Collections; import java.util.Deque; +import java.util.List; -final class HelpCommand extends Command { +final class Help extends Command { @Override - public String getOptionSyntax() { - return "[]"; + public String getName() { + return "help"; } @Override - public void displayOptionUsage() { - println(" The name of the command to get help for"); - println(); - Command.displayAvailableCommands(); + public List getOptionSyntax() { + return Collections.singletonList("[]"); + } + + protected List getAliases() { + return List.of("--help", "-h", "-?"); } @Override - public String getName() { - return "help"; + public void displayOptionUsage(PrintStream stream) { + println(" The name of the command to get help for"); } @Override public String getDescription() { - return "Display help about a command"; + return "Display all available commands, or help about a specific command"; } @Override - public void execute(Deque options) { + public void execute(Deque options) throws UserSyntaxException, UserDataException { if (options.isEmpty()) { - displayUsage(); - } else { - ensureMaxArgumentCount(options, 1); - String commandName = options.remove(); - Command c = Command.valueOf(commandName); - if (c == null) { - userFailed("Unknown command " + commandName); - } - c.displayUsage(); + Command.displayHelp(); + return; } + ensureMaxArgumentCount(options, 1); + String commandName = options.remove(); + Command c = Command.valueOf(commandName); + if (c == null) { + throw new UserDataException("unknown command '" + commandName + "'"); + } + println(c.getTitle()); + println(); + c.displayUsage(System.out); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/JSONWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/JSONWriter.java similarity index 83% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/JSONWriter.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/tool/JSONWriter.java index 8f441a38543..0e008c87325 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/JSONWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/JSONWriter.java @@ -23,63 +23,63 @@ * questions. */ -package jdk.jfr.internal.cmd; +package jdk.jfr.internal.tool; -import java.io.IOException; import java.io.PrintWriter; -import java.nio.file.Path; +import java.util.List; import jdk.jfr.EventType; import jdk.jfr.ValueDescriptor; import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; import jdk.jfr.consumer.RecordedObject; -import jdk.jfr.consumer.RecordingFile; -final class JSONWriter extends StructuredWriter { +final class JSONWriter extends EventPrintWriter { + + private boolean first = true; public JSONWriter(PrintWriter writer) { super(writer); } - public void print(Path source) throws IOException { - try (RecordingFile es = new RecordingFile(source)) { - printObjectBegin(); - printRecording(es); - printObjectEnd(); - flush(); - } - } - - private void printRecording(RecordingFile es) throws IOException { + @Override + protected void printBegin() { + printObjectBegin(); printDataStructureName("recording"); printObjectBegin(); - printEvents(es); - printObjectEnd(); - } - - private void printEvents(RecordingFile es) throws IOException { printDataStructureName("events"); printArrayBegin(); - boolean first = true; - while (es.hasMoreEvents()) { - RecordedEvent e = es.readEvent(); + } + + @Override + protected void print(List events) { + for (RecordedEvent event : events) { printNewDataStructure(first, true, null); - printEvent(e); - flush(); + printEvent(event); + flush(false); first = false; } - printArrayEnd(); } - private void printEvent(RecordedEvent e) { + @Override + protected void printEnd() { + printArrayEnd();; + printObjectEnd(); + printObjectEnd(); + } + + private void printEvent(RecordedEvent event) { printObjectBegin(); - EventType type = e.getEventType(); - printValue(true, false, "name", type.getName()); - printValue(false, false, "typeId", type.getId()); - printValue(false, false, "startTime", e.getStartTime()); - printValue(false, false, "duration", e.getDuration()); + EventType type = event.getEventType(); + printValue(true, false, "type", type.getName()); printNewDataStructure(false, false, "values"); - printObject(e); + printObjectBegin(); + boolean first = true; + for (ValueDescriptor v : event.getFields()) { + printValueDescriptor(first, false, v, getValue(event, v)); + first = false; + } + printObjectEnd(); printObjectEnd(); } @@ -122,7 +122,7 @@ public void printObject(RecordedObject object) { printObjectBegin(); boolean first = true; for (ValueDescriptor v : object.getFields()) { - printValueDescriptor(first, false, v, object.getValue(v.getName())); + printValueDescriptor(first, false, v, getValue(object, v)); first = false; } printObjectEnd(); @@ -131,8 +131,12 @@ public void printObject(RecordedObject object) { private void printArray(ValueDescriptor v, Object[] array) { printArrayBegin(); boolean first = true; + int depth = 0; for (Object arrayElement : array) { - printValueDescriptor(first, true, v, arrayElement); + if (!(arrayElement instanceof RecordedFrame) || depth < getStackDepth()) { + printValueDescriptor(first, true, v, arrayElement); + } + depth++; first = false; } printArrayEnd(); @@ -254,5 +258,4 @@ private void printEscaped(char c) { } print(c); } - } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Main.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Main.java new file mode 100644 index 00000000000..785ffda9133 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Main.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package jdk.jfr.internal.tool; + +import java.util.Arrays; +import java.util.Deque; +import java.util.LinkedList; + +/** + * Launcher class for the JDK_HOME\bin\jfr tool + * + */ +public final class Main { + + private static final int EXIT_OK = 0; + private static final int EXIT_FAILED = 1; + private static final int EXIT_WRONG_ARGUMENTS = 2; + + public static void main(String... args) { + Deque argList = new LinkedList<>(Arrays.asList(args)); + if (argList.isEmpty()) { + System.out.println(Command.title); + System.out.println(); + System.out.println("Before using this tool, you must have a recording file."); + System.out.println("A file can be created by starting a recording from command line:"); + System.out.println(); + System.out.println(" java -XX:StartFlightRecording:filename=recording.jfr,duration=30s ... "); + System.out.println(); + System.out.println("A recording can also be started on already running Java Virtual Machine:"); + System.out.println(); + System.out.println(" jcmd (to list available pids)"); + System.out.println(" jcmd JFR.start"); + System.out.println(); + System.out.println("Recording data can be dumped to file using the JFR.dump command:"); + System.out.println(); + System.out.println(" jcmd JFR.dump filename=recording.jfr"); + System.out.println(); + System.out.println("The contents of the recording can then be printed, for example:"); + System.out.println(); + System.out.println(" jfr print recording.jfr"); + System.out.println(); + System.out.println(" jfr print --events CPULoad,GarbageCollection recording.jfr"); + System.out.println(); + System.out.println(" jfr print --json --events CPULoad recording.jfr"); + System.out.println(); + System.out.println(" jfr print --categories \"GC,JVM,Java*\" recording.jfr"); + System.out.println(); + System.out.println(" jfr print --events \"jdk.*\" --stack-depth 64 recording.jfr"); + System.out.println(); + System.out.println(" jfr summary recording.jfr"); + System.out.println(); + System.out.println(" jfr metadata recording.jfr"); + System.out.println(); + System.out.println("For more information about available commands, use 'jfr help'"); + System.exit(EXIT_OK); + } + String command = argList.remove(); + for (Command c : Command.getCommands()) { + if (c.matches(command)) { + try { + c.execute(argList); + System.exit(EXIT_OK); + } catch (UserDataException ude) { + System.err.println("jfr " + c.getName() + ": " + ude.getMessage()); + System.exit(EXIT_FAILED); + } catch (UserSyntaxException use) { + System.err.println("jfr " + c.getName() + ": " + use.getMessage()); + System.err.println(); + System.err.println("Usage:"); + System.err.println(); + c.displayUsage(System.err); + System.exit(EXIT_WRONG_ARGUMENTS); + } catch (Throwable e) { + System.err.println("jfr " + c.getName() + ": unexpected internal error, " + e.getMessage()); + e.printStackTrace(); + System.exit(EXIT_FAILED); + } + } + } + System.err.println("jfr: unknown command '" + command + "'"); + System.err.println(); + System.err.println("List of available commands:"); + System.err.println(); + Command.displayAvailableCommands(System.err); + System.exit(EXIT_WRONG_ARGUMENTS); + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java new file mode 100644 index 00000000000..44c989c6ee0 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Metadata.java @@ -0,0 +1,139 @@ +/* + * 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.jfr.internal.tool; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Comparator; +import java.util.Deque; +import java.util.List; + +import jdk.jfr.consumer.RecordingFile; +import jdk.jfr.internal.Type; +import jdk.jfr.internal.consumer.RecordingInternals; + +final class Metadata extends Command { + + private static class TypeComparator implements Comparator { + + @Override + public int compare(Type t1, Type t2) { + int g1 = groupValue(t1); + int g2 = groupValue(t2); + if (g1 == g2) { + String n1 = t1.getName(); + String n2 = t2.getName(); + String package1 = n1.substring(0, n1.lastIndexOf('.') + 1); + String package2 = n2.substring(0, n2.lastIndexOf('.') + 1); + + if (package1.equals(package2)) { + return n1.compareTo(n2); + } else { + // Ensure that jdk.* are printed first + // This makes it easier to find user defined events at the end. + if (Type.SUPER_TYPE_EVENT.equals(t1.getSuperType()) && !package1.equals(package2)) { + if (package1.equals("jdk.jfr")) { + return -1; + } + if (package2.equals("jdk.jfr")) { + return 1; + } + } + return package1.compareTo(package2); + } + } else { + return Integer.compare(groupValue(t1), groupValue(t2)); + } + } + + int groupValue(Type t) { + String superType = t.getSuperType(); + if (superType == null) { + return 1; + } + if (Type.SUPER_TYPE_ANNOTATION.equals(superType)) { + return 3; + } + if (Type.SUPER_TYPE_SETTING.equals(superType)) { + return 4; + } + if (Type.SUPER_TYPE_EVENT.equals(superType)) { + return 5; + } + return 2; // reserved for enums in the future + } + } + + @Override + public String getName() { + return "metadata"; + } + + @Override + public List getOptionSyntax() { + return Collections.singletonList(""); + } + + @Override + public String getDescription() { + return "Display event metadata, such as labels, descriptions and field layout"; + } + + @Override + public void execute(Deque options) throws UserSyntaxException, UserDataException { + Path file = getJFRInputFile(options); + + boolean showIds = false; + int optionCount = options.size(); + while (optionCount > 0) { + if (acceptOption(options, "--ids")) { + showIds = true; + } + if (optionCount == options.size()) { + // No progress made + throw new UserSyntaxException("unknown option " + options.peek()); + } + optionCount = options.size(); + } + + try (PrintWriter pw = new PrintWriter(System.out)) { + PrettyWriter prettyWriter = new PrettyWriter(pw); + prettyWriter.setShowIds(showIds); + try (RecordingFile rf = new RecordingFile(file)) { + List types = RecordingInternals.INSTANCE.readTypes(rf); + Collections.sort(types, new TypeComparator()); + for (Type type : types) { + prettyWriter.printType(type); + } + prettyWriter.flush(true); + } catch (IOException ioe) { + couldNotReadError(file, ioe); + } + } + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java new file mode 100644 index 00000000000..dae86fefef8 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java @@ -0,0 +1,608 @@ +/* + * 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. + */ + +package jdk.jfr.internal.tool; + +import java.io.PrintWriter; +import java.time.Duration; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; + +import jdk.jfr.AnnotationElement; +import jdk.jfr.DataAmount; +import jdk.jfr.Frequency; +import jdk.jfr.MemoryAddress; +import jdk.jfr.Percentage; +import jdk.jfr.ValueDescriptor; +import jdk.jfr.consumer.RecordedClass; +import jdk.jfr.consumer.RecordedClassLoader; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.consumer.RecordedObject; +import jdk.jfr.consumer.RecordedStackTrace; +import jdk.jfr.consumer.RecordedThread; +import jdk.jfr.internal.PrivateAccess; +import jdk.jfr.internal.Type; +import jdk.jfr.internal.Utils; + +/** + * Print events in a human-readable format. + * + * This class is also used by {@link RecordedObject#toString()} + */ +public final class PrettyWriter extends EventPrintWriter { + private static final Duration MILLSECOND = Duration.ofMillis(1); + private static final Duration SECOND = Duration.ofSeconds(1); + private static final Duration MINUTE = Duration.ofMinutes(1); + private static final String TYPE_OLD_OBJECT = Type.TYPES_PREFIX + "OldObject"; + private final static DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss.SSS"); + private final static Long ZERO = 0L; + private boolean showIds; + private RecordedEvent currentEvent; + + public PrettyWriter(PrintWriter destination) { + super(destination); + } + + @Override + protected void print(List events) { + for (RecordedEvent e : events) { + print(e); + flush(false); + } + } + + public void printType(Type t) { + if (showIds) { + print("// id: "); + println(String.valueOf(t.getId())); + } + int commentIndex = t.getName().length() + 10; + String typeName = t.getName(); + int index = typeName.lastIndexOf("."); + if (index != -1) { + println("@Name(\"" + typeName + "\")"); + } + printAnnotations(commentIndex, t.getAnnotationElements()); + print("class " + typeName.substring(index + 1)); + String superType = t.getSuperType(); + if (superType != null) { + print(" extends " + superType); + } + println(" {"); + indent(); + boolean first = true; + for (ValueDescriptor v : t.getFields()) { + printField(commentIndex, v, first); + first = false; + } + retract(); + println("}"); + println(); + } + + private void printField(int commentIndex, ValueDescriptor v, boolean first) { + if (!first) { + println(); + } + printAnnotations(commentIndex, v.getAnnotationElements()); + printIndent(); + Type vType = PrivateAccess.getInstance().getType(v); + if (Type.SUPER_TYPE_SETTING.equals(vType.getSuperType())) { + print("static "); + } + print(makeSimpleType(v.getTypeName())); + if (v.isArray()) { + print("[]"); + } + print(" "); + print(v.getName()); + print(";"); + printCommentRef(commentIndex, v.getTypeId()); + } + + private void printCommentRef(int commentIndex, long typeId) { + if (showIds) { + int column = getColumn(); + if (column > commentIndex) { + print(" "); + } else { + while (column < commentIndex) { + print(" "); + column++; + } + } + println(" // id=" + typeId); + } else { + println(); + } + } + + private void printAnnotations(int commentIndex, List annotations) { + for (AnnotationElement a : annotations) { + printIndent(); + print("@"); + print(makeSimpleType(a.getTypeName())); + List vs = a.getValueDescriptors(); + if (!vs.isEmpty()) { + printAnnotation(a); + printCommentRef(commentIndex, a.getTypeId()); + } else { + println(); + } + } + } + + private void printAnnotation(AnnotationElement a) { + StringJoiner sj = new StringJoiner(", ", "(", ")"); + List vs = a.getValueDescriptors(); + for (ValueDescriptor v : vs) { + Object o = a.getValue(v.getName()); + if (vs.size() == 1 && v.getName().equals("value")) { + sj.add(textify(o)); + } else { + sj.add(v.getName() + "=" + textify(o)); + } + } + print(sj.toString()); + } + + private String textify(Object o) { + if (o.getClass().isArray()) { + Object[] array = (Object[]) o; + if (array.length == 1) { + return quoteIfNeeded(array[0]); + } + StringJoiner s = new StringJoiner(", ", "{", "}"); + for (Object ob : array) { + s.add(quoteIfNeeded(ob)); + } + return s.toString(); + } else { + return quoteIfNeeded(o); + } + } + + private String quoteIfNeeded(Object o) { + if (o instanceof String) { + return "\"" + o + "\""; + } else { + return String.valueOf(o); + } + } + + private String makeSimpleType(String typeName) { + int index = typeName.lastIndexOf("."); + return typeName.substring(index + 1); + } + + public void print(RecordedEvent event) { + currentEvent = event; + print(event.getEventType().getName(), " "); + println("{"); + indent(); + for (ValueDescriptor v : event.getFields()) { + String name = v.getName(); + if (!isZeroDuration(event, name) && !isLateField(name)) { + printFieldValue(event, v); + } + } + if (event.getThread() != null) { + printIndent(); + print(EVENT_THREAD_FIELD + " = "); + printThread(event.getThread(), ""); + } + if (event.getStackTrace() != null) { + printIndent(); + print(STACK_TRACE_FIELD + " = "); + printStackTrace(event.getStackTrace()); + } + retract(); + printIndent(); + println("}"); + println(); + } + + private boolean isZeroDuration(RecordedEvent event, String name) { + return name.equals("duration") && ZERO.equals(event.getValue("duration")); + } + + private void printStackTrace(RecordedStackTrace stackTrace) { + println("["); + List frames = stackTrace.getFrames(); + indent(); + int i = 0; + while (i < frames.size() && i < getStackDepth()) { + RecordedFrame frame = frames.get(i); + if (frame.isJavaFrame()) { + printIndent(); + printValue(frame, null, ""); + println(); + i++; + } + } + if (stackTrace.isTruncated() || i == getStackDepth()) { + printIndent(); + println("..."); + } + retract(); + printIndent(); + println("]"); + } + + public void print(RecordedObject struct, String postFix) { + println("{"); + indent(); + for (ValueDescriptor v : struct.getFields()) { + printFieldValue(struct, v); + } + retract(); + printIndent(); + println("}" + postFix); + } + + private void printFieldValue(RecordedObject struct, ValueDescriptor v) { + printIndent(); + print(v.getName(), " = "); + printValue(getValue(struct, v), v, ""); + } + + private void printArray(Object[] array) { + println("["); + indent(); + for (int i = 0; i < array.length; i++) { + printIndent(); + printValue(array[i], null, i + 1 < array.length ? ", " : ""); + } + retract(); + printIndent(); + println("]"); + } + + private void printValue(Object value, ValueDescriptor field, String postFix) { + if (value == null) { + println("N/A" + postFix); + return; + } + if (value instanceof RecordedObject) { + if (value instanceof RecordedThread) { + printThread((RecordedThread) value, postFix); + return; + } + if (value instanceof RecordedClass) { + printClass((RecordedClass) value, postFix); + return; + } + if (value instanceof RecordedClassLoader) { + printClassLoader((RecordedClassLoader) value, postFix); + return; + } + if (value instanceof RecordedFrame) { + RecordedFrame frame = (RecordedFrame) value; + if (frame.isJavaFrame()) { + printJavaFrame((RecordedFrame) value, postFix); + return; + } + } + if (value instanceof RecordedMethod) { + println(formatMethod((RecordedMethod) value)); + return; + } + if (field.getTypeName().equals(TYPE_OLD_OBJECT)) { + printOldObject((RecordedObject) value); + return; + } + print((RecordedObject) value, postFix); + return; + } + if (value.getClass().isArray()) { + printArray((Object[]) value); + return; + } + if (value instanceof Double) { + Double d = (Double) value; + if (Double.isNaN(d) || d == Double.NEGATIVE_INFINITY) { + println("N/A"); + return; + } + } + if (value instanceof Float) { + Float f = (Float) value; + if (Float.isNaN(f) || f == Float.NEGATIVE_INFINITY) { + println("N/A"); + return; + } + } + if (value instanceof Long) { + Long l = (Long) value; + if (l == Long.MIN_VALUE) { + println("N/A"); + return; + } + } + if (value instanceof Integer) { + Integer i = (Integer) value; + if (i == Integer.MIN_VALUE) { + println("N/A"); + return; + } + } + + if (field.getContentType() != null) { + if (printFormatted(field, value)) { + return; + } + } + String text = String.valueOf(value); + if (value instanceof String) { + text = "\"" + text + "\""; + } + println(text); + } + + private void printOldObject(RecordedObject object) { + println(" ["); + indent(); + printIndent(); + try { + printReferenceChain(object); + } catch (IllegalArgumentException iae) { + // Could not find a field + // Not possible to validate fields beforehand using RecordedObject#hasField + // since nested objects, for example object.referrer.array.index, requires + // an actual array object (which may be null). + } + retract(); + printIndent(); + println("]"); + } + + private void printReferenceChain(RecordedObject object) { + printObject(object, currentEvent.getLong("arrayElements")); + for (RecordedObject ref = object.getValue("referrer"); ref != null; ref = object.getValue("referrer")) { + long skip = ref.getLong("skip"); + if (skip > 0) { + printIndent(); + println("..."); + } + String objectHolder = ""; + long size = Long.MIN_VALUE; + RecordedObject array = ref.getValue("array"); + if (array != null) { + long index = array.getLong("index"); + size = array.getLong("size"); + objectHolder = "[" + index + "]"; + } + RecordedObject field = ref.getValue("field"); + if (field != null) { + objectHolder = field.getString("name"); + } + printIndent(); + print(objectHolder); + print(" : "); + object = ref.getValue("object"); + if (object != null) { + printObject(object, size); + } + } + } + + void printObject(RecordedObject object, long arraySize) { + RecordedClass clazz = object.getClass("type"); + if (clazz != null) { + String className = clazz.getName(); + if (className!= null && className.startsWith("[")) { + className = decodeDescriptors(className, arraySize > 0 ? Long.toString(arraySize) : "").get(0); + } + print(className); + String description = object.getString("description"); + if (description != null) { + print(" "); + print(description); + } + } + println(); + } + + private void printClassLoader(RecordedClassLoader cl, String postFix) { + // Purposely not printing class loader name to avoid cluttered output + RecordedClass clazz = cl.getType(); + print(clazz == null ? "null" : clazz.getName()); + if (clazz != null) { + print(" ("); + print("id = "); + print(String.valueOf(cl.getId())); + println(")"); + } + } + + private void printJavaFrame(RecordedFrame f, String postFix) { + print(formatMethod(f.getMethod())); + int line = f.getLineNumber(); + if (line >= 0) { + print(" line: " + line); + } + print(postFix); + } + + private String formatMethod(RecordedMethod m) { + StringBuilder sb = new StringBuilder(); + sb.append(m.getType().getName()); + sb.append("."); + sb.append(m.getName()); + sb.append("("); + StringJoiner sj = new StringJoiner(", "); + String md = m.getDescriptor().replace("/", "."); + String parameter = md.substring(1, md.lastIndexOf(")")); + for (String qualifiedName : decodeDescriptors(parameter, "")) { + String typeName = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1); + sj.add(typeName); + } + sb.append(sj); + sb.append(")"); + return sb.toString(); + } + + private void printClass(RecordedClass clazz, String postFix) { + RecordedClassLoader classLoader = clazz.getClassLoader(); + String classLoaderName = "null"; + if (classLoader != null) { + if (classLoader.getName() != null) { + classLoaderName = classLoader.getName(); + } else { + classLoaderName = classLoader.getType().getName(); + } + } + String className = clazz.getName(); + if (className.startsWith("[")) { + className = decodeDescriptors(className, "").get(0); + } + println(className + " (classLoader = " + classLoaderName + ")" + postFix); + } + + List decodeDescriptors(String descriptor, String arraySize) { + List descriptors = new ArrayList<>(); + for (int index = 0; index < descriptor.length(); index++) { + String arrayBrackets = ""; + while (descriptor.charAt(index) == '[') { + arrayBrackets = arrayBrackets + "[" + arraySize + "]" ; + arraySize = ""; + index++; + } + char c = descriptor.charAt(index); + String type; + switch (c) { + case 'L': + int endIndex = descriptor.indexOf(';', index); + type = descriptor.substring(index + 1, endIndex); + index = endIndex; + break; + case 'I': + type = "int"; + break; + case 'J': + type = "long"; + break; + case 'Z': + type = "boolean"; + break; + case 'D': + type = "double"; + break; + case 'F': + type = "float"; + break; + case 'S': + type = "short"; + break; + case 'C': + type = "char"; + break; + case 'B': + type = "byte"; + break; + default: + type = ""; + } + descriptors.add(type + arrayBrackets); + } + return descriptors; + } + + private void printThread(RecordedThread thread, String postFix) { + long javaThreadId = thread.getJavaThreadId(); + if (javaThreadId > 0) { + println("\"" + thread.getJavaName() + "\" (javaThreadId = " + thread.getJavaThreadId() + ")" + postFix); + } else { + println("\"" + thread.getOSName() + "\" (osThreadId = " + thread.getOSThreadId() + ")" + postFix); + } + } + + private boolean printFormatted(ValueDescriptor field, Object value) { + if (value instanceof Duration) { + Duration d = (Duration) value; + if (d.getSeconds() == Long.MIN_VALUE) { + println("N/A"); + return true; + } + if(d.compareTo(MILLSECOND) < 0){ + println(String.format("%.3f us", (double)d.toNanos() / 1_000)); + } else if(d.compareTo(SECOND) < 0){ + println(String.format("%.3f ms", (double)d.toNanos() / 1_000_000)); + } else if(d.compareTo(MINUTE) < 0){ + println(String.format("%.3f s", (double)d.toMillis() / 1_000)); + } else { + println(String.format("%d s", d.toSeconds())); + } + return true; + } + if (value instanceof OffsetDateTime) { + OffsetDateTime odt = (OffsetDateTime) value; + if (odt.equals(OffsetDateTime.MIN)) { + println("N/A"); + return true; + } + println(TIME_FORMAT.format(odt)); + return true; + } + Percentage percentage = field.getAnnotation(Percentage.class); + if (percentage != null) { + if (value instanceof Number) { + double d = ((Number) value).doubleValue(); + println(String.format("%.2f", d * 100) + "%"); + return true; + } + } + DataAmount dataAmount = field.getAnnotation(DataAmount.class); + if (dataAmount != null) { + if (value instanceof Number) { + Number n = (Number) value; + String bytes = Utils.formatBytes(n.longValue()); + if (field.getAnnotation(Frequency.class) != null) { + bytes += "/s"; + } + println(bytes); + return true; + } + } + MemoryAddress memoryAddress = field.getAnnotation(MemoryAddress.class); + if (memoryAddress != null) { + if (value instanceof Number) { + long d = ((Number) value).longValue(); + println(String.format("0x%08X", d)); + return true; + } + } + return false; + } + + public void setShowIds(boolean showIds) { + this.showIds = showIds; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java new file mode 100644 index 00000000000..7b5d89f9e2f --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Print.java @@ -0,0 +1,282 @@ +/* + * 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. + */ + +package jdk.jfr.internal.tool; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; + +import jdk.jfr.EventType; + +final class Print extends Command { + @Override + public String getName() { + return "print"; + } + + @Override + public List getOptionSyntax() { + List list = new ArrayList<>(); + list.add("[--xml|--json]"); + list.add("[--categories ]"); + list.add("[--events ]"); + list.add("[--stack-depth ]"); + list.add(""); + return list; + } + + @Override + protected String getTitle() { + return "Print contents of a recording file"; + } + + @Override + public String getDescription() { + return getTitle() + ". See 'jfr help print' for details."; + } + + @Override + public void displayOptionUsage(PrintStream stream) { + stream.println(" --xml Print recording in XML format"); + stream.println(); + stream.println(" --json Print recording in JSON format"); + stream.println(); + stream.println(" --categories Select events matching a category name."); + stream.println(" The filter is a comma-separated list of names,"); + stream.println(" simple and/or qualified, and/or quoted glob patterns"); + stream.println(); + stream.println(" --events Select events matching an event name."); + stream.println(" The filter is a comma-separated list of names,"); + stream.println(" simple and/or qualified, and/or quoted glob patterns"); + stream.println(); + stream.println(" --stack-depth Number of frames in stack traces, by default 5"); + stream.println(); + stream.println(" Location of the recording file (.jfr)"); + stream.println(); + stream.println(); + stream.println("Example usage:"); + stream.println(); + stream.println(" jfr print --events OldObjectSample recording.jfr"); + stream.println(); + stream.println(" jfr print --events CPULoad,GarbageCollection recording.jfr"); + stream.println(); + stream.println(" jfr print --categories \"GC,JVM,Java*\" recording.jfr"); + stream.println(); + stream.println(" jfr print --events \"jdk.*\" --stack-depth 64 recording.jfr"); + stream.println(); + stream.println(" jfr print --json --events CPULoad recording.jfr"); + } + + @Override + public void execute(Deque options) throws UserSyntaxException, UserDataException { + Path file = getJFRInputFile(options); + PrintWriter pw = new PrintWriter(System.out, false, Charset.forName("UTF-8")); + Predicate eventFilter = null; + int stackDepth = 5; + EventPrintWriter eventWriter = null; + int optionCount = options.size(); + boolean foundEventFilter = false; + boolean foundCategoryFilter = false; + while (optionCount > 0) { + if (acceptFilterOption(options, "--events")) { + if (foundEventFilter) { + throw new UserSyntaxException("use --events event1,event2,event3 to include multiple events"); + } + foundEventFilter = true; + String filter = options.remove(); + warnForWildcardExpansion("--events", filter); + eventFilter = addEventFilter(filter, eventFilter); + } + if (acceptFilterOption(options, "--categories")) { + if (foundCategoryFilter) { + throw new UserSyntaxException("use --categories category1,category2 to include multiple categories"); + } + foundCategoryFilter = true; + String filter = options.remove(); + warnForWildcardExpansion("--categories", filter); + eventFilter = addCategoryFilter(filter, eventFilter); + } + if (acceptOption(options, "--stack-depth")) { + String value = options.pop(); + try { + stackDepth = Integer.parseInt(value); + if (stackDepth < 0) { + throw new UserSyntaxException("stack depth must be zero or a positive integer."); + } + } catch (NumberFormatException nfe) { + throw new UserSyntaxException("not a valid value for --stack-depth"); + } + } + if (acceptFormatterOption(options, eventWriter, "--json")) { + eventWriter = new JSONWriter(pw); + } + if (acceptFormatterOption(options, eventWriter, "--xml")) { + eventWriter = new XMLWriter(pw); + } + if (optionCount == options.size()) { + // No progress made + checkCommonError(options, "--event", "--events"); + checkCommonError(options, "--category", "--categories"); + throw new UserSyntaxException("unknown option " + options.peek()); + } + optionCount = options.size(); + } + if (eventWriter == null) { + eventWriter = new PrettyWriter(pw); // default to pretty printer + } + eventWriter.setStackDepth(stackDepth); + if (eventFilter != null) { + eventFilter = addCache(eventFilter, eventType -> eventType.getId()); + eventWriter.setEventFilter(eventFilter); + } + try { + eventWriter.print(file); + } catch (IOException ioe) { + couldNotReadError(file, ioe); + } + pw.flush(); + } + + private void checkCommonError(Deque options, String typo, String correct) throws UserSyntaxException { + if (typo.equals(options.peek())) { + throw new UserSyntaxException("unknown option " + typo + ", did you mean " + correct + "?"); + } + } + + private static boolean acceptFormatterOption(Deque options, EventPrintWriter eventWriter, String expected) throws UserSyntaxException { + if (expected.equals(options.peek())) { + if (eventWriter != null) { + throw new UserSyntaxException("only one format can be specified at a time"); + } + options.remove(); + return true; + } + return false; + } + + private static Predicate addCache(final Predicate filter, Function cacheFunction) { + Map cache = new HashMap<>(); + return t -> cache.computeIfAbsent(cacheFunction.apply(t), x -> filter.test(t)); + } + + private static Predicate recurseIfPossible(Predicate filter) { + return x -> filter != null && filter.test(x); + } + + private static Predicate addCategoryFilter(String filterText, Predicate eventFilter) throws UserSyntaxException { + List filters = explodeFilter(filterText); + Predicate newFilter = recurseIfPossible(eventType -> { + for (String category : eventType.getCategoryNames()) { + for (String filter : filters) { + if (match(category, filter)) { + return true; + } + if (category.contains(" ") && acronomify(category).equals(filter)) { + return true; + } + } + } + return false; + }); + return eventFilter == null ? newFilter : eventFilter.or(newFilter); + } + + private static String acronomify(String multipleWords) { + boolean newWord = true; + String acronym = ""; + for (char c : multipleWords.toCharArray()) { + if (newWord) { + if (Character.isAlphabetic(c) && Character.isUpperCase(c)) { + acronym += c; + } + } + newWord = Character.isWhitespace(c); + } + return acronym; + } + + private static Predicate addEventFilter(String filterText, final Predicate eventFilter) throws UserSyntaxException { + List filters = explodeFilter(filterText); + Predicate newFilter = recurseIfPossible(eventType -> { + for (String filter : filters) { + String fullEventName = eventType.getName(); + if (match(fullEventName, filter)) { + return true; + } + String eventName = fullEventName.substring(fullEventName.lastIndexOf(".") + 1); + if (match(eventName, filter)) { + return true; + } + } + return false; + }); + return eventFilter == null ? newFilter : eventFilter.or(newFilter); + } + + private static boolean match(String text, String filter) { + if (filter.length() == 0) { + // empty filter string matches if string is empty + return text.length() == 0; + } + if (filter.charAt(0) == '*') { // recursive check + filter = filter.substring(1); + for (int n = 0; n <= text.length(); n++) { + if (match(text.substring(n), filter)) + return true; + } + } else if (text.length() == 0) { + // empty string and non-empty filter does not match + return false; + } else if (filter.charAt(0) == '?') { + // eat any char and move on + return match(text.substring(1), filter.substring(1)); + } else if (filter.charAt(0) == text.charAt(0)) { + // eat chars and move on + return match(text.substring(1), filter.substring(1)); + } + return false; + } + + private static List explodeFilter(String filter) throws UserSyntaxException { + List list = new ArrayList<>(); + for (String s : filter.split(",")) { + s = s.trim(); + if (!s.isEmpty()) { + list.add(s); + } + } + return list; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/StructuredWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/StructuredWriter.java similarity index 86% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/StructuredWriter.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/tool/StructuredWriter.java index eef11859e30..f6b5ae2d068 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/StructuredWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/StructuredWriter.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jfr.internal.cmd; +package jdk.jfr.internal.tool; import java.io.PrintWriter; @@ -36,6 +36,8 @@ abstract class StructuredWriter { private char[] indentionArray = new char[0]; private int indent = 0; private int column; + // print first event immediately so tool feels responsive + private boolean first = true; StructuredWriter(PrintWriter p) { out = p; @@ -46,9 +48,17 @@ final protected int getColumn() { } // Flush to print writer - public final void flush() { - out.print(builder.toString()); - builder.setLength(0); + public final void flush(boolean hard) { + if (hard) { + out.print(builder.toString()); + builder.setLength(0); + return; + } + if (first || builder.length() > 100_000) { + out.print(builder.toString()); + builder.setLength(0); + first = false; + } } final public void printIndent() { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SummaryCommand.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java similarity index 81% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SummaryCommand.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java index 106409d53bd..e282d6b7e33 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/SummaryCommand.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java @@ -23,18 +23,20 @@ * questions. */ -package jdk.jfr.internal.cmd; +package jdk.jfr.internal.tool; import java.io.IOException; +import java.io.PrintStream; import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.List; +import java.util.Locale; import jdk.jfr.EventType; import jdk.jfr.internal.MetadataDescriptor; @@ -42,31 +44,31 @@ import jdk.jfr.internal.consumer.ChunkHeader; import jdk.jfr.internal.consumer.RecordingInput; -final class SummaryCommand extends Command { +final class Summary extends Command { + private final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withLocale(Locale.UK).withZone(ZoneOffset.UTC); + + @Override + public String getName() { + return "summary"; + } private static class Statistics { Statistics(String name) { this.name = name; } - String name; long count; long size; } @Override - public String getOptionSyntax() { - return ""; + public List getOptionSyntax() { + return Collections.singletonList(""); } @Override - public void displayOptionUsage() { - println(" Location of the recording file (.jfr) to display information about"); - } - - @Override - public String getName() { - return "summary"; + public void displayOptionUsage(PrintStream stream) { + stream.println(" Location of the recording file (.jfr) to display information about"); } @Override @@ -75,23 +77,17 @@ public String getDescription() { } @Override - public void execute(Deque options) { - if (options.isEmpty()) { - userFailed("Missing file"); - } + public void execute(Deque options) throws UserSyntaxException, UserDataException { ensureMaxArgumentCount(options, 1); - Path p = Paths.get(options.remove()); - ensureFileExist(p); - ensureJFRFile(p); + Path p = getJFRInputFile(options); try { printInformation(p); } catch (IOException e) { - throw new IllegalStateException("Unexpected error. " + e.getMessage()); + couldNotReadError(p, e); } } private void printInformation(Path p) throws IOException { - long totalSize = 0; long totalDuration = 0; long chunks = 0; @@ -115,17 +111,14 @@ private void printInformation(Path p) throws IOException { minWidth = Math.max(minWidth, eventType.getName().length()); } - totalSize += ch.getSize(); - totalDuration += ch.getDuration(); + totalDuration += ch.getDurationNanos(); chunks++; input.position(ch.getEventStart()); while (input.position() < chunkEnd) { - long pos = input.position(); int size = input.readInt(); long eventTypeId = input.readLong(); Statistics s = stats.get(eventTypeId); - if (s != null) { s.count++; s.size += size; @@ -142,12 +135,8 @@ private void printInformation(Path p) throws IOException { long adjustNanos = first.getStartNanos() - epochSeconds * 1_000_000_000L; println(" Version: " + first.getMajor() + "." + first.getMinor()); println(" Chunks: " + chunks); - println(" Size: " + totalSize + " bytes"); - println(" Start: " + Instant.ofEpochSecond(epochSeconds, adjustNanos)); - println(" Duration: " + Duration.ofNanos(totalDuration)); - println(); - println(" Start Ticks: " + first.getStartTicks()); - println(" Ticks / Second: " + first.getTicksPerSecond()); + println(" Start: " + DATE_FORMAT.format(Instant.ofEpochSecond(epochSeconds, adjustNanos)) + " (UTC)"); + println(" Duration: " + (totalDuration + 500_000_000) / 1_000_000_000 + " s"); List statsList = new ArrayList<>(stats.values()); Collections.sort(statsList, (u, v) -> Long.compare(v.count, u.count)); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/UserDataException.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/UserDataException.java new file mode 100644 index 00000000000..a21ae95f671 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/UserDataException.java @@ -0,0 +1,49 @@ +/* + * 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.jfr.internal.tool; + +/** + * Exception that is thrown if there is something wrong with the input, for instance + * a file that can't be read or a numerical value that is out of range. + *

    + * When this exception is thrown, a user will typically not want to see the + * command line syntax, but instead information about what was wrong with the + * input. + */ +final class UserDataException extends Exception { + private static final long serialVersionUID = 6656457380115167810L; + /** + * The error message. + * + * The first letter should not be capitalized, so a context can be printed prior + * to the error message. + * + * @param errorMessage + */ + public UserDataException(String errorMessage) { + super(errorMessage); + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/UserSyntaxException.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/UserSyntaxException.java new file mode 100644 index 00000000000..db6224ccee3 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/UserSyntaxException.java @@ -0,0 +1,45 @@ +/* + * 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.jfr.internal.tool; + +/** + * Exception that is thrown if options don't follow the syntax of the command. + */ +final class UserSyntaxException extends Exception { + private static final long serialVersionUID = 3437009454344160933L; + + /** + * The error message. + * + * The first letter should not be capitalized, so a context can be printed prior + * to the error message. + * + * @param errorMessage + */ + public UserSyntaxException(String message) { + super(message); + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Version.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Version.java new file mode 100644 index 00000000000..2f3eea9902d --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Version.java @@ -0,0 +1,50 @@ +/* + * 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.jfr.internal.tool; + +import java.util.Deque; +import java.util.List; + +final class Version extends Command { + @Override + public String getName() { + return "version"; + } + + @Override + public String getDescription() { + return "Display version of the jfr tool"; + } + + @Override + public void execute(Deque options) { + System.out.println("1.0"); + } + + protected List getAliases() { + return List.of("--version"); + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/XMLWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/XMLWriter.java similarity index 75% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/XMLWriter.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/tool/XMLWriter.java index f765c0dd0c2..2db1688239b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/cmd/XMLWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/XMLWriter.java @@ -23,55 +23,60 @@ * questions. */ -package jdk.jfr.internal.cmd; +package jdk.jfr.internal.tool; -import java.io.IOException; import java.io.PrintWriter; -import java.nio.file.Path; +import java.util.List; import jdk.jfr.EventType; import jdk.jfr.ValueDescriptor; import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; import jdk.jfr.consumer.RecordedObject; -import jdk.jfr.consumer.RecordingFile; - -final class XMLWriter extends StructuredWriter { +final class XMLWriter extends EventPrintWriter { public XMLWriter(PrintWriter destination) { super(destination); } - public void print(Path source) throws IOException { - try (RecordingFile es = new RecordingFile(source)) { - println(""); - println(""); - indent(); - printIndent(); - println(""); - indent(); - while (es.hasMoreEvents()) { - printEvent(es.readEvent()); - flush(); - } - retract(); - printIndent(); - println(""); - retract(); - println(""); - flush(); + @Override + protected void printBegin() { + println(""); + println(""); + indent(); + printIndent(); + println(""); + indent(); + } + + @Override + protected void printEnd() { + retract(); + printIndent(); + println(""); + retract(); + println(""); + } + + @Override + protected void print(List events) { + for (RecordedEvent event : events) { + printEvent(event); } } - private void printEvent(RecordedEvent e) throws IOException { - EventType type = e.getEventType(); + private void printEvent(RecordedEvent event) { + EventType type = event.getEventType(); printIndent(); print(""); - printObject(e); + println(); + indent(); + for (ValueDescriptor v : event.getFields()) { + printValueDescriptor(v, getValue(event, v), -1); + } + retract(); printIndent(); println(""); println(); @@ -85,7 +90,7 @@ public void printObject(RecordedObject struct) { println(); indent(); for (ValueDescriptor v : struct.getFields()) { - printValueDescriptor(v, struct.getValue(v.getName()), -1); + printValueDescriptor(v, getValue(struct, v), -1); } retract(); } @@ -93,8 +98,13 @@ public void printObject(RecordedObject struct) { private void printArray(ValueDescriptor v, Object[] array) { println(); indent(); + int depth = 0; for (int index = 0; index < array.length; index++) { - printValueDescriptor(v, array[index], index); + Object arrayElement = array[index]; + if (!(arrayElement instanceof RecordedFrame) || depth < getStackDepth()) { + printValueDescriptor(v, array[index], index); + } + depth++; } retract(); } @@ -134,9 +144,8 @@ private boolean printBeginElement(String elementName, String name, Object value, printAttribute("index", Integer.toString(index)); } if (value == null) { - print(">"); + printAttribute("xsi:nil", "true"); + println("/>"); return false; } if (value.getClass().isArray()) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/package-info.java b/src/jdk.jfr/share/classes/jdk/jfr/package-info.java index 2af1651d956..a33e6b041d0 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/package-info.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/package-info.java @@ -105,7 +105,6 @@ * {@link jdk.jfr.ValueDescriptor#getName()}. *

    * Predefined settings - *

    * * * diff --git a/src/jdk.jfr/share/classes/module-info.java b/src/jdk.jfr/share/classes/module-info.java index 2355126c080..dc65de9eb3b 100644 --- a/src/jdk.jfr/share/classes/module-info.java +++ b/src/jdk.jfr/share/classes/module-info.java @@ -25,6 +25,12 @@ /** * Defines the API for JDK Flight Recorder. + *

    + * + *

    + *
    Tool Guides: + *
    {@extLink jfr_tool_reference jfr} + *
    * * @moduleGraph * @since 9 diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 04e02e93134..d55eeeafc0d 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -115,12 +115,12 @@ true - 20 ms + 20 ms true - 20 ms + 20 ms @@ -488,6 +488,11 @@ beginChunk + + true + beginChunk + + true beginChunk @@ -773,13 +778,42 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index fec835f1493..9023cd020f7 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -115,12 +115,12 @@ true - 10 ms + 10 ms true - 10 ms + 20 ms @@ -488,6 +488,11 @@ beginChunk + + true + beginChunk + + true beginChunk @@ -773,14 +778,43 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_ja.java b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_ja.java index 93d35187c51..61df7263f69 100644 --- a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_ja.java +++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_ja.java @@ -97,6 +97,10 @@ protected final Object[][] getContents() { "\u6c11\u56fd\u524d", "\u6c11\u56fd", }; + final String[] gregoryEras = { + "\u7d00\u5143\u524d", + "\u897f\u66a6", + }; return new Object[][] { { "MonthNames", new String[] { @@ -171,12 +175,8 @@ protected final Object[][] getContents() { "\u5348\u5f8c" // pm marker } }, - { "Eras", - new String[] { // era strings for GregorianCalendar - "\u7d00\u5143\u524d", - "\u897f\u66a6" - } - }, + { "Eras", gregoryEras }, + { "short.Eras", gregoryEras }, { "buddhist.Eras", new String[] { // era strings for Thai Buddhist calendar "\u7d00\u5143\u524d", // Kigenzen diff --git a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh.java b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh.java index 7b05db6e955..e902bfcbd26 100644 --- a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh.java +++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,6 +88,10 @@ protected final Object[][] getContents() { "\u6c11\u56fd\u524d", "\u6c11\u56fd", }; + final String[] gregoryEras = { + "\u516c\u5143\u524d", + "\u516c\u5143", + }; return new Object[][] { { "MonthNames", new String[] { @@ -263,12 +267,8 @@ protected final Object[][] getContents() { "\u4e0b\u5348" // pm marker } }, - { "Eras", - new String[] { // era strings - "\u516c\u5143\u524d", - "\u516c\u5143" - } - }, + { "Eras", gregoryEras }, + { "short.Eras", gregoryEras }, { "buddhist.Eras", new String[] { "BC", diff --git a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh_TW.java b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh_TW.java index 69003106237..fd4b8872b80 100644 --- a/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh_TW.java +++ b/src/jdk.localedata/share/classes/sun/text/resources/ext/FormatData_zh_TW.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,13 +88,13 @@ protected final Object[][] getContents() { "\u6c11\u570b\u524d", "\u6c11\u570b", }; + final String[] gregoryEras = { + "\u897f\u5143\u524d", + "\u897f\u5143", + }; return new Object[][] { - { "Eras", - new String[] { // era strings - "\u897f\u5143\u524d", - "\u897f\u5143" - } - }, + { "Eras", gregoryEras }, + { "short.Eras", gregoryEras }, { "standalone.MonthAbbreviations", new String[] { "1\u6708", diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java index 8ddde88569a..8b1231b2773 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java @@ -517,7 +517,6 @@ public interface FlightRecorderMXBean extends PlatformManagedObject { * event type is obtained by invoking * {@link jdk.jfr.EventType#getSettingDescriptors()} and * {@link jdk.jfr.ValueDescriptor#getName()}. - *

    * * @param recordingId ID of the recording * diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java index 4a9206b7772..115ed8cd87f 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.StringReader; +import java.nio.file.Path; import java.nio.file.Paths; import java.security.AccessControlContext; import java.security.AccessController; @@ -105,7 +106,8 @@ public Void run() { private static final String OPTION_DISK = "disk"; private static final String OPTION_DUMP_ON_EXIT = "dumpOnExit"; private static final String OPTION_DURATION = "duration"; - private static final List OPTIONS = Arrays.asList(new String[] { OPTION_DUMP_ON_EXIT, OPTION_DURATION, OPTION_NAME, OPTION_MAX_AGE, OPTION_MAX_SIZE, OPTION_DISK, }); + private static final String OPTION_DESTINATION = "destination"; + private static final List OPTIONS = Arrays.asList(new String[] { OPTION_DUMP_ON_EXIT, OPTION_DURATION, OPTION_NAME, OPTION_MAX_AGE, OPTION_MAX_SIZE, OPTION_DISK, OPTION_DESTINATION, }); private final StreamManager streamHandler = new StreamManager(); private final Map changes = new ConcurrentHashMap<>(); private final AtomicLong sequenceNumber = new AtomicLong(); @@ -283,6 +285,7 @@ public void setRecordingOptions(long recording, Map options) thr validateOption(ops, OPTION_MAX_AGE, MBeanUtils::duration); validateOption(ops, OPTION_MAX_SIZE, MBeanUtils::size); validateOption(ops, OPTION_DURATION, MBeanUtils::duration); + validateOption(ops, OPTION_DESTINATION, x -> MBeanUtils.destination(r, x)); // All OK, now set them.atomically setOption(ops, OPTION_DUMP_ON_EXIT, "false", MBeanUtils::booleanValue, x -> r.setDumpOnExit(x)); @@ -291,6 +294,7 @@ public void setRecordingOptions(long recording, Map options) thr setOption(ops, OPTION_MAX_AGE, null, MBeanUtils::duration, x -> r.setMaxAge(x)); setOption(ops, OPTION_MAX_SIZE, "0", MBeanUtils::size, x -> r.setMaxSize(x)); setOption(ops, OPTION_DURATION, null, MBeanUtils::duration, x -> r.setDuration(x)); + setOption(ops, OPTION_DESTINATION, null, x -> MBeanUtils.destination(r, x), x -> setOptionDestination(r, x)); } @Override @@ -305,6 +309,7 @@ public Map getRecordingOptions(long recording) throws IllegalArg Long maxSize = r.getMaxSize(); options.put(OPTION_MAX_SIZE, String.valueOf(maxSize == null ? "0" : maxSize.toString())); options.put(OPTION_DURATION, ManagementSupport.formatTimespan(r.getDuration(), " ")); + options.put(OPTION_DESTINATION, ManagementSupport.getDestinationOriginalText(r)); return options; } @@ -349,6 +354,20 @@ private static void setOption(Map options, String name, S } } + private static void setOptionDestination(Recording recording, String destination){ + try { + Path pathDestination = null; + if(destination != null){ + pathDestination = Paths.get(destination); + } + recording.setDestination(pathDestination); + } catch (IOException e) { + IllegalArgumentException iae = new IllegalArgumentException("Not a valid destination " + destination); + iae.addSuppressed(e); + throw iae; + } + } + private static void validateOption(Map options, String name, Function validator) { try { String v = options.get(name); diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/MBeanUtils.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/MBeanUtils.java index 8a69641e2a3..9cb6424230e 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/MBeanUtils.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/MBeanUtils.java @@ -24,6 +24,7 @@ */ package jdk.management.jfr; +import java.io.IOException; import java.lang.management.ManagementPermission; import java.security.Permission; import java.time.DateTimeException; @@ -37,6 +38,7 @@ import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import jdk.jfr.Recording; import jdk.jfr.internal.management.ManagementSupport; final class MBeanUtils { @@ -126,5 +128,16 @@ public static int parseBlockSize(String string, int defaultSize) { } return size; } + + public static String destination(Recording recording, String destination) throws IllegalArgumentException{ + try { + ManagementSupport.checkSetDestination(recording, destination); + return destination; + }catch(IOException e){ + IllegalArgumentException iae = new IllegalArgumentException("Not a valid destination " + destination); + iae.addSuppressed(e); + throw iae; + } + } } diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java index 7cc51e97bb8..9fcc9acee28 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/RecordingInfo.java @@ -25,7 +25,6 @@ package jdk.management.jfr; -import java.nio.file.Path; import java.time.Duration; import java.time.Instant; import java.util.LinkedHashMap; @@ -37,6 +36,7 @@ import jdk.jfr.Recording; import jdk.jfr.RecordingState; +import jdk.jfr.internal.management.ManagementSupport; /** * Management representation of a {@code Recording}. @@ -80,8 +80,7 @@ public final class RecordingInfo { startTime = s == null ? 0L : s.toEpochMilli(); Instant st = recording.getStopTime(); stopTime = st == null ? 0L : st.toEpochMilli(); - Path p = recording.getDestination(); - destination = p == null ? null : p.toString(); + destination = ManagementSupport.getDestinationOriginalText(recording); Duration duration = recording.getDuration(); durationInSeconds = duration == null ? 0 : duration.getSeconds(); settings = recording.getSettings(); diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/JarFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/JarFileSystem.java index ec138e471f3..2ee2c70198d 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/JarFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/JarFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -49,20 +49,17 @@ * @author Steve Drach */ class JarFileSystem extends ZipFileSystem { - private Function lookup; + // lookup needs to be initialized because isMultiReleaseJar is called before createVersionedLinks + private Function lookup = path -> path; @Override IndexNode getInode(byte[] path) { // check for an alias to a versioned entry - byte[] versionedPath = lookup.apply(path); - return versionedPath == null ? super.getInode(path) : super.getInode(versionedPath); + return super.getInode(lookup.apply(path)); } - JarFileSystem(ZipFileSystemProvider provider, Path zfpath, Map env) - throws IOException { + JarFileSystem(ZipFileSystemProvider provider, Path zfpath, Map env) throws IOException { super(provider, zfpath, env); - lookup = path -> path; // lookup needs to be set before isMultiReleaseJar is called - // because it eventually calls getEntry if (isMultiReleaseJar()) { int version; Object o = env.get("multi-release"); @@ -81,7 +78,7 @@ IndexNode getInode(byte[] path) { throw new IllegalArgumentException("env parameter must be String, Integer, " + "or Version"); } - lookup = createVersionedLinks(version < 0 ? 0 : version); + createVersionedLinks(version < 0 ? 0 : version); setReadOnly(); } } @@ -89,7 +86,7 @@ IndexNode getInode(byte[] path) { private boolean isMultiReleaseJar() throws IOException { try (InputStream is = newInputStream(getBytes("/META-INF/MANIFEST.MF"))) { String multiRelease = new Manifest(is).getMainAttributes() - .getValue(Attributes.Name.MULTI_RELEASE); + .getValue(Attributes.Name.MULTI_RELEASE); return "true".equalsIgnoreCase(multiRelease); } catch (NoSuchFileException x) { return false; @@ -106,27 +103,71 @@ private boolean isMultiReleaseJar() throws IOException { * then wrap the map in a function that getEntry can use to override root * entry lookup for entries that have corresponding versioned entries */ - private Function createVersionedLinks(int version) { - HashMap aliasMap = new HashMap<>(); + private void createVersionedLinks(int version) { IndexNode verdir = getInode(getBytes("/META-INF/versions")); - if (verdir != null) { - getVersionMap(version, verdir).values() - .forEach(versionNode -> { // for each META-INF/versions/{n} directory - // put all the leaf inodes, i.e. entries, into the alias map - // possibly shadowing lower versioned entries - walk(versionNode, entryNode -> { - byte[] rootName = getRootName(versionNode, entryNode); - if (rootName != null) { - IndexNode rootNode = getInode(rootName); - if (rootNode == null) { // no matching root node, make a virtual one - rootNode = IndexNode.keyOf(rootName); - } - aliasMap.put(rootNode, entryNode.name); - } - }); - }); + // nothing to do, if no /META-INF/versions + if (verdir == null) { + return; + } + // otherwise, create a map and for each META-INF/versions/{n} directory + // put all the leaf inodes, i.e. entries, into the alias map + // possibly shadowing lower versioned entries + HashMap aliasMap = new HashMap<>(); + getVersionMap(version, verdir).values().forEach(versionNode -> + walk(versionNode.child, entryNode -> + aliasMap.put( + getNodeInRootTree(getRootName(entryNode, versionNode), entryNode.isdir), + entryNode.name)) + ); + lookup = path -> { + byte[] entry = aliasMap.get(IndexNode.keyOf(path)); + return entry == null ? path : entry; + }; + } + + /** + * Return the node from the root tree. Create it, if it doesn't exist. + */ + private IndexNode getNodeInRootTree(byte[] path, boolean isdir) { + IndexNode node = getInode(path); + if (node != null) { + return node; + } + IndexNode parent = getParentDir(path); + beginWrite(); + try { + node = new IndexNode(path, isdir); + node.sibling = parent.child; + parent.child = node; + inodes.put(node, node); + return node; + } finally { + endWrite(); + } + } + + /** + * Return the parent directory node of a path. If the node doesn't exist, + * it will be created. Parent directories will be created recursively. + * Recursion fuse: We assume at latest the root path can be resolved to a node. + */ + private IndexNode getParentDir(byte[] path) { + byte[] parentPath = getParent(path); + IndexNode node = inodes.get(IndexNode.keyOf(parentPath)); + if (node != null) { + return node; + } + IndexNode parent = getParentDir(parentPath); + beginWrite(); + try { + node = new IndexNode(parentPath, true); + node.sibling = parent.child; + parent.child = node; + inodes.put(node, node); + return node; + } finally { + endWrite(); } - return path -> aliasMap.get(IndexNode.keyOf(path)); } /** @@ -138,7 +179,7 @@ private TreeMap getVersionMap(int version, IndexNode metaInf TreeMap map = new TreeMap<>(); IndexNode child = metaInfVersions.child; while (child != null) { - Integer key = getVersion(child.name, metaInfVersions.name.length + 1); + Integer key = getVersion(child, metaInfVersions); if (key != null && key <= version) { map.put(key, child); } @@ -150,9 +191,11 @@ private TreeMap getVersionMap(int version, IndexNode metaInf /** * extract the integer version number -- META-INF/versions/9 returns 9 */ - private Integer getVersion(byte[] name, int offset) { + private Integer getVersion(IndexNode inode, IndexNode metaInfVersions) { try { - return Integer.parseInt(getString(Arrays.copyOfRange(name, offset, name.length))); + byte[] fullName = inode.name; + return Integer.parseInt(getString(Arrays + .copyOfRange(fullName, metaInfVersions.name.length + 1, fullName.length))); } catch (NumberFormatException x) { // ignore this even though it might indicate issues with the JAR structure return null; @@ -162,14 +205,14 @@ private Integer getVersion(byte[] name, int offset) { /** * walk the IndexNode tree processing all leaf nodes */ - private void walk(IndexNode inode, Consumer process) { + private void walk(IndexNode inode, Consumer consumer) { if (inode == null) return; if (inode.isDir()) { - walk(inode.child, process); + walk(inode.child, consumer); } else { - process.accept(inode); + consumer.accept(inode); } - walk(inode.sibling, process); + walk(inode.sibling, consumer); } /** @@ -178,9 +221,8 @@ private void walk(IndexNode inode, Consumer process) { * and prefix META-INF/versions/9/ * returns foo/bar.class */ - private byte[] getRootName(IndexNode prefix, IndexNode inode) { - int offset = prefix.name.length; + private byte[] getRootName(IndexNode inode, IndexNode prefix) { byte[] fullName = inode.name; - return Arrays.copyOfRange(fullName, offset, fullName.length); + return Arrays.copyOfRange(fullName, prefix.name.length, fullName.length); } } diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipDirectoryStream.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipDirectoryStream.java index 21b3b60a950..935ed3f327f 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipDirectoryStream.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipDirectoryStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.IOException; import java.nio.file.ClosedDirectoryStreamException; +import java.nio.file.DirectoryIteratorException; import java.nio.file.DirectoryStream; import java.nio.file.NotDirectoryException; import java.nio.file.Path; @@ -40,21 +41,21 @@ class ZipDirectoryStream implements DirectoryStream { private final ZipFileSystem zipfs; - private final byte[] path; + private final ZipPath dir; private final DirectoryStream.Filter filter; private volatile boolean isClosed; private volatile Iterator itr; - ZipDirectoryStream(ZipPath zipPath, + ZipDirectoryStream(ZipPath dir, DirectoryStream.Filter filter) throws IOException { - this.zipfs = zipPath.getFileSystem(); - this.path = zipPath.getResolvedPath(); + this.zipfs = dir.getFileSystem(); + this.dir = dir; this.filter = filter; // sanity check - if (!zipfs.isDirectory(path)) - throw new NotDirectoryException(zipPath.toString()); + if (!zipfs.isDirectory(dir.getResolvedPath())) + throw new NotDirectoryException(dir.toString()); } @Override @@ -65,9 +66,9 @@ public synchronized Iterator iterator() { throw new IllegalStateException("Iterator has already been returned"); try { - itr = zipfs.iteratorOf(path, filter); + itr = zipfs.iteratorOf(dir, filter); } catch (IOException e) { - throw new IllegalStateException(e); + throw new DirectoryIteratorException(e); } return new Iterator() { @@ -96,5 +97,4 @@ public void remove() { public synchronized void close() throws IOException { isClosed = true; } - } diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java index 4c1074ef211..354a52992b6 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, 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 @@ -409,23 +409,31 @@ boolean isDirectory(byte[] path) } // returns the list of child paths of "path" - Iterator iteratorOf(byte[] path, + Iterator iteratorOf(ZipPath dir, DirectoryStream.Filter filter) throws IOException { beginWrite(); // iteration of inodes needs exclusive lock try { ensureOpen(); + byte[] path = dir.getResolvedPath(); IndexNode inode = getInode(path); if (inode == null) throw new NotDirectoryException(getString(path)); List list = new ArrayList<>(); IndexNode child = inode.child; while (child != null) { - // assume all path from zip file itself is "normalized" - ZipPath zp = new ZipPath(this, child.name, true); - if (filter == null || filter.accept(zp)) - list.add(zp); + // (1) Assume each path from the zip file itself is "normalized" + // (2) IndexNode.name is absolute. see IndexNode(byte[],int,int) + // (3) If parent "dir" is relative when ZipDirectoryStream + // is created, the returned child path needs to be relative + // as well. + byte[] cname = child.name; + ZipPath childPath = new ZipPath(this, cname, true); + ZipPath childFileName = childPath.getFileName(); + ZipPath zpath = dir.resolve(childFileName); + if (filter == null || filter.accept(zpath)) + list.add(zpath); child = child.sibling; } return list.iterator(); @@ -876,7 +884,7 @@ private void checkParents(byte[] path) throws IOException { } private static byte[] ROOTPATH = new byte[] { '/' }; - private static byte[] getParent(byte[] path) { + static byte[] getParent(byte[] path) { int off = getParentOff(path); if (off <= 1) return ROOTPATH; @@ -891,11 +899,11 @@ private static int getParentOff(byte[] path) { return off; } - private final void beginWrite() { + final void beginWrite() { rwlock.writeLock().lock(); } - private final void endWrite() { + final void endWrite() { rwlock.writeLock().unlock(); } @@ -918,7 +926,7 @@ private final void endRead() { private final ReadWriteLock rwlock = new ReentrantReadWriteLock(); // name -> pos (in cen), IndexNode itself can be used as a "key" - private LinkedHashMap inodes; + LinkedHashMap inodes; final byte[] getBytes(String name) { return zc.getBytes(name); @@ -1864,7 +1872,7 @@ static class IndexNode { this.pos = pos; } - // constructor for cenInit() (1) remove trailing '/' (2) pad leading '/' + // constructor for initCEN() (1) remove trailing '/' (2) pad leading '/' IndexNode(byte[] cen, int pos, int nlen) { int noff = pos + CENHDR; if (cen[noff + nlen - 1] == '/') { @@ -1878,10 +1886,51 @@ static class IndexNode { System.arraycopy(cen, noff, name, 1, nlen); name[0] = '/'; } - name(name); + name(normalize(name)); this.pos = pos; } + // Normalize the IndexNode.name field. + private byte[] normalize(byte[] path) { + int len = path.length; + if (len == 0) + return path; + byte prevC = 0; + for (int pathPos = 0; pathPos < len; pathPos++) { + byte c = path[pathPos]; + if (c == '/' && prevC == '/') + return normalize(path, pathPos - 1); + prevC = c; + } + if (len > 1 && prevC == '/') { + return Arrays.copyOf(path, len - 1); + } + return path; + } + + private byte[] normalize(byte[] path, int off) { + // As we know we have at least one / to trim, we can reduce + // the size of the resulting array + byte[] to = new byte[path.length - 1]; + int pathPos = 0; + while (pathPos < off) { + to[pathPos] = path[pathPos]; + pathPos++; + } + int toPos = pathPos; + byte prevC = 0; + while (pathPos < path.length) { + byte c = path[pathPos++]; + if (c == '/' && prevC == '/') + continue; + to[toPos++] = c; + prevC = c; + } + if (toPos > 1 && to[toPos - 1] == '/') + toPos--; + return (toPos == to.length) ? to : Arrays.copyOf(to, toPos); + } + private static final ThreadLocal cachedKey = new ThreadLocal<>(); final static IndexNode keyOf(byte[] name) { // get a lookup key; diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java index d8bf67fbff9..8d8d705ea0f 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, 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 @@ -92,8 +92,8 @@ public ZipPath getRoot() { return null; } - @Override - public Path getFileName() { + @Override + public ZipPath getFileName() { int off = path.length; if (off == 0 || off == 1 && path[0] == '/') return null; diff --git a/test/TestCommon.gmk b/test/TestCommon.gmk index 2d9b8288d7d..a51ce82c7b5 100644 --- a/test/TestCommon.gmk +++ b/test/TestCommon.gmk @@ -429,8 +429,8 @@ JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_GRAAL_DIR=${TEST_IMAGE_DIR}/hotspot/jtreg/g # Set other vm and test options JTREG_TEST_OPTIONS += $(JAVA_ARGS:%=-javaoptions:%) $(JAVA_VM_ARGS:%=-vmoption:%) -ifneq ($(JIB_JAR), ) - JTREG_BASIC_OPTIONS += -cpa:$(shell $(GETMIXEDPATH) "$(JIB_JAR)") +ifneq ($(JIB_HOME), ) + JTREG_BASIC_OPTIONS += -e:JIB_HOME=$(shell $(GETMIXEDPATH) "$(JIB_HOME)") endif ifeq ($(IGNORE_MARKED_TESTS), true) # Option to tell jtreg to not run tests marked with "ignore" diff --git a/test/hotspot/gtest/runtime/test_os_windows.cpp b/test/hotspot/gtest/runtime/test_os_windows.cpp new file mode 100644 index 00000000000..773f2304dfb --- /dev/null +++ b/test/hotspot/gtest/runtime/test_os_windows.cpp @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" + +#ifdef _WINDOWS + +#include "runtime/os.hpp" +#include "unittest.hpp" + +// The types of path modifications we randomly apply to a path. They should not change the file designated by the path. +enum ModsFilter { + Allow_None = 0, // No modifications + Allow_Sep_Mods = 1, // Replace '\\' by any sequence of '/' or '\\' or at least length 1. + Allow_Dot_Path = 2, // Add /. segments at random positions + Allow_Dot_Dot_Path = 4, // Add /../ segments at random positions. + Allow_All = Allow_Sep_Mods | Allow_Dot_Path | Allow_Dot_Dot_Path +}; + +// The mode in which to run. +enum Mode { + TEST, // Runs the test. This is the normal modus. + EXAMPLES, // Runs example which document the behaviour of the Windows system calls. + BENCH // Runs a small benchmark which tries to show the costs of using the *W variants/_wfullpath. +}; + +// Parameters of the test. +static ModsFilter mods_filter = Allow_All; +static int mods_per_path = 50; // The number of variants of a path we try. +static Mode mode = TEST; + + +// Utility methods +static void get_current_dir_w(wchar_t* path, size_t size) { + DWORD count = GetCurrentDirectoryW((DWORD) size, path); + EXPECT_GT((int) count, 0) << "Failed to get current directory: " << GetLastError(); + EXPECT_LT((size_t) count, size) << "Buffer too small for current directory: " << size; +} + +#define WITH_ABS_PATH(path) \ + wchar_t abs_path[JVM_MAXPATHLEN]; \ + wchar_t cwd[JVM_MAXPATHLEN]; \ + get_current_dir_w(cwd, JVM_MAXPATHLEN); \ + wsprintfW(abs_path, L"\\\\?\\%ls\\%ls", cwd, (path)) + +static bool file_exists_w(const wchar_t* path) { + WIN32_FILE_ATTRIBUTE_DATA file_data; + return ::GetFileAttributesExW(path, GetFileExInfoStandard, &file_data); +} + +static void create_rel_directory_w(const wchar_t* path) { + WITH_ABS_PATH(path); + EXPECT_FALSE(file_exists_w(abs_path)) << "Can't create directory: \"" << path << "\" already exists"; + BOOL result = CreateDirectoryW(abs_path, NULL); + EXPECT_TRUE(result) << "Failed to create directory \"" << path << "\" " << GetLastError(); +} + +static void delete_empty_rel_directory_w(const wchar_t* path) { + WITH_ABS_PATH(path); + EXPECT_TRUE(file_exists_w(abs_path)) << "Can't delete directory: \"" << path << "\" does not exists"; + BOOL result = RemoveDirectoryW(abs_path); + EXPECT_TRUE(result) << "Failed to delete directory \"" << path << "\": " << GetLastError(); +} + +static void create_rel_file_w(const wchar_t* path) { + WITH_ABS_PATH(path); + EXPECT_FALSE(file_exists_w(abs_path)) << "Can't create file: \"" << path << "\" already exists"; + HANDLE h = CreateFileW(abs_path, 0, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + EXPECT_NE(h, INVALID_HANDLE_VALUE) << "Failed to create file \"" << path << "\": " << GetLastError(); + CloseHandle(h); +} + +static void delete_rel_file_w(const wchar_t* path) { + WITH_ABS_PATH(path); + EXPECT_TRUE(file_exists_w(abs_path)) << "Can't delete file: \"" << path << "\" does not exists"; + BOOL result = DeleteFileW(abs_path); + EXPECT_TRUE(result) << "Failed to delete file \"" << path << "\": " << GetLastError(); +} + +static bool convert_to_cstring(char* c_str, size_t size, wchar_t* w_str) { + size_t converted; + errno_t err = wcstombs_s(&converted, c_str, size, w_str, size - 1); + EXPECT_EQ(err, ERROR_SUCCESS) << "Could not convert \"" << w_str << "\" to c-string"; + + return err == ERROR_SUCCESS; +} + +static wchar_t* my_wcscpy_s(wchar_t* dest, size_t size, wchar_t* start, const wchar_t* to_copy) { + size_t already_used = dest - start; + size_t len = wcslen(to_copy); + + if (already_used + len < size) { + wcscpy_s(dest, size - already_used, to_copy); + } + + return dest + wcslen(to_copy); +} + +// The currently finite list of seperator sequences we might use instead of '\\'. +static const wchar_t* sep_replacements[] = { + L"\\", L"\\/", L"/", L"//", L"\\\\/\\", L"//\\/" +}; + +// Takes a path and modifies it in a way that it should still designate the same file. +static bool unnormalize_path(wchar_t* result, size_t size, bool is_dir, const wchar_t* path) { + wchar_t* dest = result; + const wchar_t* src = path; + const wchar_t* path_start; + + if (wcsncmp(src, L"\\\\?\\UNC\\", 8) == 0) { + path_start = src + 8; + } else if (wcsncmp(src, L"\\\\?\\", 4) == 0) { + if (src[5] == L':') { + path_start = src + 6; + } else { + path_start = wcschr(src + 4, L'\\'); + } + } else if (wcsncmp(src, L"\\\\", 2) == 0) { + path_start = wcschr(src + 2, L'?'); + + if (path_start == NULL) { + path_start = wcschr(src + 2, L'\\'); + } else { + path_start = wcschr(path_start, L'\\'); + } + } else { + path_start = wcschr(src + 1, L'\\'); + } + + bool allow_sep_change = (mods_filter & Allow_Sep_Mods) && (os::random() & 1) == 0; + bool allow_dot_change = (mods_filter & Allow_Dot_Path) && (os::random() & 1) == 0; + bool allow_dotdot_change = (mods_filter & Allow_Dot_Dot_Path) && (os::random() & 1) == 0; + + while ((*src != L'\0') && (result + size > dest)) { + wchar_t c = *src; + *dest = c; + ++src; + ++dest; + + if (c == L'\\') { + if (allow_sep_change && (os::random() & 3) == 3) { + int i = os::random() % (sizeof(sep_replacements) / sizeof(sep_replacements[0])); + + if (i >= 0) { + const wchar_t* replacement = sep_replacements[i]; + dest = my_wcscpy_s(dest - 1, size, result, replacement); + } + } else if (path_start != NULL) { + if (allow_dotdot_change && (src > path_start + 1) && ((os::random() & 7) == 7)) { + wchar_t const* last_sep = src - 2; + + while (last_sep[0] != L'\\') { + --last_sep; + } + + if (last_sep > path_start) { + dest = my_wcscpy_s(dest, size, result, L"../"); + src = last_sep + 1; + } + } else if (allow_dot_change && (src > path_start + 1) && ((os::random() & 7) == 7)) { + dest = my_wcscpy_s(dest, size, result, L"./"); + } + } + } + } + + while (is_dir && ((os::random() & 15) == 1)) { + dest = my_wcscpy_s(dest, size, result, L"/"); + } + + if (result + size > dest) { + *dest = L'\0'; + } + + // Use this modification only if not too close to the max size. + return result + size - 10 > dest; +} + +static void check_dir_impl(wchar_t* path, bool should_be_empty) { + char buf[JVM_MAXPATHLEN]; + + if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { + struct stat st; + EXPECT_EQ(os::stat(buf, &st), 0) << "os::stat failed for \"" << path << "\""; + EXPECT_EQ(st.st_mode & S_IFMT, S_IFDIR) << "\"" << path << "\" is not a directory according to os::stat"; + errno = ERROR_SUCCESS; + bool is_empty = os::dir_is_empty(buf); + errno_t err = errno; + EXPECT_EQ(is_empty, should_be_empty) << "os::dir_is_empty assumed \"" << path << "\" is " + << (should_be_empty ? "not ": "") << "empty"; + EXPECT_EQ(err, ERROR_SUCCESS) << "os::dir_is_empty failed for \"" << path << "\"with errno " << err; + } +} + +static void check_file_impl(wchar_t* path) { + char buf[JVM_MAXPATHLEN]; + + if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { + struct stat st; + EXPECT_EQ(os::stat(buf, &st), 0) << "os::stat failed for \"" << path << "\""; + EXPECT_EQ(st.st_mode & S_IFMT, S_IFREG) << "\"" << path << "\" is not a regular file according to os::stat"; + int fd = os::open(buf, O_RDONLY, 0); + EXPECT_NE(fd, -1) << "os::open failed for \"" << path << "\" with errno " << errno; + if (fd >= 0) { + ::close(fd); + } + } +} + +static void check_file_not_present_impl(wchar_t* path) { + char buf[JVM_MAXPATHLEN]; + + if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { + struct stat st; + int stat_ret; + EXPECT_EQ(stat_ret = os::stat(buf, &st), -1) << "os::stat did not fail for \"" << path << "\""; + if (stat_ret != -1) { + // Only check open if stat not already failed. + int fd = os::open(buf, O_RDONLY, 0); + EXPECT_EQ(fd, -1) << "os::open did not fail for \"" << path << "\""; + if (fd >= 0) { + ::close(fd); + } + } + } +} + +static void check_dir(wchar_t* path, bool should_be_empty) { + check_dir_impl(path, should_be_empty); + + for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) { + wchar_t tmp[JVM_MAXPATHLEN]; + if (unnormalize_path(tmp, JVM_MAXPATHLEN, true, path)) { + check_dir_impl(tmp, should_be_empty); + } + } +} + +static void check_file(wchar_t* path) { + check_file_impl(path); + + for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) { + wchar_t tmp[JVM_MAXPATHLEN]; + if (unnormalize_path(tmp, JVM_MAXPATHLEN, false, path)) { + check_file_impl(tmp); + } + } +} + +static void check_file_not_present(wchar_t* path) { + check_file_not_present_impl(path); + + for (int i = 0; mods_filter != Allow_None && i < mods_per_path; ++i) { + wchar_t tmp[JVM_MAXPATHLEN]; + if (unnormalize_path(tmp, JVM_MAXPATHLEN, false, path)) { + check_file_not_present_impl(tmp); + } + } +} + +static void record_path(char const* name, char const* len_name, wchar_t* path) { + char buf[JVM_MAXPATHLEN]; + + if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { + ::testing::Test::RecordProperty(name, buf); + os::snprintf(buf, JVM_MAXPATHLEN, "%d", (int) wcslen(path)); + ::testing::Test::RecordProperty(len_name, buf); + } +} + +static void bench_path(wchar_t* path) { + char buf[JVM_MAXPATHLEN]; + int reps = 100000; + + if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { + jlong wtime[2]; + + for (int t = 0; t < 2; ++t) { + wtime[t] = os::javaTimeNanos(); + + for (int i = 0; i < reps; ++i) { + bool succ = false; + size_t buf_len = strlen(buf); + wchar_t* w_path = (wchar_t*) os::malloc(sizeof(wchar_t) * (buf_len + 1), mtInternal); + + if (w_path != NULL) { + size_t converted_chars; + if (::mbstowcs_s(&converted_chars, w_path, buf_len + 1, buf, buf_len) == ERROR_SUCCESS) { + if (t == 1) { + wchar_t* tmp = (wchar_t*) os::malloc(sizeof(wchar_t) * JVM_MAXPATHLEN, mtInternal); + + if (tmp) { + if (_wfullpath(tmp, w_path, JVM_MAXPATHLEN)) { + succ = true; + } + + // Note that we really don't use the full path name, but just add the cost of running _wfullpath. + os::free(tmp); + } + if (!succ) { + printf("Failed fullpathing \"%s\"\n", buf); + return; + } + succ = false; + } + HANDLE h = ::CreateFileW(w_path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + + if (h != INVALID_HANDLE_VALUE) { + ::CloseHandle(h); + succ = true; + } + } + } + + os::free(w_path); + if (!succ) { + printf("Failed getting W*attr. \"%s\"\n", buf); + return; + } + } + + wtime[t] = os::javaTimeNanos() - wtime[t]; + } + + jlong ctime = os::javaTimeNanos(); + + for (int i = 0; i < reps; ++i) { + HANDLE h = ::CreateFileA(buf, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + + if (h == INVALID_HANDLE_VALUE) { + return; + } + + ::CloseHandle(h); + } + + ctime = os::javaTimeNanos() - ctime; + + printf("\"%s\" %f us for *A, %f us for *W, %f us for *W with fullpath\n", buf, + 0.001 * ctime / reps, 0.001 * wtime[0] / reps, 0.001 * wtime[1] / reps); + } +} + +static void print_attr_result_for_path(wchar_t* path) { + WIN32_FILE_ATTRIBUTE_DATA file_data; + struct stat st; + char buf[JVM_MAXPATHLEN]; + wchar_t abs[JVM_MAXPATHLEN]; + + _wfullpath(abs, path, JVM_MAXPATHLEN); + printf("Checking \"%ls\" (%d chars):\n", path, (int) wcslen(path)); + printf("_wfullpath %ls (%d chars)\n", abs, (int) wcslen(abs)); + BOOL bret = ::GetFileAttributesExW(path, GetFileExInfoStandard, &file_data); + printf("GetFileAttributesExW() %s\n", bret ? "success" : "failed"); + + if (convert_to_cstring(buf, JVM_MAXPATHLEN, path)) { + bret = ::GetFileAttributesExA(buf, GetFileExInfoStandard, &file_data); + printf("GetFileAttributesExA() %s\n", bret ? "success" : "failed"); + + bool succ = os::stat(buf, &st) != -1; + printf("os::stat() %s\n", succ ? "success" : "failed"); + } +} + +static void print_attr_result(wchar_t* format, ...) { + va_list argptr; + wchar_t buf[JVM_MAXPATHLEN]; + + va_start(argptr, format); + wvsprintfW(buf, format, argptr); + print_attr_result_for_path(buf); + va_end(argptr); +} + +#define RECORD_PATH(name) record_path(#name, #name "Len", name) +#define NAME_PART_50 L"01234567890123456789012345678901234567890123456789" +#define NAME_PART_250 NAME_PART_50 NAME_PART_50 NAME_PART_50 NAME_PART_50 NAME_PART_50 + +// Test which tries to find out if the os::stat, os::open and os::dir_is_empty methods +// can handle long path names correctly. +TEST_VM(os_windows, handle_long_paths) { + static wchar_t cwd[JVM_MAXPATHLEN]; + static wchar_t nearly_long_rel_path[JVM_MAXPATHLEN]; + static wchar_t long_rel_path[JVM_MAXPATHLEN]; + static wchar_t empty_dir_rel_path[JVM_MAXPATHLEN]; + static wchar_t not_empty_dir_rel_path[JVM_MAXPATHLEN]; + static wchar_t file_rel_path[JVM_MAXPATHLEN]; + static wchar_t nearly_long_file_rel_path[JVM_MAXPATHLEN]; + static wchar_t nearly_long_path[JVM_MAXPATHLEN]; + static wchar_t empty_dir_path[JVM_MAXPATHLEN]; + static wchar_t not_empty_dir_path[JVM_MAXPATHLEN]; + static wchar_t nearly_long_file_path[JVM_MAXPATHLEN]; + static wchar_t file_path[JVM_MAXPATHLEN]; + static wchar_t nearly_long_unc_path[JVM_MAXPATHLEN]; + static wchar_t empty_dir_unc_path[JVM_MAXPATHLEN]; + static wchar_t not_empty_dir_unc_path[JVM_MAXPATHLEN]; + static wchar_t nearly_long_file_unc_path[JVM_MAXPATHLEN]; + static wchar_t file_unc_path[JVM_MAXPATHLEN]; + static wchar_t root_dir_path[JVM_MAXPATHLEN]; + static wchar_t root_rel_dir_path[JVM_MAXPATHLEN]; + + wchar_t* dir_prefix = L"os_windows_long_paths_dir_"; + wchar_t* empty_dir_name = L"empty_directory_with_long_path"; + wchar_t* not_empty_dir_name = L"not_empty_directory_with_long_path"; + wchar_t* file_name = L"file"; + wchar_t dir_letter; + WIN32_FILE_ATTRIBUTE_DATA file_data; + bool can_test_unc = false; + + get_current_dir_w(cwd, sizeof(cwd) / sizeof(wchar_t)); + dir_letter = (cwd[1] == L':' ? cwd[0] : L'\0'); + int cwd_len = (int) wcslen(cwd); + int dir_prefix_len = (int) wcslen(dir_prefix); + int rel_path_len = MAX2(dir_prefix_len, 235 - cwd_len); + + memcpy(nearly_long_rel_path, dir_prefix, sizeof(wchar_t) * dir_prefix_len); + + for (int i = dir_prefix_len; i < rel_path_len; ++i) { + nearly_long_rel_path[i] = L'L'; + } + + nearly_long_rel_path[rel_path_len] = L'\0'; + + wsprintfW(long_rel_path, L"%ls\\%ls", nearly_long_rel_path, NAME_PART_250); + wsprintfW(empty_dir_rel_path, L"%ls\\%ls", nearly_long_rel_path, empty_dir_name); + wsprintfW(not_empty_dir_rel_path, L"%ls\\%ls", nearly_long_rel_path, not_empty_dir_name); + wsprintfW(nearly_long_file_rel_path, L"%ls\\%ls", nearly_long_rel_path, file_name); + wsprintfW(file_rel_path, L"%ls\\%ls\\%ls", nearly_long_rel_path, not_empty_dir_name, file_name); + wsprintfW(nearly_long_path, L"\\\\?\\%ls\\%ls", cwd, nearly_long_rel_path); + wsprintfW(empty_dir_path, L"%ls\\%ls", nearly_long_path, empty_dir_name); + wsprintfW(not_empty_dir_path, L"%ls\\%ls", nearly_long_path, not_empty_dir_name); + wsprintfW(nearly_long_file_path, L"%ls\\%ls", nearly_long_path, file_name); + wsprintfW(file_path, L"%ls\\%ls\\%ls", nearly_long_path, not_empty_dir_name, file_name); + wsprintfW(nearly_long_unc_path, L"\\\\localhost\\%lc$\\%s", dir_letter, nearly_long_path + 7); + wsprintfW(empty_dir_unc_path, L"%s\\%s", nearly_long_unc_path, empty_dir_name); + wsprintfW(not_empty_dir_unc_path, L"%s\\%s", nearly_long_unc_path, not_empty_dir_name); + wsprintfW(nearly_long_file_unc_path, L"%ls\\%ls", nearly_long_unc_path, file_name); + wsprintfW(file_unc_path, L"%s\\%s\\%s", nearly_long_unc_path, not_empty_dir_name, file_name); + wsprintfW(root_dir_path, L"%lc:\\", dir_letter); + wsprintfW(root_rel_dir_path, L"%lc:", dir_letter); + + RECORD_PATH(long_rel_path); + RECORD_PATH(nearly_long_rel_path); + RECORD_PATH(nearly_long_path); + RECORD_PATH(nearly_long_unc_path); + RECORD_PATH(empty_dir_rel_path); + RECORD_PATH(empty_dir_path); + RECORD_PATH(empty_dir_unc_path); + RECORD_PATH(not_empty_dir_rel_path); + RECORD_PATH(not_empty_dir_path); + RECORD_PATH(not_empty_dir_unc_path); + RECORD_PATH(nearly_long_file_rel_path); + RECORD_PATH(nearly_long_file_path); + RECORD_PATH(nearly_long_file_unc_path); + RECORD_PATH(file_rel_path); + RECORD_PATH(file_path); + RECORD_PATH(file_unc_path); + + create_rel_directory_w(nearly_long_rel_path); + create_rel_directory_w(long_rel_path); + create_rel_directory_w(empty_dir_rel_path); + create_rel_directory_w(not_empty_dir_rel_path); + create_rel_file_w(nearly_long_file_rel_path); + create_rel_file_w(file_rel_path); + + // For UNC path test we assume that the current DRIVE has a share + // called "$" (so for D: we expect \\localhost\D$ to be + // the same). Since this is only an assumption, we have to skip + // the UNC tests if the share is missing. + if (dir_letter && !::GetFileAttributesExW(nearly_long_unc_path, GetFileExInfoStandard, &file_data)) { + printf("Disabled UNC path test, since %lc: is not mapped as share %lc$.\n", dir_letter, dir_letter); + } else { + can_test_unc = true; + } + + if (mode == BENCH) { + bench_path(nearly_long_path + 4); + bench_path(nearly_long_rel_path); + bench_path(nearly_long_file_path + 4); + bench_path(nearly_long_file_rel_path); + } else if (mode == EXAMPLES) { + printf("Working directory: %ls", cwd); + + if (dir_letter) { + static wchar_t top_buf[JVM_MAXPATHLEN]; + wchar_t* top_path = wcschr(cwd + 3, L'\\'); + + if (top_path) { + size_t top_len = (top_path - cwd) - 3; + + memcpy(top_buf, cwd + 3, top_len * 2); + top_buf[top_len] = L'\0'; + top_path = top_buf; + } + + print_attr_result(L"%lc:\\", dir_letter); + print_attr_result(L"%lc:\\.\\", dir_letter); + + if (top_path) { + print_attr_result(L"%lc:\\%ls\\..\\%ls\\", dir_letter, top_path, top_path); + } + + print_attr_result(L"%lc:", dir_letter); + print_attr_result(L"%lc:.", dir_letter); + print_attr_result(L"%lc:\\COM1", dir_letter); + print_attr_result(L"%lc:\\PRN", dir_letter); + print_attr_result(L"%lc:\\PRN\\COM1", dir_letter); + print_attr_result(L"\\\\?\\UNC\\localhost\\%lc$\\", dir_letter); + print_attr_result(L"\\\\?\\UNC\\\\localhost\\%lc$\\", dir_letter); + print_attr_result(nearly_long_unc_path); + print_attr_result(L"%ls\\.\\", nearly_long_unc_path); + print_attr_result(L"%ls\\..\\%ls", nearly_long_unc_path, nearly_long_rel_path); + print_attr_result(L"\\\\?\\UNC\\%ls", nearly_long_unc_path + 2); + print_attr_result(file_unc_path); + print_attr_result(L"%ls\\%ls\\..\\%ls\\%ls", nearly_long_unc_path, not_empty_dir_name, not_empty_dir_name, file_name); + print_attr_result(L"%ls\\%ls\\.\\%ls", nearly_long_unc_path, not_empty_dir_name, file_name); + print_attr_result(L"\\\\?\\UNC\\%ls", file_unc_path + 2); + print_attr_result(L"\\\\?\\UNC\\%ls\\%ls\\.\\%ls", nearly_long_unc_path + 2, not_empty_dir_name, file_name); + print_attr_result(L"\\\\?\\UNC\\%ls\\%ls\\..\\%ls\\%ls", nearly_long_unc_path + 2, not_empty_dir_name, not_empty_dir_name, file_name); + } + + print_attr_result(nearly_long_rel_path); + print_attr_result(L"%ls\\.\\", nearly_long_rel_path); + print_attr_result(L"%ls\\..\\%ls", nearly_long_rel_path, nearly_long_rel_path); + print_attr_result(L"%\\\\?\\%ls", nearly_long_rel_path); + print_attr_result(L"\\\\?\\%ls\\.\\", nearly_long_rel_path); + print_attr_result(L"\\\\?\\%ls\\..\\%ls", nearly_long_rel_path, nearly_long_rel_path); + + print_attr_result(nearly_long_path + 4); + print_attr_result(L"%ls\\.\\", nearly_long_path + 4); + print_attr_result(L"%ls\\..\\%ls", nearly_long_path + 4, nearly_long_rel_path); + print_attr_result(nearly_long_path); + print_attr_result(L"%ls\\.\\", nearly_long_path); + print_attr_result(L"%ls\\..\\%ls", nearly_long_path, nearly_long_rel_path); + } else { + check_file_not_present(L""); + + // Check relative paths + check_dir(nearly_long_rel_path, false); + check_dir(long_rel_path, true); + check_dir(empty_dir_rel_path, true); + check_dir(not_empty_dir_rel_path, false); + check_file(nearly_long_file_rel_path); + check_file(file_rel_path); + + // Check absolute paths + if (dir_letter) { + check_dir(root_dir_path, false); + check_dir(root_rel_dir_path, false); + } + + check_dir(cwd, false); + check_dir(nearly_long_path + 4, false); + check_dir(empty_dir_path + 4, true); + check_dir(not_empty_dir_path + 4, false); + check_file(nearly_long_file_path + 4); + check_file(file_path + 4); + + // Check UNC paths + if (can_test_unc) { + check_dir(nearly_long_unc_path, false); + check_dir(empty_dir_unc_path, true); + check_dir(not_empty_dir_unc_path, false); + check_file(nearly_long_file_unc_path); + check_file(file_unc_path); + } + + // Check handling of :/../:/path/... + // The other drive letter should not overwrite the original one. + if (dir_letter) { + static wchar_t tmp[JVM_MAXPATHLEN]; + wchar_t* other_letter = dir_letter == L'D' ? L"C" : L"D"; + wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", nearly_long_file_path, other_letter, nearly_long_file_path + 2); + check_file_not_present(tmp); + wsprintfW(tmp, L"%2ls\\..\\%ls:%ls", file_path, other_letter, file_path + 2); + check_file_not_present(tmp); + } + } + + delete_rel_file_w(file_rel_path); + delete_rel_file_w(nearly_long_file_rel_path); + delete_empty_rel_directory_w(not_empty_dir_rel_path); + delete_empty_rel_directory_w(empty_dir_rel_path); + delete_empty_rel_directory_w(long_rel_path); + delete_empty_rel_directory_w(nearly_long_rel_path); +} + +#endif diff --git a/test/hotspot/gtest/utilities/test_ostream.cpp b/test/hotspot/gtest/utilities/test_ostream.cpp new file mode 100644 index 00000000000..164f0d34b2b --- /dev/null +++ b/test/hotspot/gtest/utilities/test_ostream.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019 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. + * + */ + +#include "precompiled.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" + +#include "unittest.hpp" + +static size_t print_lorem(outputStream* st, bool short_len) { + // Create a ResourceMark just to make sure the stream does not use ResourceArea + ResourceMark rm; + static const char* const lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, " + "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lacinia at quis " + "risus sed vulputate odio ut enim blandit. Amet risus nullam eget felis eget. Viverra " + "orci sagittis eu volutpat odio facilisis mauris sit. Erat velit scelerisque in dictum non."; + static const size_t len_lorem = strlen(lorem); + size_t len; + if (short_len) { + len = os::random() % 10; + } else { + len = MAX2(1, (int)(os::random() % len_lorem)); + } + st->write(lorem, len); + return len; +} + +static void test_stringStream_is_zero_terminated(const stringStream* ss) { + ASSERT_EQ(ss->base()[ss->size()], '\0'); +} + + +static void do_test_stringStream(stringStream* ss, bool short_len, size_t expected_cap) { + test_stringStream_is_zero_terminated(ss); + size_t written = 0; + for (int i = 0; i < 1000; i ++) { + written += print_lorem(ss, short_len); + if (expected_cap > 0 && written >= expected_cap) { + ASSERT_EQ(ss->size(), expected_cap - 1); + } else { + ASSERT_EQ(ss->size(), written); + } + // Internal buffer should always be zero-terminated. + test_stringStream_is_zero_terminated(ss); + } + // Reset should zero terminate too + ss->reset(); + ASSERT_EQ(ss->size(), (size_t)0); + test_stringStream_is_zero_terminated(ss); +} + +TEST_VM(ostream, stringStream_dynamic_realloc_1) { + stringStream ss(2); // dynamic buffer with very small starting size + do_test_stringStream(&ss, false, 0); +} + +TEST_VM(ostream, stringStream_dynamic_realloc_2) { + stringStream ss(2); // dynamic buffer with very small starting size + do_test_stringStream(&ss, true, 0); +} + +TEST_VM(ostream, stringStream_static) { + char buffer[128 + 1]; + char* canary_at = buffer + sizeof(buffer) - 1; + *canary_at = 'X'; + size_t stream_buf_size = sizeof(buffer) - 1; + stringStream ss(buffer, stream_buf_size); + do_test_stringStream(&ss, false, stream_buf_size); + ASSERT_EQ(*canary_at, 'X'); // canary +} + +TEST_VM(ostream, bufferedStream_static) { + char buf[100 + 1]; + char* canary_at = buf + sizeof(buf) - 1; + *canary_at = 'X'; + size_t stream_buf_size = sizeof(buf) - 1; + bufferedStream bs(buf, stream_buf_size); + size_t written = 0; + for (int i = 0; i < 100; i ++) { + written += print_lorem(&bs, true); + if (written < stream_buf_size) { + ASSERT_EQ(bs.size(), written); + } else { + ASSERT_EQ(bs.size(), stream_buf_size - 1); + } + } + ASSERT_EQ(*canary_at, 'X'); // canary +} + +TEST_VM(ostream, bufferedStream_dynamic_small) { + bufferedStream bs(1); // small to excercise realloc. + size_t written = 0; + // The max cap imposed is 100M, we should be safely below this in this test. + for (int i = 0; i < 10; i ++) { + written += print_lorem(&bs, true); + ASSERT_EQ(bs.size(), written); + } +} + +/* Activate to manually test bufferedStream dynamic cap. + +TEST_VM(ostream, bufferedStream_dynamic_large) { + bufferedStream bs(1); // small to excercise realloc. + size_t written = 0; + // The max cap imposed is 100M. Writing this much should safely hit it. + // Note that this will assert in debug builds which is the expected behavior. + size_t expected_cap_at = 100 * M; + for (int i = 0; i < 10000000; i ++) { + written += print_lorem(&bs, false); + if (written < expected_cap_at) { + ASSERT_EQ(bs.size(), written); + } else { + ASSERT_EQ(bs.size(), expected_cap_at - 1); + } + } +} + +*/ + + + + diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index f9197349194..404556e5859 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -69,6 +69,7 @@ gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java 8156755 gener gc/survivorAlignment/TestPromotionToSurvivor.java 8129886 generic-all gc/g1/logging/TestG1LoggingFailure.java 8169634 generic-all gc/g1/humongousObjects/TestHeapCounters.java 8178918 generic-all +gc/stress/gclocker/TestExcessGCLockerCollections.java 8229120 generic-all gc/stress/gclocker/TestGCLockerWithParallel.java 8180622 generic-all gc/stress/gclocker/TestGCLockerWithG1.java 8180622 generic-all gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java 8177765 generic-all diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 72212c4cf26..f6725697582 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -35,7 +35,9 @@ groups=TEST.groups TEST.quick-groups # to determine additional characteristics of the system for use with the @requires tag. # Note: compiled bootlibs code will be located in the folder 'bootClasses' requires.extraPropDefns = ../../jtreg-ext/requires/VMProps.java -requires.extraPropDefns.bootlibs = ../../lib/sun ../../lib/jdk/test/lib/Platform.java +requires.extraPropDefns.bootlibs = ../../lib/sun \ + ../../lib/jdk/test/lib/Platform.java \ + ../../lib/jdk/test/lib/Container.java requires.extraPropDefns.vmOpts = -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:bootClasses requires.properties= \ sun.arch.data.model \ @@ -56,7 +58,7 @@ requires.properties= \ vm.hasSAandCanAttach \ vm.hasJFR \ vm.rtm.cpu \ - vm.rtm.os \ + vm.rtm.compiler \ vm.aot \ vm.cds \ vm.cds.custom.loaders \ diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 72953ed2928..4748333ce0e 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -59,7 +59,8 @@ hotspot_misc = \ -:hotspot_compiler \ -:hotspot_gc \ -:hotspot_runtime \ - -:hotspot_serviceability + -:hotspot_serviceability \ + -:hotspot_containers hotspot_native_sanity = \ native_sanity diff --git a/test/hotspot/jtreg/compiler/c2/TestUnreachableRegionDuringCCP.java b/test/hotspot/jtreg/compiler/c2/TestUnreachableRegionDuringCCP.java new file mode 100644 index 00000000000..86209f27a9b --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestUnreachableRegionDuringCCP.java @@ -0,0 +1,63 @@ +/* + * 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 8210387 + * @summary Test removal of unreachable regions during CCP. + * @library /test/lib + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileOnly=compiler.c2.TestUnreachableRegionDuringCCP::test + * compiler.c2.TestUnreachableRegionDuringCCP + */ + +package compiler.c2; + +import jdk.test.lib.Asserts; + +public class TestUnreachableRegionDuringCCP { + static int iFld1 = -1; + static int iFld2 = -1; + static int iArrFld[] = new int[100]; + + public static void test() { + int i = 1; + do { + iArrFld[i] = iFld1; + iFld1 = 42; + for (int j = 1; j < 5; j++) { + if (i != 0) { + return; // Always returns + } + iFld2 += j; + } + } while (++i < 10); + } + + public static void main(String[] args) { + test(); + Asserts.assertEQ(iFld1, 42); + Asserts.assertEQ(iFld2, -1); + Asserts.assertEQ(iArrFld[1], -1); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/ConvI2LWideningAssertTooStrong.java b/test/hotspot/jtreg/compiler/c2/aarch64/ConvI2LWideningAssertTooStrong.java new file mode 100644 index 00000000000..b291675b08a --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/aarch64/ConvI2LWideningAssertTooStrong.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8229701 + * @summary C2 OSR compilation fails with "shouldn't process one node several times" in final graph reshaping + * + * @run main/othervm ConvI2LWideningAssertTooStrong + * + */ + +public class ConvI2LWideningAssertTooStrong { + + public static final int N = 400; + + public static long instanceCount=708L; + public static volatile int iFld1=30517; + public static int iArrFld[]=new int[N]; + + public static void vMeth(short s) { + int i9=29117, i11=-6; + + for (i9 = 11; i9 < 377; i9++) { + switch ((i9 % 8) + 22) { + case 24: + instanceCount = i9; + instanceCount += instanceCount; + break; + case 25: + try { + i11 = (20705 % i11); + iArrFld[i9 - 1] = (55094 / iFld1); + } catch (ArithmeticException a_e) {} + break; + default: + } + } + } + + public static void main(String[] strArr) { + ConvI2LWideningAssertTooStrong _instance = new ConvI2LWideningAssertTooStrong(); + for (int i = 0; i < 10 * 202 * 8; i++ ) { + _instance.vMeth((short)20806); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileCAE.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileCAE.java new file mode 100644 index 00000000000..f9bec79d62b --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileCAE.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.aarch64; + +import java.lang.reflect.Field; +import jdk.internal.misc.Unsafe; + +class TestUnsafeVolatileCAE +{ + public volatile int f_int = 0; + public volatile Integer f_obj = Integer.valueOf(0); + public volatile long f_long = 0; + public volatile byte f_byte = 0; + public volatile short f_short = 0; + + public static Unsafe unsafe = Unsafe.getUnsafe(); + public static Field f_int_field; + public static Field f_obj_field; + public static Field f_long_field; + public static Field f_byte_field; + public static Field f_short_field; + public static long f_int_off; + public static long f_obj_off; + public static long f_long_off; + public static long f_byte_off; + public static long f_short_off; + + static { + try { + f_int_field = TestUnsafeVolatileCAE.class.getField("f_int"); + f_obj_field = TestUnsafeVolatileCAE.class.getField("f_obj"); + f_long_field = TestUnsafeVolatileCAE.class.getField("f_long"); + f_byte_field = TestUnsafeVolatileCAE.class.getField("f_byte"); + f_short_field = TestUnsafeVolatileCAE.class.getField("f_short"); + f_int_off = unsafe.objectFieldOffset(f_int_field); + f_obj_off = unsafe.objectFieldOffset(f_obj_field); + f_long_off = unsafe.objectFieldOffset(f_long_field); + f_byte_off = unsafe.objectFieldOffset(f_byte_field); + f_short_off = unsafe.objectFieldOffset(f_short_field); + } catch (Exception e) { + System.out.println("reflection failed " + e); + e.printStackTrace(); + } + } + + public static void main(String[] args) + { + final TestUnsafeVolatileCAE t = new TestUnsafeVolatileCAE(); + for (int i = 0; i < 100_000; i++) { + t.f_int = -1; + int res = t.testInt(-1, i); + if (res != -1 || t.f_int != i) { + throw new RuntimeException("bad result!"); + } + } + for (int i = 0; i < 100_000; i++) { + t.f_long = -1; + long res = t.testLong(-1, i); + if (res != -1 || t.f_long != i) { + throw new RuntimeException("bad result!"); + } + } + for (int i = 0; i < 100_000; i++) { + t.f_byte = -1; + byte i_b = (byte)i; + byte res = t.testByte((byte)-1, i_b); + if (res != (byte)-1 || t.f_byte != i_b) { + throw new RuntimeException("bad result!"); + } + } + for (int i = 0; i < 100_000; i++) { + t.f_short = -1; + short i_s = (short)i; + short res = t.testShort((byte)-1, i_s); + if (res != (short)-1 || t.f_short != i_s) { + throw new RuntimeException("bad result!"); + } + } + Integer minusOne = Integer.valueOf(-1); + for (int i = 0; i < 100_000; i++) { + t.f_obj = minusOne; + Object res = t.testObj(minusOne, Integer.valueOf(i)); + if (res != minusOne || t.f_obj != i) { + throw new RuntimeException("bad result!"); + } + } + } + + public int testInt(int x, int i) + { + return unsafe.compareAndExchangeInt(this, f_int_off, x, i); + } + + public Object testObj(Object x, Object o) + { + return unsafe.compareAndExchangeObject(this, f_obj_off, x, o); + } + public long testLong(long x, long i) + { + return unsafe.compareAndExchangeLong(this, f_long_off, x, i); + } + + public byte testByte(byte x, byte i) + { + return unsafe.compareAndExchangeByte(this, f_byte_off, x, i); + } + + public short testShort(short x, short i) + { + return unsafe.compareAndExchangeShort(this, f_short_off, x, i); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileCAS.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileCAS.java index 0539af2db79..50913705aa1 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileCAS.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileCAS.java @@ -30,19 +30,34 @@ class TestUnsafeVolatileCAS { public volatile int f_int = 0; public volatile Integer f_obj = Integer.valueOf(0); + public volatile long f_long = 0; + public volatile byte f_byte = 0; + public volatile short f_short = 0; public static Unsafe unsafe = Unsafe.getUnsafe(); public static Field f_int_field; public static Field f_obj_field; + public static Field f_long_field; + public static Field f_byte_field; + public static Field f_short_field; public static long f_int_off; public static long f_obj_off; + public static long f_long_off; + public static long f_byte_off; + public static long f_short_off; static { try { f_int_field = TestUnsafeVolatileCAS.class.getField("f_int"); f_obj_field = TestUnsafeVolatileCAS.class.getField("f_obj"); + f_long_field = TestUnsafeVolatileCAS.class.getField("f_long"); + f_byte_field = TestUnsafeVolatileCAS.class.getField("f_byte"); + f_short_field = TestUnsafeVolatileCAS.class.getField("f_short"); f_int_off = unsafe.objectFieldOffset(f_int_field); f_obj_off = unsafe.objectFieldOffset(f_obj_field); + f_long_off = unsafe.objectFieldOffset(f_long_field); + f_byte_off = unsafe.objectFieldOffset(f_byte_field); + f_short_off = unsafe.objectFieldOffset(f_short_field); } catch (Exception e) { System.out.println("reflection failed " + e); e.printStackTrace(); @@ -59,6 +74,29 @@ public static void main(String[] args) throw new RuntimeException("bad result!"); } } + for (int i = 0; i < 100_000; i++) { + t.f_long = -1; + t.testLong(-1, i); + if (t.f_long != i) { + throw new RuntimeException("bad result!"); + } + } + for (int i = 0; i < 100_000; i++) { + t.f_byte = -1; + byte i_b = (byte)i; + t.testByte((byte)-1, i_b); + if (t.f_byte != i_b) { + throw new RuntimeException("bad result!"); + } + } + for (int i = 0; i < 100_000; i++) { + t.f_short = -1; + short i_s = (short)i; + t.testShort((byte)-1, i_s); + if (t.f_short != i_s) { + throw new RuntimeException("bad result!"); + } + } Integer minusOne = Integer.valueOf(-1); for (int i = 0; i < 100_000; i++) { t.f_obj = minusOne; @@ -68,6 +106,7 @@ public static void main(String[] args) } } } + public void testInt(int x, int i) { unsafe.compareAndSetInt(this, f_int_off, x, i); @@ -77,4 +116,19 @@ public void testObj(Object x, Object o) { unsafe.compareAndSetObject(this, f_obj_off, x, o); } + + public void testLong(long x, long i) + { + unsafe.compareAndSetLong(this, f_long_off, x, i); + } + + public void testByte(byte x, byte i) + { + unsafe.compareAndSetByte(this, f_byte_off, x, i); + } + + public void testShort(short x, short i) + { + unsafe.compareAndSetShort(this, f_short_off, x, i); + } } diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileGAA.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileGAA.java new file mode 100644 index 00000000000..25a8af804de --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileGAA.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.aarch64; + +import java.lang.reflect.Field; +import jdk.internal.misc.Unsafe; + +class TestUnsafeVolatileGAA +{ + public volatile int f_int = -1; + public volatile long f_long = -1; + + public static Unsafe unsafe = Unsafe.getUnsafe(); + public static Field f_int_field; + public static Field f_long_field; + public static long f_int_off; + public static long f_long_off; + + static { + try { + f_int_field = TestUnsafeVolatileGAA.class.getField("f_int"); + f_long_field = TestUnsafeVolatileGAA.class.getField("f_long"); + f_int_off = unsafe.objectFieldOffset(f_int_field); + f_long_off = unsafe.objectFieldOffset(f_long_field); + } catch (Exception e) { + System.out.println("reflection failed " + e); + e.printStackTrace(); + } + } + + public static void main(String[] args) + { + final TestUnsafeVolatileGAA t = new TestUnsafeVolatileGAA(); + for (int i = 0; i < 100_000; i++) { + if (t.testInt() != i-1) { + throw new RuntimeException("bad result!"); + } + } + for (int i = 0; i < 100_000; i++) { + if (t.testLong() != i-1) { + throw new RuntimeException("bad result!"); + } + } + } + + public int testInt() + { + return unsafe.getAndAddInt(this, f_int_off, 1); + } + + public long testLong() + { + return unsafe.getAndAddLong(this, f_long_off, 1); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileGAS.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileGAS.java new file mode 100644 index 00000000000..c74ce048453 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileGAS.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.aarch64; + +import java.lang.reflect.Field; +import jdk.internal.misc.Unsafe; + +class TestUnsafeVolatileGAS +{ + public volatile int f_int = -1; + public volatile Integer f_obj = Integer.valueOf(-1); + public volatile long f_long = -1; + + public static Unsafe unsafe = Unsafe.getUnsafe(); + public static Field f_int_field; + public static Field f_obj_field; + public static Field f_long_field; + public static long f_int_off; + public static long f_obj_off; + public static long f_long_off; + + static { + try { + f_int_field = TestUnsafeVolatileGAS.class.getField("f_int"); + f_obj_field = TestUnsafeVolatileGAS.class.getField("f_obj"); + f_long_field = TestUnsafeVolatileGAS.class.getField("f_long"); + f_int_off = unsafe.objectFieldOffset(f_int_field); + f_obj_off = unsafe.objectFieldOffset(f_obj_field); + f_long_off = unsafe.objectFieldOffset(f_long_field); + } catch (Exception e) { + System.out.println("reflection failed " + e); + e.printStackTrace(); + } + } + + public static void main(String[] args) + { + final TestUnsafeVolatileGAS t = new TestUnsafeVolatileGAS(); + for (int i = 0; i < 100_000; i++) { + if (t.testInt(i) != i-1) { + throw new RuntimeException("bad result!"); + } + } + for (int i = 0; i < 100_000; i++) { + if (t.testLong(i) != i-1) { + throw new RuntimeException("bad result!"); + } + } + for (int i = 0; i < 100_000; i++) { + if ((Integer)t.testObj(Integer.valueOf(i)) != i-1) { + throw new RuntimeException("bad result!"); + } + } + } + + public int testInt(int i) + { + return unsafe.getAndSetInt(this, f_int_off, i); + } + + public Object testObj(Object o) + { + return unsafe.getAndSetObject(this, f_obj_off, o); + } + public long testLong(long i) + { + return unsafe.getAndSetLong(this, f_long_off, i); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileWeakCAS.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileWeakCAS.java new file mode 100644 index 00000000000..39f4baf9c7f --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestUnsafeVolatileWeakCAS.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.aarch64; + +import java.lang.reflect.Field; +import jdk.internal.misc.Unsafe; + +class TestUnsafeVolatileWeakCAS +{ + public volatile int f_int = 0; + public volatile Integer f_obj = Integer.valueOf(0); + public volatile long f_long = 0; + public volatile byte f_byte = 0; + public volatile short f_short = 0; + + public static Unsafe unsafe = Unsafe.getUnsafe(); + public static Field f_int_field; + public static Field f_obj_field; + public static Field f_long_field; + public static Field f_byte_field; + public static Field f_short_field; + public static long f_int_off; + public static long f_obj_off; + public static long f_long_off; + public static long f_byte_off; + public static long f_short_off; + + static { + try { + f_int_field = TestUnsafeVolatileWeakCAS.class.getField("f_int"); + f_obj_field = TestUnsafeVolatileWeakCAS.class.getField("f_obj"); + f_long_field = TestUnsafeVolatileWeakCAS.class.getField("f_long"); + f_byte_field = TestUnsafeVolatileWeakCAS.class.getField("f_byte"); + f_short_field = TestUnsafeVolatileWeakCAS.class.getField("f_short"); + f_int_off = unsafe.objectFieldOffset(f_int_field); + f_obj_off = unsafe.objectFieldOffset(f_obj_field); + f_long_off = unsafe.objectFieldOffset(f_long_field); + f_byte_off = unsafe.objectFieldOffset(f_byte_field); + f_short_off = unsafe.objectFieldOffset(f_short_field); + } catch (Exception e) { + System.out.println("reflection failed " + e); + e.printStackTrace(); + } + } + + public static void main(String[] args) + { + final TestUnsafeVolatileWeakCAS t = new TestUnsafeVolatileWeakCAS(); + for (int i = 0; i < 100_000; i++) { + t.f_int = -1; + if (t.testInt(-1, i)) { + if (t.f_int != i) { + throw new RuntimeException("bad result!"); + } + } + } + for (int i = 0; i < 100_000; i++) { + t.f_long = -1; + if (t.testLong(-1, i)) { + if (t.f_long != i) { + throw new RuntimeException("bad result!"); + } + } + } + for (int i = 0; i < 100_000; i++) { + t.f_byte = -1; + byte i_b = (byte)i; + if (t.testByte((byte)-1, i_b)) { + if (t.f_byte != i_b) { + throw new RuntimeException("bad result!"); + } + } + } + for (int i = 0; i < 100_000; i++) { + t.f_short = -1; + short i_s = (short)i; + if (t.testShort((byte)-1, i_s)) { + if (t.f_short != i_s) { + throw new RuntimeException("bad result!"); + } + } + } + Integer minusOne = Integer.valueOf(-1); + for (int i = 0; i < 100_000; i++) { + t.f_obj = minusOne; + if (t.testObj(minusOne, Integer.valueOf(i))) { + if (t.f_obj != i) { + throw new RuntimeException("bad result!"); + } + } + } + } + + public boolean testInt(int x, int i) + { + return unsafe.weakCompareAndSetInt(this, f_int_off, x, i); + } + + public boolean testObj(Object x, Object o) + { + return unsafe.weakCompareAndSetObject(this, f_obj_off, x, o); + } + + public boolean testLong(long x, long i) + { + return unsafe.weakCompareAndSetLong(this, f_long_off, x, i); + } + + public boolean testByte(byte x, byte i) + { + return unsafe.weakCompareAndSetByte(this, f_byte_off, x, i); + } + + public boolean testShort(short x, short i) + { + return unsafe.weakCompareAndSetShort(this, f_short_off, x, i); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java index f8c90d2c500..72e0312518e 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java @@ -31,7 +31,10 @@ * TestVolatileStore, * TestUnsafeVolatileLoad, * TestUnsafeVolatileStore, - * TestUnsafeVolatileCAS} + * TestUnsafeVolatileCAS, + * TestUnsafeVolatileWeakCAS, + * TestUnsafeVolatileCAE, + * TestUnsafeVolatileGAS} * and in {G1, * CMS, * CMSCondMark, @@ -43,13 +46,16 @@ package compiler.c2.aarch64; import java.util.List; +import java.util.ListIterator; import java.util.Iterator; +import java.util.regex.Pattern; import java.io.*; import jdk.test.lib.Asserts; import jdk.test.lib.compiler.InMemoryJavaCompiler; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import sun.hotspot.WhiteBox; // runner class that spawns a new JVM to exercises a combination of // volatile MemOp and GC. The ops are compiled with the dmb --> @@ -68,28 +74,28 @@ public void runtest(String classname, String testType) throws Throwable { // i.e. GC type plus GC conifg switch(testType) { case "G1": - argcount = 8; + argcount = 9; procArgs = new String[argcount]; procArgs[argcount - 2] = "-XX:+UseG1GC"; break; case "Parallel": - argcount = 8; + argcount = 9; procArgs = new String[argcount]; procArgs[argcount - 2] = "-XX:+UseParallelGC"; break; case "Serial": - argcount = 8; + argcount = 9; procArgs = new String[argcount]; procArgs[argcount - 2] = "-XX:+UseSerialGC"; break; case "CMS": - argcount = 9 ; + argcount = 10; procArgs = new String[argcount]; procArgs[argcount - 3] = "-XX:+UseConcMarkSweepGC"; procArgs[argcount - 2] = "-XX:-UseCondCardMark"; break; case "CMSCondMark": - argcount = 9 ; + argcount = 10; procArgs = new String[argcount]; procArgs[argcount - 3] = "-XX:+UseConcMarkSweepGC"; procArgs[argcount - 2] = "-XX:+UseCondCardMark"; @@ -106,42 +112,46 @@ public void runtest(String classname, String testType) throws Throwable { // disable the transform. procArgs[0] = "-XX:-UseBarriersForVolatile"; + procArgs[1] = "-XX:+UseCompressedOops"; - procArgs[1] = "-XX:-TieredCompilation"; - procArgs[2] = "-XX:+PrintOptoAssembly"; - procArgs[3] = "-XX:CompileCommand=compileonly," + fullclassname + "::" + "test*"; - procArgs[4] = "--add-exports"; - procArgs[5] = "java.base/jdk.internal.misc=ALL-UNNAMED"; + procArgs[2] = "-XX:-TieredCompilation"; + procArgs[3] = "-XX:+PrintOptoAssembly"; + procArgs[4] = "-XX:CompileCommand=compileonly," + fullclassname + "::" + "test*"; + procArgs[5] = "--add-exports"; + procArgs[6] = "java.base/jdk.internal.misc=ALL-UNNAMED"; procArgs[argcount - 1] = fullclassname; - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(procArgs); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - - output.stderrShouldBeEmptyIgnoreVMWarnings(); - output.stdoutShouldNotBeEmpty(); - output.shouldHaveExitValue(0); - - // check the output for the correct asm sequence as - // appropriate to test class, test type and whether transform - // was applied - - checkoutput(output, classname, testType, false); - + runtest(classname, testType, false, true, procArgs); // rerun the test class without the transform applied and // check the alternative generation is as expected procArgs[0] = "-XX:+UseBarriersForVolatile"; + runtest(classname, testType, true, true, procArgs); + + if (!classname.equals("TestUnsafeVolatileGAA")) { + procArgs[0] = "-XX:-UseBarriersForVolatile"; + procArgs[1] = "-XX:-UseCompressedOops"; + runtest(classname, testType, false, false, procArgs); + + procArgs[0] = "-XX:+UseBarriersForVolatile"; + runtest(classname, testType, true, false, procArgs); + } + } - pb = ProcessTools.createJavaProcessBuilder(procArgs); - output = new OutputAnalyzer(pb.start()); + + public void runtest(String classname, String testType, boolean useBarriersForVolatile, boolean useCompressedOops, String[] procArgs) throws Throwable { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(procArgs); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.stderrShouldBeEmptyIgnoreVMWarnings(); output.stdoutShouldNotBeEmpty(); output.shouldHaveExitValue(0); - // again check the output for the correct asm sequence + // check the output for the correct asm sequence as + // appropriate to test class, test type and whether transform + // was applied - checkoutput(output, classname, testType, true); + checkoutput(output, classname, testType, useBarriersForVolatile, useCompressedOops); } // skip through output returning a line containing the desireed @@ -150,7 +160,7 @@ private String skipTo(Iterator iter, String substring) { while (iter.hasNext()) { String nextLine = iter.next(); - if (nextLine.contains(substring)) { + if (nextLine.matches(".*" + substring + ".*")) { return nextLine; } } @@ -163,7 +173,7 @@ private String skipTo(Iterator iter, String substring) // n.b. the spawned JVM's output is included in the exception // message to make it easeir to identify what is missing. - private void checkCompile(Iterator iter, String methodname, String[] expected, OutputAnalyzer output) + private boolean checkCompile(Iterator iter, String methodname, String[] expected, OutputAnalyzer output, boolean do_throw) { // trace call to allow eyeball check of what we are checking against System.out.println("checkCompile(" + methodname + ","); @@ -176,30 +186,43 @@ private void checkCompile(Iterator iter, String methodname, String[] exp System.out.println(" })"); // look for the start of an opto assembly print block - String match = skipTo(iter, "{method}"); + String match = skipTo(iter, Pattern.quote("{method}")); if (match == null) { - throw new RuntimeException("Missing compiler output for " + methodname + "!\n\n" + output.getOutput()); + if (do_throw) { + throw new RuntimeException("Missing compiler output for " + methodname + "!\n\n" + output.getOutput()); + } + return false; } // check the compiled method name is right - match = skipTo(iter, "- name:"); + match = skipTo(iter, Pattern.quote("- name:")); if (match == null) { - throw new RuntimeException("Missing compiled method name!\n\n" + output.getOutput()); + if (do_throw) { + throw new RuntimeException("Missing compiled method name!\n\n" + output.getOutput()); + } + return false; } if (!match.contains(methodname)) { - throw new RuntimeException("Wrong method " + match + "!\n -- expecting " + methodname + "\n\n" + output.getOutput()); + if (do_throw) { + throw new RuntimeException("Wrong method " + match + "!\n -- expecting " + methodname + "\n\n" + output.getOutput()); + } + return false; } // make sure we can match each expected term in order for (String s : expected) { match = skipTo(iter, s); if (match == null) { - throw new RuntimeException("Missing expected output " + s + "!\n\n" + output.getOutput()); + if (do_throw) { + throw new RuntimeException("Missing expected output " + s + "!\n\n" + output.getOutput()); + } + return false; } } + return true; } // check for expected asm output from a volatile load - private void checkload(OutputAnalyzer output, String testType, boolean useBarriersForVolatile) throws Throwable + private void checkload(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable { Iterator iter = output.asLines().listIterator(); @@ -211,7 +234,7 @@ private void checkload(OutputAnalyzer output, String testType, boolean useBarrie if (!useBarriersForVolatile) { matches = new String[] { "ldarw", - "membar_acquire (elided)", + "membar_acquire \\(elided\\)", "ret" }; } else { @@ -223,15 +246,30 @@ private void checkload(OutputAnalyzer output, String testType, boolean useBarrie }; } - checkCompile(iter, "testInt", matches, output); + checkCompile(iter, "testInt", matches, output, true); - checkCompile(iter, "testObj", matches, output) ; + if (!useBarriersForVolatile) { + matches = new String[] { + useCompressedOops ? "ldarw?" : "ldar", + "membar_acquire \\(elided\\)", + "ret" + }; + } else { + matches = new String[] { + useCompressedOops ? "ldrw?" : "ldr", + "membar_acquire", + "dmb ish", + "ret" + }; + } + + checkCompile(iter, "testObj", matches, output, true); } // check for expected asm output from a volatile store - private void checkstore(OutputAnalyzer output, String testType, boolean useBarriersForVolatile) throws Throwable + private void checkstore(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable { Iterator iter = output.asLines().listIterator(); @@ -241,9 +279,9 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri if (!useBarriersForVolatile) { // this is the sequence of instructions for all cases matches = new String[] { - "membar_release (elided)", + "membar_release \\(elided\\)", "stlrw", - "membar_volatile (elided)", + "membar_volatile \\(elided\\)", "ret" }; } else { @@ -258,7 +296,7 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri }; } - checkCompile(iter, "testInt", matches, output); + checkCompile(iter, "testInt", matches, output, true); // object stores will be as above except for when the GC // introduces barriers for card marking @@ -268,9 +306,9 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri default: // this is the basic sequence of instructions matches = new String[] { - "membar_release (elided)", - "stlrw", - "membar_volatile (elided)", + "membar_release \\(elided\\)", + useCompressedOops ? "stlrw?" : "stlr", + "membar_volatile \\(elided\\)", "ret" }; break; @@ -278,12 +316,12 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri // a card mark volatile barrier should be generated // before the card mark strb matches = new String[] { - "membar_release (elided)", - "stlrw", + "membar_release \\(elided\\)", + useCompressedOops ? "stlrw?" : "stlr", "membar_volatile", "dmb ish", "strb", - "membar_volatile (elided)", + "membar_volatile \\(elided\\)", "ret" }; break; @@ -292,13 +330,13 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri // before the card mark strb from the StoreCM and the // storestore barrier from the StoreCM should be elided matches = new String[] { - "membar_release (elided)", - "stlrw", + "membar_release \\(elided\\)", + useCompressedOops ? "stlrw?" : "stlr", "membar_volatile", "dmb ish", - "storestore (elided)", + "storestore \\(elided\\)", "strb", - "membar_volatile (elided)", + "membar_volatile \\(elided\\)", "ret" }; break; @@ -308,12 +346,12 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri // storestore barrier from the StoreCM should be // generated as "dmb ishst" matches = new String[] { - "membar_release (elided)", - "stlrw", + "membar_release \\(elided\\)", + useCompressedOops ? "stlrw?" : "stlr", "storestore", "dmb ishst", "strb", - "membar_volatile (elided)", + "membar_volatile \\(elided\\)", "ret" }; break; @@ -325,7 +363,7 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri matches = new String[] { "membar_release", "dmb ish", - "strw", + useCompressedOops ? "strw?" : "str", "membar_volatile", "dmb ish", "ret" @@ -337,7 +375,7 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri matches = new String[] { "membar_release", "dmb ish", - "strw", + useCompressedOops ? "strw?" : "str", "membar_volatile", "dmb ish", "strb", @@ -353,10 +391,10 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri matches = new String[] { "membar_release", "dmb ish", - "strw", + useCompressedOops ? "strw?" : "str", "membar_volatile", "dmb ish", - "storestore (elided)", + "storestore \\(elided\\)", "strb", "membar_volatile", "dmb ish", @@ -371,7 +409,7 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri matches = new String[] { "membar_release", "dmb ish", - "strw", + useCompressedOops ? "strw?" : "str", "storestore", "dmb ishst", "strb", @@ -383,39 +421,389 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useBarri } } - checkCompile(iter, "testObj", matches, output); + checkCompile(iter, "testObj", matches, output, true); } // check for expected asm output from a volatile cas - private void checkcas(OutputAnalyzer output, String testType, boolean useBarriersForVolatile) throws Throwable + private void checkcas(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable { Iterator iter = output.asLines().listIterator(); String[] matches; + String[][] tests = { + { "testInt", "cmpxchgw" }, + { "testLong", "cmpxchg" }, + { "testByte", "cmpxchgb" }, + { "testShort", "cmpxchgs" }, + }; + + for (String[] test : tests) { + // non object stores are straightforward + if (!useBarriersForVolatile) { + // this is the sequence of instructions for all cases + matches = new String[] { + "membar_release \\(elided\\)", + test[1] + "_acq", + "membar_acquire \\(elided\\)", + "ret" + }; + } else { + // this is the alternative sequence of instructions + matches = new String[] { + "membar_release", + "dmb ish", + test[1] + " ", + "membar_acquire", + "dmb ish", + "ret" + }; + } + + checkCompile(iter, test[0], matches, output, true); + } + + // object stores will be as above except for when the GC + // introduces barriers for card marking - // non object stores are straightforward if (!useBarriersForVolatile) { - // this is the sequence of instructions for all cases - matches = new String[] { - "membar_release (elided)", - "cmpxchgw_acq", - "membar_acquire (elided)", - "ret" - }; + switch (testType) { + default: + // this is the basic sequence of instructions + matches = new String[] { + "membar_release \\(elided\\)", + useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", + "strb", + "membar_acquire \\(elided\\)", + "ret" + }; + break; + case "G1": + // a card mark volatile barrier should be generated + // before the card mark strb + matches = new String[] { + "membar_release \\(elided\\)", + useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", + "membar_volatile", + "dmb ish", + "strb", + "membar_acquire \\(elided\\)", + "ret" + }; + break; + case "CMSCondMark": + // a card mark volatile barrier should be generated + // before the card mark strb from the StoreCM and the + // storestore barrier from the StoreCM should be elided + matches = new String[] { + "membar_release \\(elided\\)", + useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", + "membar_volatile", + "dmb ish", + "storestore \\(elided\\)", + "strb", + "membar_acquire \\(elided\\)", + "ret" + }; + break; + case "CMS": + // a volatile card mark membar should not be generated + // before the card mark strb from the StoreCM and the + // storestore barrier from the StoreCM should be elided + matches = new String[] { + "membar_release \\(elided\\)", + useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", + "storestore", + "dmb ishst", + "strb", + "membar_acquire \\(elided\\)", + "ret" + }; + break; + } } else { - // this is the alternative sequence of instructions - matches = new String[] { - "membar_release", - "dmb ish", - "cmpxchgw", - "membar_acquire", - "dmb ish", - "ret" - }; + switch (testType) { + default: + // this is the basic sequence of instructions + matches = new String[] { + "membar_release", + "dmb ish", + useCompressedOops ? "cmpxchgw? " : "cmpxchg ", + "membar_acquire", + "dmb ish", + "ret" + }; + break; + case "G1": + // a card mark volatile barrier should be generated + // before the card mark strb + matches = new String[] { + "membar_release", + "dmb ish", + useCompressedOops ? "cmpxchgw? " : "cmpxchg ", + "membar_volatile", + "dmb ish", + "strb", + "membar_acquire", + "dmb ish", + "ret" + }; + break; + case "CMSCondMark": + // a card mark volatile barrier should be generated + // before the card mark strb from the StoreCM and the + // storestore barrier from the StoreCM should be elided + matches = new String[] { + "membar_release", + "dmb ish", + useCompressedOops ? "cmpxchgw? " : "cmpxchg ", + "membar_volatile", + "dmb ish", + "storestore \\(elided\\)", + "strb", + "membar_acquire", + "dmb ish", + "ret" + }; + break; + case "CMS": + // a volatile card mark membar should not be generated + // before the card mark strb from the StoreCM and the + // storestore barrier from the StoreCM should be generated + // as "dmb ishst" + matches = new String[] { + "membar_release", + "dmb ish", + useCompressedOops ? "cmpxchgw? " : "cmpxchg ", + "storestore", + "dmb ishst", + "strb", + "membar_acquire", + "dmb ish", + "ret" + }; + break; + } } - checkCompile(iter, "testInt", matches, output); + checkCompile(iter, "testObj", matches, output, true); + } + + private void checkcae(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable + { + ListIterator iter = output.asLines().listIterator(); + + String[] matches; + String[][] tests = { + { "testInt", "cmpxchgw" }, + { "testLong", "cmpxchg" }, + { "testByte", "cmpxchgb" }, + { "testShort", "cmpxchgs" }, + }; + + for (String[] test : tests) { + // non object stores are straightforward + if (!useBarriersForVolatile) { + // this is the sequence of instructions for all cases + matches = new String[] { + "membar_release \\(elided\\)", + test[1] + "_acq", + "membar_acquire \\(elided\\)", + "ret" + }; + } else { + // this is the alternative sequence of instructions + matches = new String[] { + "membar_release", + "dmb ish", + test[1] + " ", + "membar_acquire", + "dmb ish", + "ret" + }; + } + + checkCompile(iter, test[0], matches, output, true); + } + + // object stores will be as above except for when the GC + // introduces barriers for card marking + + if (!useBarriersForVolatile) { + switch (testType) { + default: + // this is the basic sequence of instructions + matches = new String[] { + "membar_release \\(elided\\)", + "strb", + useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", + "membar_acquire \\(elided\\)", + "ret" + }; + + // card marking store may be scheduled before or after + // the cmpxchg so try both sequences. + int idx = iter.nextIndex(); + if (!checkCompile(iter, "testObj", matches, output, false)) { + iter = output.asLines().listIterator(idx); + + matches = new String[] { + "membar_release \\(elided\\)", + useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", + "strb", + "membar_acquire \\(elided\\)", + "ret" + }; + + checkCompile(iter, "testObj", matches, output, true); + } + return; + + case "G1": + // a card mark volatile barrier should be generated + // before the card mark strb + matches = new String[] { + "membar_release \\(elided\\)", + useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", + "membar_volatile", + "dmb ish", + "strb", + "membar_acquire \\(elided\\)", + "ret" + }; + break; + case "CMSCondMark": + // a card mark volatile barrier should be generated + // before the card mark strb from the StoreCM and the + // storestore barrier from the StoreCM should be elided + matches = new String[] { + "membar_release \\(elided\\)", + useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", + "membar_volatile", + "dmb ish", + "storestore \\(elided\\)", + "strb", + "membar_acquire \\(elided\\)", + "ret" + }; + break; + case "CMS": + // a volatile card mark membar should not be generated + // before the card mark strb from the StoreCM and the + // storestore barrier from the StoreCM should be elided + matches = new String[] { + "membar_release \\(elided\\)", + useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", + "storestore", + "dmb ishst", + "strb", + "membar_acquire \\(elided\\)", + "ret" + }; + break; + } + } else { + switch (testType) { + default: + // this is the basic sequence of instructions + matches = new String[] { + "membar_release", + "dmb ish", + useCompressedOops ? "cmpxchgw? " : "cmpxchg ", + "membar_acquire", + "dmb ish", + "ret" + }; + break; + case "G1": + // a card mark volatile barrier should be generated + // before the card mark strb + matches = new String[] { + "membar_release", + "dmb ish", + useCompressedOops ? "cmpxchgw? " : "cmpxchg ", + "membar_volatile", + "dmb ish", + "strb", + "membar_acquire", + "dmb ish", + "ret" + }; + break; + case "CMSCondMark": + // a card mark volatile barrier should be generated + // before the card mark strb from the StoreCM and the + // storestore barrier from the StoreCM should be elided + matches = new String[] { + "membar_release", + "dmb ish", + useCompressedOops ? "cmpxchgw? " : "cmpxchg ", + "membar_volatile", + "dmb ish", + "storestore \\(elided\\)", + "strb", + "membar_acquire", + "dmb ish", + "ret" + }; + break; + case "CMS": + // a volatile card mark membar should not be generated + // before the card mark strb from the StoreCM and the + // storestore barrier from the StoreCM should be generated + // as "dmb ishst" + matches = new String[] { + "membar_release", + "dmb ish", + useCompressedOops ? "cmpxchgw? " : "cmpxchg ", + "storestore", + "dmb ishst", + "strb", + "membar_acquire", + "dmb ish", + "ret" + }; + break; + } + } + + checkCompile(iter, "testObj", matches, output, true); + } + + private void checkgas(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable + { + Iterator iter = output.asLines().listIterator(); + + String[] matches; + String[][] tests = { + { "testInt", "atomic_xchgw" }, + { "testLong", "atomic_xchg" }, + }; + + for (String[] test : tests) { + // non object stores are straightforward + if (!useBarriersForVolatile) { + // this is the sequence of instructions for all cases + matches = new String[] { + "membar_release \\(elided\\)", + test[1] + "_acq", + "membar_acquire \\(elided\\)", + "ret" + }; + } else { + // this is the alternative sequence of instructions + matches = new String[] { + "membar_release", + "dmb ish", + test[1] + " ", + "membar_acquire", + "dmb ish", + "ret" + }; + } + + checkCompile(iter, test[0], matches, output, true); + } // object stores will be as above except for when the GC // introduces barriers for card marking @@ -425,10 +813,10 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useBarrier default: // this is the basic sequence of instructions matches = new String[] { - "membar_release (elided)", - "cmpxchgw_acq", + "membar_release \\(elided\\)", + useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", "strb", - "membar_acquire (elided)", + "membar_acquire \\(elided\\)", "ret" }; break; @@ -436,12 +824,12 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useBarrier // a card mark volatile barrier should be generated // before the card mark strb matches = new String[] { - "membar_release (elided)", - "cmpxchgw_acq", + "membar_release \\(elided\\)", + useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", "membar_volatile", "dmb ish", "strb", - "membar_acquire (elided)", + "membar_acquire \\(elided\\)", "ret" }; break; @@ -450,13 +838,13 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useBarrier // before the card mark strb from the StoreCM and the // storestore barrier from the StoreCM should be elided matches = new String[] { - "membar_release (elided)", - "cmpxchgw_acq", + "membar_release \\(elided\\)", + useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", "membar_volatile", "dmb ish", - "storestore (elided)", + "storestore \\(elided\\)", "strb", - "membar_acquire (elided)", + "membar_acquire \\(elided\\)", "ret" }; break; @@ -465,12 +853,12 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useBarrier // before the card mark strb from the StoreCM and the // storestore barrier from the StoreCM should be elided matches = new String[] { - "membar_release (elided)", - "cmpxchgw_acq", + "membar_release \\(elided\\)", + useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", "storestore", "dmb ishst", "strb", - "membar_acquire (elided)", + "membar_acquire \\(elided\\)", "ret" }; break; @@ -482,7 +870,7 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useBarrier matches = new String[] { "membar_release", "dmb ish", - "cmpxchgw", + useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ", "membar_acquire", "dmb ish", "ret" @@ -494,7 +882,7 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useBarrier matches = new String[] { "membar_release", "dmb ish", - "cmpxchgw", + useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ", "membar_volatile", "dmb ish", "strb", @@ -510,10 +898,10 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useBarrier matches = new String[] { "membar_release", "dmb ish", - "cmpxchgw", + useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ", "membar_volatile", "dmb ish", - "storestore (elided)", + "storestore \\(elided\\)", "strb", "membar_acquire", "dmb ish", @@ -528,7 +916,7 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useBarrier matches = new String[] { "membar_release", "dmb ish", - "cmpxchgw", + useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ", "storestore", "dmb ishst", "strb", @@ -540,12 +928,49 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useBarrier } } - checkCompile(iter, "testObj", matches, output); + checkCompile(iter, "testObj", matches, output, true); + } + + private void checkgaa(OutputAnalyzer output, String testType, boolean useBarriersForVolatile) throws Throwable + { + Iterator iter = output.asLines().listIterator(); + + String[] matches; + String[][] tests = { + { "testInt", "get_and_addI" }, + { "testLong", "get_and_addL" }, + }; + + for (String[] test : tests) { + // non object stores are straightforward + if (!useBarriersForVolatile) { + // this is the sequence of instructions for all cases + matches = new String[] { + "membar_release \\(elided\\)", + test[1] + "_acq", + "membar_acquire \\(elided\\)", + "ret" + }; + } else { + // this is the alternative sequence of instructions + matches = new String[] { + "membar_release", + "dmb ish", + test[1] + " ", + "membar_acquire", + "dmb ish", + "ret" + }; + } + + checkCompile(iter, test[0], matches, output, true); + } + } // perform a check appropriate to the classname - private void checkoutput(OutputAnalyzer output, String classname, String testType, boolean useBarriersForVolatile) throws Throwable + private void checkoutput(OutputAnalyzer output, String classname, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable { // trace call to allow eyeball check of what is being checked System.out.println("checkoutput(" + @@ -556,19 +981,29 @@ private void checkoutput(OutputAnalyzer output, String classname, String testTyp switch (classname) { case "TestVolatileLoad": - checkload(output, testType, useBarriersForVolatile); + checkload(output, testType, useBarriersForVolatile, useCompressedOops); break; case "TestVolatileStore": - checkstore(output, testType, useBarriersForVolatile); + checkstore(output, testType, useBarriersForVolatile, useCompressedOops); break; case "TestUnsafeVolatileLoad": - checkload(output, testType, useBarriersForVolatile); + checkload(output, testType, useBarriersForVolatile, useCompressedOops); break; case "TestUnsafeVolatileStore": - checkstore(output, testType, useBarriersForVolatile); + checkstore(output, testType, useBarriersForVolatile, useCompressedOops); break; case "TestUnsafeVolatileCAS": - checkcas(output, testType, useBarriersForVolatile); + case "TestUnsafeVolatileWeakCAS": + checkcas(output, testType, useBarriersForVolatile, useCompressedOops); + break; + case "TestUnsafeVolatileCAE": + checkcae(output, testType, useBarriersForVolatile, useCompressedOops); + break; + case "TestUnsafeVolatileGAS": + checkgas(output, testType, useBarriersForVolatile, useCompressedOops); + break; + case "TestUnsafeVolatileGAA": + checkgaa(output, testType, useBarriersForVolatile); break; } } diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesCMS.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesCMS.java index e65250ff579..3397fda6a4d 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesCMS.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesCMS.java @@ -38,6 +38,9 @@ * compiler.c2.aarch64.TestVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileCAS + * compiler.c2.aarch64.TestUnsafeVolatileWeakCAS + * compiler.c2.aarch64.TestUnsafeVolatileCAE + * compiler.c2.aarch64.TestUnsafeVolatileGAS * * @run driver compiler.c2.aarch64.TestVolatilesCMS * TestVolatileLoad CMS @@ -53,6 +56,15 @@ * * @run driver compiler.c2.aarch64.TestVolatilesCMS * TestUnsafeVolatileCAS CMS + * + * @run driver compiler.c2.aarch64.TestVolatilesCMS + * TestUnsafeVolatileWeakCAS CMS + * + * @run driver compiler.c2.aarch64.TestVolatilesCMS + * TestUnsafeVolatileCAE CMS + * + * @run driver compiler.c2.aarch64.TestVolatilesCMS + * TestUnsafeVolatileGAS CMS */ package compiler.c2.aarch64; diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesCMSCondMark.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesCMSCondMark.java index b0931b1631b..29ce80493c8 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesCMSCondMark.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesCMSCondMark.java @@ -38,6 +38,9 @@ * compiler.c2.aarch64.TestVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileCAS + * compiler.c2.aarch64.TestUnsafeVolatileWeakCAS + * compiler.c2.aarch64.TestUnsafeVolatileCAE + * compiler.c2.aarch64.TestUnsafeVolatileGAS * * @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark * TestVolatileLoad CMSCondMark @@ -53,6 +56,15 @@ * * @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark * TestUnsafeVolatileCAS CMSCondMark + * + * @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark + * TestUnsafeVolatileWeakCAS CMSCondMark + * + * @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark + * TestUnsafeVolatileCAE CMSCondMark + * + * @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark + * TestUnsafeVolatileGAS CMSCondMark */ package compiler.c2.aarch64; diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesG1.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesG1.java index 658e5ad9d39..88d747e44d9 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesG1.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesG1.java @@ -38,6 +38,10 @@ * compiler.c2.aarch64.TestVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileCAS + * compiler.c2.aarch64.TestUnsafeVolatileWeakCAS + * compiler.c2.aarch64.TestUnsafeVolatileCAE + * compiler.c2.aarch64.TestUnsafeVolatileGAS + * compiler.c2.aarch64.TestUnsafeVolatileGAA * * @run driver compiler.c2.aarch64.TestVolatilesG1 * TestVolatileLoad G1 @@ -53,8 +57,21 @@ * * @run driver compiler.c2.aarch64.TestVolatilesG1 * TestUnsafeVolatileCAS G1 + * + * @run driver compiler.c2.aarch64.TestVolatilesG1 + * TestUnsafeVolatileWeakCAS G1 + * + * @run driver compiler.c2.aarch64.TestVolatilesG1 + * TestUnsafeVolatileCAE G1 + * + * @run driver compiler.c2.aarch64.TestVolatilesG1 + * TestUnsafeVolatileGAS G1 + * + * @run driver compiler.c2.aarch64.TestVolatilesG1 + * TestUnsafeVolatileGAA G1 */ + package compiler.c2.aarch64; public class TestVolatilesG1 { diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesParallel.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesParallel.java index 8f6a78efcf2..c3203c0b276 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesParallel.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesParallel.java @@ -38,6 +38,9 @@ * compiler.c2.aarch64.TestVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileCAS + * compiler.c2.aarch64.TestUnsafeVolatileWeakCAS + * compiler.c2.aarch64.TestUnsafeVolatileCAE + * compiler.c2.aarch64.TestUnsafeVolatileGAS * * @run driver compiler.c2.aarch64.TestVolatilesParallel * TestVolatileLoad Parallel @@ -53,6 +56,15 @@ * * @run driver compiler.c2.aarch64.TestVolatilesParallel * TestUnsafeVolatileCAS Parallel + * + * @run driver compiler.c2.aarch64.TestVolatilesParallel + * TestUnsafeVolatileWeakCAS Parallel + * + * @run driver compiler.c2.aarch64.TestVolatilesParallel + * TestUnsafeVolatileCAE Parallel + * + * @run driver compiler.c2.aarch64.TestVolatilesParallel + * TestUnsafeVolatileGAS Parallel */ package compiler.c2.aarch64; diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesSerial.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesSerial.java index 470ae748e12..c04c3594497 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesSerial.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatilesSerial.java @@ -38,6 +38,9 @@ * compiler.c2.aarch64.TestVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileStore * compiler.c2.aarch64.TestUnsafeVolatileCAS + * compiler.c2.aarch64.TestUnsafeVolatileWeakCAS + * compiler.c2.aarch64.TestUnsafeVolatileCAE + * compiler.c2.aarch64.TestUnsafeVolatileGAS * * @run driver compiler.c2.aarch64.TestVolatilesSerial * TestVolatileLoad Serial @@ -53,6 +56,15 @@ * * @run driver compiler.c2.aarch64.TestVolatilesSerial * TestUnsafeVolatileCAS Serial + * + * @run driver compiler.c2.aarch64.TestVolatilesSerial + * TestUnsafeVolatileWeakCAS Serial + * + * @run driver compiler.c2.aarch64.TestVolatilesSerial + * TestUnsafeVolatileCAE Serial + * + * @run driver compiler.c2.aarch64.TestVolatilesSerial + * TestUnsafeVolatileGAS Serial */ package compiler.c2.aarch64; diff --git a/test/hotspot/jtreg/compiler/controldependency/TestAntiDependentMembar.java b/test/hotspot/jtreg/compiler/controldependency/TestAntiDependentMembar.java new file mode 100644 index 00000000000..0ce689883ff --- /dev/null +++ b/test/hotspot/jtreg/compiler/controldependency/TestAntiDependentMembar.java @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2019, 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 8228772 + * @summary Test correct insertion of anti-dependencies if load is already control dependent on membar. + * @run main/othervm -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=inline,compiler.controldependency.TestAntiDependentMembar::hitSearchLimit + * compiler.controldependency.TestAntiDependentMembar + * @run main/othervm -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=inline,compiler.controldependency.TestAntiDependentMembar::hitSearchLimit + * -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:DominatorSearchLimit=0 + * compiler.controldependency.TestAntiDependentMembar + */ + +package compiler.controldependency; + +public class TestAntiDependentMembar { + + static volatile int step1 = 0; + static volatile int step2 = 0; + + public static int test1(int count, int b1, int b2) { + int[] result = {0}; + + // Complex control flow to generate Region with 4 paths and therefore bail out of Node::dominates + if (b1 == 0) { + count += 1; + } else if (b1 == 1) { + if (b2 == 1) { + count += 2; + } + } + + for (int i = 0; i < count; ++i) { + // Volatile field write adds a membar + step1 = i; + // Load that is dependent on the membar + result[0] += count; + } + return result[0]; + } + + // Same as test1 but bailing out of Node::dominates due to hitting DominatorSearchLimit + public static int test2(int count) { + int[] result = {0}; + + // Large method with regions to hit the DominatorSearchLimit + hitSearchLimit(); + + for (int i = 0; i < count; ++i) { + step1 = i; + result[0] += count; + } + return result[0]; + } + + // Same as test2 but with multiple membars before the load + public static int test3(int count) { + int[] result = {0}; + + hitSearchLimit(); + + for (int i = 0; i < count; ++i) { + step1 = i; + step2 = i; + step1 = i; + step2 = i; + result[0] += count; + } + return result[0]; + } + + public static void main(String[] args) { + for (int i = 0; i < 50_000; ++i) { + test1(10, 0, 0); + test1(10, 1, 1); + test1(10, 1, 0); + test1(10, 0, 1); + test2(10); + test3(10); + } + } + + public static void hitSearchLimit() { + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + step1++; + step2++; + } +} diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestArrayCopy.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestArrayCopy.java index 91c09a05acb..4ad0ff80c80 100644 --- a/test/hotspot/jtreg/compiler/escapeAnalysis/TestArrayCopy.java +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestArrayCopy.java @@ -33,7 +33,7 @@ * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * - * @run main/othervm + * @run main/othervm/timeout=300 * -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestSelfArrayCopy.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestSelfArrayCopy.java new file mode 100644 index 00000000000..434498c2928 --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestSelfArrayCopy.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019, 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 8229016 8231055 + * @summary Test correct elimination of array allocation with arraycopy to itself. + * @library /test/lib + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.escapeAnalysis.TestSelfArrayCopy::test* + * compiler.escapeAnalysis.TestSelfArrayCopy + */ + +package compiler.escapeAnalysis; + +import jdk.test.lib.Utils; + +public class TestSelfArrayCopy { + private static boolean b = false; + private static final int rI1 = Utils.getRandomInstance().nextInt(); + private static final int rI2 = Utils.getRandomInstance().nextInt(); + + private static int test1() { + // Non-escaping allocation + Integer[] array = {rI1, rI2}; + // Arraycopy with src == dst + System.arraycopy(array, 0, array, 0, array.length - 1); + if (b) { + // Uncommon trap + System.out.println(array[0]); + } + return array[0] + array[1]; + } + + private static int test2() { + // Non-escaping allocation + Integer[] array = {rI1, rI2}; + // Arraycopy with src == dst + System.arraycopy(array, 0, array, 1, 1); + if (b) { + // Uncommon trap + System.out.println(array[0]); + } + return array[0] + array[1]; + } + + public static void main(String[] args) { + int expected1 = rI1 + rI2; + int expected2 = rI1 + rI1; + // Trigger compilation + for (int i = 0; i < 20_000; ++i) { + int result = test1(); + if (result != expected1) { + throw new RuntimeException("Incorrect result: " + result + " != " + expected1); + } + result = test2(); + if (result != expected2) { + throw new RuntimeException("Incorrect result: " + result + " != " + expected2); + } + } + b = true; + int result = test1(); + if (result != expected1) { + throw new RuntimeException("Incorrect result: " + result + " != " + expected1); + } + result = test2(); + if (result != expected2) { + throw new RuntimeException("Incorrect result: " + result + " != " + expected2); + } + } +} diff --git a/test/hotspot/jtreg/compiler/gcbarriers/EqvUncastStepOverBarrier.java b/test/hotspot/jtreg/compiler/gcbarriers/EqvUncastStepOverBarrier.java new file mode 100644 index 00000000000..532f490a112 --- /dev/null +++ b/test/hotspot/jtreg/compiler/gcbarriers/EqvUncastStepOverBarrier.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8212673 + * @summary Node::eqv_uncast() shouldn't step over load barriers unconditionally + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-UseOnStackReplacement -XX:-TieredCompilation -XX:-BackgroundCompilation EqvUncastStepOverBarrier + */ + +import sun.hotspot.WhiteBox; +import java.lang.reflect.Method; + +public class EqvUncastStepOverBarrier { + static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static Object field = new A(); + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 20_000; i++) { + test(); + test(); + test_helper(null, 0); + } + Method m = EqvUncastStepOverBarrier.class.getDeclaredMethod("test"); + WHITE_BOX.enqueueMethodForCompilation(m, 4); + if (!WHITE_BOX.isMethodCompiled(m, false)) { + throw new RuntimeException("Method compilation failed"); + } + } + + private static Object test() { + Object o = field; + if (o == null) {} + for (int i = 1; i < 100; i *= 2) { + int j = 0; + for (; j < 4; j++) ; + o = test_helper(o, j); + } + return o; + } + + private static Object test_helper(Object o, int j) { + if (j == 4) { + A a = (A) o; + o = a; + } else { + o = new Object(); + } + return o; + } + + private static class A { + } +} diff --git a/test/hotspot/jtreg/compiler/graalunit/JttLangMathALTest.java b/test/hotspot/jtreg/compiler/graalunit/JttLangMathALTest.java index 3ba1127bb4d..e17fa343021 100644 --- a/test/hotspot/jtreg/compiler/graalunit/JttLangMathALTest.java +++ b/test/hotspot/jtreg/compiler/graalunit/JttLangMathALTest.java @@ -34,5 +34,6 @@ * * @run driver jdk.test.lib.FileInstaller ../../ProblemList-graal.txt ExcludeList.txt * - * @run main/othervm compiler.graalunit.common.GraalUnitTestLauncher -prefix org.graalvm.compiler.jtt.lang.Math_[a-lA-L] -exclude ExcludeList.txt + * @run main/othervm/timeout=300 compiler.graalunit.common.GraalUnitTestLauncher + * -prefix org.graalvm.compiler.jtt.lang.Math_[a-lA-L] -exclude ExcludeList.txt */ diff --git a/test/hotspot/jtreg/compiler/graalunit/JttLangMathMZTest.java b/test/hotspot/jtreg/compiler/graalunit/JttLangMathMZTest.java index 874e697d047..86e09fe10e0 100644 --- a/test/hotspot/jtreg/compiler/graalunit/JttLangMathMZTest.java +++ b/test/hotspot/jtreg/compiler/graalunit/JttLangMathMZTest.java @@ -34,5 +34,6 @@ * * @run driver jdk.test.lib.FileInstaller ../../ProblemList-graal.txt ExcludeList.txt * - * @run main/othervm compiler.graalunit.common.GraalUnitTestLauncher -prefix org.graalvm.compiler.jtt.lang.Math_[m-zM-Z] -exclude ExcludeList.txt + * @run main/othervm/timeout=300 compiler.graalunit.common.GraalUnitTestLauncher + * -prefix org.graalvm.compiler.jtt.lang.Math_[m-zM-Z] -exclude ExcludeList.txt */ diff --git a/test/hotspot/jtreg/compiler/intrinsics/object/TestClone.java b/test/hotspot/jtreg/compiler/intrinsics/object/TestClone.java index e239f55d597..98cc9a93ff1 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/object/TestClone.java +++ b/test/hotspot/jtreg/compiler/intrinsics/object/TestClone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -29,7 +29,7 @@ * @library /test/lib * * @run main/othervm -XX:-TieredCompilation -Xbatch - * -XX:CompileCommand=compileonly,compiler.intrinsics.object.TestClone::f + * -XX:CompileCommand=compileonly,compiler.intrinsics.object.TestClone::test* * compiler.intrinsics.object.TestClone */ @@ -37,6 +37,43 @@ import jdk.test.lib.Asserts; +abstract class MyAbstract { + + public Object myClone1() throws CloneNotSupportedException { + return this.clone(); + } + + public Object myClone2() throws CloneNotSupportedException { + return this.clone(); + } + + public Object myClone3() throws CloneNotSupportedException { + return this.clone(); + } +} + +class MyClass1 extends MyAbstract { + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} + +class MyClass2 extends MyAbstract { + +} + +class MyClass3 extends MyAbstract implements Cloneable { + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } +} + +class MyClass4 extends MyAbstract implements Cloneable { + +} + public class TestClone implements Cloneable { static class A extends TestClone {} static class B extends TestClone { @@ -56,29 +93,70 @@ public D clone() { } static TestClone a = new A(), b = new B(), c = new C(), d = new D(); - public static Object f(TestClone o) throws CloneNotSupportedException { + public static Object test1(TestClone o) throws CloneNotSupportedException { // Polymorphic call site: >90% Object::clone / <10% other methods return o.clone(); } + public static void test2(MyAbstract obj, boolean shouldThrow) throws Exception { + try { + obj.myClone1(); + } catch (Exception e) { + return; // Expected + } + Asserts.assertFalse(shouldThrow, "No exception thrown"); + } + + public static void test3(MyAbstract obj, boolean shouldThrow) throws Exception { + try { + obj.myClone2(); + } catch (Exception e) { + return; // Expected + } + Asserts.assertFalse(shouldThrow, "No exception thrown"); + } + + public static void test4(MyAbstract obj, boolean shouldThrow) throws Exception { + try { + obj.myClone3(); + } catch (Exception e) { + return; // Expected + } + Asserts.assertFalse(shouldThrow, "No exception thrown"); + } + public static void main(String[] args) throws Exception { TestClone[] params1 = {a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, b, c, d}; + MyClass1 obj1 = new MyClass1(); + MyClass2 obj2 = new MyClass2(); + MyClass3 obj3 = new MyClass3(); + MyClass4 obj4 = new MyClass4(); + for (int i = 0; i < 15000; i++) { - f(params1[i % params1.length]); + test1(params1[i % params1.length]); + + test2(obj1, true); + test2(obj2, true); + + test3(obj3, false); + test3(obj2, true); + + test4(obj3, false); + test4(obj4, false); } - Asserts.assertTrue(f(a) != a); - Asserts.assertTrue(f(b) == b); - Asserts.assertTrue(f(c) == c); - Asserts.assertTrue(f(d) == d); + Asserts.assertTrue(test1(a) != a); + Asserts.assertTrue(test1(b) == b); + Asserts.assertTrue(test1(c) == c); + Asserts.assertTrue(test1(d) == d); try { - f(null); - throw new AssertionError(""); + test1(null); + throw new AssertionError("No exception thrown"); } catch (NullPointerException e) { /* expected */ } System.out.println("TEST PASSED"); diff --git a/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java b/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java index 7fdd282033d..f41f883597f 100644 --- a/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java +++ b/test/hotspot/jtreg/compiler/jsr292/ContinuousCallSiteTargetChange.java @@ -25,7 +25,7 @@ * @test * @library /test/lib / * - * @run driver compiler.jsr292.ContinuousCallSiteTargetChange + * @run driver/timeout=300 compiler.jsr292.ContinuousCallSiteTargetChange */ package compiler.jsr292; diff --git a/test/hotspot/jtreg/compiler/linkage/TestLinkageErrorInGenerateOopMap.java b/test/hotspot/jtreg/compiler/linkage/TestLinkageErrorInGenerateOopMap.java index 52b523b612a..0a352517427 100644 --- a/test/hotspot/jtreg/compiler/linkage/TestLinkageErrorInGenerateOopMap.java +++ b/test/hotspot/jtreg/compiler/linkage/TestLinkageErrorInGenerateOopMap.java @@ -44,6 +44,8 @@ public static void main(String args[]) throws Exception { // Spawn new VM instance to execute test String[] flags = {"-noverify", "-XX:-TieredCompilation", "-XX:CompileCommand=dontinline,compiler/linkage/OSRWithBadOperandStack.m*", + "-XX:-CreateCoredumpOnCrash", + "-Xmx64m", "compiler.linkage.TestLinkageErrorInGenerateOopMap", "run"}; ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(flags); OutputAnalyzer out = new OutputAnalyzer(pb.start()); diff --git a/test/hotspot/jtreg/compiler/loopopts/SplitIfSharedFastLockBehindCastPP.java b/test/hotspot/jtreg/compiler/loopopts/SplitIfSharedFastLockBehindCastPP.java new file mode 100644 index 00000000000..628a5a4cb75 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/SplitIfSharedFastLockBehindCastPP.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8231620 + * @summary assert(bol->is_Bool()) crash during split if due to FastLockNode + * + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement SplitIfSharedFastLockBehindCastPP + */ + + +public class SplitIfSharedFastLockBehindCastPP { + private static boolean field; + private static A obj_field; + + public static void main(String[] args) { + A lock = new A(); + obj_field = lock; + for (int i = 0; i < 20_000; i++) { + test1(true, lock); + test1(false, lock); + test2(true); + test2(false); + } + } + + private static void test1(boolean flag, Object obj) { + if (obj == null) { + } + + boolean flag2; + if (flag) { + flag2 = true; + } else { + flag2 = false; + obj = obj_field; + } + + // This loop will be unswitched. The condition becomes candidate for split if + for (int i = 0; i < 100; i++) { + if (flag2) { + field = true; + } else { + field = false; + } + synchronized (obj) { + field = true; + } + } + } + + private static Object test2(boolean flag) { + int integer; + if (flag) { + field = true; + integer = 1; + } else { + field = false; + integer = 2; + } + + Object obj = integer; + + // This loop will be unswitched. The condition becomes candidate for split if + for (int i = 0; i < 100; i++) { + if (integer == 1) { + field = true; + } else { + field = false; + } + synchronized (obj) { + field = true; + } + } + return obj; + } + + private static final class A { + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/StrangeControl.jasm b/test/hotspot/jtreg/compiler/loopopts/StrangeControl.jasm new file mode 100644 index 00000000000..c36217ddb05 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/StrangeControl.jasm @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019, 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. + * + */ + +super public class compiler/loopopts/StrangeControl + version 51:0 +{ + +static Field field:"I"; + +public static Method test:"(I)V" + stack 2 locals 2 +{ + iconst_0; + istore 1; + L1: stack_frame_type append; + locals_map int; + iinc 1, 1; + iload 1; + iconst_2; + if_icmple L1; + L2: stack_frame_type same; + iload_0; + putstatic Field field:"I"; + goto L1; +} + +} // end Class StrangeControl diff --git a/test/hotspot/jtreg/compiler/loopopts/TestCMovWithOpaque.java b/test/hotspot/jtreg/compiler/loopopts/TestCMovWithOpaque.java new file mode 100644 index 00000000000..f463702b0f4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestCMovWithOpaque.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, 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 8231223 + * @summary Test conditional move optimization encountering an Opaque4Node. + * @run main/othervm -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=inline,compiler.loopopts.TestCMovWithOpaque::test + * compiler.loopopts.TestCMovWithOpaque + */ + +package compiler.loopopts; + +public class TestCMovWithOpaque { + + public static void test(int array[]) { + for (int i = 1; i < 8; i += 3) { + for (int j = 0; j < 4; ++j) { + switch (i % 4) { + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + array[j] += 42; + break; + } + } + } + } + + public static void main(String[] args) { + int[] array = new int[4]; + for (int i = 0; i < 20_000; ++i) { + test(array); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestDivZeroCheckControl.java b/test/hotspot/jtreg/compiler/loopopts/TestDivZeroCheckControl.java new file mode 100644 index 00000000000..e54fa346b88 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestDivZeroCheckControl.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019, 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 8229496 + * @summary Verify that zero check is executed before division/modulo operation. + * @run main/othervm -Xbatch -XX:LoopUnrollLimit=0 + * -XX:CompileCommand=dontinline,compiler.loopopts.TestDivZeroCheckControl::test* + * compiler.loopopts.TestDivZeroCheckControl + */ + +package compiler.loopopts; + +public class TestDivZeroCheckControl { + + public static int test1(int div, int array[]) { + int res = 0; + for (int i = 0; i < 256; i++) { + int j = 0; + do { + array[i] = i; + try { + res = 1 % div; + } catch (ArithmeticException ex) { } + } while (++j < 9); + } + return res; + } + + // Same as test1 but with division instead of modulo + public static int test2(int div, int array[]) { + int res = 0; + for (int i = 0; i < 256; i++) { + int j = 0; + do { + array[i] = i; + try { + res = 1 / div; + } catch (ArithmeticException ex) { } + } while (++j < 9); + } + return res; + } + + // Same as test1 but with long + public static long test3(long div, int array[]) { + long res = 0; + for (int i = 0; i < 256; i++) { + int j = 0; + do { + array[i] = i; + try { + res = 1L % div; + } catch (ArithmeticException ex) { } + } while (++j < 9); + } + return res; + } + + // Same as test2 but with long + public static long test4(long div, int array[]) { + long res = 0; + for (int i = 0; i < 256; i++) { + int j = 0; + do { + array[i] = i; + try { + res = 1L / div; + } catch (ArithmeticException ex) { } + } while (++j < 9); + } + return res; + } + + public static void main(String[] args) { + int array[] = new int[256]; + for (int i = 0; i < 50_000; ++i) { + test1(0, array); + test2(0, array); + test3(0, array); + test4(0, array); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestRemoveEmptyLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestRemoveEmptyLoop.java new file mode 100644 index 00000000000..94c79c9c214 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestRemoveEmptyLoop.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019, Huawei Technologies Co. Ltd. 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 8231988 + * @summary Unexpected test result caused by C2 IdealLoopTree::do_remove_empty_loop + * + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation + * compiler.loopopts.TestRemoveEmptyLoop + */ + +package compiler.loopopts; + +public class TestRemoveEmptyLoop { + + public void test() { + int i = 34; + for (; i > 0; i -= 11); + if (i < 0) { + // do nothing + } else { + throw new RuntimeException("Test failed."); + } + } + + public static void main(String[] args) { + TestRemoveEmptyLoop _instance = new TestRemoveEmptyLoop(); + for (int i = 0; i < 50000; i++) { + _instance.test(); + } + System.out.println("Test passed."); + } + +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestStrangeControl.java b/test/hotspot/jtreg/compiler/loopopts/TestStrangeControl.java new file mode 100644 index 00000000000..d93ed991073 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestStrangeControl.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019, 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 8228888 + * @summary Test PhaseIdealLoop::has_local_phi_input() with phi input with non-dominating control. + * @compile StrangeControl.jasm + * @run main/othervm -Xbatch -XX:CompileCommand=inline,compiler.loopopts.StrangeControl::test + * compiler.loopopts.TestStrangeControl + */ + +package compiler.loopopts; + +public class TestStrangeControl { + + public static void main(String[] args) throws Exception { + Thread thread = new Thread() { + public void run() { + // Run this in an own thread because it's basically an endless loop + StrangeControl.test(42); + } + }; + thread.start(); + // Give thread executing strange control loop enough time to trigger OSR compilation + Thread.sleep(4000); + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SuperWordIntermediateUse.java b/test/hotspot/jtreg/compiler/loopopts/superword/SuperWordIntermediateUse.java new file mode 100644 index 00000000000..1d8357fd32e --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SuperWordIntermediateUse.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019, 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 8230062 + * @summary The IR of this test contains a reduction chain which corresponds to a pack in which the 2nd last element has a usage outside of the optimized loop. + * + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.loopopts.superword.SuperWordIntermediateUse::test + * compiler.loopopts.superword.SuperWordIntermediateUse + */ + +package compiler.loopopts.superword; + +public class SuperWordIntermediateUse { + + private int iFld; + private int[] iArr = new int[1024]; + + public void test() { + int local = 4; + + /** + * Before unrolling this loop: + * iFld: AddI 1 = -85 + Phi 1 + * local: MulI 2 = Phi 1 * LoadI 3 + * + * This loop is now unrolled. 'local' is a reduction. The loop is first copied: + * iFldCopy: AddI C1 = -85 + Phi C1 + * localCopy: MulI C2 = Phi C1 * LoadI C3 + * + * iFld: AddI 1 = -85 + Phi 1 + * local: MulI 2 = Phi 1 * LoadI 3 + * + * Then, the unnecessary nodes like phis are removed from the original loop by igvn: + * (iFldCopy: AddI C1 = -85 + Phi C1) field store optimized away + * localCopy: MulI C2 = Phi C1 * LoadI C3 + * + * iFld: AddI 1 = -85 + MulI C2 + * local: MulI 2 = MulI C2 * LoadI 3 -> Input into Phi C1 + * + * As a result AddI 1 has an input from MulI C2 which isn't the last operation in the reduction chain + * Phi C1 -> MulI C2 -> MulI 2 -> Phi C1 and therefore not the last element in a pack. + * Additionally, AddI 1 does not belong to the loop being optimized: The store node for iFld is put outside of the loop being optimized. + * This triggers the assertion bug when unrolled at least 4 times which creates packs of at least size 4. + */ + for (int i = 0; i < 1024; i++) { + iFld = -85; + iFld = iFld + local; + local = local * iArr[i]; + iArr[i] = 3; // Just used to trigger SuperWord optimization + } + } + + public static void main(String[] strArr) { + SuperWordIntermediateUse instance = new SuperWordIntermediateUse(); + for (int i = 0; i < 1000; i++) { + instance.test(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestFuzzPreLoop.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestFuzzPreLoop.java new file mode 100644 index 00000000000..61fd78d3a0a --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestFuzzPreLoop.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8134739 8010500 + * @summary SEGV in SuperWord::get_pre_loop_end + * @run main/othervm compiler.loopopts.superword.TestFuzzPreLoop + */ + +package compiler.loopopts.superword; + +public class TestFuzzPreLoop { + static Object sink; + short sFld = -19206; + + void doTest() { + int[] arr = new int[400]; + + for (int i1 = 0; i1 < 200; i1++) { + for (int i2 = 0; i2 < 100; i2++) { + sink = new int[400]; + } + arr[i1] = 0; + } + + float f1 = 0; + for (int i3 = 0; i3 < 200; i3++) { + f1 += i3 * i3; + } + for (int i4 = 0; i4 < 200; i4++) { + f1 += i4 - sFld; + } + + System.out.println(arr); + System.out.println(f1); + } + + public static void main(String... args) throws Exception { + TestFuzzPreLoop test = new TestFuzzPreLoop(); + for (int i = 0; i < 100; i++) { + test.doTest(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopstripmining/AntiDependentLoadInOuterStripMinedLoop.java b/test/hotspot/jtreg/compiler/loopstripmining/AntiDependentLoadInOuterStripMinedLoop.java new file mode 100644 index 00000000000..16b992ef282 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopstripmining/AntiDependentLoadInOuterStripMinedLoop.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8229483 + * @summary Sinking load out of loop may trigger: assert(found_sfpt) failed: no node in loop that's not input to safepoint + * + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:LoopMaxUnroll=0 AntiDependentLoadInOuterStripMinedLoop + * + */ + +public class AntiDependentLoadInOuterStripMinedLoop { + private static int field; + private static volatile int barrier; + + public static void main(String[] args) { + int[] array = new int[1]; + A a = new A(); + for (int i = 0; i < 20_000; i++) { + test1(array); + test2(a, array); + test2_helper(array, 0, 0); + } + } + + private static int test1(int[] array) { + int res = 1; + + for (int i = 0; i < 10; i++) { + barrier = 1; + // field load doesn't float higher than here + + for (int j = 0; j < 2000; j++) { + array[0] = j; // seen as anti dependence by C2 during loop opts, sunk out of loop + res *= j; + } + } + + return field + res + field * 2; + } + + private static int test2(A a, int[] array) { + int ignore = a.field; + int res = 1; + + int k = 0; + for (k = 0; k < 2; k++) { + } + + for (int i = 0; i < 10; i++) { + barrier = 1; + + for (int j = 0; j < 2000; j++) { + test2_helper(array, k, j); + res *= j; + } + } + + return a.field + res + a.field * 2; + } + + private static void test2_helper(int[] array, int k, int j) { + if (k == 2) { + array[0] = j; + } + } + + private static class A { + public int field; + } +} diff --git a/test/hotspot/jtreg/compiler/loopstripmining/DeadNodesInOuterLoopAtLoopCloning.java b/test/hotspot/jtreg/compiler/loopstripmining/DeadNodesInOuterLoopAtLoopCloning.java new file mode 100644 index 00000000000..3d722fc9ba3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopstripmining/DeadNodesInOuterLoopAtLoopCloning.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8230061 + * @summary loop unrolling breaks when outer strip mined loop contains dead node + * + * @run main/othervm -Xmx1G DeadNodesInOuterLoopAtLoopCloning + * + */ + +public class DeadNodesInOuterLoopAtLoopCloning { + + public static final int N = 400; + + public static long instanceCount=-2288355609708559532L; + + public static double checkSum(double[] a) { + double sum = 0; + for (int j = 0; j < a.length; j++) { + sum += (a[j] / (j + 1) + a[j] % (j + 1)); + } + return sum; + } + + public static int iMeth(double d1) { + + int i4=6022, i5=-211, i6=-15841, iArr[]=new int[N]; + double d2=-8.78129, dArr[]=new double[N]; + + i5 = 1; + do { + i6 = 1; + while (++i6 < 5) { + i4 = -933; + i4 *= i4; + dArr[i5 + 1] = i4; + i4 -= i4; + d2 = 1; + do { + iArr[(int)(d2 + 1)] += (int)instanceCount; + try { + i4 = (i4 % -51430); + i4 = (iArr[i6] % 31311); + iArr[i6 + 1] = (24197 / i5); + } catch (ArithmeticException a_e) {} + i4 -= (int)instanceCount; + i4 <<= i5; + i4 &= 12; + } while (++d2 < 1); + } + } while (++i5 < 320); + long meth_res = Double.doubleToLongBits(checkSum(dArr)); + return (int)meth_res; + } + + public static void main(String[] strArr) { + DeadNodesInOuterLoopAtLoopCloning _instance = new DeadNodesInOuterLoopAtLoopCloning(); + for (int i = 0; i < 10 * 320; i++ ) { + _instance.iMeth(0.8522); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopstripmining/LoadDependsOnIfIdenticalToLoopExit.java b/test/hotspot/jtreg/compiler/loopstripmining/LoadDependsOnIfIdenticalToLoopExit.java new file mode 100644 index 00000000000..44c38ec5bc1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopstripmining/LoadDependsOnIfIdenticalToLoopExit.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8229450 + * @summary shared an identical bool node with a strip-mined loop + * + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:LoopMaxUnroll=0 -XX:CompileCommand=dontinline,LoadDependsOnIfIdenticalToLoopExit::not_inlined -XX:CompileCommand=compileonly,LoadDependsOnIfIdenticalToLoopExit::test1 LoadDependsOnIfIdenticalToLoopExit + * + */ + +public class LoadDependsOnIfIdenticalToLoopExit { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test1(false, false); + test1(true, true); + } + } + + private static int test1(boolean flag1, boolean flag2) { + int res = 1; + int[] array = new int[10]; + not_inlined(array); + int i; + for (i = 0; i < 2000; i++) { + res *= i; + } + + if (flag1) { + if (flag2) { + res++; + } + } + + if (i >= 2000) { + res *= array[0]; + } + return res; + } + + private static void not_inlined(int[] array) { + } +} diff --git a/test/hotspot/jtreg/compiler/print/PrintCompileQueue.java b/test/hotspot/jtreg/compiler/print/PrintCompileQueue.java new file mode 100644 index 00000000000..ee368b54bea --- /dev/null +++ b/test/hotspot/jtreg/compiler/print/PrintCompileQueue.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019, Loongson Technology Co. Ltd. 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 8230943 + * @summary possible deadlock was detected when ran with -XX:+CIPrintCompileQueue + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+CIPrintCompileQueue + * compiler.print.PrintCompileQueue + * + */ + +package compiler.print; + +public class PrintCompileQueue { + public static void main(String[] args) { + System.out.println("Passed"); + } +} diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java b/test/hotspot/jtreg/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java index 5a05b5a6b0c..7800fd2ca22 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnSupportedConfig.java @@ -24,12 +24,12 @@ /** * @test * @bug 8031320 - * @summary Verify PrintPreciseRTMLockingStatistics on CPUs with + * @summary Verify PrintPreciseRTMLockingStatistics on CPUs and OSs with * rtm support and on VM with rtm locking support, * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java b/test/hotspot/jtreg/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java index 76e380c3934..de289f2f108 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig.java @@ -24,12 +24,12 @@ /** * @test * @bug 8031320 - * @summary Verify PrintPreciseRTMLockingStatistics on CPUs without + * @summary Verify PrintPreciseRTMLockingStatistics on CPUs or OSs without * rtm support and/or unsupported VM. * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires !(vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os) + * @requires !vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @build compiler.rtm.cli.TestPrintPreciseRTMLockingStatisticsOptionOnUnsupportedConfig * @run driver ClassFileInstaller sun.hotspot.WhiteBox diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMAbortThresholdOption.java b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMAbortThresholdOption.java index c314e68dcd7..e6e4893065a 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMAbortThresholdOption.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMAbortThresholdOption.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * + * @requires vm.rtm.compiler * @run main/othervm compiler.rtm.cli.TestRTMAbortThresholdOption */ diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMLockingCalculationDelayOption.java b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMLockingCalculationDelayOption.java index d8823501397..119be8b985a 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMLockingCalculationDelayOption.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMLockingCalculationDelayOption.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * + * @requires vm.rtm.compiler * @run main/othervm compiler.rtm.cli.TestRTMLockingCalculationDelayOption */ diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMLockingThresholdOption.java b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMLockingThresholdOption.java index 532e61e69b5..a00c408565b 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMLockingThresholdOption.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMLockingThresholdOption.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * + * @requires vm.rtm.compiler * @run main/othervm compiler.rtm.cli.TestRTMLockingThresholdOption */ diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMRetryCountOption.java b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMRetryCountOption.java index 8a472ec1bcb..d87f6399f0c 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMRetryCountOption.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMRetryCountOption.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * + * @requires vm.rtm.compiler * @run main/othervm compiler.rtm.cli.TestRTMRetryCountOption */ diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMSpinLoopCountOption.java b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMSpinLoopCountOption.java index 15868ff12ed..ddfa4573088 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMSpinLoopCountOption.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMSpinLoopCountOption.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * + * @requires vm.rtm.compiler * @run main/othervm compiler.rtm.cli.TestRTMSpinLoopCountOption */ diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java index 4ceae005539..3d7023f2680 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestRTMTotalCountIncrRateOptionOnSupportedConfig.java @@ -24,12 +24,12 @@ /** * @test * @bug 8031320 - * @summary Verify RTMTotalCountIncrRate option processing on CPU with + * @summary Verify RTMTotalCountIncrRate option processing on CPU and OS with * rtm support and on VM with rtm locking support. * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java index 3f66ab39568..44467ceac56 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMDeoptOptionOnSupportedConfig.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java index da1a207d16c..37035712e4e 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMDeoptOptionOnUnsupportedConfig.java @@ -24,12 +24,12 @@ /** * @test * @bug 8031320 - * @summary Verify UseRTMDeopt option processing on CPUs without rtm support + * @summary Verify UseRTMDeopt option processing on CPUs or OSs without rtm support * or on VMs without rtm locking support. * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires !(vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os) + * @requires !vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java index f52d8561db5..2d232cb11ed 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnSupportedConfig.java @@ -24,12 +24,12 @@ /** * @test * @bug 8031320 - * @summary Verify UseRTMForStackLocks option processing on CPU with + * @summary Verify UseRTMForStackLocks option processing on CPU and OS with * rtm support when VM supports rtm locking. * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java index 49bfdb0ba7f..16c29d78e1d 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMForStackLocksOptionOnUnsupportedConfig.java @@ -24,12 +24,12 @@ /** * @test * @bug 8031320 - * @summary Verify UseRTMForStackLocks option processing on CPUs without + * @summary Verify UseRTMForStackLocks option processing on CPUs or OSs without * rtm support and/or on VMs without rtm locking support. * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires !(vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os) + * @requires !vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java index 7ed1c3de26a..54fd18d938d 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionOnSupportedConfig.java @@ -24,12 +24,12 @@ /** * @test * @bug 8031320 - * @summary Verify UseRTMLocking option processing on CPU with rtm support and - * on VM with rtm-locking support. + * @summary Verify UseRTMLocking option processing on CPU and OS with rtm support and + * on VM with rtm locking support. * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java index f45c8cda89e..d6c45b6c42e 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionOnUnsupportedCPU.java @@ -24,12 +24,12 @@ /** * @test * @bug 8031320 - * @summary Verify UseRTMLocking option processing on CPU without + * @summary Verify UseRTMLocking option processing on CPUs without * rtm support. * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires (!vm.rtm.cpu) & (vm.flavor == "server" & !vm.emulatedClient) + * @requires !vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java index f133ccc405b..8fe96a19825 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMLockingOptionWithBiasedLocking.java @@ -25,11 +25,11 @@ * @test * @bug 8031320 * @summary Verify processing of UseRTMLocking and UseBiasedLocking - * options combination on CPU and VM with rtm support. + * options combination on CPU, OS, and VM with rtm support. * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMXendForLockBusyOption.java b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMXendForLockBusyOption.java index bf94689be6c..49a5ca169db 100644 --- a/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMXendForLockBusyOption.java +++ b/test/hotspot/jtreg/compiler/rtm/cli/TestUseRTMXendForLockBusyOption.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * + * @requires vm.rtm.compiler * @run main/othervm compiler.rtm.cli.TestUseRTMXendForLockBusyOption */ diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAbortRatio.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAbortRatio.java index 3613d5c4cf8..5ce08feb258 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAbortRatio.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAbortRatio.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAbortThreshold.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAbortThreshold.java index 98bc11256b5..b42abe13f20 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAbortThreshold.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAbortThreshold.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java index ba0a1ef6d44..8677e1b9277 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java @@ -31,7 +31,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java index 677456fae08..494381e1046 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMDeoptOnHighAbortRatio.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java index 402ead2a640..48ebead642e 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMLockingCalculationDelay.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMLockingCalculationDelay.java index 25cf21ff64d..8c81a4e0451 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMLockingCalculationDelay.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMLockingCalculationDelay.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMLockingThreshold.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMLockingThreshold.java index 65fc9eecea9..7bdb62eab9b 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMLockingThreshold.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMLockingThreshold.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMRetryCount.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMRetryCount.java index ae492d76c76..a1a80e13e3d 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMRetryCount.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMRetryCount.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMSpinLoopCount.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMSpinLoopCount.java index 3f641e0f7e9..13119a24c78 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMSpinLoopCount.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMSpinLoopCount.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMTotalCountIncrRate.java b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMTotalCountIncrRate.java index 2712bc4dd1e..fdb2933b749 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestRTMTotalCountIncrRate.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestRTMTotalCountIncrRate.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMAfterLockInflation.java b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMAfterLockInflation.java index 0d92cfee490..2cdc91c1f99 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMAfterLockInflation.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMAfterLockInflation.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMDeopt.java b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMDeopt.java index 294def6b37a..0a4cd460a8a 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMDeopt.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMDeopt.java @@ -25,11 +25,11 @@ * @test * @bug 8031320 * @summary Verify that UseRTMDeopt affects uncommon trap installation in - * copmpiled methods with synchronized block. + * compiled methods with synchronized block. * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMForInflatedLocks.java b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMForInflatedLocks.java index d76c8cf820f..0acb6e9dcc7 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMForInflatedLocks.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMForInflatedLocks.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMForStackLocks.java b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMForStackLocks.java index 77c55d04b2c..be8c391f207 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMForStackLocks.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMForStackLocks.java @@ -28,7 +28,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMXendForLockBusy.java b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMXendForLockBusy.java index 0f2a1da6dc3..74265f96ebb 100644 --- a/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMXendForLockBusy.java +++ b/test/hotspot/jtreg/compiler/rtm/locking/TestUseRTMXendForLockBusy.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/method_options/TestNoRTMLockElidingOption.java b/test/hotspot/jtreg/compiler/rtm/method_options/TestNoRTMLockElidingOption.java index 2a3cdf97961..e6243fcedff 100644 --- a/test/hotspot/jtreg/compiler/rtm/method_options/TestNoRTMLockElidingOption.java +++ b/test/hotspot/jtreg/compiler/rtm/method_options/TestNoRTMLockElidingOption.java @@ -29,7 +29,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/method_options/TestUseRTMLockElidingOption.java b/test/hotspot/jtreg/compiler/rtm/method_options/TestUseRTMLockElidingOption.java index 71aae8d167c..2537b2082f5 100644 --- a/test/hotspot/jtreg/compiler/rtm/method_options/TestUseRTMLockElidingOption.java +++ b/test/hotspot/jtreg/compiler/rtm/method_options/TestUseRTMLockElidingOption.java @@ -30,7 +30,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java b/test/hotspot/jtreg/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java index 8c6a11b76f8..16663ac5116 100644 --- a/test/hotspot/jtreg/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java +++ b/test/hotspot/jtreg/compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java @@ -31,7 +31,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management - * @requires vm.flavor == "server" & !vm.emulatedClient & vm.rtm.cpu & vm.rtm.os + * @requires vm.rtm.cpu & vm.rtm.compiler * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/test/hotspot/jtreg/containers/docker/JfrNetwork.java b/test/hotspot/jtreg/containers/docker/JfrNetwork.java new file mode 100644 index 00000000000..c1cbbb208f3 --- /dev/null +++ b/test/hotspot/jtreg/containers/docker/JfrNetwork.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.file.Paths; +import java.util.List; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.process.OutputAnalyzer; + + +// This class is intended to run inside a container +public class JfrNetwork { + // use a unique hostname for container + public static final String HOST_NAME = "container-unique-8221711"; + public static final String JFR_REPORTED_CONTAINER_HOSTNAME_TAG = "jfr_reported_container_hostname="; + + public static void main(String[] args) throws Exception { + String event = args[0]; + try (ServerSocket ss = new ServerSocket()) { + testNetworkInfo(ss, event); + } + } + + private static void assertTrue(boolean expr, String msg) { + if (!expr) { + throw new RuntimeException(msg); + } + } + + private static void testNetworkInfo(ServerSocket ss, String event) throws Exception { + ServerSocketListener server = new ServerSocketListener(ss); + server.start(); + SocketWriter writer = new SocketWriter(ss.getLocalSocketAddress()); + + // setup and start the recording + String recordingPath = event + ".jfr"; + log("========= Recording event: " + event); + Recording r = new Recording(); + r.enable(event); + r.setDestination(Paths.get("/", "tmp", recordingPath)); + r.start(); + + // start the socker writer thread, write some data into the socket + writer.start(); + + // wait for writer thread to terminate, then for server thread, then stop recording + writer.joinAndThrow(); + server.joinAndThrow(); + r.stop(); + + // analyze the recording + List events = RecordingFile.readAllEvents(r.getDestination()); + events.forEach(e -> log ("event = " + e)); + assertTrue(!events.isEmpty(), "No recorded network events"); + RecordedEvent e = events.get(0); + log(JFR_REPORTED_CONTAINER_HOSTNAME_TAG + e.getString("host")); + verifyIpAddress(e.getString("address")); + } + + private static void verifyIpAddress(String eventIp) throws Exception { + ProcessBuilder pb = new ProcessBuilder("hostname", "--ip-address"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); + log("hostname --ip-address returned: " + out.getOutput()); + out.shouldContain(eventIp); + } + + private static void log(String msg) { + System.out.println(msg); + } + + + private static class ServerSocketListener extends Thread { + Exception exception; + ServerSocket ss; + + ServerSocketListener(ServerSocket socket) throws Exception { + ss = socket; + ss.setReuseAddress(true); + ss.bind(null); + log("ServerSocker Local Address: " + ss.getLocalSocketAddress()); + } + + public void joinAndThrow() throws Exception { + join(); + if (exception != null) { + throw exception; + } + } + + public void run() { + try { + try (Socket s = ss.accept(); InputStream is = s.getInputStream()) { + System.out.println("ServerSocketListener: accepted socket connection: s = " + s); + is.read(); + is.read(); + is.read(); + } + } catch (Exception e) { + exception = e; + } + } + } + + + private static class SocketWriter extends Thread { + Exception exception; + private SocketAddress ssAddr; + + public SocketWriter(SocketAddress sa) { + this.ssAddr = sa; + System.out.println("SocketWriter(): sa = " + sa); + } + + public void joinAndThrow() throws Exception { + join(); + if (exception != null) { + throw exception; + } + } + + public void run() { + try (Socket s = new Socket()) { + s.connect(ssAddr); + try (OutputStream os = s.getOutputStream()) { + os.write('A'); + os.write('B'); + os.write('C'); + } + } catch (Exception e) { + exception = e; + } + } + } + +} diff --git a/test/hotspot/jtreg/containers/docker/JfrReporter.java b/test/hotspot/jtreg/containers/docker/JfrReporter.java index 983fb50ba0a..0c3537f1073 100644 --- a/test/hotspot/jtreg/containers/docker/JfrReporter.java +++ b/test/hotspot/jtreg/containers/docker/JfrReporter.java @@ -22,53 +22,30 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - +import java.nio.file.Path; import java.nio.file.Paths; import jdk.jfr.Recording; +import jdk.jfr.ValueDescriptor; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordingFile; - // This class is intended to run inside a container public class JfrReporter { - public static final String TEST_REPORTED_CORES="TEST_REPORTED_CORES"; - public static final String TEST_REPORTED_MEMORY="TEST_REPORTED_MEMORY"; - public static final String TEST_REPORTED_PID="TEST_REPORTED_PID"; - public static final String TESTCASE_CPU="cpu"; - public static final String TESTCASE_MEMORY="memory"; - public static final String TESTCASE_PROCESS="process"; - public static void main(String[] args) throws Exception { - String testCase = args[0]; - System.out.println("Testcase: " + testCase); - switch (testCase) { - case TESTCASE_CPU: - RecordedEvent event = testEvent("jdk.CPUInformation", "cpu.jfr"); - System.out.println(TEST_REPORTED_CORES + "=" + event.getInt("cores")); - break; - case TESTCASE_MEMORY: - event = testEvent("jdk.PhysicalMemory", "memory.jfr"); - System.out.println(TEST_REPORTED_MEMORY + "=" + event.getLong("totalSize")); - break; - case TESTCASE_PROCESS: - event = testEvent("jdk.SystemProcess", "process.jfr"); - System.out.println(TEST_REPORTED_PID + "=" + event.getString("pid")); - break; - default: - throw new IllegalArgumentException("Invalid test case"); + String eventName = args[0]; + try(Recording r = new Recording()) { + r.enable(eventName); + r.start(); + r.stop(); + Path p = Paths.get("/", "tmp", eventName + ".jfr"); + r.dump(p); + for (RecordedEvent e : RecordingFile.readAllEvents(p)) { + System.out.println("===== EventType: " + e.getEventType().getName()); + for (ValueDescriptor v : e.getEventType().getFields()) { + System.out.println(v.getName() + " = " + e.getValue(v.getName())); + } + } } } - - private static RecordedEvent testEvent(String event, String recordingPath) throws Exception { - System.out.println("========= Testing event: " + event); - Recording r = new Recording(); - r.enable(event); - r.setDestination(Paths.get("tmp", recordingPath)); - r.start(); - r.stop(); - - RecordedEvent recordedEvent = RecordingFile.readAllEvents(r.getDestination()).get(0); - System.out.println("RecordedEvent: " + recordedEvent); - return recordedEvent; - } } + \ No newline at end of file diff --git a/test/hotspot/jtreg/containers/docker/TestJFREvents.java b/test/hotspot/jtreg/containers/docker/TestJFREvents.java index 73e6ac178fa..0b30e66b20f 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFREvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFREvents.java @@ -36,14 +36,19 @@ * @build JfrReporter * @run driver TestJFREvents */ +import java.util.List; import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.Utils; public class TestJFREvents { private static final String imageName = Common.imageName("jfr-events"); + private static final String TEST_ENV_VARIABLE = "UNIQUE_VARIABLE_ABC592903XYZ"; + private static final String TEST_ENV_VALUE = "unique_value_abc592903xyz"; private static final int availableCPUs = Runtime.getRuntime().availableProcessors(); public static void main(String[] args) throws Exception { @@ -68,6 +73,7 @@ public static void main(String[] args) throws Exception { testProcessInfo(); + testEnvironmentVariables(); } finally { DockerTestUtils.removeDockerImage(imageName); } @@ -79,14 +85,12 @@ private static void testCPUInfo(int valueToSet, int expectedValue) throws Except DockerTestUtils.dockerRunJava( commonDockerOpts() .addDockerOpts("--cpus=" + valueToSet) - .addClassOptions(JfrReporter.TESTCASE_CPU)) - .shouldHaveExitValue(0) - .shouldContain(JfrReporter.TEST_REPORTED_CORES); - + .addClassOptions("jdk.CPUInformation")) + .shouldHaveExitValue(0); // The following assertion is currently disabled due to JFR reporting incorrect values. // JFR reports values for the host system as opposed to values for the container. // @ignore 8219999 - // .shouldContain(JfrReporter.TEST_REPORTED_CORES + "=" + expectedValue); + // .shouldContain("cores = " + expectedValue"); } @@ -95,9 +99,9 @@ private static void testMemory(String valueToSet, String expectedValue) throws E DockerTestUtils.dockerRunJava( commonDockerOpts() .addDockerOpts("--memory=" + valueToSet) - .addClassOptions(JfrReporter.TESTCASE_MEMORY)) + .addClassOptions("jdk.PhysicalMemory")) .shouldHaveExitValue(0) - .shouldContain(JfrReporter.TEST_REPORTED_MEMORY + "=" + expectedValue); + .shouldContain("totalSize = " + expectedValue); } @@ -105,10 +109,9 @@ private static void testProcessInfo() throws Exception { Common.logNewTestCase("ProcessInfo"); DockerTestUtils.dockerRunJava( commonDockerOpts() - .addClassOptions(JfrReporter.TESTCASE_PROCESS)) + .addClassOptions("jdk.SystemProcess")) .shouldHaveExitValue(0) - .shouldContain(JfrReporter.TEST_REPORTED_PID + "=1"); - + .shouldContain("pid = 1"); } @@ -117,4 +120,31 @@ private static DockerRunOptions commonDockerOpts() { .addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/") .addJavaOpts("-cp", "/test-classes/"); } + + + private static void testEnvironmentVariables() throws Exception { + Common.logNewTestCase("EnvironmentVariables"); + + List cmd = DockerTestUtils.buildJavaCommand( + commonDockerOpts() + .addClassOptions("jdk.InitialEnvironmentVariable")); + + ProcessBuilder pb = new ProcessBuilder(cmd); + // Container has JAVA_HOME defined via the Dockerfile; make sure + // it is reported by JFR event. + // Environment variable set in host system should not be visible inside a container, + // and should not be reported by JFR. + pb.environment().put(TEST_ENV_VARIABLE, TEST_ENV_VALUE); + + System.out.println("[COMMAND]\n" + Utils.getCommandLine(pb)); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + System.out.println("[STDERR]\n" + out.getStderr()); + System.out.println("[STDOUT]\n" + out.getStdout()); + + out.shouldHaveExitValue(0) + .shouldContain("key = JAVA_HOME") + .shouldContain("value = /jdk") + .shouldNotContain(TEST_ENV_VARIABLE) + .shouldNotContain(TEST_ENV_VALUE); + } } diff --git a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java new file mode 100644 index 00000000000..2f9f6305a00 --- /dev/null +++ b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * @summary Test JFR network related events inside a container; make sure + * the reported host ip and host name are correctly reported within + * the container. + * @requires docker.support + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * jdk.jartool/sun.tools.jar + * @build JfrNetwork + * @run driver TestJFRNetworkEvents + */ +import jdk.test.lib.containers.docker.Common; +import jdk.test.lib.containers.docker.DockerRunOptions; +import jdk.test.lib.containers.docker.DockerTestUtils; +import jdk.test.lib.Utils; + + +public class TestJFRNetworkEvents { + private static final String imageName = Common.imageName("jfr-network"); + private static final int availableCPUs = Runtime.getRuntime().availableProcessors(); + + public static void main(String[] args) throws Exception { + System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); + if (!DockerTestUtils.canTestDocker()) { + return; + } + + DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-BasicTest", "jdk-docker"); + + try { + runTest("jdk.SocketWrite"); + } finally { + DockerTestUtils.removeDockerImage(imageName); + } + } + + private static void runTest(String event) throws Exception { + DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "JfrNetwork") + .addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/") + .addJavaOpts("-cp", "/test-classes/") + .addDockerOpts("--hostname", JfrNetwork.HOST_NAME) + .addClassOptions(event); + DockerTestUtils.dockerRunJava(opts) + .shouldHaveExitValue(0) + .shouldContain(JfrNetwork.JFR_REPORTED_CONTAINER_HOSTNAME_TAG + JfrNetwork.HOST_NAME); + } +} diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 45c83de781b..f89fa81ffd6 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; - +import jdk.test.lib.process.OutputAnalyzer; public class TestMemoryAwareness { private static final String imageName = Common.imageName("memory"); @@ -98,15 +98,26 @@ private static void testMemorySoftLimit(String valueToSet, String expectedTraceV private static void testOOM(String dockerMemLimit, int sizeToAllocInMb) throws Exception { Common.logNewTestCase("OOM"); + // add "--memory-swappiness 0" so as to disable anonymous page swapping. DockerRunOptions opts = Common.newOpts(imageName, "AttemptOOM") - .addDockerOpts("--memory", dockerMemLimit, "--memory-swap", dockerMemLimit); + .addDockerOpts("--memory", dockerMemLimit, "--memory-swappiness", "0", "--memory-swap", dockerMemLimit); opts.classParams.add("" + sizeToAllocInMb); - DockerTestUtils.dockerRunJava(opts) - .shouldHaveExitValue(1) - .shouldContain("Entering AttemptOOM main") - .shouldNotContain("AttemptOOM allocation successful") - .shouldContain("java.lang.OutOfMemoryError"); + // make sure we avoid inherited Xmx settings from the jtreg vmoptions + // set Xmx ourselves instead + System.out.println("sizeToAllocInMb is:" + sizeToAllocInMb + " sizeToAllocInMb/2 is:" + sizeToAllocInMb/2); + String javaHeapSize = sizeToAllocInMb/2 + "m"; + opts.addJavaOptsAppended("-Xmx" + javaHeapSize); + + OutputAnalyzer out = DockerTestUtils.dockerRunJava(opts); + + if (out.getExitValue() == 0) { + throw new RuntimeException("We exited successfully, but we wanted to provoke an OOM inside the container"); + } + + out.shouldContain("Entering AttemptOOM main") + .shouldNotContain("AttemptOOM allocation successful") + .shouldContain("java.lang.OutOfMemoryError"); } } diff --git a/test/hotspot/jtreg/gc/epsilon/TestAlwaysPretouch.java b/test/hotspot/jtreg/gc/epsilon/TestAlwaysPretouch.java index b15ef7c7993..094125c259d 100644 --- a/test/hotspot/jtreg/gc/epsilon/TestAlwaysPretouch.java +++ b/test/hotspot/jtreg/gc/epsilon/TestAlwaysPretouch.java @@ -26,7 +26,12 @@ * @key gc * @requires vm.gc.Epsilon & !vm.graal.enabled * @summary Basic sanity test for Epsilon - * @run main/othervm -Xmx1g -XX:+AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC TestAlwaysPretouch + * @run main/othervm -Xms128m -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC TestAlwaysPretouch + * @run main/othervm -Xms128m -Xmx1g -XX:-AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC TestAlwaysPretouch + * @run main/othervm -Xms128m -Xmx1g -XX:+AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC TestAlwaysPretouch + * @run main/othervm -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC TestAlwaysPretouch + * @run main/othervm -Xmx1g -XX:-AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC TestAlwaysPretouch + * @run main/othervm -Xmx1g -XX:+AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC TestAlwaysPretouch */ public class TestAlwaysPretouch { diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java b/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java new file mode 100644 index 00000000000..08d6c5a86c7 --- /dev/null +++ b/test/hotspot/jtreg/gc/stress/gclocker/TestExcessGCLockerCollections.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package gc.stress.gclocker; + +/* + * @test TestExcessGCLockerCollections + * @key gc + * @bug 8048556 + * @summary Check for GC Locker initiated GCs that immediately follow another + * GC and so have very little needing to be collected. + * @requires vm.gc != "Z" + * @requires vm.gc != "Epsilon" + * @requires vm.gc != "Shenandoah" + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver/timeout=1000 gc.stress.gclocker.TestExcessGCLockerCollections 300 4 2 + */ + +import java.util.HashMap; +import java.util.Map; + +import java.util.zip.Deflater; + +import java.util.ArrayList; +import java.util.Arrays; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +class TestExcessGCLockerCollectionsAux { + static private final int LARGE_MAP_SIZE = 64 * 1024; + + static private final int MAP_ARRAY_LENGTH = 4; + static private final int MAP_SIZE = 1024; + + static private final int BYTE_ARRAY_LENGTH = 128 * 1024; + + static private void println(String str) { System.out.println(str); } + + static private volatile boolean keepRunning = true; + + static Map populateMap(int size) { + Map map = new HashMap(); + for (int i = 0; i < size; i += 1) { + Integer keyInt = Integer.valueOf(i); + String valStr = "value is [" + i + "]"; + map.put(keyInt,valStr); + } + return map; + } + + static private class AllocatingWorker implements Runnable { + private final Object[] array = new Object[MAP_ARRAY_LENGTH]; + private int arrayIndex = 0; + + private void doStep() { + Map map = populateMap(MAP_SIZE); + array[arrayIndex] = map; + arrayIndex = (arrayIndex + 1) % MAP_ARRAY_LENGTH; + } + + public void run() { + while (keepRunning) { + doStep(); + } + } + } + + static private class JNICriticalWorker implements Runnable { + private int count; + + private void doStep() { + byte[] inputArray = new byte[BYTE_ARRAY_LENGTH]; + for (int i = 0; i < inputArray.length; i += 1) { + inputArray[i] = (byte) (count + i); + } + + Deflater deflater = new Deflater(); + deflater.setInput(inputArray); + deflater.finish(); + + byte[] outputArray = new byte[2 * inputArray.length]; + deflater.deflate(outputArray); + + count += 1; + } + + public void run() { + while (keepRunning) { + doStep(); + } + } + } + + static public Map largeMap; + + static public void main(String args[]) { + long durationSec = Long.parseLong(args[0]); + int allocThreadNum = Integer.parseInt(args[1]); + int jniCriticalThreadNum = Integer.parseInt(args[2]); + + println("Running for " + durationSec + " secs"); + + largeMap = populateMap(LARGE_MAP_SIZE); + + println("Starting " + allocThreadNum + " allocating threads"); + for (int i = 0; i < allocThreadNum; i += 1) { + new Thread(new AllocatingWorker()).start(); + } + + println("Starting " + jniCriticalThreadNum + " jni critical threads"); + for (int i = 0; i < jniCriticalThreadNum; i += 1) { + new Thread(new JNICriticalWorker()).start(); + } + + long durationMS = (long) (1000 * durationSec); + long start = System.currentTimeMillis(); + long now = start; + long soFar = now - start; + while (soFar < durationMS) { + try { + Thread.sleep(durationMS - soFar); + } catch (Exception e) { + } + now = System.currentTimeMillis(); + soFar = now - start; + } + println("Done."); + keepRunning = false; + } +} + +public class TestExcessGCLockerCollections { + private static final String locker = + "\\[gc\\s*\\] .* \\(GCLocker Initiated GC\\)"; + private static final String ANY_LOCKER = locker + " [1-9][0-9]*M"; + private static final String BAD_LOCKER = locker + " [1-9][0-9]?M"; + + private static final String[] COMMON_OPTIONS = new String[] { + "-Xmx1G", "-Xms1G", "-Xmn256M", "-Xlog:gc" }; + + public static void main(String args[]) throws Exception { + if (args.length < 3) { + System.out.println("usage: TestExcessGCLockerCollectionsAux" + + " " + + " "); + throw new RuntimeException("Invalid arguments"); + } + + ArrayList finalArgs = new ArrayList(); + finalArgs.addAll(Arrays.asList(COMMON_OPTIONS)); + finalArgs.add(TestExcessGCLockerCollectionsAux.class.getName()); + finalArgs.addAll(Arrays.asList(args)); + + // GC and other options obtained from test framework. + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + true, finalArgs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + //System.out.println("------------- begin stdout ----------------"); + //System.out.println(output.getStdout()); + //System.out.println("------------- end stdout ----------------"); + output.stdoutShouldMatch(ANY_LOCKER); + output.stdoutShouldNotMatch(BAD_LOCKER); + } +} diff --git a/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java b/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java index 972d2ea014e..ef1d29eeba6 100644 --- a/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java +++ b/test/hotspot/jtreg/runtime/ClassUnload/UnloadTest.java @@ -23,6 +23,7 @@ /* * @test UnloadTest + * @bug 8210559 * @requires vm.opt.final.ClassUnloading * @modules java.base/jdk.internal.misc * @library /runtime/testlibrary /test/lib @@ -30,7 +31,7 @@ * @build sun.hotspot.WhiteBox test.Empty * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI UnloadTest + * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xlog:class+unload=debug UnloadTest */ import sun.hotspot.WhiteBox; @@ -60,8 +61,16 @@ private static void run() throws Exception { ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here"); + String loaderName = cl.getName(); + int loadedRefcount = wb.getSymbolRefcount(loaderName); + System.out.println("Refcount of symbol " + loaderName + " is " + loadedRefcount); + cl = null; c = null; o = null; ClassUnloadCommon.triggerUnloading(); ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded"); + + int unloadedRefcount = wb.getSymbolRefcount(loaderName); + System.out.println("Refcount of symbol " + loaderName + " is " + unloadedRefcount); + ClassUnloadCommon.failIf(unloadedRefcount != (loadedRefcount - 1), "Refcount must be decremented"); } } diff --git a/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java b/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java index 870e8ea94bf..cb45f00d666 100644 --- a/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java +++ b/test/hotspot/jtreg/runtime/CreateMirror/ArraysNewInstanceBug.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, 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,6 +31,7 @@ // This test crashes in compiled code with race, because the compiler generates code that assumes this ordering. import java.lang.reflect.Array; +import java.io.File; import java.net.URL; import java.net.URLClassLoader; @@ -55,13 +56,13 @@ public void run() { public static void main(String[] args) throws Throwable { Class c = ArraysNewInstanceBug.class; - ClassLoader apploader = c.getClassLoader(); + ClassLoader apploader = c.getClassLoader(); + File testClasses = new File(System.getProperty("test.classes")); for (int iter = 0; iter < 10 ; iter++) { // 10 is enough to get it to crash on my machine. System.err.print('['); classes = new Class[1000]; - String urlpath = "file://" + System.getProperty("test.classes") + "/"; for (int i = 0; i < classes.length; i++) { - ClassLoader loader = new URLClassLoader(new URL[] { new URL(urlpath) }, apploader.getParent()); + ClassLoader loader = new URLClassLoader(new URL[] { testClasses.toURI().toURL() }, apploader.getParent()); classes[i] = loader.loadClass(c.getSimpleName()); } System.err.print(']'); diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/VeryEarlyAssertTest.java b/test/hotspot/jtreg/runtime/ErrorHandling/VeryEarlyAssertTest.java new file mode 100644 index 00000000000..69c343b8328 --- /dev/null +++ b/test/hotspot/jtreg/runtime/ErrorHandling/VeryEarlyAssertTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, SAP. 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 8214975 + * @summary No hs-err file if fatal error is raised during dynamic initialization. + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @requires (vm.debug == true) + * @requires os.family == "linux" + */ + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.util.regex.Pattern; +import java.util.Map; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class VeryEarlyAssertTest { + + public static void main(String[] args) throws Exception { + + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xmx64M", + "-XX:-CreateCoredumpOnCrash", + "-version"); + Map env = pb.environment(); + env.put("HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION", "1"); + + OutputAnalyzer output_detail = new OutputAnalyzer(pb.start()); + + // we should have crashed with an assert with a specific message: + output_detail.shouldMatch("# A fatal error has been detected by the Java Runtime Environment:.*"); + output_detail.shouldMatch("#.*HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION.*"); + + // extract hs-err file + String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); + if (hs_err_file == null) { + throw new RuntimeException("Did not find hs-err file in output.\n"); + } + + // scan hs-err file: File should contain the same assertion message. Other than that, + // do not expect too much: file will be littered with secondary errors. The test + // should test that we get a hs-err file at all. + File f = new File(hs_err_file); + if (!f.exists()) { + throw new RuntimeException("hs-err file missing at " + + f.getAbsolutePath() + ".\n"); + } + + System.out.println("Found hs_err file. Scanning..."); + + FileInputStream fis = new FileInputStream(f); + BufferedReader br = new BufferedReader(new InputStreamReader(fis)); + String line = null; + + Pattern[] pattern = new Pattern[]{ + Pattern.compile(".*HOTSPOT_FATAL_ERROR_DURING_DYNAMIC_INITIALIZATION.*") + }; + int currentPattern = 0; + + String lastLine = null; + while ((line = br.readLine()) != null) { + if (currentPattern < pattern.length) { + if (pattern[currentPattern].matcher(line).matches()) { + System.out.println("Found: " + line + "."); + currentPattern++; + } + } + lastLine = line; + } + br.close(); + + if (currentPattern < pattern.length) { + throw new RuntimeException("hs-err file incomplete (first missing pattern: " + currentPattern + ")"); + } + + if (!lastLine.equals("END.")) { + throw new RuntimeException("hs-err file incomplete (missing END marker.)"); + } else { + System.out.println("End marker found."); + } + + System.out.println("OK."); + + } + +} + + diff --git a/test/hotspot/jtreg/runtime/LoadClass/LongBCP.java b/test/hotspot/jtreg/runtime/LoadClass/LongBCP.java index e1404c032d2..98ca4495966 100644 --- a/test/hotspot/jtreg/runtime/LoadClass/LongBCP.java +++ b/test/hotspot/jtreg/runtime/LoadClass/LongBCP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,13 +29,14 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.management + * jdk.jartool/sun.tools.jar * @run main LongBCP */ +import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; -import jdk.test.lib.Platform; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; @@ -81,6 +82,23 @@ public static void main(String args[]) throws Exception { output.shouldContain("Hello World") .shouldHaveExitValue(0); + // create a hello.jar + sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar"); + String helloJar = destDir.toString() + File.separator + "hello.jar"; + if (!jarTool.run(new String[] + {"-cf", helloJar, "-C", destDir.toString(), "Hello.class"})) { + throw new RuntimeException("Could not write the Hello jar file"); + } + + // run with long bootclasspath to hello.jar + bootCP = "-Xbootclasspath/a:" + helloJar; + pb = ProcessTools.createJavaProcessBuilder( + bootCP, "Hello"); + + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Hello World") + .shouldHaveExitValue(0); + // relative path tests // We currently cannot handle relative path specified in the // -Xbootclasspath/a on windows. @@ -98,13 +116,8 @@ public static void main(String args[]) throws Exception { bootCP, "Hello"); output = new OutputAnalyzer(pb.start()); - if (!Platform.isWindows()) { - output.shouldContain("Hello World") - .shouldHaveExitValue(0); - } else { - output.shouldContain("Could not find or load main class Hello") - .shouldHaveExitValue(1); - } + output.shouldContain("Hello World") + .shouldHaveExitValue(0); // total relative path length exceeds MAX_PATH destDir = Paths.get(destDir.toString(), "yyyyyyyy"); @@ -116,12 +129,7 @@ public static void main(String args[]) throws Exception { bootCP, "Hello"); output = new OutputAnalyzer(pb.start()); - if (!Platform.isWindows()) { - output.shouldContain("Hello World") - .shouldHaveExitValue(0); - } else { - output.shouldContain("Could not find or load main class Hello") - .shouldHaveExitValue(1); - } + output.shouldContain("Hello World") + .shouldHaveExitValue(0); } } diff --git a/test/hotspot/jtreg/runtime/StackTrace/HiddenFrameTest.java b/test/hotspot/jtreg/runtime/StackTrace/HiddenFrameTest.java new file mode 100644 index 00000000000..540a1e31efb --- /dev/null +++ b/test/hotspot/jtreg/runtime/StackTrace/HiddenFrameTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2019, 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 8216977 + * @summary Test null source file and negative line number from hidden frame produces correct output. + * @library /test/lib + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames HiddenFrameTest visible + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-ShowHiddenFrames HiddenFrameTest hidden + */ + +import jdk.test.lib.Asserts; + +public class HiddenFrameTest { + + @FunctionalInterface + private static interface SomeFunctionalInterface { + String someMethod(String a, String b); + } + + static void assertContains(String expected, String actual, Exception e, boolean framesAreHidden) throws Exception { + if (!framesAreHidden && !actual.contains(expected)) { + throw new RuntimeException("Expected: " + expected + "; Actual: " + actual, e); + } else if (framesAreHidden && actual.contains(expected)) { + throw new RuntimeException("Unexpected: " + expected + "; Actual: " + actual, e); + } + } + + static void checkException(Exception e, boolean framesAreHidden) throws Exception { + StackTraceElement[] fs = e.getStackTrace(); + + if (fs.length < 2) { + throw new RuntimeException("Exception should have at least two frames", e); + } + + assertContains("someMethod(Unknown Source)", fs[0].toString(), e, framesAreHidden); + } + + public static void main(String[] args) throws Exception { + boolean framesAreHidden = false; + if (args.length > 0) { + String arg = args[0]; + if (arg.equals("hidden")) framesAreHidden = true; + } + + try { + final SomeFunctionalInterface concatter = String::concat; + final String nullString = null; + if (concatter != null) { + // This throws NPE from the lambda expression which is a hidden frame + concatter.someMethod(nullString, "validString"); + } + } catch (NullPointerException e) { + e.printStackTrace(); + checkException(e, framesAreHidden); + } + } +} + diff --git a/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java new file mode 100644 index 00000000000..ee865fd353e --- /dev/null +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java @@ -0,0 +1,141 @@ +/* + * 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 + * @summary Test IntegerCache integrity in various scenarios + * @requires vm.cds.archived.java.heap + * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds + * @modules java.base/jdk.internal.misc + * java.management + * jdk.jartool/sun.tools.jar + * @build sun.hotspot.WhiteBox + * @compile CheckIntegerCacheApp.java + * @run driver ClassFileInstaller -jar integer.jar CheckIntegerCacheApp + * @run driver ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox + * @run main ArchivedIntegerCacheTest + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import jdk.test.lib.process.OutputAnalyzer; + +public class ArchivedIntegerCacheTest { + + public static void main(String[] args) throws Exception { + String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar"); + String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar; + String appJar = ClassFileInstaller.getJarPath("integer.jar"); + + Path userDir = Paths.get(System.getProperty("user.dir")); + Path moduleDir = Files.createTempDirectory(userDir, "mods"); + + // + // Dump default archive + // + OutputAnalyzer output = TestCommon.dump(appJar, + TestCommon.list("CheckIntegerCacheApp"), + use_whitebox_jar); + TestCommon.checkDump(output); + + // Test case 1) + // - Default options + System.out.println("----------------------- Test case 1 ----------------------"); + output = TestCommon.exec(appJar, use_whitebox_jar, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "CheckIntegerCacheApp", + "127", + "true"); + TestCommon.checkExec(output); + + // Test case 2) + // - Default archive + // - Larger -XX:AutoBoxCacheMax + System.out.println("----------------------- Test case 2 ----------------------"); + output = TestCommon.exec(appJar, use_whitebox_jar, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:AutoBoxCacheMax=20000", + "CheckIntegerCacheApp", + "20000", + "false"); + TestCommon.checkExec(output); + + // + // Dump with -XX:AutoBoxCacheMax specified + // + output = TestCommon.dump(appJar, + TestCommon.list("CheckIntegerCacheApp"), + "-XX:AutoBoxCacheMax=20000", + use_whitebox_jar); + TestCommon.checkDump(output); + + // Test case 3) + // - Large archived cache + // - Default options + System.out.println("----------------------- Test case 3 ----------------------"); + output = TestCommon.exec(appJar, use_whitebox_jar, + "--module-path", + moduleDir.toString(), + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "CheckIntegerCacheApp", + "127", + "true"); + TestCommon.checkExec(output); + + + // Test case 4) + // - Large archived cache + // - Matching options + System.out.println("----------------------- Test case 4 ----------------------"); + output = TestCommon.exec(appJar, use_whitebox_jar, + "--module-path", + moduleDir.toString(), + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:AutoBoxCacheMax=20000", + "CheckIntegerCacheApp", + "20000", + "true"); + TestCommon.checkExec(output); + + // Test case 5) + // - Large archived cache + // - Larger requested cache + System.out.println("----------------------- Test case 5 ----------------------"); + output = TestCommon.exec(appJar, use_whitebox_jar, + "--module-path", + moduleDir.toString(), + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:AutoBoxCacheMax=30000", + "CheckIntegerCacheApp", + "30000", + "false"); + TestCommon.checkExec(output); + } +} diff --git a/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleComboTest.java b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleComboTest.java index accf3327096..de1034d6f3a 100644 --- a/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleComboTest.java +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleComboTest.java @@ -54,41 +54,49 @@ public static void main(String[] args) throws Exception { Path userDir = Paths.get(System.getProperty("user.dir")); Path moduleDir = Files.createTempDirectory(userDir, "mods"); - // Dump without --module-path + // + // Dump without --module-path, without --show-module-resolution + // OutputAnalyzer output = TestCommon.dump(appJar, TestCommon.list("CheckArchivedModuleApp"), use_whitebox_jar); TestCommon.checkDump(output); // Test case 1) - // - Dump without --module-path - // - Run from -cp only, archived boot layer module ModuleDescriptors - // should be used. + // - Dump without --module-path, without --show-module-resolution + // - Run from -cp only and without --show-module-resolution + // + archived boot layer module ModuleDescriptors should be used + // + archived boot layer configuration should be used System.out.println("----------------------- Test case 1 ----------------------"); output = TestCommon.exec(appJar, use_whitebox_jar, "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "CheckArchivedModuleApp", + "yes", "yes"); TestCommon.checkExec(output); // Test case 2) - // - Dump without --module-path - // - Run from -cp only, archived boot layer module ModuleDescriptors - // should be used with --show-module-resolution (requires resolution). + // - Dump without --module-path, without --show-module-resolution + // - Run from -cp only and with --show-module-resolution + // + archived boot layer module ModuleDescriptors should be used with + // --show-module-resolution (requires resolution) + // + archived boot layer Configuration should not be disabled System.out.println("----------------------- Test case 2 ----------------------"); output = TestCommon.exec(appJar, use_whitebox_jar, "--show-module-resolution", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "CheckArchivedModuleApp", - "yes"); - TestCommon.checkExec(output); + "yes", + "no"); + TestCommon.checkExec(output, "root java.base jrt:/java.base"); // Test case 3) - // - Dump without --module-path - // - Run with --module-path, archived boot layer module ModuleDescriptors - // should be disabled. + // - Dump without --module-path, without --show-module-resolution + // - Run with --module-path + // + archived boot layer module ModuleDescriptors should be disabled + // + archived boot layer Configuration should be disabled System.out.println("----------------------- Test case 3 ----------------------"); output = TestCommon.exec(appJar, use_whitebox_jar, "--module-path", @@ -96,12 +104,15 @@ public static void main(String[] args) throws Exception { "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "CheckArchivedModuleApp", + "no", "no"); TestCommon.checkExec(output); + // // Dump with --module-path specified (test case 4, 5). Use an // empty directory as it's simple and still triggers the case // where system module objects are not archived. + // output = TestCommon.dump(appJar, TestCommon.list("CheckArchivedModuleApp"), "--module-path", @@ -112,19 +123,20 @@ public static void main(String[] args) throws Exception { // Test case 4) // - Dump with --module-path // - Run from -cp only, no archived boot layer module ModuleDescriptors - // should be found. + // and Configuration should be found. System.out.println("----------------------- Test case 4 ----------------------"); output = TestCommon.exec(appJar, use_whitebox_jar, "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "CheckArchivedModuleApp", + "no", "no"); TestCommon.checkExec(output); // Test case 5) // - Dump with --module-path // - Run with --module-path, no archived boot layer module ModuleDescriptors - // should be found. + // and Configuration should be found. System.out.println("----------------------- Test case 5 ----------------------"); output = TestCommon.exec(appJar, use_whitebox_jar, "--module-path", @@ -132,7 +144,47 @@ public static void main(String[] args) throws Exception { "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "CheckArchivedModuleApp", + "no", "no"); TestCommon.checkExec(output); + + // + // Dump without --module-path, with --show-module-resolution + // + output = TestCommon.dump(appJar, + TestCommon.list("CheckArchivedModuleApp"), + "--show-module-resolution", + use_whitebox_jar); + TestCommon.checkDump(output, "root java.base jrt:/java.base"); + + // Test case 6) + // - Dump without --module-path, with --show-module-resolution + // - Run from -cp only and without --show-module-resolution + // + archived boot layer module ModuleDescriptors should be used + // + archived boot layer Configuration should be used + System.out.println("----------------------- Test case 6 ----------------------"); + output = TestCommon.exec(appJar, use_whitebox_jar, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "CheckArchivedModuleApp", + "yes", + "yes"); + TestCommon.checkExec(output); + + // Test case 7) + // - Dump without --module-path, with --show-module-resolution + // - Run from -cp only and with --show-module-resolution + // + archived boot layer module ModuleDescriptors should be used with + // --show-module-resolution (requires resolution) + // + archived boot layer Configuration should be disabled + System.out.println("----------------------- Test case 7 ----------------------"); + output = TestCommon.exec(appJar, use_whitebox_jar, + "--show-module-resolution", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "CheckArchivedModuleApp", + "yes", + "no"); + TestCommon.checkExec(output, "root java.base jrt:/java.base"); } } diff --git a/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleWithCustomImageTest.java b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleWithCustomImageTest.java index 1a2e07103d3..c393d7ec325 100644 --- a/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleWithCustomImageTest.java +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedModuleWithCustomImageTest.java @@ -130,6 +130,7 @@ private static void testArchivedModuleUsingImage(Path image) "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "CheckArchivedModuleApp", + "yes", "yes"}; printCommand(runCmd); ProcessBuilder pbRun = new ProcessBuilder(); diff --git a/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckArchivedModuleApp.java b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckArchivedModuleApp.java index 144c71b9983..57eb2d67db1 100644 --- a/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckArchivedModuleApp.java +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckArchivedModuleApp.java @@ -23,7 +23,9 @@ */ import java.io.File; +import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; +import java.util.List; import java.util.Set; import sun.hotspot.WhiteBox; @@ -41,16 +43,23 @@ public static void main(String args[]) throws Exception { return; } - boolean expectArchived = "yes".equals(args[0]); - checkModuleDescriptors(expectArchived); + if (args.length != 2) { + throw new RuntimeException( + "FAILED. Incorrect argument length: " + args.length); + } + boolean expectArchivedDescriptors = "yes".equals(args[0]); + boolean expectArchivedConfiguration = "yes".equals(args[1]); + checkModuleDescriptors(expectArchivedDescriptors); + checkConfiguration(expectArchivedConfiguration); + checkEmptyConfiguration(expectArchivedConfiguration); } - private static void checkModuleDescriptors(boolean expectArchived) { + private static void checkModuleDescriptors(boolean expectArchivedDescriptors) { Set modules = ModuleLayer.boot().modules(); for (Module m : modules) { ModuleDescriptor md = m.getDescriptor(); String name = md.name(); - if (expectArchived) { + if (expectArchivedDescriptors) { if (wb.isShared(md)) { System.out.println(name + " is archived. Expected."); } else { @@ -67,4 +76,58 @@ private static void checkModuleDescriptors(boolean expectArchived) { } } } + + private static void checkEmptyConfiguration(boolean expectArchivedConfiguration) { + // Configuration.EMPTY_CONFIGURATION uses the singletons, + // ListN.EMPTY_LIST, SetN.EMPTY_SET and MapN.EMPTY_MAP in + // ImmutableCollections for the 'parents', 'modules' and + // 'graph' fields. The ImmutableCollections singletons + // can be accessed via List.of(), Set.of() and Map.of() APIs. + // Configuration public APIs also allow access to the + // EMPTY_CONFIGURATION's 'parents' and 'modules'. When the + // archived java heap data is enabled at runtime, make sure + // the EMPTY_CONFIGURATION.parents and EMPTY_CONFIGURATION.modules + // are the archived ImmutableCollections singletons. + Configuration emptyCf = Configuration.empty(); + List emptyCfParents = emptyCf.parents(); + Set emptyCfModules = emptyCf.modules(); + if (expectArchivedConfiguration) { + if (emptyCfParents == List.of() && + wb.isShared(emptyCfParents)) { + System.out.println("Empty Configuration has expected parents."); + } else { + throw new RuntimeException( + "FAILED. Unexpected parents for empty Configuration."); + } + if (emptyCfModules == Set.of() && + wb.isShared(emptyCfModules)) { + System.out.println("Empty Configuration has expected module set."); + } else { + throw new RuntimeException( + "FAILED. Unexpected module set for empty Configuration."); + } + } + } + + + + private static void checkConfiguration(boolean expectArchivedConfiguration) { + Configuration cf = ModuleLayer.boot().configuration(); + + if (expectArchivedConfiguration) { + if (wb.isShared(cf)) { + System.out.println("Boot layer configuration is archived. Expected."); + } else { + throw new RuntimeException( + "FAILED. Boot layer configuration is not archived."); + } + } else { + if (!wb.isShared(cf)) { + System.out.println("Boot layer configuration is not archived. Expected."); + } else { + throw new RuntimeException( + "FAILED. Boot layer configuration is archived."); + } + } + } } diff --git a/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckIntegerCacheApp.java b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckIntegerCacheApp.java new file mode 100644 index 00000000000..0c6545e6e2f --- /dev/null +++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/CheckIntegerCacheApp.java @@ -0,0 +1,88 @@ +/* + * 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. + * + */ + +import sun.hotspot.WhiteBox; + +// +// Help test archived integer cache consistency. +// +// Takes two arguments: +// 0: the expected AutoBoxCacheMax setting +// 1: if the values are expected to be retrieved from the archive or not +// +public class CheckIntegerCacheApp { + static WhiteBox wb; + + public static void main(String[] args) throws Exception { + wb = WhiteBox.getWhiteBox(); + + if (!wb.areOpenArchiveHeapObjectsMapped()) { + System.out.println("This may happen during normal operation. Test Skipped."); + return; + } + + if (args.length != 2) { + throw new RuntimeException( + "FAILED. Incorrect argument length: " + args.length); + } + + boolean archivedExpected = Boolean.parseBoolean(args[1]); + + // Base JLS compliance check + for (int i = -128; i <= 127; i++) { + if (Integer.valueOf(i) != Integer.valueOf(i)) { + throw new RuntimeException( + "FAILED. All values in range [-128, 127] should be interned in cache: " + i); + } + checkArchivedAsExpected(archivedExpected, i); + } + + int high = Integer.parseInt(args[0]); + if (Integer.valueOf(high) != Integer.valueOf(high)) { + throw new RuntimeException( + "FAILED. Value expected to be retrieved from cache: " + high); + } + checkArchivedAsExpected(archivedExpected, Integer.valueOf(high)); + + if (Integer.valueOf(high + 1) == Integer.valueOf(high + 1)) { + throw new RuntimeException( + "FAILED. Value not expected to be retrieved from cache: " + high); + } + checkArchivedAsExpected(false, Integer.valueOf(high + 1)); + } + + private static void checkArchivedAsExpected(boolean archivedExpected, Integer value) { + if (archivedExpected) { + if (!wb.isShared(Integer.valueOf(value))) { + throw new RuntimeException( + "FAILED. Value expected to be archived: " + value); + } + } else { + if (wb.isShared(Integer.valueOf(value))) { + throw new RuntimeException( + "FAILED. Value not expected to be archived: " + value); + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationApp.java b/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationApp.java index 1328f583031..ecb4da0b137 100644 --- a/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationApp.java +++ b/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationApp.java @@ -116,10 +116,10 @@ public static void main(String args[]) throws Throwable { System.out.println("INFO: AppCDSv1 " + (wb.isSharedClass(InstrumentationApp.class) ? "enabled" :"disabled")); System.out.println("INFO: AppCDSv2 " + (isAppCDSV2Enabled() ? "enabled" : "disabled")); - File bootJar = new File(args[0]); - File appJar = new File(args[1]); - File custJar = new File(args[2]); - String flagFile = args[3]; + String flagFile = args[0]; + File bootJar = new File(args[1]); + File appJar = new File(args[2]); + File custJar = new File(args[3]); waitAttach(flagFile); instrumentation = InstrumentationRegisterClassFileTransformer.getInstrumentation(); diff --git a/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationTest.java b/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationTest.java index 8ee5803fd4c..b1ce6dabbd5 100644 --- a/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationTest.java +++ b/test/hotspot/jtreg/runtime/appcds/jvmti/InstrumentationTest.java @@ -120,7 +120,7 @@ public static void runTest(boolean attachAgent) throws Throwable { "-XX:+WhiteBoxAPI", "-Xshare:off", agentCmdArg, - "InstrumentationApp", bootJar, appJar, custJar, flagFile); + "InstrumentationApp", flagFile, bootJar, appJar, custJar); TestCommon.executeAndLog(pb, "no-sharing").shouldHaveExitValue(0); checkAttach(t); @@ -155,7 +155,7 @@ public static void runTest(boolean attachAgent) throws Throwable { "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", agentCmdArg, - "InstrumentationApp", bootJar, appJar, custJar, flagFile); + "InstrumentationApp", flagFile, bootJar, appJar, custJar); CDSOptions opts = (new CDSOptions()).setXShareMode("auto"); TestCommon.checkExec(out, opts); diff --git a/test/hotspot/jtreg/runtime/testlibrary/ClassUnloadCommon.java b/test/hotspot/jtreg/runtime/testlibrary/ClassUnloadCommon.java index 33e2d6c56ea..254411efeeb 100644 --- a/test/hotspot/jtreg/runtime/testlibrary/ClassUnloadCommon.java +++ b/test/hotspot/jtreg/runtime/testlibrary/ClassUnloadCommon.java @@ -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 @@ -73,7 +73,7 @@ public static ClassLoader newClassLoader() { .map(Paths::get) .map(ClassUnloadCommon::toURL) .toArray(URL[]::new); - return new URLClassLoader(urls) { + return new URLClassLoader("ClassUnloadCommonClassLoader", urls, new ClassUnloadCommon().getClass().getClassLoader()) { @Override public Class loadClass(String cn, boolean resolve) throws ClassNotFoundException diff --git a/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdConnectTest.java b/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdConnectTest.java new file mode 100644 index 00000000000..59a6b98fde3 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdConnectTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2019, 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 8209790 + * @summary Checks ability for connecting to debug server (jstack, jmap, jinfo, jsnap) + * @requires vm.hasSAandCanAttach + * @requires os.family != "windows" + * @modules java.base/jdk.internal.misc + * @library /test/lib + * + * @run main/othervm DebugdConnectTest + */ + +import java.io.IOException; + +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.process.OutputAnalyzer; + + +public class DebugdConnectTest { + + private static OutputAnalyzer runJHSDB(String command, String id) throws IOException, InterruptedException { + JDKToolLauncher jhsdbLauncher = JDKToolLauncher.createUsingTestJDK("jhsdb"); + jhsdbLauncher.addToolArg(command); + jhsdbLauncher.addToolArg("--connect"); + if (id != null) { + jhsdbLauncher.addToolArg(id + "@localhost"); + } else { + jhsdbLauncher.addToolArg("localhost"); + } + + Process jhsdb = (new ProcessBuilder(jhsdbLauncher.getCommand())).start(); + OutputAnalyzer out = new OutputAnalyzer(jhsdb); + + jhsdb.waitFor(); + + System.out.println(out.getStdout()); + System.err.println(out.getStderr()); + + return out; + } + + private static void runJSTACK(String id) throws IOException, InterruptedException { + OutputAnalyzer out = runJHSDB("jstack", id); + + out.shouldContain("LingeredApp"); + out.stderrShouldBeEmpty(); + out.shouldHaveExitValue(0); + } + + private static void runJMAP(String id) throws IOException, InterruptedException { + OutputAnalyzer out = runJHSDB("jmap", id); + + out.shouldContain("JVM version is"); + out.stderrShouldBeEmpty(); + out.shouldHaveExitValue(0); + } + + private static void runJINFO(String id) throws IOException, InterruptedException { + OutputAnalyzer out = runJHSDB("jinfo", id); + + out.shouldContain("Java System Properties:"); + out.stderrShouldBeEmpty(); + out.shouldHaveExitValue(0); + } + + private static void runJSNAP(String id) throws IOException, InterruptedException { + OutputAnalyzer out = runJHSDB("jsnap", id); + + out.shouldContain("java.vm.name="); + out.stderrShouldBeEmpty(); + out.shouldHaveExitValue(0); + } + + private static void runTests(String id, long debuggeePid) throws IOException, InterruptedException { + DebugdUtils debugd = new DebugdUtils(id); + debugd.attach(debuggeePid); + + try { + runJSTACK(id); + runJMAP(id); + runJINFO(id); + runJSNAP(id); + } finally { + debugd.detach(); + } + } + + public static void main(String[] args) throws Exception { + LingeredApp app = null; + + try { + app = LingeredApp.startApp(); + System.out.println("Started LingeredApp with pid " + app.getPid()); + + System.out.println("debugd connection test with server id:"); + runTests("test", app.getPid()); + + System.out.println("debugd connection test without server id:"); + runTests(null, app.getPid()); + } finally { + LingeredApp.stopApp(app); + } + + } + +} diff --git a/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdUtils.java b/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdUtils.java new file mode 100644 index 00000000000..39bcf023843 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdUtils.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; + +import jdk.test.lib.JDKToolLauncher; + + +public class DebugdUtils { + + private static final String GOLDEN = "Debugger attached"; + + private final String id; + + private Process debugdProcess; + + public DebugdUtils(String id) { + this.id = id; + debugdProcess = null; + } + + public void attach(long pid) throws IOException { + JDKToolLauncher jhsdbLauncher = JDKToolLauncher.createUsingTestJDK("jhsdb"); + jhsdbLauncher.addToolArg("debugd"); + jhsdbLauncher.addToolArg("--pid"); + jhsdbLauncher.addToolArg(Long.toString(pid)); + if (id != null) { + jhsdbLauncher.addToolArg("--serverid"); + jhsdbLauncher.addToolArg(id); + } + debugdProcess = (new ProcessBuilder(jhsdbLauncher.getCommand())).start(); + + // Wait until debug server attached + try (BufferedReader reader = new BufferedReader(new InputStreamReader(debugdProcess.getErrorStream()))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.contains(GOLDEN)) { + break; + } + } + } + } + + public void detach() throws InterruptedException { + if (debugdProcess != null) { + debugdProcess.destroy(); + debugdProcess.waitFor(); + } + } +} diff --git a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java index 4b4a02a56ad..fabf95b61b0 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java +++ b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java @@ -263,6 +263,8 @@ private String[] cmd(long classStart, long classStop) { "-XX:-UseCounterDecay", "-XX:-ShowMessageBoxOnError", "-XX:+UnlockDiagnosticVMOptions", + // redirect VM output to cerr so it won't collide w/ ctw output + "-XX:+DisplayVMOutputToStderr", // define phase start "-DCompileTheWorldStartAt=" + classStart, "-DCompileTheWorldStopAt=" + classStop, diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java new file mode 100644 index 00000000000..757ae8b061c --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test + * + * @summary JDB problem running monitor command + * VM Testbase keywords: [jpda, jdb] + * VM Testbase readme: + * DESCRIPTION + * Make sure 'monitor unmonitor 1' does not cause ConcurrentModificationException + * in the debugger. + * The jdb sets up line breakpoint at the debugged application. Then one command + * 'monitor unmonitor 1' is set. After resuming the debuggee stops at the breakpoint. + * The test passes if correct reply for "unmonitor 1" commanda is found in jdb stdout + * stream. + * The test consists of two program: + * monitor002.java - launches jdb and debuggee, writes commands to jdb, reads the jdb output, + * monitor002a.java - the debugged application. + * + * @library /vmTestbase + * /test/lib + * @run driver jdk.test.lib.FileInstaller . . + * @build nsk.jdb.monitor.monitor002.monitor002 + * nsk.jdb.monitor.monitor002.monitor002a + * @run main/othervm PropertyResolvingWrapper nsk.jdb.monitor.monitor002.monitor002 + * -arch=${os.family}-${os.simpleArch} + * -waittime=5 + * -debugee.vmkind=java + * -transport.address=dynamic + * -jdb=${test.jdk}/bin/jdb + * -java.options="${test.vm.opts} ${test.java.opts}" + * -workdir=. + * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" + */ + +package nsk.jdb.monitor.monitor002; + +import nsk.share.*; +import nsk.share.jdb.*; + +import java.io.*; +import java.util.*; + +public class monitor002 extends JdbTest { + + public static void main (String argv[]) { + System.exit(run(argv, System.out) + JCK_STATUS_BASE); + } + + public static int run(String argv[], PrintStream out) { + debuggeeClass = DEBUGGEE_CLASS; + firstBreak = FIRST_BREAK; + lastBreak = LAST_BREAK; + return new monitor002().runTest(argv, out); + } + + static final String PACKAGE_NAME = "nsk.jdb.monitor.monitor002"; + static final String TEST_CLASS = PACKAGE_NAME + ".monitor002"; + static final String DEBUGGEE_CLASS = TEST_CLASS + "a"; + static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main"; + static final String LAST_BREAK = DEBUGGEE_CLASS + ".lastBreak"; + static final int LINE_NUMBER = 47; + + static final String[] CHECKED_COMMANDS = { + JdbCommand.unmonitor + "1" + }; + + protected void runCases() { + String[] reply; + Paragrep grep; + int count; + Vector v; + String found; + + reply = jdb.receiveReplyFor(JdbCommand.stop_at + DEBUGGEE_CLASS + ":" + LINE_NUMBER); + + for (int i = 0; i < CHECKED_COMMANDS.length; i++) { + reply = jdb.receiveReplyFor(JdbCommand.monitor + CHECKED_COMMANDS[i]); + } + + int repliesCount = CHECKED_COMMANDS.length + 1; + reply = jdb.receiveReplyFor(JdbCommand.cont, true, repliesCount); + + reply = jdb.receiveReplyFor(JdbCommand.monitor); + if (reply.length != 1) { + log.complain("Expected no active monitors after exectuting monitored command: " + CHECKED_COMMANDS[0]); + success = false; + } + + jdb.contToExit(1); + + reply = jdb.getTotalReply(); + + if (!checkCommands(reply)) { + success = false; + } + } + + private boolean checkCommands(String[] reply) { + Paragrep grep; + boolean result = true; + int count; + + grep = new Paragrep(reply); + + if ((count = grep.find("Unmonitoring 1: unmonitor 1")) != 1) { + log.complain("Wrong number of execution of monitored command: " + CHECKED_COMMANDS[0]); + log.complain(" Expected: 1; found: " + count); + result = false; + } + + return result; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002a.java new file mode 100644 index 00000000000..cad54b701f7 --- /dev/null +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002a.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package nsk.jdb.monitor.monitor002; + +import nsk.share.*; +import nsk.share.jpda.*; +import nsk.share.jdb.*; + +import java.io.*; + +// THIS TEST IS LINE NUMBER SENSITIVE + +/* This is debuggee aplication */ +public class monitor002a { + static monitor002a _monitor002a = new monitor002a(); + + public static void main(String args[]) { + System.exit(monitor002.JCK_STATUS_BASE + _monitor002a.runIt(args, System.out)); + } + + static void lastBreak () {} + + public int runIt(String args[], PrintStream out) { + JdbArgumentHandler argumentHandler = new JdbArgumentHandler(args); + Log log = new Log(out, argumentHandler); + int localInt = 0; // monitor002.LINE_NUMBER + localInt++; // dummy breakpoint + log.display("Debuggee PASSED"); + return monitor002.PASSED; + } +} diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/TestDescription.java index c7bf3df62fb..386dd36cbe8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/Allocate/alloc001/TestDescription.java @@ -42,6 +42,8 @@ * @library /vmTestbase * /test/lib * @requires os.family != "aix" + * @comment Test is incompatible with ZGC, due to ZGC's address space requirements. + * @requires vm.gc != "Z" * @run driver jdk.test.lib.FileInstaller . . * @build nsk.jvmti.Allocate.alloc001 * @run shell alloc001.sh diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/MonitorWait/monitorwait001/monitorwait001.c b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/MonitorWait/monitorwait001/monitorwait001.c index b8dcd2646b4..86d0d8d828b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/MonitorWait/monitorwait001/monitorwait001.c +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/MonitorWait/monitorwait001/monitorwait001.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -159,10 +159,6 @@ static int clean() { JVMTI_EVENT_MONITOR_WAIT, NULL))) nsk_jvmti_setFailStatus(); - /* dispose global references */ - NSK_CPP_STUB2(DeleteGlobalRef, jni, object); - NSK_CPP_STUB2(DeleteGlobalRef, jni, thread); - return NSK_TRUE; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/MonitorWaited/monitorwaited001/monitorwaited001.c b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/MonitorWaited/monitorwaited001/monitorwaited001.c index bfb09355f43..efccdec5122 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/MonitorWaited/monitorwaited001/monitorwaited001.c +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/MonitorWaited/monitorwaited001/monitorwaited001.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -160,10 +160,6 @@ static int clean() { JVMTI_EVENT_MONITOR_WAITED, NULL))) nsk_jvmti_setFailStatus(); - /* dispose global references */ - NSK_CPP_STUB2(DeleteGlobalRef, jni, object); - NSK_CPP_STUB2(DeleteGlobalRef, jni, thread); - return NSK_TRUE; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted002/TestDescription.java index 4bd9c7c9ea1..aa62fb7f580 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted002/TestDescription.java @@ -39,8 +39,8 @@ * @run driver jdk.test.lib.FileInstaller . . * @run main/othervm/native * -agentlib:resexhausted=-waittime=5 - * -Xms8m - * -Xmx8m + * -Xms128m + * -Xmx128m * -XX:-UseGCOverheadLimit * nsk.jvmti.ResourceExhausted.resexhausted002 */ diff --git a/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfoOnCompilation/run.sh b/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfoOnCompilation/run.sh index 3c41316d891..3159eb22e1a 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfoOnCompilation/run.sh +++ b/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfoOnCompilation/run.sh @@ -27,7 +27,7 @@ TESTED_JAVA_HOME="$TESTJAVA" ver=$(${TESTED_JAVA_HOME}/bin/java ${JAVA_OPTS} -version 2>&1) isComp=$( echo ${ver} | grep -c "compiled mode") -if [[ $isComp != 1 ]]; then +if [ "$isComp" -ne 1 ]; then echo "skipped. This test works only with -Xcomp" exit fi @@ -40,7 +40,7 @@ pattern="(CodeCache|(CodeHeap.*)): size=${size_pattern} used=${size_pattern} max res=$(${TESTED_JAVA_HOME}/bin/java ${JAVA_OPTS} -XX:+PrintCodeCacheOnCompilation -XX:-Inline vm.compiler.CodeCacheInfoOnCompilation.PrintOnCall | egrep -ce "${pattern}") echo "res: " ${res} -if (( "${res}" != "0" )); then +if [ "$res" -ne 0 ]; then echo "passed" true else diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/correctBootstrap/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/correctBootstrap/TestDescription.java index 1d1d23c7ad9..f5fcea91fd9 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/correctBootstrap/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/correctBootstrap/TestDescription.java @@ -50,7 +50,7 @@ * @build vm.mlvm.share.ClassfileGeneratorTest * @run driver vm.mlvm.share.IndifiedClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * vm.mlvm.share.ClassfileGeneratorTest * -generator vm.mlvm.cp.share.GenManyIndyCorrectBootstrap */ diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/incorrectBootstrap/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/incorrectBootstrap/TestDescription.java index e82f7881fff..df8f5f83b53 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/incorrectBootstrap/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/incorrectBootstrap/TestDescription.java @@ -51,7 +51,7 @@ * @build vm.mlvm.share.ClassfileGeneratorTest * @run driver vm.mlvm.share.IndifiedClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * vm.mlvm.share.ClassfileGeneratorTest * -generator vm.mlvm.cp.share.GenManyIndyIncorrectBootstrap */ diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/mh/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/mh/TestDescription.java index 132267c067f..afbcea913e3 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/mh/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/mh/TestDescription.java @@ -50,6 +50,6 @@ * @build vm.mlvm.share.ClassfileGeneratorTest * @run driver vm.mlvm.share.IndifiedClassesBuilder * - * @run main/othervm vm.mlvm.share.ClassfileGeneratorTest -generator vm.mlvm.cp.share.GenCPFullOfMH + * @run main/othervm/timeout=300 vm.mlvm.share.ClassfileGeneratorTest -generator vm.mlvm.cp.share.GenCPFullOfMH */ diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/mt/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/mt/TestDescription.java index 18155a3ffd1..b50296fcdea 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/mt/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/cp/stress/classfmt/mt/TestDescription.java @@ -50,6 +50,6 @@ * @build vm.mlvm.share.ClassfileGeneratorTest * @run driver vm.mlvm.share.IndifiedClassesBuilder * - * @run main/othervm vm.mlvm.share.ClassfileGeneratorTest -generator vm.mlvm.cp.share.GenCPFullOfMT + * @run main/othervm/timeout=300 vm.mlvm.share.ClassfileGeneratorTest -generator vm.mlvm.cp.share.GenCPFullOfMT */ diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/gc/createLotsOfMHConsts/Test.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/gc/createLotsOfMHConsts/Test.java index 5d0a916af0d..0630b3b896e 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/gc/createLotsOfMHConsts/Test.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/meth/stress/gc/createLotsOfMHConsts/Test.java @@ -50,7 +50,7 @@ * @build vm.mlvm.meth.stress.gc.createLotsOfMHConsts.Test * @run driver vm.mlvm.share.IndifiedClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * vm.mlvm.meth.stress.gc.createLotsOfMHConsts.Test * -stressIterationsFactor 100000 * -generator vm.mlvm.cp.share.GenCPFullOfMH diff --git a/test/jaxp/javax/xml/jaxp/unittest/transform/StAX2DOMTest.java b/test/jaxp/javax/xml/jaxp/unittest/transform/StAX2DOMTest.java new file mode 100644 index 00000000000..a751402f885 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/transform/StAX2DOMTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package transform; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.stax.StAXSource; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Node; + +/* + * @test + * @bug 8016914 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng transform.StAX2DOMTest + * @summary Verifies transforming a StAXSource to a DOMResult. + */ +public class StAX2DOMTest { + /** + * Data files for test. + * Column(s): xml file + * + * @return data for test + */ + @DataProvider(name = "datafiles") + public Object[][] getData() { + return new Object[][] { + { "StAX2DOMTest.xml"}, //without declaration + { "StAX2DOMTest1.xml"}, //with declaration + }; + } + + /** + * Verifies that transforming a StAX source to a DOM result passes with + * or without the XML declaration. + * + * @param file the XML file + * @throws Exception if the test fails + */ + @Test(dataProvider = "datafiles") + public void test(String file) throws Exception { + final XMLInputFactory xif = XMLInputFactory.newInstance(); + final XMLStreamReader xsr = xif.createXMLStreamReader( + this.getClass().getResourceAsStream(file)); + xsr.nextTag(); // Advance to statements element + + final TransformerFactory tf = TransformerFactory.newInstance(); + final Transformer t = tf.newTransformer(); + while(xsr.nextTag() == XMLStreamConstants.START_ELEMENT) { + final DOMResult result = new DOMResult(); + t.transform(new StAXSource(xsr), result); + final Node domNode = result.getNode(); + System.out.println(domNode); + } + } +} diff --git a/test/jaxp/javax/xml/jaxp/unittest/transform/StAX2DOMTest.xml b/test/jaxp/javax/xml/jaxp/unittest/transform/StAX2DOMTest.xml new file mode 100644 index 00000000000..e09845566fa --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/transform/StAX2DOMTest.xml @@ -0,0 +1,119 @@ + + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications + with XML. + + + Ralls, Kim + Midnight Rain + Fantasy + 5.95 + 2000-12-16 + A former architect battles corporate zombies, + an evil sorceress, and her own childhood to become queen + of the world. + + + Corets, Eva + Maeve Ascendant + Fantasy + 5.95 + 2000-11-17 + After the collapse of a nanotechnology + society in England, the young survivors lay the + foundation for a new society. + + + Corets, Eva + Oberon's Legacy + Fantasy + 5.95 + 2001-03-10 + In post-apocalypse England, the mysterious + agent known only as Oberon helps to create a new life + for the inhabitants of London. Sequel to Maeve + Ascendant. + + + Corets, Eva + The Sundered Grail + Fantasy + 5.95 + 2001-09-10 + The two daughters of Maeve, half-sisters, + battle one another for control of England. Sequel to + Oberon's Legacy. + + + Randall, Cynthia + Lover Birds + Romance + 4.95 + 2000-09-02 + When Carla meets Paul at an ornithology + conference, tempers fly as feathers get ruffled. + + + Thurman, Paula + Splish Splash + Romance + 4.95 + 2000-11-02 + A deep sea diver finds true love twenty + thousand leagues beneath the sea. + + + Knorr, Stefan + Creepy Crawlies + Horror + 4.95 + 2000-12-06 + An anthology of horror stories about roaches, + centipedes, scorpions and other insects. + + + Kress, Peter + Paradox Lost + Science Fiction + 6.95 + 2000-11-02 + After an inadvertant trip through a Heisenberg + Uncertainty Device, James Salway discovers the problems + of being quantum. + + + O'Brien, Tim + Microsoft .NET: The Programming Bible + Computer + 36.95 + 2000-12-09 + Microsoft's .NET initiative is explored in + detail in this deep programmer's reference. + + + O'Brien, Tim + MSXML3: A Comprehensive Guide + Computer + 36.95 + 2000-12-01 + The Microsoft MSXML3 parser is covered in + detail, with attention to XML DOM interfaces, XSLT processing, + SAX and more. + + + Galos, Mike + Visual Studio 7: A Comprehensive Guide + Computer + 49.95 + 2001-04-16 + Microsoft Visual Studio 7 is explored in depth, + looking at how Visual Basic, Visual C++, C#, and ASP+ are + integrated into a comprehensive development + environment. + + diff --git a/test/jaxp/javax/xml/jaxp/unittest/transform/StAX2DOMTest1.xml b/test/jaxp/javax/xml/jaxp/unittest/transform/StAX2DOMTest1.xml new file mode 100644 index 00000000000..c703274f7ae --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/transform/StAX2DOMTest1.xml @@ -0,0 +1,120 @@ + + + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications + with XML. + + + Ralls, Kim + Midnight Rain + Fantasy + 5.95 + 2000-12-16 + A former architect battles corporate zombies, + an evil sorceress, and her own childhood to become queen + of the world. + + + Corets, Eva + Maeve Ascendant + Fantasy + 5.95 + 2000-11-17 + After the collapse of a nanotechnology + society in England, the young survivors lay the + foundation for a new society. + + + Corets, Eva + Oberon's Legacy + Fantasy + 5.95 + 2001-03-10 + In post-apocalypse England, the mysterious + agent known only as Oberon helps to create a new life + for the inhabitants of London. Sequel to Maeve + Ascendant. + + + Corets, Eva + The Sundered Grail + Fantasy + 5.95 + 2001-09-10 + The two daughters of Maeve, half-sisters, + battle one another for control of England. Sequel to + Oberon's Legacy. + + + Randall, Cynthia + Lover Birds + Romance + 4.95 + 2000-09-02 + When Carla meets Paul at an ornithology + conference, tempers fly as feathers get ruffled. + + + Thurman, Paula + Splish Splash + Romance + 4.95 + 2000-11-02 + A deep sea diver finds true love twenty + thousand leagues beneath the sea. + + + Knorr, Stefan + Creepy Crawlies + Horror + 4.95 + 2000-12-06 + An anthology of horror stories about roaches, + centipedes, scorpions and other insects. + + + Kress, Peter + Paradox Lost + Science Fiction + 6.95 + 2000-11-02 + After an inadvertant trip through a Heisenberg + Uncertainty Device, James Salway discovers the problems + of being quantum. + + + O'Brien, Tim + Microsoft .NET: The Programming Bible + Computer + 36.95 + 2000-12-09 + Microsoft's .NET initiative is explored in + detail in this deep programmer's reference. + + + O'Brien, Tim + MSXML3: A Comprehensive Guide + Computer + 36.95 + 2000-12-01 + The Microsoft MSXML3 parser is covered in + detail, with attention to XML DOM interfaces, XSLT processing, + SAX and more. + + + Galos, Mike + Visual Studio 7: A Comprehensive Guide + Computer + 49.95 + 2001-04-16 + Microsoft Visual Studio 7 is explored in depth, + looking at how Visual Basic, Visual C++, C#, and ASP+ are + integrated into a comprehensive development + environment. + + diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index d09f9cf8e38..5b99a0feed8 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -221,7 +221,7 @@ java/awt/font/TextLayout/CombiningPerf.java 8192931 generic-all java/awt/font/TextLayout/TextLayoutBounds.java 8169188 generic-all java/awt/font/StyledMetrics/BoldSpace.java 8198422 linux-all java/awt/FontMetrics/FontCrash.java 8198336 windows-all -java/awt/FontMetrics/MaxAdvanceIsMax.java 8221305 solaris-all,macosx-all +java/awt/FontMetrics/MaxAdvanceIsMax.java 8221305,8231495 solaris-all,macosx-all,linux-all java/awt/image/DrawImage/IncorrectAlphaSurface2SW.java 8056077 generic-all java/awt/image/DrawImage/IncorrectClipXorModeSW2Surface.java 8196025 windows-all java/awt/image/DrawImage/IncorrectClipXorModeSurface2Surface.java 8196025 windows-all diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index 7ec211c8158..e3b9da06c36 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -52,7 +52,9 @@ groups=TEST.groups # to determine additional characteristics of the system for use with the @requires tag. # Note: compiled bootlibs code will be located in the folder 'bootClasses' requires.extraPropDefns = ../../test/jtreg-ext/requires/VMProps.java [../../closed/test/jtreg-ext/requires/VMPropsExt.java] -requires.extraPropDefns.bootlibs = ../../test/lib/sun ../../test/lib/jdk/test/lib/Platform.java +requires.extraPropDefns.bootlibs = ../../test/lib/sun \ + ../../test/lib/jdk/test/lib/Platform.java \ + ../../test/lib/jdk/test/lib/Container.java requires.extraPropDefns.vmOpts = -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:bootClasses requires.properties= \ sun.arch.data.model \ diff --git a/test/jdk/java/awt/Focus/NullActiveWindowOnFocusLost/NullActiveWindowOnFocusLost.java b/test/jdk/java/awt/Focus/NullActiveWindowOnFocusLost/NullActiveWindowOnFocusLost.java index 880e6345022..0924413bec4 100644 --- a/test/jdk/java/awt/Focus/NullActiveWindowOnFocusLost/NullActiveWindowOnFocusLost.java +++ b/test/jdk/java/awt/Focus/NullActiveWindowOnFocusLost/NullActiveWindowOnFocusLost.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, 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,7 +31,6 @@ * @test * @key headful * @bug 8211435 - * @requires (os.family == "mac") * @modules java.desktop/sun.awt */ public final class NullActiveWindowOnFocusLost { diff --git a/test/jdk/java/awt/GraphicsDevice/IncorrectDisplayModeExitFullscreen.java b/test/jdk/java/awt/GraphicsDevice/IncorrectDisplayModeExitFullscreen.java index ce21bfb7a68..c2992c133d6 100644 --- a/test/jdk/java/awt/GraphicsDevice/IncorrectDisplayModeExitFullscreen.java +++ b/test/jdk/java/awt/GraphicsDevice/IncorrectDisplayModeExitFullscreen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, 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 @@ -46,6 +46,7 @@ public static void main(final String[] args) { GraphicsEnvironment.getLocalGraphicsEnvironment() .getScreenDevices(); if (devices.length < 2 || devices[0].getDisplayModes().length < 2 + || !devices[0].isDisplayChangeSupported() || !devices[0].isFullScreenSupported() || !devices[1].isFullScreenSupported()) { System.err.println("Testcase is not applicable"); diff --git a/test/jdk/java/awt/GraphicsEnvironment/LoadLock/GE_init5.java b/test/jdk/java/awt/GraphicsEnvironment/LoadLock/GE_init5.java index d0b40315ef0..d30e571c282 100644 --- a/test/jdk/java/awt/GraphicsEnvironment/LoadLock/GE_init5.java +++ b/test/jdk/java/awt/GraphicsEnvironment/LoadLock/GE_init5.java @@ -25,10 +25,10 @@ * @test * @bug 7002839 * @summary Static init deadlock Win32GraphicsEnvironment and WToolkit - * @run main/othervm -Djava.awt.headless=true GE_init4 + * @run main/othervm -Djava.awt.headless=true GE_init5 */ -import java.awt.Toolkit; +import java.awt.GraphicsEnvironment; public class GE_init5 { public static void main(String[] args) { diff --git a/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java new file mode 100644 index 00000000000..ddf4f7e7fdb --- /dev/null +++ b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +import java.awt.Color; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.util.List; + +/** + * @test + * @key headful + * @bug 8215105 + * @summary tests that Robot can capture the common colors without artifacts + */ +public final class CheckCommonColors { + + private static final Frame frame = new Frame(); + private static Robot robot; + + public static void main(final String[] args) throws Exception { + robot = new Robot(); + try { + test(); + } finally { + frame.dispose(); + } + } + + private static void test() { + frame.setSize(400, 400); + frame.setLocationRelativeTo(null); + frame.setUndecorated(true); + for (final Color color : List.of(Color.WHITE, Color.LIGHT_GRAY, + Color.GRAY, Color.DARK_GRAY, + Color.BLACK, Color.RED, Color.PINK, + Color.ORANGE, Color.YELLOW, + Color.GREEN, Color.MAGENTA, Color.CYAN, + Color.BLUE)) { + frame.dispose(); + frame.setBackground(color); + frame.setVisible(true); + checkPixels(color); + } + } + + private static void checkPixels(final Color color) { + int attempt = 0; + while (true) { + Point p = frame.getLocationOnScreen(); + Color pixel = robot.getPixelColor(p.x + frame.getWidth() / 2, + p.y + frame.getHeight() / 2); + if (color.equals(pixel)) { + return; + } + if (attempt > 10) { + System.err.println("Expected: " + color); + System.err.println("Actual: " + pixel); + throw new RuntimeException("Too many attempts: " + attempt); + } + // skip Robot.waitForIdle to speedup the common case, but also take + // care about slow systems + robot.delay((int) Math.pow(2.2, attempt++)); + } + } +} diff --git a/test/jdk/java/lang/module/ModuleDescriptorTest.java b/test/jdk/java/lang/module/ModuleDescriptorTest.java index 83518001b37..839b51cf193 100644 --- a/test/jdk/java/lang/module/ModuleDescriptorTest.java +++ b/test/jdk/java/lang/module/ModuleDescriptorTest.java @@ -147,7 +147,12 @@ private Requires requires(String mn) { public void testRequiresWithRequires() { Requires r1 = requires("foo"); ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").requires(r1).build(); - Requires r2 = descriptor.requires().iterator().next(); + assertEquals(descriptor.requires().size(), 2); + var iterator = descriptor.requires().iterator(); + Requires r2 = iterator.next(); + if (r2.name().equals("java.base")) { + r2 = iterator.next(); + } assertEquals(r1, r2); } diff --git a/test/jdk/java/lang/reflect/callerCache/ReflectionCallerCacheTest.java b/test/jdk/java/lang/reflect/callerCache/ReflectionCallerCacheTest.java index c69637f0493..5ccffa2020d 100644 --- a/test/jdk/java/lang/reflect/callerCache/ReflectionCallerCacheTest.java +++ b/test/jdk/java/lang/reflect/callerCache/ReflectionCallerCacheTest.java @@ -25,8 +25,10 @@ * @test * @bug 8202113 * @summary Test the caller class loader is not kept strongly reachable - * by reflection API + * by reflection API * @library /test/lib/ + * @modules jdk.compiler + * java.base/java.lang.reflect:+open * @build ReflectionCallerCacheTest Members jdk.test.lib.compiler.CompilerUtils * @run testng/othervm ReflectionCallerCacheTest */ diff --git a/test/jdk/java/net/URL/RacyHandler.java b/test/jdk/java/net/URL/RacyHandler.java index 1255465d68b..6067e1e8bf8 100644 --- a/test/jdk/java/net/URL/RacyHandler.java +++ b/test/jdk/java/net/URL/RacyHandler.java @@ -32,6 +32,7 @@ * @test * @bug 8213942 * @summary URLStreamHandler initialization race + * @modules java.base/java.net:open * @run main/othervm RacyHandler * @run main/othervm RacyHandler * @run main/othervm RacyHandler @@ -110,4 +111,4 @@ protected URLConnection openConnection(URL u) throws IOException { return null; } } -} \ No newline at end of file +} diff --git a/test/jdk/java/net/httpclient/whitebox/ConnectionPoolTestDriver.java b/test/jdk/java/net/httpclient/whitebox/ConnectionPoolTestDriver.java index 91eb090f52d..23478be57bc 100644 --- a/test/jdk/java/net/httpclient/whitebox/ConnectionPoolTestDriver.java +++ b/test/jdk/java/net/httpclient/whitebox/ConnectionPoolTestDriver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8187044 8187111 + * @bug 8187044 8187111 8221395 * @summary Verifies that the ConnectionPool correctly handle * connection deadlines and purges the right connections * from the cache. @@ -35,4 +35,8 @@ * @run main/othervm * --add-reads java.net.http=java.management * java.net.http/jdk.internal.net.http.ConnectionPoolTest testPoolSize + * @run main/othervm + * --add-reads java.net.http=java.management + * -Djdk.httpclient.HttpClient.log=errors,requests,headers,content,ssl,trace,channel + * java.net.http/jdk.internal.net.http.ConnectionPoolTest testCloseOrReturnToPool */ diff --git a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/ConnectionPoolTest.java b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/ConnectionPoolTest.java index 37144fcfe14..5d30b19562b 100644 --- a/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/ConnectionPoolTest.java +++ b/test/jdk/java/net/httpclient/whitebox/java.net.http/jdk/internal/net/http/ConnectionPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,25 @@ import java.io.IOException; import java.lang.management.ManagementFactory; +import java.lang.ref.Reference; import java.net.Authenticator; import java.net.CookieHandler; import java.net.InetSocketAddress; import java.net.ProxySelector; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketOption; +import java.net.http.HttpHeaders; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; +import java.nio.channels.spi.SelectorProvider; import java.time.Duration; -import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Random; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.Flow; @@ -53,7 +61,7 @@ * @summary Verifies that the ConnectionPool correctly handle * connection deadlines and purges the right connections * from the cache. - * @bug 8187044 8187111 + * @bug 8187044 8187111 8221395 * @author danielfuchs */ public class ConnectionPoolTest { @@ -78,7 +86,10 @@ public static void main(String[] args) throws Exception { } else if ("testPoolSize".equals(arg)) { assert args.length == 1 : "testPoolSize should be run in its own VM"; testPoolSize(); - } + } else if ("testCloseOrReturnToPool".equals(arg)) { + assert args.length == 1 : "testCloseOrReturnToPool should be run in its own VM"; + testCloseOrReturnToPool(); + } else throw new RuntimeException("unknown test case: " + arg); } } @@ -226,6 +237,113 @@ public static void testPoolSize() throws Exception { } } + public static void testCloseOrReturnToPool() throws Exception { + HttpClientFacade facade = (HttpClientFacade)HttpClient.newHttpClient(); + HttpClientImpl client = facade.impl; + ConnectionPool pool = client.connectionPool(); + InetSocketAddress proxy = InetSocketAddress.createUnresolved("bar", 80); + + InetSocketAddress addr = InetSocketAddress.createUnresolved("foo1", 80); + HttpConnectionStub conn1 = new HttpConnectionStub(facade, client, addr, proxy, true); + HttpHeaders hdrs = HttpHeaders.of(new HashMap<>(), (s1,s2) -> true); + HttpConnection conn; + + conn1.reopen(); + if (!conn1.isOpen()) { + throw new RuntimeException("conn1 finished"); + } + + conn1.closeOrReturnToCache(hdrs); + + // Check we can find conn1 in the pool + if (conn1 != (conn = pool.getConnection(true, addr, proxy))) { + throw new RuntimeException("conn1 not returned, got: " + conn); + } + System.out.println("Found connection in the pool: " + conn ); + + // Try to return it with no headers: the connection should + // be closed and not returned to the pool (EOF). + conn.closeOrReturnToCache(null); + if ((conn = pool.getConnection(true, addr, proxy)) != null) { + throw new RuntimeException(conn + " found in the pool!"); + } + if (!conn1.closed) { + throw new RuntimeException("conn1 not closed!"); + } + System.out.println("EOF connection successfully closed when returned to pool"); + + // reopen the connection + conn1.reopen(); + if (!conn1.isOpen()) { + throw new RuntimeException("conn1 finished"); + } + + // Try to return it with empty headers: the connection should + // be returned to the pool. + conn1.closeOrReturnToCache(hdrs); + if (conn1 != (conn = pool.getConnection(true, addr, proxy))) { + throw new RuntimeException("conn1 not returned to pool, got: " + conn); + } + if (conn1.closed) { + throw new RuntimeException("conn1 closed"); + } + if (!conn1.isOpen()) { + throw new RuntimeException("conn1 finished"); + } + + System.out.println("Keep alive connection successfully returned to pool"); + + // Try to return it with connection: close headers: the connection should + // not be returned to the pool, and should be closed. + HttpHeaders hdrs2 = HttpHeaders.of(Map.of("connection", List.of("close")), (s1, s2) -> true); + conn1.closeOrReturnToCache(hdrs2); + if ((conn = pool.getConnection(true, addr, proxy)) != null) { + throw new RuntimeException(conn + " found in the pool!"); + } + if (!conn1.closed) { + throw new RuntimeException("conn1 not closed!"); + } + System.out.println("Close connection successfully closed when returned to pool"); + + // reopen and finish the connection. + conn1.reopen(); + conn1.finish(true); + if (conn1.closed) { + throw new RuntimeException("conn1 closed"); + } + if (conn1.isOpen()) { + throw new RuntimeException("conn1 is opened!"); + } + conn1.closeOrReturnToCache(hdrs2); + if ((conn = pool.getConnection(true, addr, proxy)) != null) { + throw new RuntimeException(conn + " found in the pool!"); + } + if (!conn1.closed) { + throw new RuntimeException("conn1 not closed!"); + } + System.out.println("Finished 'close' connection successfully closed when returned to pool"); + + // reopen and finish the connection. + conn1.reopen(); + conn1.finish(true); + if (conn1.closed) { + throw new RuntimeException("conn1 closed"); + } + if (conn1.isOpen()) { + throw new RuntimeException("conn1 is opened!"); + } + conn1.closeOrReturnToCache(hdrs); + if ((conn = pool.getConnection(true, addr, proxy)) != null) { + throw new RuntimeException(conn + " found in the pool!"); + } + if (!conn1.closed) { + throw new RuntimeException("conn1 not closed!"); + } + System.out.println("Finished keep-alive connection successfully closed when returned to pool"); + + Reference.reachabilityFence(facade); + } + static T error() { throw new InternalError("Should not reach here: wrong test assumptions!"); } @@ -241,22 +359,108 @@ public void onSubscribe(Flow.Subscription subscription) { } @Override public void subscribe(Flow.Subscriber> subscriber) { } - @Override public boolean isFinished() { return conn.closed; } + @Override public boolean isFinished() { return conn.finished; } + } + + static class SocketChannelStub extends SocketChannel { + + SocketChannelStub() { super(SelectorProvider.provider()); } + + @Override + public SocketChannel bind(SocketAddress local) throws IOException { + return error(); + } + @Override + public SocketChannel setOption(SocketOption name, T value) throws IOException { + return error(); + } + @Override + public SocketChannel shutdownInput() throws IOException { + return error(); + } + @Override + public SocketChannel shutdownOutput() throws IOException { + return error(); + } + @Override + public Socket socket() { return error(); } + @Override + public boolean isConnected() { return true; } + @Override + public boolean isConnectionPending() { return false; } + @Override + public boolean connect(SocketAddress remote) throws IOException { + return error(); + } + @Override + public boolean finishConnect() throws IOException { + return error(); + } + @Override + public SocketAddress getRemoteAddress() throws IOException { + return error(); + } + @Override + public int read(ByteBuffer dst) throws IOException { + return error(); + } + @Override + public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { + return error(); + } + @Override + public int write(ByteBuffer src) throws IOException { + return error(); + } + @Override + public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { + return 0; + } + @Override + public SocketAddress getLocalAddress() throws IOException { + return error(); + } + @Override + public T getOption(SocketOption name) throws IOException { + return error(); + } + @Override + public Set> supportedOptions() { + return error(); + } + @Override + protected void implCloseSelectableChannel() throws IOException { + error(); + } + @Override + protected void implConfigureBlocking(boolean block) throws IOException { + error(); + } } // Emulates an HttpConnection that has a strong reference to its HttpClient. static class HttpConnectionStub extends HttpConnection { - public HttpConnectionStub(HttpClient client, + public HttpConnectionStub( + HttpClient client, InetSocketAddress address, InetSocketAddress proxy, boolean secured) { - super(address, null); + this(client, null, address, proxy, secured); + } + public HttpConnectionStub( + HttpClient client, + HttpClientImpl impl, + InetSocketAddress address, + InetSocketAddress proxy, + boolean secured) { + super(address, impl); this.key = ConnectionPool.cacheKey(address, proxy); this.address = address; this.proxy = proxy; this.secured = secured; this.client = client; + this.channel = new SocketChannelStub(); this.flow = new FlowTubeStub(this); } @@ -266,16 +470,23 @@ public HttpConnectionStub(HttpClient client, final ConnectionPool.CacheKey key; final HttpClient client; final FlowTubeStub flow; - volatile boolean closed; + final SocketChannel channel; + volatile boolean closed, finished; + + // Used for testing closeOrReturnToPool. + void finish(boolean finished) { this.finished = finished; } + void reopen() { closed = finished = false;} // All these return something @Override boolean connected() {return !closed;} @Override boolean isSecure() {return secured;} @Override boolean isProxied() {return proxy!=null;} @Override ConnectionPool.CacheKey cacheKey() {return key;} + @Override FlowTube getConnectionFlow() {return flow;} + @Override SocketChannel channel() {return channel;} @Override public void close() { - closed=true; + closed=finished=true; System.out.println("closed: " + this); } @Override @@ -283,13 +494,11 @@ public String toString() { return "HttpConnectionStub: " + address + " proxy: " + proxy; } + // All these throw errors @Override public HttpPublisher publisher() {return error();} @Override public CompletableFuture connectAsync(Exchange e) {return error();} @Override public CompletableFuture finishConnect() {return error();} - @Override SocketChannel channel() {return error();} - @Override - FlowTube getConnectionFlow() {return flow;} } // Emulates an HttpClient that has a strong reference to its connection pool. static class HttpClientStub extends HttpClient { diff --git a/test/jdk/java/util/EnumSet/BogusEnumSet.java b/test/jdk/java/util/EnumSet/BogusEnumSet.java index c24bbfbbbee..9ee5d80aa15 100644 --- a/test/jdk/java/util/EnumSet/BogusEnumSet.java +++ b/test/jdk/java/util/EnumSet/BogusEnumSet.java @@ -32,11 +32,12 @@ public class BogusEnumSet { public static void main(String[] args) throws Throwable { - // This test depends on the current serialVersionUID of EnumSet, - // which may change if the EnumSet class is modified. - // The current value is -2409567991088730183L = 0xde8f7eadb5012fb9L - // If the value changes, it will have to be patched into the - // serialized byte stream below at the location noted. + // This test depends on the computed serialVersionUID of EnumSet, + // which is 1009687484059888093L = 0x0e03216acd8c29ddL. This + // value should remain the same in order to remain compatible + // with JDK 8. If this value changes, then EnumSet has changed + // incompatibly. The value is embedded within the serialized + // byte stream below at the location noted. byte[] serializedForm = { (byte)0xac, (byte)0xed, 0x0, 0x5, 0x73, 0x72, 0x0, 0x18, 0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, @@ -47,7 +48,7 @@ public static void main(String[] args) throws Throwable { 0x11, 0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, 0x6c, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, // EnumSet's serialVersionUID is the following eight bytes (big-endian) - (byte)0xde, (byte)0x8f, 0x7e, (byte)0xad, (byte)0xb5, (byte)0x01, 0x2f, (byte)0xb9, + 0x0e, 0x03, 0x21, 0x6a, (byte)0xcd, (byte)0x8c, 0x29, (byte)0xdd, 0x2, 0x0, 0x2, 0x4c, 0x0, 0xb, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x74, 0x0, 0x11, 0x4c, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x43, 0x6c, 0x61, 0x73, diff --git a/test/jdk/java/util/EnumSet/EnumSetClassSerialization.java b/test/jdk/java/util/EnumSet/EnumSetClassSerialization.java new file mode 100644 index 00000000000..3f8fc5f17a5 --- /dev/null +++ b/test/jdk/java/util/EnumSet/EnumSetClassSerialization.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019, 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 8227368 + * @summary Test deserialization of a stream containing EnumSet.class object + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.EnumSet; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class EnumSetClassSerialization { + + public static void main(String[] args) throws Exception { + // EnumSet.class object serialized with JDK 8 + int[] bytes = { + 0xac, 0xed, 0x00, 0x05, 0x76, 0x72, 0x00, 0x11, 0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, + 0x6c, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, 0x0e, 0x03, 0x21, 0x6a, 0xcd, 0x8c, 0x29, + 0xdd, 0x02, 0x00, 0x02, 0x4c, 0x00, 0x0b, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x74, 0x00, 0x11, 0x4c, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x3b, 0x5b, 0x00, 0x08, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, + 0x65, 0x74, 0x00, 0x11, 0x5b, 0x4c, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, + 0x45, 0x6e, 0x75, 0x6d, 0x3b, 0x78, 0x70 + }; + + InputStream in = new InputStream() { + int i = 0; + + @Override + public int read() { + return i < bytes.length ? bytes[i++] & 0xFF : -1; + } + }; + ObjectInputStream ois = new ObjectInputStream(in); + + Object res = ois.readObject(); + + if (res != EnumSet.class) { + throw new AssertionError( + "Expected: " + EnumSet.class + ", got: " + res); + } + } + + /** + * This class can be used to print out lines that constitute + * the 'bytes' variable initializer in the test. + */ + public static class Serializer { + public static void main(String[] args) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(EnumSet.class); + oos.close(); + byte[] bytes = baos.toByteArray(); + int bpl = 16; + System.out.print( + IntStream + .range(0, (bytes.length + bpl - 1) / bpl) + .mapToObj(i -> IntStream + .range( + i * bpl, + Math.min(i * bpl + bpl, bytes.length) + ) + .mapToObj(ii -> { + String s = Integer.toHexString(bytes[ii] & 0xFF); + return s.length() == 1 ? "0x0" + s : "0x" + s; + }) + .collect(Collectors.joining(", ")) + ) + .collect(Collectors.joining(",\n ", "int[] bytes = {\n ", "\n};")) + ); + } + } +} diff --git a/test/jdk/java/util/Locale/LocaleProviders.java b/test/jdk/java/util/Locale/LocaleProviders.java index c1558930b4d..342ea91fd1d 100644 --- a/test/jdk/java/util/Locale/LocaleProviders.java +++ b/test/jdk/java/util/Locale/LocaleProviders.java @@ -241,12 +241,16 @@ static void bug8013903Test() { } static void bug8027289Test(String expectedCodePoint) { - char[] expectedSymbol = Character.toChars(Integer.valueOf(expectedCodePoint, 16)); - NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.CHINA); - char formatted = nf.format(7000).charAt(0); - System.out.println("returned: " + formatted + ", expected: " + expectedSymbol[0]); - if (formatted != expectedSymbol[0]) { - throw new RuntimeException("Unexpected Chinese currency symbol. returned: " + formatted + ", expected: " + expectedSymbol[0]); + if (System.getProperty("os.name").startsWith("Windows")) { + char[] expectedSymbol = Character.toChars(Integer.valueOf(expectedCodePoint, 16)); + NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.CHINA); + char formatted = nf.format(7000).charAt(0); + System.out.println("returned: " + formatted + ", expected: " + expectedSymbol[0]); + if (formatted != expectedSymbol[0]) { + throw new RuntimeException( + "Unexpected Chinese currency symbol. returned: " + + formatted + ", expected: " + expectedSymbol[0]); + } } } diff --git a/test/jdk/java/util/Locale/LocaleProviders.sh b/test/jdk/java/util/Locale/LocaleProviders.sh index 652dadf0d81..bf56968ef6c 100644 --- a/test/jdk/java/util/Locale/LocaleProviders.sh +++ b/test/jdk/java/util/Locale/LocaleProviders.sh @@ -25,7 +25,7 @@ # @test # @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8008577 # 8010666 8013086 8013233 8013903 8015960 8028771 8054482 8062006 -# 8150432 8220227 +# 8150432 8220227 8215913 # @summary tests for "java.locale.providers" system property # @modules java.base/sun.util.locale # java.base/sun.util.locale.provider diff --git a/test/jdk/java/util/zip/FlaterTest.java b/test/jdk/java/util/zip/FlaterTest.java index 2d7124de42d..1545a2b91f3 100644 --- a/test/jdk/java/util/zip/FlaterTest.java +++ b/test/jdk/java/util/zip/FlaterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,11 @@ /** * @test - * @bug 6348045 6341887 + * @bug 6348045 6341887 8231770 * @summary GZipOutputStream/InputStream goes critical(calls JNI_Get*Critical) - * and causes slowness. This test uses Deflater and Inflater directly. + * and causes slowness. This test uses Deflater and Inflater directly. * @key randomness + * @run main/othervm -Xcheck:jni FlaterTest */ import java.nio.*; diff --git a/test/jdk/javax/swing/JEditorPane/8226513/JEditorPaneLayoutTest.java b/test/jdk/javax/swing/JEditorPane/8226513/JEditorPaneLayoutTest.java new file mode 100644 index 00000000000..6f2bae353f5 --- /dev/null +++ b/test/jdk/javax/swing/JEditorPane/8226513/JEditorPaneLayoutTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2019, 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 + * @key headful + * @bug 8226513 + * @summary JEditorPane is shown with incorrect size + * @run main/othervm -Dsun.java2d.uiScale=1.0 JEditorPaneLayoutTest + */ + +import javax.swing.JFrame; +import javax.swing.JEditorPane; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.html.HTMLEditorKit; +import java.awt.Dimension; +import java.awt.Robot; + +public class JEditorPaneLayoutTest { + + public static final String TEXT = + "some text some text some text
    some text"; + static JFrame frame; + static JEditorPane editorPane; + static Dimension size1; + static Dimension size2; + static Dimension size3; + static Dimension size4; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame(); + editorPane = new JEditorPane("text/html", TEXT); + size1 = editorPane.getPreferredSize(); + editorPane.setText(TEXT); + frame.add(editorPane); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(300); + + SwingUtilities.invokeAndWait(() -> { + size2 = editorPane.getSize(); + frame.dispose(); + + frame = new JFrame(); + editorPane = new JEditorPane("text/html", TEXT); + editorPane.getPreferredSize(); + editorPane.setText(TEXT); + frame.add(editorPane); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(300); + + if (!size1.equals(size2)) { + SwingUtilities.invokeLater(frame::dispose); + throw new RuntimeException("Wrong size " + size2 + + " expected " + size1); + } + + SwingUtilities.invokeAndWait(() -> { + editorPane.setText(TEXT); + frame.pack(); + size3 = editorPane.getSize(); + frame.dispose(); + + frame = new JFrame(); + editorPane = new JEditorPane("text/html", TEXT); + editorPane.getPreferredSize(); + editorPane.setSize(1, 1); + Document doc = new HTMLEditorKit().createDefaultDocument(); + try { + doc.insertString(0, TEXT, null); + } catch (BadLocationException e) { + e.printStackTrace(); + } + editorPane.setDocument(doc); + editorPane.setText(TEXT); + frame.add(editorPane); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(300); + + if (!size1.equals(size3)) { + SwingUtilities.invokeLater(frame::dispose); + throw new RuntimeException("Wrong size " + size3 + + " expected " + size1); + } + + SwingUtilities.invokeAndWait(() -> { + size4 = editorPane.getSize(); + frame.dispose(); + }); + + robot.waitForIdle(); + robot.delay(300); + + if (!size1.equals(size4)) { + SwingUtilities.invokeLater(frame::dispose); + throw new RuntimeException("Wrong size " + size4 + + " expected " + size1); + } + } +} diff --git a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java index c0e7884171f..46df8826648 100644 --- a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, 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 @@ -51,6 +51,7 @@ public static void main(String[] args) throws Exception { DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "jdk.test.lib.containers.cgroup.MetricsTester"); opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/"); + opts.addDockerOpts("--memory=256m"); opts.addJavaOpts("-cp", "/test-classes/"); opts.addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED"); DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!"); diff --git a/test/jdk/jdk/jfr/api/metadata/annotations/TestFormatMissingValue.java b/test/jdk/jdk/jfr/api/metadata/annotations/TestFormatMissingValue.java index e920996ed7d..fa17fcdfbc2 100644 --- a/test/jdk/jdk/jfr/api/metadata/annotations/TestFormatMissingValue.java +++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestFormatMissingValue.java @@ -97,24 +97,12 @@ public static void main(String[] args) throws Exception { for (RecordedEvent e : Events.fromRecording(r)) { String t = e.toString(); - // jdk11u shows different output compared to jdk12 or higher - // because PrettyWriter is of an older version. - // Should JDK-8205516 ever get integrated to jdk11u, - // this test will have to be updated. - - // assertContains(t, "a = N/A"); - // assertContains(t, "c = N/A"); - // assertContains(t, "e = N/A"); - // assertContains(t, "g = N/A"); - // assertContains(t, "h = N/A"); - // assertContains(t, "j = N/A"); - - assertContains(t, "a = -9223372036854775808"); - assertContains(t, "c = -2147483648"); - assertContains(t, "e = -Infinity"); - assertContains(t, "g = NaN"); - assertContains(t, "h = -Infinity"); - assertContains(t, "j = NaN"); + assertContains(t, "a = N/A"); + assertContains(t, "c = N/A"); + assertContains(t, "e = N/A"); + assertContains(t, "g = N/A"); + assertContains(t, "h = N/A"); + assertContains(t, "j = N/A"); assertNotContains(t, "b = N/A"); assertNotContains(t, "d = N/A"); diff --git a/test/jdk/jdk/jfr/event/os/TestVirtualizationInfo.java b/test/jdk/jdk/jfr/event/os/TestVirtualizationInfo.java new file mode 100644 index 00000000000..b3a09191873 --- /dev/null +++ b/test/jdk/jdk/jfr/event/os/TestVirtualizationInfo.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 2019, 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.jfr.event.os; + +import java.util.List; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.event.os.TestVirtualizationInfo + */ +public class TestVirtualizationInfo { + private final static String EVENT_NAME = EventNames.VirtualizationInformation; + + public static void main(String[] args) throws Throwable { + Recording recording = new Recording(); + recording.enable(EVENT_NAME); + recording.start(); + recording.stop(); + List events = Events.fromRecording(recording); + Events.hasEvents(events); + for (RecordedEvent event : events) { + System.out.println("Event: " + event); + Events.assertField(event, "name").notEmpty(); + } + } +} diff --git a/test/jdk/jdk/jfr/javaagent/EventEmitterAgent.java b/test/jdk/jdk/jfr/javaagent/EventEmitterAgent.java new file mode 100644 index 00000000000..0e19589d65d --- /dev/null +++ b/test/jdk/jdk/jfr/javaagent/EventEmitterAgent.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.javaagent; + +import java.lang.instrument.Instrumentation; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.jfr.Configuration; +import jdk.jfr.Event; +import jdk.jfr.Name; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; + +// Java agent that emits in multiple threads +public class EventEmitterAgent { + + private static final int THREADS = 5; + private static final int EVENTS_PER_THREAD = 150_000; + private static final int EXPECTED_COUNT = THREADS * EVENTS_PER_THREAD; + private static final Path DUMP_PATH = Paths.get("dump.jfr").toAbsolutePath(); + + // Called when agent is loaded from command line + public static void agentmain(String agentArgs, Instrumentation inst) throws Exception { + agentWork(); + } + + // Called when agent is dynamically loaded + public static void premain(String agentArgs, Instrumentation inst) throws Exception { + agentWork(); + } + + private static void agentWork() throws Exception { + try (Recording r = new Recording(Configuration.getConfiguration("default"))) { + r.enable(EventNames.JavaExceptionThrow); + r.setDestination(DUMP_PATH); + r.start(); + Thread[] threads = new Thread[THREADS]; + for (int i = 0; i < THREADS; i++) { + threads[i] = new Thread(EventEmitterAgent::emitEvents); + threads[i].start(); + } + for (int i = 0; i < THREADS; i++) { + threads[i].join(); + } + r.stop(); + } + } + + public static void emitEvents() { + for (int i = 0; i < EVENTS_PER_THREAD; i++) { + TestEvent e = new TestEvent(); + e.msg = "Long message that puts pressure on the string pool " + i % 100; + e.count = i; + e.thread = Thread.currentThread(); + e.clazz = String.class; + e.commit(); + if (i % 10000 == 0) { + try { + Thread.sleep(1); + } catch (InterruptedException ie) { + // ignore + } + } + } + } + + @Name("Test") + static class TestEvent extends Event { + String msg; + int count; + Thread thread; + Class clazz; + } + + public static void validateRecording() throws Exception { + long testEventCount = RecordingFile.readAllEvents(DUMP_PATH) + .stream() + .filter(e -> e.getEventType().getName().equals("Test")) + .count(); + Asserts.assertTrue(testEventCount == EXPECTED_COUNT, "Mismatch in TestEvent count"); + } +} diff --git a/test/jdk/jdk/jfr/javaagent/JavaAgentBuilder.java b/test/jdk/jdk/jfr/javaagent/JavaAgentBuilder.java new file mode 100644 index 00000000000..22b7304d8b4 --- /dev/null +++ b/test/jdk/jdk/jfr/javaagent/JavaAgentBuilder.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.lib.util; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import jdk.test.lib.Utils; +import jdk.test.lib.util.JarUtils; + +/** + * A builder for a common Java agent. + * Can be used directly from the jtreg test header to + * build a java agent before the test is executed. + * + * E.g.: + * @run driver jdk.test.lib.util.JavaAgentBuilder + * jdk.jfr.javaagent.EventEmitterAgent EventEmitterAgent.jar + * + */ +public class JavaAgentBuilder { + + /** + * Build a java agent jar file with a given agent class. + * + * @param args[0] fully qualified name of an agent class + * @param args[1] file name of the agent jar to be created + * @throws IOException + */ + public static void main(String... args) throws IOException { + String agentClass = args[0]; + String agentJar = args[1]; + System.out.println("Building " + agentJar + " with agent class " + agentClass); + build(agentClass, agentJar); + } + + /** + * Build a java agent jar file with a given agent class. + * The agent class will be added as both premain class and agent class. + * + * @param agentClass fully qualified name of an agent class + * @param agentJar file name of the agent jar to be created + * the file will be placed in a current work directory + * @throws IOException + */ + public static void build(String agentClass, String agentJar) throws IOException { + Manifest mf = new Manifest(); + Attributes attrs = mf.getMainAttributes(); + attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); + attrs.putValue("Premain-Class", agentClass); + attrs.putValue("Agent-Class", agentClass); + + Path jarFile = Paths.get(".", agentJar); + String testClasses = Utils.TEST_CLASSES; + String agentPath = agentClass.replace(".", File.separator) + ".class"; + Path agentFile = Paths.get(testClasses, agentPath); + Path dir = Paths.get(testClasses); + JarUtils.createJarFile(jarFile, mf, dir, agentFile); + System.out.println("Agent built:" + jarFile.toAbsolutePath()); + } +} diff --git a/test/jdk/jdk/jfr/javaagent/TestLoadedAgent.java b/test/jdk/jdk/jfr/javaagent/TestLoadedAgent.java new file mode 100644 index 00000000000..5cf428b3626 --- /dev/null +++ b/test/jdk/jdk/jfr/javaagent/TestLoadedAgent.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019, 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 + * @key jfr + * @summary Tests emitting events in a dynamically loaded Java agent + * @requires vm.hasJFR + * + * @library /test/lib /test/jdk + * @modules java.instrument + * + * @build jdk.jfr.javaagent.EventEmitterAgent + * + * @run driver jdk.test.lib.util.JavaAgentBuilder + * jdk.jfr.javaagent.EventEmitterAgent EventEmitterAgent.jar + * + * @run main/othervm -Djdk.attach.allowAttachSelf=true jdk.jfr.javaagent.TestLoadedAgent + */ + +package jdk.jfr.javaagent; + +import com.sun.tools.attach.VirtualMachine; +import jdk.jfr.FlightRecorder; +import jdk.jfr.FlightRecorderListener; +import jdk.jfr.Recording; +import jdk.jfr.RecordingState; + + +public class TestLoadedAgent { + public static void main(String... arg) throws Exception { + long pid = ProcessHandle.current().pid(); + VirtualMachine vm = VirtualMachine.attach(Long.toString(pid)); + vm.loadAgent("EventEmitterAgent.jar"); + vm.detach(); + EventEmitterAgent.validateRecording(); + } +} diff --git a/test/jdk/jdk/jfr/javaagent/TestPremainAgent.java b/test/jdk/jdk/jfr/javaagent/TestPremainAgent.java new file mode 100644 index 00000000000..19a39ff7ef0 --- /dev/null +++ b/test/jdk/jdk/jfr/javaagent/TestPremainAgent.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019, 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 + * @key jfr + * @summary Tests emitting event before main using a Java agent + * @requires vm.hasJFR + * + * @library /test/lib + * @modules java.instrument + * + * @build jdk.jfr.javaagent.EventEmitterAgent + * + * @run driver jdk.test.lib.util.JavaAgentBuilder + * jdk.jfr.javaagent.EventEmitterAgent EventEmitterAgent.jar + * + * @run main/othervm -javaagent:EventEmitterAgent.jar jdk.jfr.javaagent.TestPremainAgent + */ + +package jdk.jfr.javaagent; + + +public class TestPremainAgent { + public static void main(String... arg) throws Exception { + EventEmitterAgent.validateRecording(); + } +} diff --git a/test/jdk/jdk/jfr/jmx/TestRecordingOptions.java b/test/jdk/jdk/jfr/jmx/TestRecordingOptions.java index 6ba4a51fdf0..7192eec3411 100644 --- a/test/jdk/jdk/jfr/jmx/TestRecordingOptions.java +++ b/test/jdk/jdk/jfr/jmx/TestRecordingOptions.java @@ -25,6 +25,7 @@ package jdk.jfr.jmx; +import java.io.File; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -49,7 +50,7 @@ public static void main(String[] args) throws Exception { options.put("dumpOnExit", "false"); options.put("disk", "false"); options.put("duration", "1 h"); // don't want recording to stop - + options.put("destination", "." + File.separator + "dump.jfr"); FlightRecorderMXBean bean = JmxHelper.getFlighteRecorderMXBean(); long recId = bean.newRecording(); Map defaults = bean.getRecordingOptions(recId); @@ -72,6 +73,7 @@ public static void main(String[] args) throws Exception { Asserts.assertEquals(outOptions.get("dumpOnExit"), "false", "Wrong dumpOnExit"); Asserts.assertEquals(outOptions.get("disk"), "false", "Wrong disk"); Asserts.assertEquals(outOptions.get("duration"), "1 h", "Wrong duration"); + Asserts.assertEquals(outOptions.get("destination"), "." + File.separator + "dump.jfr", "Wrong destination"); // try empty map bean.setRecordingOptions(recId, new HashMap<>()); @@ -116,6 +118,7 @@ public static void main(String[] args) throws Exception { nullMap.put("dumpOnExit", null); nullMap.put("disk", null); nullMap.put("duration", null); + nullMap.put("destination", null); bean.setRecordingOptions(recId, nullMap); Asserts.assertEquals(bean.getRecordingOptions(recId), defaults); diff --git a/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java b/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java index 29fc877cb75..77667547f35 100644 --- a/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java +++ b/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -24,6 +24,7 @@ */ package jdk.jfr.jvm; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -54,49 +55,70 @@ public class TestDumpOnCrash { private static final CharSequence LOG_FILE_EXTENSION = ".log"; private static final CharSequence JFR_FILE_EXTENSION = ".jfr"; - static class Crasher { + static class CrasherIllegalAccess { public static void main(String[] args) { Unsafe.getUnsafe().putInt(0L, 0); } } + static class CrasherHalt { + public static void main(String[] args) { + System.out.println("Running Runtime.getRuntime.halt"); + Runtime.getRuntime().halt(17); + } + } + + static class CrasherSig { + public static void main(String[] args) throws Exception { + String signalName = args[0]; + System.out.println("Sending SIG" + signalName + " to process " + ProcessHandle.current().pid()); + Runtime.getRuntime().exec("kill -" + signalName + " " + ProcessHandle.current().pid()).waitFor(); + } + } + public static void main(String[] args) throws Exception { - processOutput(runProcess()); + verify(runProcess(CrasherIllegalAccess.class.getName(), "", true)); + verify(runProcess(CrasherIllegalAccess.class.getName(), "", false)); + verify(runProcess(CrasherHalt.class.getName(), "", true)); + verify(runProcess(CrasherHalt.class.getName(), "", false)); + + // Verification is excluded for the test case below until 8219680 is fixed + long pid = runProcess(CrasherSig.class.getName(), "FPE", true); + // @ignore 8219680 + // verify(pid); } - private static OutputAnalyzer runProcess() throws Exception { - return new OutputAnalyzer( - ProcessTools.createJavaProcessBuilder(true, + private static long runProcess(String crasher, String signal, boolean disk) throws Exception { + System.out.println("Test case for crasher " + crasher); + final String flightRecordingOptions = "dumponexit=true,disk=" + Boolean.toString(disk); + Process p = ProcessTools.createJavaProcessBuilder(true, "-Xmx64m", - "-Xint", "-XX:-TransmitErrorReport", "-XX:-CreateCoredumpOnCrash", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:StartFlightRecording=dumponexit=true", - Crasher.class.getName()).start()); + "-XX:StartFlightRecording=" + flightRecordingOptions, + crasher, + signal) + .start(); + + OutputAnalyzer output = new OutputAnalyzer(p); + System.out.println("========== Crasher process output:"); + System.out.println(output.getOutput()); + System.out.println("=================================="); + + return p.pid(); } - private static void processOutput(OutputAnalyzer output) throws Exception { - output.shouldContain("CreateCoredumpOnCrash turned off, no core file dumped"); + private static void verify(long pid) throws IOException { + String fileName = "hs_err_pid" + pid + ".jfr"; + Path file = Paths.get(fileName).toAbsolutePath().normalize(); - final Path jfrEmergencyFilePath = getHsErrJfrPath(output); - Asserts.assertTrue(Files.exists(jfrEmergencyFilePath), "No emergency jfr recording file " + jfrEmergencyFilePath + " exists"); - Asserts.assertNotEquals(Files.size(jfrEmergencyFilePath), 0L, "File length 0. Should at least be some bytes"); - System.out.printf("File size=%d%n", Files.size(jfrEmergencyFilePath)); + Asserts.assertTrue(Files.exists(file), "No emergency jfr recording file " + file + " exists"); + Asserts.assertNotEquals(Files.size(file), 0L, "File length 0. Should at least be some bytes"); + System.out.printf("File size=%d%n", Files.size(file)); - List events = RecordingFile.readAllEvents(jfrEmergencyFilePath); + List events = RecordingFile.readAllEvents(file); Asserts.assertFalse(events.isEmpty(), "No event found"); System.out.printf("Found event %s%n", events.get(0).getEventType().getName()); } - - private static Path getHsErrJfrPath(OutputAnalyzer output) throws Exception { - // extract to find hs-err_pid log file location - final String hs_err_pid_log_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); - if (hs_err_pid_log_file == null) { - throw new RuntimeException("Did not find hs_err_pid.log file in output.\n"); - } - // the dumped out jfr file should have the same name and location but with a .jfr extension - final String hs_err_pid_jfr_file = hs_err_pid_log_file.replace(LOG_FILE_EXTENSION, JFR_FILE_EXTENSION); - return Paths.get(hs_err_pid_jfr_file); - } } diff --git a/test/jdk/jdk/jfr/startupargs/TestStartNoSettings.java b/test/jdk/jdk/jfr/startupargs/TestStartNoSettings.java new file mode 100644 index 00000000000..0a65d5eed75 --- /dev/null +++ b/test/jdk/jdk/jfr/startupargs/TestStartNoSettings.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019, 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.jfr.startupargs; + +import jdk.jfr.Event; +import jdk.jfr.EventType; +import jdk.jfr.FlightRecorder; +import jdk.jfr.Name; +import jdk.jfr.Recording; + +/** + * @test + * @summary Start a FlightRecording without any settings (not even default). + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.startupargs.TestStartNoSettings + * -XX:StartFlightRecording=settings=none + */ +public class TestStartNoSettings { + + @Name("UserEvent") + static class UserEvent extends Event { + } + + public static void main(String[] a) throws Exception { + boolean userEnabled = false; + try (Recording r = new Recording()) { + r.start(); + UserEvent e = new UserEvent(); + e.commit(); + for (EventType et : FlightRecorder.getFlightRecorder().getEventTypes()) { + if (et.isEnabled()) { + if (!et.getName().equals("UserEvent")) { + throw new Exception("Only 'UserEvent' should be enabled"); + } + userEnabled = true; + } + } + } + + if (!userEnabled) { + throw new Exception("Expected 'UserEvent' to be enabled with -XX:StartFlightRecording=settings=none"); + } + } +} diff --git a/test/jdk/jdk/jfr/cmd/ExecuteHelper.java b/test/jdk/jdk/jfr/tool/ExecuteHelper.java similarity index 88% rename from test/jdk/jdk/jfr/cmd/ExecuteHelper.java rename to test/jdk/jdk/jfr/tool/ExecuteHelper.java index dee5db70460..51347af5bd3 100644 --- a/test/jdk/jdk/jfr/cmd/ExecuteHelper.java +++ b/test/jdk/jdk/jfr/tool/ExecuteHelper.java @@ -23,16 +23,16 @@ * questions. */ -package jdk.jfr.cmd; +package jdk.jfr.tool; import java.nio.file.Path; -import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; import jdk.jfr.Configuration; import jdk.jfr.Event; import jdk.jfr.Recording; +import jdk.test.lib.JDKToolLauncher; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools;; @@ -53,18 +53,6 @@ static class CustomEvent extends Event { double trickyDouble; } - public static OutputAnalyzer run(String... args) { - String[] array = new String[args.length + 1]; - System.arraycopy(args, 0, array, 1, args.length); - array[0] = "jdk.jfr.internal.cmd.Execute"; - try { - return ProcessTools.executeTestJava(array); - } catch (Exception e) { - String message = String.format("Caught exception while executing '%s'", Arrays.asList(array)); - throw new RuntimeException(message, e); - } - } - public static void emitCustomEvents() { // Custom events with potentially tricky values CustomEvent event1 = new CustomEvent(); @@ -137,4 +125,12 @@ private static void provokeClassLoading() { Matcher m = p.matcher("aaaaab"); m.matches(); } + + public static OutputAnalyzer jfr(String... args) throws Throwable { + JDKToolLauncher l = JDKToolLauncher.createUsingTestJDK("jfr"); + for (String arg : args) { + l.addToolArg(arg); + } + return ProcessTools.executeCommand(l.getCommand()); + } } diff --git a/test/jdk/jdk/jfr/cmd/TestReconstruct.java b/test/jdk/jdk/jfr/tool/TestAssemble.java similarity index 80% rename from test/jdk/jdk/jfr/cmd/TestReconstruct.java rename to test/jdk/jdk/jfr/tool/TestAssemble.java index dc4e4738b96..0f21cceecd5 100644 --- a/test/jdk/jdk/jfr/cmd/TestReconstruct.java +++ b/test/jdk/jdk/jfr/tool/TestAssemble.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jfr.cmd; +package jdk.jfr.tool; import java.io.FileWriter; import java.io.IOException; @@ -48,9 +48,9 @@ * @requires vm.hasJFR * @library /test/lib /test/jdk * @modules jdk.jfr/jdk.jfr.internal - * @run main/othervm jdk.jfr.cmd.TestReconstruct + * @run main/othervm jdk.jfr.tool.TestAssemble */ -public class TestReconstruct { +public class TestAssemble { @Name("Correlation") static class CorrelationEvent extends Event { @@ -59,7 +59,7 @@ static class CorrelationEvent extends Event { private static int RECORDING_COUNT = 5; @SuppressWarnings("resource") - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Throwable { // Create some disk recordings Recording[] recordings = new Recording[5]; for (int i = 0; i < RECORDING_COUNT; i++) { @@ -89,33 +89,32 @@ public static void main(String[] args) throws Exception { String destination = destinationPath.toAbsolutePath().toString(); // Test failure - OutputAnalyzer output = ExecuteHelper.run("reconstruct"); + OutputAnalyzer output = ExecuteHelper.jfr("assemble"); + output.shouldContain("too few arguments"); - output.shouldContain("Too few arguments"); + output = ExecuteHelper.jfr("assemble", directory); + output.shouldContain("too few arguments"); - output = ExecuteHelper.run("reconstruct", directory); - output.shouldContain("Too few arguments"); + output = ExecuteHelper.jfr("assemble", "not-a-directory", destination); + output.shouldContain("directory does not exist, not-a-directory"); - output = ExecuteHelper.run("reconstruct", "not-a-directory", destination); - output.shouldContain("Could not find disk repository at"); + output = ExecuteHelper.jfr("assemble", directory, "not-a-destination"); + output.shouldContain("filename must end with '.jfr'"); - output = ExecuteHelper.run("reconstruct", directory, "not-a-destination"); - output.shouldContain("Filename must end with .jfr"); - - output = ExecuteHelper.run("reconstruct", "--wrongOption", directory, destination); - output.shouldContain("Too many arguments"); + output = ExecuteHelper.jfr("assemble", "--wrongOption", directory, destination); + output.shouldContain("too many arguments"); FileWriter fw = new FileWriter(destination); fw.write('d'); fw.close(); - output = ExecuteHelper.run("reconstruct", directory, destination); + output = ExecuteHelper.jfr("assemble", directory, destination); output.shouldContain("already exists"); Files.delete(destinationPath); // test success - output = ExecuteHelper.run("reconstruct", directory, destination); + output = ExecuteHelper.jfr("assemble", directory, destination); System.out.println(output.getOutput()); - output.shouldContain("Reconstruction complete"); + output.shouldContain("Finished."); long reconstructedCount = countEventInRecording(destinationPath); Asserts.assertEquals(expectedCount, reconstructedCount); diff --git a/test/jdk/jdk/jfr/cmd/TestSplit.java b/test/jdk/jdk/jfr/tool/TestDisassemble.java similarity index 70% rename from test/jdk/jdk/jfr/cmd/TestSplit.java rename to test/jdk/jdk/jfr/tool/TestDisassemble.java index dbce3875314..29d28531a02 100644 --- a/test/jdk/jdk/jfr/cmd/TestSplit.java +++ b/test/jdk/jdk/jfr/tool/TestDisassemble.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jfr.cmd; +package jdk.jfr.tool; import java.io.IOException; import java.nio.file.Files; @@ -44,59 +44,63 @@ * @key jfr * @requires vm.hasJFR * @library /test/lib /test/jdk - * @run main/othervm jdk.jfr.cmd.TestSplit + * @run main/othervm jdk.jfr.tool.TestDisassemble */ -public class TestSplit { +public class TestDisassemble { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Throwable { SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss"); String dateText = formatter.format(new Date()); Path recordingFileA = Paths.get("many-chunks-A-" + dateText + ".jfr"); Path recordingFileB = Paths.get("many-chunks-B-" + dateText + ".jfr"); + Path recordingFileC = Paths.get("many-chunks-C-" + dateText + ".jfr"); makeRecordingWithChunks(6, recordingFileA); Files.copy(recordingFileA, recordingFileB); + Files.copy(recordingFileA, recordingFileC); String fileAText = recordingFileA.toAbsolutePath().toString(); String fileBText = recordingFileB.toAbsolutePath().toString(); + String fileCText = recordingFileC.toAbsolutePath().toString(); - OutputAnalyzer output = ExecuteHelper.run("split"); - output.shouldContain("Missing file"); + OutputAnalyzer output = ExecuteHelper.jfr("disassemble"); + output.shouldContain("missing file"); - output = ExecuteHelper.run("split", "--wrongOption1", "..wrongOption2", "..wrongOption3", fileAText); - output.shouldContain("Too many arguments"); + output = ExecuteHelper.jfr("disassemble", "--wrongOption", fileAText); + output.shouldContain("unknown option"); - output = ExecuteHelper.run("split", "--wrongOption", fileAText); - output.shouldContain("Unknown option"); + output = ExecuteHelper.jfr("disassemble", "--wrongOption", "1", fileAText); + output.shouldContain("unknown option"); - output = ExecuteHelper.run("split", "--wrongOption", "1", fileAText); - output.shouldContain("Unknown option"); + output = ExecuteHelper.jfr("disassemble", "--max-chunks", "-3", fileAText); + output.shouldContain("max chunks must be at least 1"); - output = ExecuteHelper.run("split", "--maxchunks", "-3", fileAText); - output.shouldContain("Must be at least one chunk per file"); - - output = ExecuteHelper.run("split", "--maxchunks", "1000", fileAText); - output.shouldContain("Number of chunks in recording"); + output = ExecuteHelper.jfr("disassemble", "--max-chunks", "1000", fileAText); + output.shouldContain("number of chunks in recording"); output.shouldContain("doesn't exceed max chunks"); - output = ExecuteHelper.run("split", fileAText); // maxchunks is 5 by + output = ExecuteHelper.jfr("disassemble", fileAText); // maxchunks is 5 by // default System.out.println(output.getOutput()); System.out.println(fileAText); verifyRecording(fileAText.substring(0, fileAText.length() - 4) + "_1.jfr"); verifyRecording(fileAText.substring(0, fileAText.length() - 4) + "_2.jfr"); - output = ExecuteHelper.run("split", "--maxchunks", "2", fileBText); + output = ExecuteHelper.jfr("disassemble", "--max-chunks", "2", fileBText); verifyRecording(fileBText.substring(0, fileBText.length() - 4) + "_1.jfr"); verifyRecording(fileBText.substring(0, fileBText.length() - 4) + "_2.jfr"); verifyRecording(fileBText.substring(0, fileBText.length() - 4) + "_3.jfr"); - output = ExecuteHelper.run("split", "--maxchunks", "2", fileBText); + output = ExecuteHelper.jfr("disassemble", "--max-chunks", "2", fileBText); output.shouldContain("file with that name already exist"); + + // sanity check + output = ExecuteHelper.jfr("disassemble", "--max-size", "10000", fileCText); + verifyRecording(fileCText.substring(0, fileCText.length() - 4) + "_01.jfr"); } private static void verifyRecording(String name) throws IOException { - System.out.println("split name " + name); + System.out.println("Disassembling: " + name); try (RecordingFile rf = new RecordingFile(Paths.get(name))) { rf.readEvent(); } diff --git a/test/jdk/jdk/jfr/cmd/TestHelp.java b/test/jdk/jdk/jfr/tool/TestHelp.java similarity index 70% rename from test/jdk/jdk/jfr/cmd/TestHelp.java rename to test/jdk/jdk/jfr/tool/TestHelp.java index c6aa2c75379..406a68cd74c 100644 --- a/test/jdk/jdk/jfr/cmd/TestHelp.java +++ b/test/jdk/jdk/jfr/tool/TestHelp.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jfr.cmd; +package jdk.jfr.tool; import jdk.test.lib.process.OutputAnalyzer; @@ -33,25 +33,24 @@ * @key jfr * @requires vm.hasJFR * @library /test/lib /test/jdk - * @run main/othervm jdk.jfr.cmd.TestHelp + * @run main/othervm jdk.jfr.tool.TestHelp */ public class TestHelp { - public static void main(String[] args) throws Exception { - OutputAnalyzer output = ExecuteHelper.run("help"); - output.shouldContain("Available commands are:"); + public static void main(String[] args) throws Throwable { + OutputAnalyzer output = ExecuteHelper.jfr("help"); output.shouldContain("print"); - output.shouldContain("reconstruct"); + output.shouldContain("assemble"); + output.shouldContain("disassemble"); + output.shouldContain("metadata"); output.shouldContain("summary"); output.shouldContain("help"); - output = ExecuteHelper.run("help", "help"); - output.shouldContain("Available commands are:"); + output = ExecuteHelper.jfr("help", "version"); + output.shouldContain("Display version of the jfr tool"); + output.shouldContain("jfr version"); - output = ExecuteHelper.run("help", "wrongcommand"); - output.shouldContain("Unknown command"); - - output = ExecuteHelper.run("help", "wrongcommand", "wrongarguments"); - output.shouldContain("Too many arguments"); + output = ExecuteHelper.jfr("help", "wrongcommand"); + output.shouldContain("unknown command 'wrongcommand'"); } } diff --git a/test/jdk/jdk/jfr/tool/TestMetadata.java b/test/jdk/jdk/jfr/tool/TestMetadata.java new file mode 100644 index 00000000000..45cc55324f4 --- /dev/null +++ b/test/jdk/jdk/jfr/tool/TestMetadata.java @@ -0,0 +1,63 @@ +/* + * 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.jfr.tool; + +import java.nio.file.Path; + +import jdk.jfr.EventType; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.process.OutputAnalyzer; + +/** + * @test + * @summary Test jfr info + * @key jfr + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main/othervm jdk.jfr.tool.TestMetadata + */ +public class TestMetadata { + + public static void main(String[] args) throws Throwable { + Path f = ExecuteHelper.createProfilingRecording().toAbsolutePath(); + String file = f.toAbsolutePath().toString(); + + OutputAnalyzer output = ExecuteHelper.jfr("metadata"); + output.shouldContain("missing file"); + + output = ExecuteHelper.jfr("metadata", "--wrongOption", file); + output.shouldContain("unknown option --wrongOption"); + + output = ExecuteHelper.jfr("metadata", file); + try (RecordingFile rf = new RecordingFile(f)) { + for (EventType t : rf.readEventTypes()) { + String name = t.getName(); + name = name.substring(name.lastIndexOf(".") + 1); + output.shouldContain(name); + } + } + } +} diff --git a/test/jdk/jdk/jfr/cmd/TestPrint.java b/test/jdk/jdk/jfr/tool/TestPrint.java similarity index 69% rename from test/jdk/jdk/jfr/cmd/TestPrint.java rename to test/jdk/jdk/jfr/tool/TestPrint.java index b32269f6dfc..88c5ac0840a 100644 --- a/test/jdk/jdk/jfr/cmd/TestPrint.java +++ b/test/jdk/jdk/jfr/tool/TestPrint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ * questions. */ -package jdk.jfr.cmd; +package jdk.jfr.tool; import java.io.FileWriter; import java.nio.file.Files; @@ -38,29 +38,24 @@ * @key jfr * @requires vm.hasJFR * @library /test/lib /test/jdk - * @run main/othervm jdk.jfr.cmd.TestPrint + * @run main/othervm jdk.jfr.tool.TestPrint */ public class TestPrint { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Throwable { - OutputAnalyzer output = ExecuteHelper.run("print"); - output.shouldContain("Missing file"); + OutputAnalyzer output = ExecuteHelper.jfr("print"); + output.shouldContain("missing file"); - output = ExecuteHelper.run("print", "missing.jfr"); - output.shouldContain("Could not find file "); - - output = ExecuteHelper.run("print", "missing.jfr", "option1", "option2"); - output.shouldContain("Too many arguments"); + output = ExecuteHelper.jfr("print", "missing.jfr"); + output.shouldContain("could not open file "); Path file = Utils.createTempFile("faked-print-file", ".jfr"); FileWriter fw = new FileWriter(file.toFile()); fw.write('d'); fw.close(); - output = ExecuteHelper.run("print", "--wrongOption", file.toAbsolutePath().toString()); - output.shouldContain("Unknown option"); + output = ExecuteHelper.jfr("print", "--wrongOption", file.toAbsolutePath().toString()); + output.shouldContain("unknown option"); Files.delete(file); - - // Also see TestPrintJSON, TestPrintXML and TestPrintDefault. } } diff --git a/test/jdk/jdk/jfr/cmd/TestPrintDefault.java b/test/jdk/jdk/jfr/tool/TestPrintDefault.java similarity index 89% rename from test/jdk/jdk/jfr/cmd/TestPrintDefault.java rename to test/jdk/jdk/jfr/tool/TestPrintDefault.java index 1e7b022b9e6..a03b76d2f91 100644 --- a/test/jdk/jdk/jfr/cmd/TestPrintDefault.java +++ b/test/jdk/jdk/jfr/tool/TestPrintDefault.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jfr.cmd; +package jdk.jfr.tool; import java.nio.file.Path; @@ -39,15 +39,15 @@ * @modules java.scripting * jdk.jfr * - * @run main/othervm jdk.jfr.cmd.TestPrintDefault + * @run main/othervm jdk.jfr.tool.TestPrintDefault */ public class TestPrintDefault { - public static void main(String... args) throws Exception { + public static void main(String... args) throws Throwable { Path recordingFile = ExecuteHelper.createProfilingRecording().toAbsolutePath(); - OutputAnalyzer output = ExecuteHelper.run("print", recordingFile.toString()); + OutputAnalyzer output = ExecuteHelper.jfr("print", recordingFile.toString()); output.shouldContain("JVMInformation"); } } diff --git a/test/jdk/jdk/jfr/cmd/TestPrintJSON.java b/test/jdk/jdk/jfr/tool/TestPrintJSON.java similarity index 73% rename from test/jdk/jdk/jfr/cmd/TestPrintJSON.java rename to test/jdk/jdk/jfr/tool/TestPrintJSON.java index 6cf356c3377..71337904c98 100644 --- a/test/jdk/jdk/jfr/cmd/TestPrintJSON.java +++ b/test/jdk/jdk/jfr/tool/TestPrintJSON.java @@ -23,13 +23,19 @@ * questions. */ -package jdk.jfr.cmd; +package jdk.jfr.tool; import java.nio.file.Path; +import java.time.OffsetDateTime; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; +import jdk.jfr.Timespan; +import jdk.jfr.Timestamp; import jdk.jfr.ValueDescriptor; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordedObject; @@ -48,15 +54,15 @@ * @modules jdk.scripting.nashorn * jdk.jfr * - * @run main/othervm jdk.jfr.cmd.TestPrintJSON + * @run main/othervm jdk.jfr.tool.TestPrintJSON */ public class TestPrintJSON { - public static void main(String... args) throws Exception { + public static void main(String... args) throws Throwable { Path recordingFile = ExecuteHelper.createProfilingRecording().toAbsolutePath(); - OutputAnalyzer output = ExecuteHelper.run("print", "--json", recordingFile.toString()); + OutputAnalyzer output = ExecuteHelper.jfr("print", "--json", "--stack-depth", "999", recordingFile.toString()); String json = output.getStdout(); // Parse JSON using Nashorn @@ -66,22 +72,20 @@ public static void main(String... args) throws Exception { engine.eval(statement); JSObject o = (JSObject) engine.get("jsonObject"); JSObject recording = (JSObject) o.getMember("recording"); - JSObject events = (JSObject) recording.getMember("events"); + JSObject jsonEvents = (JSObject) recording.getMember("events"); + List events = RecordingFile.readAllEvents(recordingFile); + Collections.sort(events, (e1, e2) -> e1.getEndTime().compareTo(e2.getEndTime())); // Verify events are equal - try (RecordingFile rf = new RecordingFile(recordingFile)) { - for (Object jsonEvent : events.values()) { - RecordedEvent recordedEvent = rf.readEvent(); - double typeId = recordedEvent.getEventType().getId(); - String startTime = recordedEvent.getStartTime().toString(); - String duration = recordedEvent.getDuration().toString(); - Asserts.assertEquals(typeId, ((Number) ((JSObject) jsonEvent).getMember("typeId")).doubleValue()); - Asserts.assertEquals(startTime, ((JSObject) jsonEvent).getMember("startTime")); - Asserts.assertEquals(duration, ((JSObject) jsonEvent).getMember("duration")); - assertEquals(jsonEvent, recordedEvent); - } - Asserts.assertFalse(rf.hasMoreEvents(), "Incorrect number of events"); + Iterator it = events.iterator(); + + for (Object jsonEvent : jsonEvents.values()) { + RecordedEvent recordedEvent = it.next(); + String typeName = recordedEvent.getEventType().getName(); + Asserts.assertEquals(typeName, ((JSObject) jsonEvent).getMember("type").toString()); + assertEquals(jsonEvent, recordedEvent); } + Asserts.assertFalse(events.size() != jsonEvents.values().size(), "Incorrect number of events"); } private static void assertEquals(Object jsonObject, Object jfrObject) throws Exception { @@ -92,7 +96,17 @@ private static void assertEquals(Object jsonObject, Object jfrObject) throws Exc Asserts.assertEquals(values.values().size(), recObject.getFields().size()); for (ValueDescriptor v : recObject.getFields()) { String name = v.getName(); - assertEquals(values.getMember(name), recObject.getValue(name)); + Object jsonValue = values.getMember(name); + Object expectedValue = recObject.getValue(name); + if (v.getAnnotation(Timestamp.class) != null) { + // Make instant of OffsetDateTime + jsonValue = OffsetDateTime.parse("" + jsonValue).toInstant().toString(); + expectedValue = recObject.getInstant(name); + } + if (v.getAnnotation(Timespan.class) != null) { + expectedValue = recObject.getDuration(name); + } + assertEquals(jsonValue, expectedValue); return; } } diff --git a/test/jdk/jdk/jfr/cmd/TestPrintXML.java b/test/jdk/jdk/jfr/tool/TestPrintXML.java similarity index 71% rename from test/jdk/jdk/jfr/cmd/TestPrintXML.java rename to test/jdk/jdk/jfr/tool/TestPrintXML.java index c389953b121..f84ee1372c4 100644 --- a/test/jdk/jdk/jfr/cmd/TestPrintXML.java +++ b/test/jdk/jdk/jfr/tool/TestPrintXML.java @@ -23,35 +23,42 @@ * questions. */ -package jdk.jfr.cmd; +package jdk.jfr.tool; +import java.io.File; import java.io.StringReader; import java.nio.file.Path; -import java.time.Duration; -import java.time.Instant; +import java.time.OffsetDateTime; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Stack; +import javax.xml.XMLConstants; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; - -import jdk.jfr.ValueDescriptor; -import jdk.jfr.consumer.RecordedEvent; -import jdk.jfr.consumer.RecordedObject; -import jdk.jfr.consumer.RecordingFile; -import jdk.test.lib.process.OutputAnalyzer; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; +import jdk.jfr.Timespan; +import jdk.jfr.Timestamp; +import jdk.jfr.ValueDescriptor; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedObject; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.process.OutputAnalyzer; + /** * @test * @key jfr @@ -59,36 +66,49 @@ * @requires vm.hasJFR * * @library /test/lib /test/jdk - * @modules java.scripting - * java.xml - * jdk.jfr + * @modules java.scripting java.xml jdk.jfr * - * @run main/othervm jdk.jfr.cmd.TestPrintXML + * @run main/othervm jdk.jfr.tool.TestPrintXML */ public class TestPrintXML { - public static void main(String... args) throws Exception { + public static void main(String... args) throws Throwable { Path recordingFile = ExecuteHelper.createProfilingRecording().toAbsolutePath(); - OutputAnalyzer output = ExecuteHelper.run("print", "--xml", recordingFile.toString()); + OutputAnalyzer output = ExecuteHelper.jfr("print", "--xml", "--stack-depth", "9999", recordingFile.toString()); + System.out.println(recordingFile); String xml = output.getStdout(); - System.out.println(xml); - // Parse XML string + + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + Schema schema = schemaFactory.newSchema(new File(System.getProperty("test.src"), "jfr.xsd")); + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setSchema(schema); + factory.setNamespaceAware(true); + SAXParser sp = factory.newSAXParser(); XMLReader xr = sp.getXMLReader(); RecordingHandler handler = new RecordingHandler(); xr.setContentHandler(handler); + xr.setErrorHandler(handler); xr.parse(new InputSource(new StringReader(xml))); // Verify that all data was written correctly - Iterator it = RecordingFile.readAllEvents(recordingFile).iterator(); + List events = RecordingFile.readAllEvents(recordingFile); + Collections.sort(events, (e1, e2) -> e1.getEndTime().compareTo(e2.getEndTime())); + Iterator it = events.iterator(); for (XMLEvent xmlEvent : handler.events) { RecordedEvent re = it.next(); if (!compare(re, xmlEvent.values)) { + System.out.println("Expected:"); + System.out.println("----------------------"); System.out.println(re); - System.out.println(xmlEvent.values.toString()); + System.out.println(); + System.out.println("Was (XML)"); + System.out.println("----------------------"); + System.out.println(xmlEvent); + System.out.println(); throw new Exception("Event doesn't match"); } } @@ -109,7 +129,17 @@ static boolean compare(Object eventObject, Object xmlObject) { } for (ValueDescriptor v : fields) { String name = v.getName(); - if (!compare(re.getValue(name), xmlMap.get(name))) { + Object xmlValue = xmlMap.get(name); + Object expectedValue = re.getValue(name); + if (v.getAnnotation(Timestamp.class) != null) { + // Make instant of OffsetDateTime + xmlValue = OffsetDateTime.parse("" + xmlValue).toInstant().toString(); + expectedValue = re.getInstant(name); + } + if (v.getAnnotation(Timespan.class) != null) { + expectedValue = re.getDuration(name); + } + if (!compare(expectedValue, xmlValue)) { return false; } } @@ -135,14 +165,10 @@ static boolean compare(Object eventObject, Object xmlObject) { static class XMLEvent { String name; - Instant startTime; - Duration duration; - Map values = new HashMap<>(); + private Map values = new HashMap<>(); - XMLEvent(String name, Instant startTime, Duration duration) { + XMLEvent(String name) { this.name = name; - this.startTime = startTime; - this.duration = duration; } } @@ -155,15 +181,15 @@ public static final class RecordingHandler extends DefaultHandler { @Override public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { elements.push(new SimpleEntry<>(attrs.getValue("name"), attrs.getValue("index"))); - switch (qName) { - case "null": - objects.pop(); + String nil = attrs.getValue("xsi:nil"); + if ("true".equals(nil)) { objects.push(null); - break; + return; + } + + switch (qName) { case "event": - Instant startTime = Instant.parse(attrs.getValue("startTime")); - Duration duration = Duration.parse(attrs.getValue("duration")); - objects.push(new XMLEvent(attrs.getValue("name"), startTime, duration)); + objects.push(new XMLEvent(attrs.getValue("type"))); break; case "struct": objects.push(new HashMap()); @@ -218,5 +244,17 @@ public void endElement(String uri, String localName, String qName) { } } } + + public void warning(SAXParseException spe) throws SAXException { + throw new SAXException(spe); + } + + public void error(SAXParseException spe) throws SAXException { + throw new SAXException(spe); + } + + public void fatalError(SAXParseException spe) throws SAXException { + throw new SAXException(spe); + } } } diff --git a/test/jdk/jdk/jfr/cmd/TestSummary.java b/test/jdk/jdk/jfr/tool/TestSummary.java similarity index 82% rename from test/jdk/jdk/jfr/cmd/TestSummary.java rename to test/jdk/jdk/jfr/tool/TestSummary.java index 52a6a90fbbe..dcbc5a4da6f 100644 --- a/test/jdk/jdk/jfr/cmd/TestSummary.java +++ b/test/jdk/jdk/jfr/tool/TestSummary.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.jfr.cmd; +package jdk.jfr.tool; import java.nio.file.Path; @@ -37,21 +37,21 @@ * @key jfr * @requires vm.hasJFR * @library /test/lib /test/jdk - * @run main/othervm jdk.jfr.cmd.TestSummary + * @run main/othervm jdk.jfr.tool.TestSummary */ public class TestSummary { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Throwable { Path f = ExecuteHelper.createProfilingRecording().toAbsolutePath(); String file = f.toAbsolutePath().toString(); - OutputAnalyzer output = ExecuteHelper.run("summary"); - output.shouldContain("Missing file"); + OutputAnalyzer output = ExecuteHelper.jfr("summary"); + output.shouldContain("missing file"); - output = ExecuteHelper.run("summary", "--wrongOption", file); - output.shouldContain("Too many arguments"); + output = ExecuteHelper.jfr("summary", "--wrongOption", file); + output.shouldContain("too many arguments"); - output = ExecuteHelper.run("summary", file); + output = ExecuteHelper.jfr("summary", file); try (RecordingFile rf = new RecordingFile(f)) { for (EventType t : rf.readEventTypes()) { output.shouldContain(t.getName()); diff --git a/test/jdk/jdk/jfr/tool/jfr.xsd b/test/jdk/jdk/jfr/tool/jfr.xsd new file mode 100644 index 00000000000..adf44493f86 --- /dev/null +++ b/test/jdk/jdk/jfr/tool/jfr.xsd @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/jdk/jdk/nio/zipfs/Basic.java b/test/jdk/jdk/nio/zipfs/Basic.java index 54c10c136f5..e3831ff75ea 100644 --- a/test/jdk/jdk/nio/zipfs/Basic.java +++ b/test/jdk/jdk/nio/zipfs/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ import java.nio.file.AccessMode; import java.nio.file.ClosedFileSystemException; -import java.nio.file.DirectoryStream; import java.nio.file.FileStore; import java.nio.file.FileSystem; import java.nio.file.FileSystems; @@ -87,18 +86,6 @@ public static void main(String[] args) throws Exception { // Test: exercise directory iterator and retrieval of basic attributes Files.walkFileTree(fs.getPath("/"), new FileTreePrinter()); - // Test: DirectoryStream - found = false; - try (DirectoryStream stream = Files.newDirectoryStream(fs.getPath("/"))) { - for (Path entry: stream) { - found = entry.toString().equals("/META-INF"); - if (found) break; - } - } - - if (!found) - throw new RuntimeException("Expected file not found"); - // Test: copy file from zip file to current (scratch) directory Path source = fs.getPath("/META-INF/services/java.nio.file.spi.FileSystemProvider"); if (Files.exists(source)) { @@ -133,6 +120,8 @@ public static void main(String[] args) throws Exception { try { fs.provider().checkAccess(fs.getPath("/missing"), AccessMode.READ); } catch (ClosedFileSystemException x) { } + + Files.deleteIfExists(jarFile); } // FileVisitor that pretty prints a file tree diff --git a/test/jdk/jdk/nio/zipfs/DirectoryStreamTests.java b/test/jdk/jdk/nio/zipfs/DirectoryStreamTests.java new file mode 100644 index 00000000000..a8fc0ebad47 --- /dev/null +++ b/test/jdk/jdk/nio/zipfs/DirectoryStreamTests.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.spi.FileSystemProvider; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.regex.PatternSyntaxException; +import java.util.zip.ZipException; + +import static org.testng.Assert.*; + +/** + * @test + * @bug 8211385 8211919 + * @summary ZIP File System tests that leverage DirectoryStream + * @modules jdk.zipfs + * @compile DirectoryStreamTests.java + * @run testng DirectoryStreamTests + * @run testng/othervm/java.security.policy=test.policy DirectoryStreamTests + */ +public class DirectoryStreamTests { + + // Map to used for creating a ZIP archive + private static final Map ZIPFS_MAP = Map.of("create", "true"); + + // Map to used for extracting a ZIP archive + private static final Map UNZIPFS_MAP = Map.of(); + + // The ZIP file system provider + private static final FileSystemProvider ZIPFS_PROVIDER = getZipFSProvider(); + + // Primary jar file used for testing + private static Path jarFile; + + // Jar file used to validate the behavior of the navigation of an empty directory + private static Path emptyJarFile; + + /** + * Create the JAR files used by the tests + */ + @BeforeClass + public void setUp() throws Exception { + emptyJarFile = Paths.get("emptyDir.jar"); + try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(emptyJarFile, ZIPFS_MAP)) { + + jarFile = Utils.createJarFile("basic.jar", + "META-INF/services/java.nio.file.spi.FileSystemProvider"); + + Files.createDirectory(zipfs.getPath("emptyDir")); + } + } + + /** + * Remove JAR files used by test as part of clean-up + */ + @AfterClass + public void tearDown() throws Exception { + Files.deleteIfExists(jarFile); + Files.deleteIfExists(emptyJarFile); + } + + /** + * Validate that you can specify a DirectoryStream filter using the ZIP File + * System and that the returned Iterator correctly indicates whether the + * filter has been matched + */ + @Test(dataProvider = "filterTestValues") + public void test0000(String glob, boolean expectedResult, String errMsg) + throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP); + DirectoryStream ds = Files.newDirectoryStream(zipfs.getPath("/"), + new DirectoryStream.Filter() { + private PathMatcher matcher = + zipfs.getPathMatcher("glob:" + glob); + public boolean accept(Path file) { + return matcher.matches(file.getFileName()); + } + })) + { + assertEquals(ds.iterator().hasNext(), expectedResult, errMsg); + } + } + + /** + * Validate that you can specify a glob using the ZIP File System and that the + * returned Iterator correctly indicates whether the glob pattern has been matched + */ + @Test(dataProvider = "filterTestValues") + public void test0001(String glob, boolean expectedResult, String errMsg) + throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP); + DirectoryStream ds = + Files.newDirectoryStream(zipfs.getPath("/"), glob)) { + assertEquals(ds.iterator().hasNext(), expectedResult, errMsg); + } + } + + /** + * Validate a PatternSyntaxException is thrown when specifying an invalid + * glob pattern with the ZIP File system + */ + @Test + public void test0002() throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP)) { + assertThrows(PatternSyntaxException.class, () -> + Files.newDirectoryStream(zipfs.getPath("/"), "*[a-z")); + } + } + + /** + * Validate that the correct type of paths are returned when creating a + * DirectoryStream + */ + @Test(dataProvider = "startPaths") + public void test0003(String startPath, String expectedPath) + throws IOException { + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP); + DirectoryStream stream = + Files.newDirectoryStream(zipfs.getPath(startPath))) { + + for (Path entry : stream) { + assertTrue(entry.toString().equals(expectedPath), + String.format("Error: Expected path %s not found when" + + " starting at %s%n", expectedPath, entry)); + } + } + } + + /** + * Validate a NotDirectoryException is thrown when specifying a file for the + * starting path for creating a DirectoryStream with the ZIP File System + */ + @Test + public void test0004() throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP)) { + assertThrows(NotDirectoryException.class, + () -> Files.newDirectoryStream( + zipfs.getPath("META-INF/services/java.nio.file.spi." + + "FileSystemProvider"))); + } + } + + /** + * Validate an IllegalStateException is thrown when accessing the Iterator + * more than once with the ZIP File System + */ + @Test + public void test0005() throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP); + DirectoryStream ds = + Files.newDirectoryStream(zipfs.getPath("/"))) { + ds.iterator(); + assertThrows(IllegalStateException.class, () -> ds.iterator()); + + } + } + + /** + * Validate an IllegalStateException is thrown when accessing the Iterator + * after the DirectoryStream has been closed with the ZIP File System + */ + @Test + public void test0006() throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP); + DirectoryStream ds = + Files.newDirectoryStream(zipfs.getPath("/"))) { + ds.close(); + assertThrows(IllegalStateException.class, () -> ds.iterator()); + + // ZipDirectoryStream.iterator() throws ClosedDirectoryStream when + // obtaining an Iterator when the DirectoryStream is closed + assertThrows(ClosedDirectoryStreamException.class, () -> ds.iterator()); + + } + } + + /** + * Validate an UnsupportedOperationException is thrown when invoking an + * Iterator operation that is not supported with the ZIP File System + */ + @Test + public void test0007() throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP); + DirectoryStream ds = + Files.newDirectoryStream(zipfs.getPath("/"))) { + Iterator i = ds.iterator(); + + assertThrows(UnsupportedOperationException.class, () -> i.remove()); + } + } + + /** + * Validate an NoSuchElementException is thrown when invoking an + * Iterator.next() on a closed DirectoryStream with the ZIP File System + */ + @Test + public void test0008() throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP); + DirectoryStream ds = + Files.newDirectoryStream(zipfs.getPath("/"))) { + Iterator i = ds.iterator(); + ds.close(); + assertThrows(NoSuchElementException.class, () -> i.next()); + } + } + + /** + * Validate Iterator.hasNext() returns false when the directory is empty with + * the ZIP File System + */ + @Test + public void test0009() throws Exception { + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(emptyJarFile, UNZIPFS_MAP); + DirectoryStream ds = + Files.newDirectoryStream(zipfs.getPath("emptyDir"))) { + assertFalse(ds.iterator().hasNext(), "Error: directory was not empty!"); + + } + } + + /** + * Validate Iterator.hasNext() returns false when the DirectoryStream is closed + * with the ZIP File System + */ + @Test + public void test0010() throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP); + DirectoryStream ds = + Files.newDirectoryStream(zipfs.getPath("/"))) { + Iterator i = ds.iterator(); + ds.close(); + assertFalse(i.hasNext(), + "Error: false should be returned as DirectoryStream is closed!"); + } + } + + /** + * Validate that an IOException thrown by a filter is returned as the cause + * via a DirectoryIteratorException + */ + @Test + public void test0011() throws Exception { + + try (FileSystem zipfs = + ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), UNZIPFS_MAP); + DirectoryStream ds = Files.newDirectoryStream(zipfs.getPath("/"), + new DirectoryStream.Filter() { + public boolean accept(Path file) throws IOException { + throw new java.util.zip.ZipException(); + } + })) + { + ds.iterator().hasNext(); + throw new RuntimeException("Expected DirectoryIteratorException not thrown"); + + } catch (DirectoryIteratorException x) { + IOException cause = x.getCause(); + if (!(cause instanceof ZipException)) + throw new RuntimeException("Expected IOException not propagated"); + } + } + + /** + * Glob values to use to validate filtering + */ + @DataProvider(name = "filterTestValues") + public static Object[][] filterValues() { + + String expectedMsg = "Error: Matching entries were expected but not found!!!"; + String notExpectedMsg = "Error: No matching entries expected but were found!!!"; + return new Object[][]{ + + {"M*", true, expectedMsg}, + {"I*", false, notExpectedMsg} + }; + } + + /** + * Starting Path for the DirectoryStream and the expected path to be returned + * when traversing the stream + */ + @DataProvider(name = "startPaths") + public static Object[][] Name() { + return new Object[][]{ + + {"META-INF", "META-INF/services"}, + {"/META-INF", "/META-INF/services"}, + {"/META-INF/../META-INF","/META-INF/../META-INF/services" }, + {"./META-INF", "./META-INF/services"}, + {"", "META-INF"}, + {"/", "/META-INF"}, + {".", "./META-INF"}, + {"./", "./META-INF"} + }; + } + + /** + * Returns the Zip FileSystem Provider + */ + private static FileSystemProvider getZipFSProvider() { + for (FileSystemProvider fsProvider : FileSystemProvider.installedProviders()) { + if ("jar".equals(fsProvider.getScheme())) { + return fsProvider; + } + } + return null; + } + +} diff --git a/test/jdk/jdk/nio/zipfs/InvalidZipHeaderTests.java b/test/jdk/jdk/nio/zipfs/InvalidZipHeaderTests.java new file mode 100644 index 00000000000..7d9419a05f0 --- /dev/null +++ b/test/jdk/jdk/nio/zipfs/InvalidZipHeaderTests.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.stream.Collectors; + +import static java.nio.file.Files.walk; +import static org.testng.Assert.*; + +/** + * @test + * @bug 8222807 + * @summary Validate that you can iterate a ZIP file with invalid ZIP header entries + * @modules jdk.zipfs + * @compile InvalidZipHeaderTests.java + * @run testng InvalidZipHeaderTests + * @run testng/othervm/java.security.policy=test.policy InvalidZipHeaderTests + */ +public class InvalidZipHeaderTests { + + + // Name of Jar file used in tests + private static final String INVALID_JAR_FILE = "invalid.jar"; + + /** + * Create the JAR files used by the tests + */ + @BeforeClass + public void setUp() throws Exception { + createInvalidJarFile(); + } + + /** + * Remove JAR files used by test as part of clean-up + */ + @AfterClass + public void tearDown() throws Exception { + Files.deleteIfExists(Path.of(INVALID_JAR_FILE)); + } + + + /** + * Validate that you can walk a ZIP archive with header entries + * such as "foo//" + */ + @Test(dataProvider = "startPaths") + public void walkInvalidHeaderTest(String startPath, List expectedPaths) + throws IOException { + try (FileSystem zipfs = + FileSystems.newFileSystem(Path.of(INVALID_JAR_FILE), null)) { + List result = walk(zipfs.getPath(startPath)) + .map(f -> f.toString()).collect(Collectors.toList()); + assertTrue(result.equals(expectedPaths), + String.format("Error: Expected paths not found when walking" + + "%s, starting at %s%n", INVALID_JAR_FILE, + startPath)); + } + } + + + /** + * Starting Path for walking the ZIP archive and the expected paths to be returned + * when traversing the archive + */ + @DataProvider(name = "startPaths") + public static Object[][] Name() { + return new Object[][]{ + + {"luckydog", List.of("luckydog", "luckydog/outfile.txt")}, + {"/luckydog", List.of("/luckydog", "/luckydog/outfile.txt")}, + {"./luckydog", List.of("./luckydog", "./luckydog/outfile.txt")}, + {"", List.of( "", "luckydog", "luckydog/outfile.txt")}, + {"/", List.of("/", "/luckydog", "/luckydog/outfile.txt")}, + {".", List.of(".", "./luckydog", "./luckydog/outfile.txt")}, + {"./", List.of(".", "./luckydog", "./luckydog/outfile.txt")} + }; + } + + /** + * Create a jar file with invalid CEN and LOC headers + * @throws IOException + */ + static void createInvalidJarFile() throws IOException { + + try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(INVALID_JAR_FILE))) { + JarEntry je = new JarEntry("luckydog//"); + jos.putNextEntry(je); + jos.closeEntry(); + je = new JarEntry("luckydog//outfile.txt"); + jos.putNextEntry(je); + jos.write("Tennis Anyone!!".getBytes()); + jos.closeEntry(); + } + } + +} diff --git a/test/jdk/jdk/nio/zipfs/jarfs/JFSTester.java b/test/jdk/jdk/nio/zipfs/jarfs/JFSTester.java index 78a663f7a7f..8bd2a2d9fc5 100644 --- a/test/jdk/jdk/nio/zipfs/jarfs/JFSTester.java +++ b/test/jdk/jdk/nio/zipfs/jarfs/JFSTester.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +23,16 @@ /* * @test - * @bug 8164389 + * @bug 8164389 8222440 * @summary walk entries in a jdk.nio.zipfs.JarFileSystem - * @modules jdk.jartool/sun.tools.jar + * @library /lib/testlibrary/java/util/jar + * @modules jdk.jartool * jdk.zipfs + * @build Compiler JarBuilder * @run testng JFSTester */ import org.testng.Assert; -import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -50,57 +51,76 @@ public class JFSTester { private URI jarURI; - private Path jarfile; + + final private String root_dir1_leaf1_txt = "This is leaf 1." + System.lineSeparator(); + final private String root_dir1_leaf2_txt = "This is leaf 2." + System.lineSeparator(); + final private String root_dir2_leaf3_txt = "This is leaf 3." + System.lineSeparator(); + final private String root_dir2_leaf4_txt = "This is leaf 4." + System.lineSeparator(); + final private String v9_root_dir2_leaf3_txt = "This is version 9 leaf 3." + System.lineSeparator(); + final private String v9_root_dir2_leaf4_txt = "This is version 9 leaf 4." + System.lineSeparator(); + final private String v9_root_dir3_leaf5_txt = "This is version 9 leaf 5." + System.lineSeparator(); + final private String v9_root_dir3_leaf6_txt = "This is version 9 leaf 6." + System.lineSeparator(); + final private String v10_root_dir3_leaf5_txt = "This is version 10 leaf 5." + System.lineSeparator(); + final private String v10_root_dir3_leaf6_txt = "This is version 10 leaf 6." + System.lineSeparator(); @BeforeClass public void initialize() throws Exception { - String userdir = System.getProperty("user.dir","."); - jarfile = Paths.get(userdir, "test.jar"); - String srcdir = System.getProperty("test.src"); - String[] args = ( - "-cf " - + jarfile.toString() - + " -C " - + srcdir - + " root --release 9 -C " - + srcdir - + System.getProperty("file.separator") - + "v9 root" - ).split(" +"); - new sun.tools.jar.Main(System.out, System.err, "jar").run(args); - String ssp = jarfile.toUri().toString(); - jarURI = new URI("jar", ssp, null); - } - - @AfterClass - public void close() throws IOException { - Files.deleteIfExists(jarfile); + Path jarfile = Paths.get("test.jar"); + JarBuilder jb = new JarBuilder(jarfile.toString()); + jb.addAttribute("Multi-Release", "true"); + jb.addEntry("root/dir1/leaf1.txt", root_dir1_leaf1_txt.getBytes()); + jb.addEntry("root/dir1/leaf2.txt", root_dir1_leaf2_txt.getBytes()); + jb.addEntry("root/dir2/leaf3.txt", root_dir2_leaf3_txt.getBytes()); + jb.addEntry("root/dir2/leaf4.txt", root_dir2_leaf4_txt.getBytes()); + jb.addEntry("META-INF/versions/9/root/dir2/leaf3.txt", v9_root_dir2_leaf3_txt.getBytes()); + jb.addEntry("META-INF/versions/9/root/dir2/leaf4.txt", v9_root_dir2_leaf4_txt.getBytes()); + jb.addEntry("META-INF/versions/9/root/dir3/leaf5.txt", v9_root_dir3_leaf5_txt.getBytes()); + jb.addEntry("META-INF/versions/9/root/dir3/leaf6.txt", v9_root_dir3_leaf6_txt.getBytes()); + jb.addEntry("META-INF/versions/10/root/dir3/leaf5.txt", v10_root_dir3_leaf5_txt.getBytes()); + jb.addEntry("META-INF/versions/10/root/dir3/leaf6.txt", v10_root_dir3_leaf6_txt.getBytes()); + jb.build(); + System.out.println("Created " + jarfile + ": " + Files.exists(jarfile)); + jarURI = new URI("jar", jarfile.toUri().toString(), null); } @Test public void testWalk() throws IOException { - - // no configuration, treat multi-release jar as unversioned - Map env = new HashMap<>(); + // treat multi-release jar as unversioned + Map env = new HashMap<>(); Set contents = doTest(env); - Set baseContents = Set.of( - "This is leaf 1.\n", - "This is leaf 2.\n", - "This is leaf 3.\n", - "This is leaf 4.\n" + Set expectedContents = Set.of( + root_dir1_leaf1_txt, + root_dir1_leaf2_txt, + root_dir2_leaf3_txt, + root_dir2_leaf4_txt ); - Assert.assertEquals(contents, baseContents); + Assert.assertEquals(contents, expectedContents); - // a configuration and jar file is multi-release + // open file as multi-release for version 9 env.put("multi-release", "9"); contents = doTest(env); - Set versionedContents = Set.of( - "This is versioned leaf 1.\n", - "This is versioned leaf 2.\n", - "This is versioned leaf 3.\n", - "This is versioned leaf 4.\n" + expectedContents = Set.of( + root_dir1_leaf1_txt, + root_dir1_leaf2_txt, + v9_root_dir2_leaf3_txt, + v9_root_dir2_leaf4_txt, + v9_root_dir3_leaf5_txt, + v9_root_dir3_leaf6_txt + ); + Assert.assertEquals(contents, expectedContents); + + // open file as multi-release for version 10 + env.put("multi-release", "10"); + contents = doTest(env); + expectedContents = Set.of( + root_dir1_leaf1_txt, + root_dir1_leaf2_txt, + v9_root_dir2_leaf3_txt, + v9_root_dir2_leaf4_txt, + v10_root_dir3_leaf5_txt, + v10_root_dir3_leaf6_txt ); - Assert.assertEquals(contents, versionedContents); + Assert.assertEquals(contents, expectedContents); } private Set doTest(Map env) throws IOException { @@ -108,9 +128,10 @@ private Set doTest(Map env) throws IOException { try (FileSystem fs = FileSystems.newFileSystem(jarURI, env)) { Path root = fs.getPath("root"); contents = Files.walk(root) - .filter(p -> !Files.isDirectory(p)) - .map(this::pathToContents) - .collect(Collectors.toSet()); + .filter(p -> !Files.isDirectory(p)) + .map(this::pathToContents) + .sorted() + .collect(Collectors.toSet()); } return contents; } diff --git a/test/jdk/jdk/nio/zipfs/jarfs/root/dir1/leaf1.txt b/test/jdk/jdk/nio/zipfs/jarfs/root/dir1/leaf1.txt deleted file mode 100644 index 05f9592a818..00000000000 --- a/test/jdk/jdk/nio/zipfs/jarfs/root/dir1/leaf1.txt +++ /dev/null @@ -1 +0,0 @@ -This is leaf 1. diff --git a/test/jdk/jdk/nio/zipfs/jarfs/root/dir1/leaf2.txt b/test/jdk/jdk/nio/zipfs/jarfs/root/dir1/leaf2.txt deleted file mode 100644 index 19229fa2322..00000000000 --- a/test/jdk/jdk/nio/zipfs/jarfs/root/dir1/leaf2.txt +++ /dev/null @@ -1 +0,0 @@ -This is leaf 2. diff --git a/test/jdk/jdk/nio/zipfs/jarfs/root/dir2/leaf3.txt b/test/jdk/jdk/nio/zipfs/jarfs/root/dir2/leaf3.txt deleted file mode 100644 index 724fae66d88..00000000000 --- a/test/jdk/jdk/nio/zipfs/jarfs/root/dir2/leaf3.txt +++ /dev/null @@ -1 +0,0 @@ -This is leaf 3. diff --git a/test/jdk/jdk/nio/zipfs/jarfs/root/dir2/leaf4.txt b/test/jdk/jdk/nio/zipfs/jarfs/root/dir2/leaf4.txt deleted file mode 100644 index 3fafaadeda0..00000000000 --- a/test/jdk/jdk/nio/zipfs/jarfs/root/dir2/leaf4.txt +++ /dev/null @@ -1 +0,0 @@ -This is leaf 4. diff --git a/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir1/leaf1.txt b/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir1/leaf1.txt deleted file mode 100644 index 9092c1883d3..00000000000 --- a/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir1/leaf1.txt +++ /dev/null @@ -1 +0,0 @@ -This is versioned leaf 1. diff --git a/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir1/leaf2.txt b/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir1/leaf2.txt deleted file mode 100644 index 9a2d266edf1..00000000000 --- a/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir1/leaf2.txt +++ /dev/null @@ -1 +0,0 @@ -This is versioned leaf 2. diff --git a/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir2/leaf3.txt b/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir2/leaf3.txt deleted file mode 100644 index 6491cae8b83..00000000000 --- a/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir2/leaf3.txt +++ /dev/null @@ -1 +0,0 @@ -This is versioned leaf 3. diff --git a/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir2/leaf4.txt b/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir2/leaf4.txt deleted file mode 100644 index aa5563cb709..00000000000 --- a/test/jdk/jdk/nio/zipfs/jarfs/v9/root/dir2/leaf4.txt +++ /dev/null @@ -1 +0,0 @@ -This is versioned leaf 4. diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/ComodoCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/ComodoCA.java index e3edae41261..3b3466116ef 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/ComodoCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/ComodoCA.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8189131 + * @bug 8189131 8231887 * @summary Interoperability tests with Comodo RSA, ECC, userTrust RSA, and * userTrust ECC CAs * @build ValidatePathWithParams @@ -110,6 +110,59 @@ class ComodoRSA { + "pLwltum95OmYdBbxN4SBB7SC\n" + "-----END CERTIFICATE-----"; + // Owner: CN=comodorsacertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, O=Sectigo Limited, + // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, + // OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.3=GB, + // SERIALNUMBER=04058690 + // Issuer: CN=COMODO RSA Extended Validation Secure Server CA, O=COMODO CA Limited, L=Salford, + // ST=Greater Manchester, C=GB + // Serial number: a0c7cabcc25ed9358ded02cc1d485545 + // Valid from: Sun Sep 29 17:00:00 PDT 2019 until: Tue Dec 28 15:59:59 PST 2021 + private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIH0TCCBrmgAwIBAgIRAKDHyrzCXtk1je0CzB1IVUUwDQYJKoZIhvcNAQELBQAw\n" + + "gZIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\n" + + "BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYD\n" + + "VQQDEy9DT01PRE8gUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl\n" + + "ciBDQTAeFw0xOTA5MzAwMDAwMDBaFw0yMTEyMjgyMzU5NTlaMIIBPjERMA8GA1UE\n" + + "BRMIMDQwNTg2OTAxEzARBgsrBgEEAYI3PAIBAxMCR0IxHTAbBgNVBA8TFFByaXZh\n" + + "dGUgT3JnYW5pemF0aW9uMQswCQYDVQQGEwJHQjEPMA0GA1UEERMGTTUgM0VRMRAw\n" + + "DgYDVQQHEwdTYWxmb3JkMRYwFAYDVQQJEw1UcmFmZm9yZCBSb2FkMRYwFAYDVQQJ\n" + + "Ew1FeGNoYW5nZSBRdWF5MSUwIwYDVQQJExwzcmQgRmxvb3IsIDI2IE9mZmljZSBW\n" + + "aWxsYWdlMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxGjAYBgNVBAsTEUNPTU9E\n" + + "TyBFViBTR0MgU1NMMTgwNgYDVQQDEy9jb21vZG9yc2FjZXJ0aWZpY2F0aW9uYXV0\n" + + "aG9yaXR5LWV2LmNvbW9kb2NhLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n" + + "AQoCggEBAND/eZQBTjpBDsuteKwl+zpTitF8tJzwHAhcQHC2AaLF/GJl1rnjx4Of\n" + + "elMhKhN1Od9KU6onHGOd2w4mD4EiYK9TpXwuwTyzfkCmnkqxZjYK3KAJN013o4L+\n" + + "8y1zsGVUulpN/GfMaxTb4XdmeSekTP91Phw3xezijBq3sa++1rO5RBaT1IHeHhHv\n" + + "iC9WNrG8CIg/j5MyC9i43LZHiRXLER1LzT/MCIRsiG5AEbiYXV5BNd5SiiHtBJ1q\n" + + "0ZJH+AxL2ERaT41VCppboZwThmJGGoky9FWjp6z8U6Enx0fAMJIZNEzW6LAJFKPE\n" + + "ynEU004jFFCEumPUqqCC4ogxulphY80CAwEAAaOCA3EwggNtMB8GA1UdIwQYMBaA\n" + + "FDna/8ooFIqodBMIueQOqdL6fp1pMB0GA1UdDgQWBBQ+S4ZhIrwOoeGs9BBT4uXq\n" + + "89Ux/jAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggr\n" + + "BgEFBQcDAQYIKwYBBQUHAwIwTwYDVR0gBEgwRjA7BgwrBgEEAbIxAQIBBQEwKzAp\n" + + "BggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9DUFMwBwYFZ4EM\n" + + "AQEwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09N\n" + + "T0RPUlNBRXh0ZW5kZWRWYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGHBggr\n" + + "BgEFBQcBAQR7MHkwUQYIKwYBBQUHMAKGRWh0dHA6Ly9jcnQuY29tb2RvY2EuY29t\n" + + "L0NPTU9ET1JTQUV4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAk\n" + + "BggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMDoGA1UdEQQzMDGC\n" + + "L2NvbW9kb3JzYWNlcnRpZmljYXRpb25hdXRob3JpdHktZXYuY29tb2RvY2EuY29t\n" + + "MIIBfQYKKwYBBAHWeQIEAgSCAW0EggFpAWcAdQDuS723dc5guuFCaR+r4Z5mow9+\n" + + "X7By2IMAxHuJeqj9ywAAAW2DAXefAAAEAwBGMEQCIDqP1einOiPHnaG1fOZMDrEc\n" + + "RAxjq3vEl94fp4pkmke7AiBsJOvPE6irgcOO1/lnP7NRuln7iPJjU7T20PEK5/rm\n" + + "KwB2AFWB1MIWkDYBSuoLm1c8U/DA5Dh4cCUIFy+jqh0HE9MMAAABbYMBd0kAAAQD\n" + + "AEcwRQIhALgUI5XxM1NHbJDdr19h2pe3LhzK4tpuB/OQ9BgCyrGXAiBdr6mNCB/G\n" + + "rbdVx0u7iezwC7mq7iaWugR3rrWlSA8fWQB2ALvZ37wfinG1k5Qjl6qSe0c4V5UK\n" + + "q1LoGpCWZDaOHtGFAAABbYMBd1oAAAQDAEcwRQIgXbG32dagMeLhuZb+LSpJO1vI\n" + + "BmxmRnNdiz5FbG9cCbwCIQCr1X9f+ebT5fhlDUNBURUorTtM8QQciBiueBqvHk7+\n" + + "1DANBgkqhkiG9w0BAQsFAAOCAQEAM/A/1dgoc5NP1n+w3SX9qWcN7QT7ExdrnZSl\n" + + "Ygn0PF2fx4gz7cvNKucbpQJNA4C9awGydyYK8/o5KDUXt3K7eb1OAZ/NZBjygsJs\n" + + "ikXvxlBh8oEoqBOfOtr24l0NGUWnP8Qeu/VPcIMER4V8qX+in0pCXkSd67nkp6Bs\n" + + "EcqhDPgmzdSC1gQHsZuBdotG14OfdH1cG1bRK6GadISLG1h8BFukVem42B149v8F\n" + + "MCIUQAYprAVv2WlTZKBx9XzuK6IK3+klHZ07Jfvjvt7PPG5HKSMWBMnMaTHKcyQI\n" + + "G3t91yw7BnNNInZlBSsFtqjbHhDcr7uruZdbi0rerSsi2qDr0w==\n" + + "-----END CERTIFICATE-----"; + // Owner: CN=comodorsacertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, O=Sectigo Limited, // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, // ST=Greater Manchester, OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, @@ -118,7 +171,7 @@ class ComodoRSA { // ST=Greater Manchester, C=GB // Serial number: d3df2597cbed1ab6e02ee82021771614 // Valid from: Wed Nov 28 16:00:00 PST 2018 until: Fri Feb 26 15:59:59 PST 2021 - private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + "MIIH7jCCBtagAwIBAgIRANPfJZfL7Rq24C7oICF3FhQwDQYJKoZIhvcNAQELBQAw\n" + "gZIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\n" + "BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYD\n" + @@ -164,60 +217,6 @@ class ComodoRSA { "YrTYerPngjPbZB0bfLOja0vb\n" + "-----END CERTIFICATE-----"; - // Owner: CN=comodorsacertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, O=COMODO CA Limited, - // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, - // ST=Greater Manchester, OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, - // OID.1.3.6.1.4.1.311.60.2.1.3=GB, SERIALNUMBER=04058690 - // Issuer: CN=COMODO RSA Extended Validation Secure Server CA, O=COMODO CA Limited, L=Salford, - // ST=Greater Manchester, C=GB - // Serial number: 720aa2cfa40094521224f901a984b167 - // Valid from: Thu Jun 29 17:00:00 PDT 2017 until: Sun Sep 29 16:59:59 PDT 2019 - private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + - "MIIH8jCCBtqgAwIBAgIQcgqiz6QAlFISJPkBqYSxZzANBgkqhkiG9w0BAQsFADCB\n" + - "kjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n" + - "A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxODA2BgNV\n" + - "BAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQgVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVy\n" + - "IENBMB4XDTE3MDYzMDAwMDAwMFoXDTE5MDkyOTIzNTk1OVowggFdMREwDwYDVQQF\n" + - "EwgwNDA1ODY5MDETMBEGCysGAQQBgjc8AgEDEwJHQjEdMBsGA1UEDxMUUHJpdmF0\n" + - "ZSBPcmdhbml6YXRpb24xCzAJBgNVBAYTAkdCMQ8wDQYDVQQREwZNNSAzRVExGzAZ\n" + - "BgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEWMBQG\n" + - "A1UECRMNVHJhZmZvcmQgUm9hZDEWMBQGA1UECRMNRXhjaGFuZ2UgUXVheTElMCMG\n" + - "A1UECRMcM3JkIEZsb29yLCAyNiBPZmZpY2UgVmlsbGFnZTEaMBgGA1UEChMRQ09N\n" + - "T0RPIENBIExpbWl0ZWQxGjAYBgNVBAsTEUNPTU9ETyBFViBTR0MgU1NMMTgwNgYD\n" + - "VQQDEy9jb21vZG9yc2FjZXJ0aWZpY2F0aW9uYXV0aG9yaXR5LWV2LmNvbW9kb2Nh\n" + - "LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAND/eZQBTjpBDsut\n" + - "eKwl+zpTitF8tJzwHAhcQHC2AaLF/GJl1rnjx4OfelMhKhN1Od9KU6onHGOd2w4m\n" + - "D4EiYK9TpXwuwTyzfkCmnkqxZjYK3KAJN013o4L+8y1zsGVUulpN/GfMaxTb4Xdm\n" + - "eSekTP91Phw3xezijBq3sa++1rO5RBaT1IHeHhHviC9WNrG8CIg/j5MyC9i43LZH\n" + - "iRXLER1LzT/MCIRsiG5AEbiYXV5BNd5SiiHtBJ1q0ZJH+AxL2ERaT41VCppboZwT\n" + - "hmJGGoky9FWjp6z8U6Enx0fAMJIZNEzW6LAJFKPEynEU004jFFCEumPUqqCC4ogx\n" + - "ulphY80CAwEAAaOCA3QwggNwMB8GA1UdIwQYMBaAFDna/8ooFIqodBMIueQOqdL6\n" + - "fp1pMB0GA1UdDgQWBBQ+S4ZhIrwOoeGs9BBT4uXq89Ux/jAOBgNVHQ8BAf8EBAMC\n" + - "BaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\n" + - "TwYDVR0gBEgwRjA7BgwrBgEEAbIxAQIBBQEwKzApBggrBgEFBQcCARYdaHR0cHM6\n" + - "Ly9zZWN1cmUuY29tb2RvLmNvbS9DUFMwBwYFZ4EMAQEwVgYDVR0fBE8wTTBLoEmg\n" + - "R4ZFaHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RPUlNBRXh0ZW5kZWRWYWxp\n" + - "ZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGHBggrBgEFBQcBAQR7MHkwUQYIKwYB\n" + - "BQUHMAKGRWh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET1JTQUV4dGVuZGVk\n" + - "VmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAkBggrBgEFBQcwAYYYaHR0cDov\n" + - "L29jc3AuY29tb2RvY2EuY29tMDoGA1UdEQQzMDGCL2NvbW9kb3JzYWNlcnRpZmlj\n" + - "YXRpb25hdXRob3JpdHktZXYuY29tb2RvY2EuY29tMIIBgAYKKwYBBAHWeQIEAgSC\n" + - "AXAEggFsAWoAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAVz5\n" + - "cV7GAAAEAwBHMEUCIQCpgc0Eqw3g4pr+oX88h5xgL1VEAiDpqAhbRtilgYwBbgIg\n" + - "UaIm+n8AHi55nB//Sb4Nz18GYVcfELfpIzRh1vW9HbYAdwBWFAaaL9fC7NP14b1E\n" + - "sj7HRna5vJkRXMDvlJhV1onQ3QAAAVz5cVybAAAEAwBIMEYCIQDdsgC4KZ++OP44\n" + - "X7LbUcNaxe0kFzbctF2L3bnmhp9nXQIhAM0/g+PrZBIBpYlOtzidePi8bBHrLWn2\n" + - "uBiP3pYIntl4AHcA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFc\n" + - "+XFeoQAABAMASDBGAiEAoySTb/QKw7JwtZtPHnECEMzgENQSFy58Kl+Mvcd3SmcC\n" + - "IQD8cU66Ih3ejvt0OTX+lfxQPKyggQfm4Uk/lwn5LEJXbDANBgkqhkiG9w0BAQsF\n" + - "AAOCAQEAKEaSYWn3Hi8rfJS4cMTJoMkVp2vpPH2dGXySBEy67TEGRw9+f75w3q95\n" + - "r1m3P+xsR6dBoidTq/6wqUYI51lB4Fq9ylh1Stp5Gj54CuyT+S31l7lD7sl0KMsn\n" + - "HDUDQHId7hKeORYpiIZOcrKOglKdi1uiGwDgoiLKh98lUrZA6durrhH+sl69wqp2\n" + - "0XAu+3hurXzCoZFJfyngTO1kt9qcFUAxc5LofIa9QvC6VR7dI4aAh7dUpIRlnjG3\n" + - "jJ1mUMTqWO6TFTtddb+uQjDqNgkYYYNuSax1WMEIZWbIi13EjXK1GPQUXJe6gQin\n" + - "NUq9JH9NPK6m8A1YKT+wgzfTDeaV2Q==\n" + - "-----END CERTIFICATE-----"; - public void runTest(ValidatePathWithParams pathValidator) throws Exception { // Validate valid pathValidator.validate(new String[]{VALID, INT}, @@ -226,7 +225,7 @@ public void runTest(ValidatePathWithParams pathValidator) throws Exception { // Validate Revoked pathValidator.validate(new String[]{REVOKED, INT}, ValidatePathWithParams.Status.REVOKED, - "Thu Nov 29 08:41:09 PST 2018", System.out); + "Wed Oct 02 06:06:24 PDT 2019", System.out); } } @@ -261,6 +260,51 @@ class ComodoECC { + "lnxmeeOBnnCaDIxAcA3aCj2Gtdt3sA==\n" + "-----END CERTIFICATE-----"; + // Owner: CN=comodoecccertificationauthority-ev.comodoca.com, OU=COMODO EV SSL, O=Sectigo Limited, + // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, + // OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.3=GB, + // SERIALNUMBER=04058690 + // Issuer: CN=COMODO ECC Extended Validation Secure Server CA, O=COMODO CA Limited, L=Salford, + // ST=Greater Manchester, C=GB + // Serial number: 7972d9d8472a2d52ad1ee6edfb16cbe1 + // Valid from: Sun Sep 29 17:00:00 PDT 2019 until: Tue Dec 28 15:59:59 PST 2021 + private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIGPzCCBeWgAwIBAgIQeXLZ2EcqLVKtHubt+xbL4TAKBggqhkjOPQQDAjCBkjEL\n" + + "MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n" + + "BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMT\n" + + "L0NPTU9ETyBFQ0MgRXh0ZW5kZWQgVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB\n" + + "MB4XDTE5MDkzMDAwMDAwMFoXDTIxMTIyODIzNTk1OVowggE6MREwDwYDVQQFEwgw\n" + + "NDA1ODY5MDETMBEGCysGAQQBgjc8AgEDEwJHQjEdMBsGA1UEDxMUUHJpdmF0ZSBP\n" + + "cmdhbml6YXRpb24xCzAJBgNVBAYTAkdCMQ8wDQYDVQQREwZNNSAzRVExEDAOBgNV\n" + + "BAcTB1NhbGZvcmQxFjAUBgNVBAkTDVRyYWZmb3JkIFJvYWQxFjAUBgNVBAkTDUV4\n" + + "Y2hhbmdlIFF1YXkxJTAjBgNVBAkTHDNyZCBGbG9vciwgMjYgT2ZmaWNlIFZpbGxh\n" + + "Z2UxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEWMBQGA1UECxMNQ09NT0RPIEVW\n" + + "IFNTTDE4MDYGA1UEAxMvY29tb2RvZWNjY2VydGlmaWNhdGlvbmF1dGhvcml0eS1l\n" + + "di5jb21vZG9jYS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS3bqoFLtNG\n" + + "7/J9H5GKosDNbYL5SykVmU5FzgSEt81gyAWShkqMSfAnO50fpr65E+o86E+BR3o8\n" + + "V9FAU5wuOaGBo4IDcDCCA2wwHwYDVR0jBBgwFoAU007DGbpYWdEcYLdhU0c7p3eP\n" + + "+IowHQYDVR0OBBYEFOlnS3MqxwXDpne8IQMXMZHlVKRXMA4GA1UdDwEB/wQEAwIF\n" + + "gDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBP\n" + + "BgNVHSAESDBGMDsGDCsGAQQBsjEBAgEFATArMCkGCCsGAQUFBwIBFh1odHRwczov\n" + + "L3NlY3VyZS5jb21vZG8uY29tL0NQUzAHBgVngQwBATBWBgNVHR8ETzBNMEugSaBH\n" + + "hkVodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9FQ0NFeHRlbmRlZFZhbGlk\n" + + "YXRpb25TZWN1cmVTZXJ2ZXJDQS5jcmwwgYcGCCsGAQUFBwEBBHsweTBRBggrBgEF\n" + + "BQcwAoZFaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPRUNDRXh0ZW5kZWRW\n" + + "YWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8v\n" + + "b2NzcC5jb21vZG9jYS5jb20wOgYDVR0RBDMwMYIvY29tb2RvZWNjY2VydGlmaWNh\n" + + "dGlvbmF1dGhvcml0eS1ldi5jb21vZG9jYS5jb20wggF8BgorBgEEAdZ5AgQCBIIB\n" + + "bASCAWgBZgB1AO5Lvbd1zmC64UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAABbYME\n" + + "EzgAAAQDAEYwRAIgbdo71lBleuJiq+D0ZLp51oVUyWD9EyrtgBSCNwIW4cMCIAqg\n" + + "0VFTWHEmAVjaV23fGj3Ybu3mpSiHr6viGlgA2lYaAHUAVYHUwhaQNgFK6gubVzxT\n" + + "8MDkOHhwJQgXL6OqHQcT0wwAAAFtgwQTKAAABAMARjBEAiBb/gW1RU7kgFBiNpHx\n" + + "LStujKIocyENUTXsMbsac+LktwIgXbEr8vOOCEdBdXQ2F/FKec8ft6gz57mHNmwl\n" + + "pp7phbQAdgC72d+8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAW2DBBM6\n" + + "AAAEAwBHMEUCIQDjKN3h86ofR94+JxLFoYuoA+DRtxEY8XGg+NQXlZfUrgIgEoO2\n" + + "ZzKbGfohdwj/WtDwJDRX5pjXF4M0nECiwtYXDIwwCgYIKoZIzj0EAwIDSAAwRQIg\n" + + "AkIRVQBwrElFjrnqk5XPvnlnwkIm1A70ayqOf1FexoQCIQC8tBTn//RCfrhcgTjd\n" + + "ER4wRjFfFoc6lC68OHGVg9CZZg==\n" + + "-----END CERTIFICATE-----"; + // Owner: CN=comodoecccertificationauthority-ev.comodoca.com, OU=COMODO EV SSL, O=Sectigo Limited, // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, // ST=Greater Manchester, OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, @@ -269,7 +313,7 @@ class ComodoECC { // ST=Greater Manchester, C=GB // Serial number: 603a5c2f85b63e00ba46ce8c3f6000b0 // Valid from: Wed Nov 28 16:00:00 PST 2018 until: Fri Feb 26 15:59:59 PST 2021 - private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + "MIIGXzCCBgWgAwIBAgIQYDpcL4W2PgC6Rs6MP2AAsDAKBggqhkjOPQQDAjCBkjEL\n" + "MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n" + "BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMT\n" + @@ -307,52 +351,6 @@ class ComodoECC { "KOC7\n" + "-----END CERTIFICATE-----"; - // Owner: CN=comodoecccertificationauthority-ev.comodoca.com, OU=COMODO EV SSL, O=COMODO CA Limited, - // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, - // ST=Greater Manchester, OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, - // OID.1.3.6.1.4.1.311.60.2.1.3=GB, SERIALNUMBER=04058690 - // Issuer: CN=COMODO ECC Extended Validation Secure Server CA, O=COMODO CA Limited, L=Salford, - // ST=Greater Manchester, C=GB - // Serial number: 414e5d66ec7d15ca504213f2811d57af - // Valid from: Mon Jul 03 17:00:00 PDT 2017 until: Thu Oct 03 16:59:59 PDT 2019 - private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + - "MIIGYDCCBgWgAwIBAgIQQU5dZux9FcpQQhPygR1XrzAKBggqhkjOPQQDAjCBkjEL\n" + - "MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n" + - "BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMT\n" + - "L0NPTU9ETyBFQ0MgRXh0ZW5kZWQgVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB\n" + - "MB4XDTE3MDcwNDAwMDAwMFoXDTE5MTAwMzIzNTk1OVowggFZMREwDwYDVQQFEwgw\n" + - "NDA1ODY5MDETMBEGCysGAQQBgjc8AgEDEwJHQjEdMBsGA1UEDxMUUHJpdmF0ZSBP\n" + - "cmdhbml6YXRpb24xCzAJBgNVBAYTAkdCMQ8wDQYDVQQREwZNNSAzRVExGzAZBgNV\n" + - "BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEWMBQGA1UE\n" + - "CRMNVHJhZmZvcmQgUm9hZDEWMBQGA1UECRMNRXhjaGFuZ2UgUXVheTElMCMGA1UE\n" + - "CRMcM3JkIEZsb29yLCAyNiBPZmZpY2UgVmlsbGFnZTEaMBgGA1UEChMRQ09NT0RP\n" + - "IENBIExpbWl0ZWQxFjAUBgNVBAsTDUNPTU9ETyBFViBTU0wxODA2BgNVBAMTL2Nv\n" + - "bW9kb2VjY2NlcnRpZmljYXRpb25hdXRob3JpdHktZXYuY29tb2RvY2EuY29tMFkw\n" + - "EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEt26qBS7TRu/yfR+RiqLAzW2C+UspFZlO\n" + - "Rc4EhLfNYMgFkoZKjEnwJzudH6a+uRPqPOhPgUd6PFfRQFOcLjmhgaOCA3EwggNt\n" + - "MB8GA1UdIwQYMBaAFNNOwxm6WFnRHGC3YVNHO6d3j/iKMB0GA1UdDgQWBBTpZ0tz\n" + - "KscFw6Z3vCEDFzGR5VSkVzAOBgNVHQ8BAf8EBAMCBYAwDAYDVR0TAQH/BAIwADAd\n" + - "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTwYDVR0gBEgwRjA7BgwrBgEE\n" + - "AbIxAQIBBQEwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNv\n" + - "bS9DUFMwBwYFZ4EMAQEwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5jb21v\n" + - "ZG9jYS5jb20vQ09NT0RPRUNDRXh0ZW5kZWRWYWxpZGF0aW9uU2VjdXJlU2VydmVy\n" + - "Q0EuY3JsMIGHBggrBgEFBQcBAQR7MHkwUQYIKwYBBQUHMAKGRWh0dHA6Ly9jcnQu\n" + - "Y29tb2RvY2EuY29tL0NPTU9ET0VDQ0V4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNl\n" + - "cnZlckNBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29t\n" + - "MDoGA1UdEQQzMDGCL2NvbW9kb2VjY2NlcnRpZmljYXRpb25hdXRob3JpdHktZXYu\n" + - "Y29tb2RvY2EuY29tMIIBfQYKKwYBBAHWeQIEAgSCAW0EggFpAWcAdgCkuQmQtBhY\n" + - "FIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAV0NLqsqAAAEAwBHMEUCIAz9Jjq3\n" + - "qLUd/a2PYZnLGsEG/MrL7vab5rmGBg8RGAJxAiEA7JJnar07NIjCLLO77xJ3UFcu\n" + - "UMM3M8JgGC8wbuRwxbUAdgBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ\n" + - "3QAAAV0NLqjmAAAEAwBHMEUCIHRvPWKr7vPMBWx1gLPkt8inPINWPNSoax178e5A\n" + - "D0cPAiEAvRL/VP4DLiyHvcU9AOqTzQXGuWCzswWKG59hSm7gS4kAdQDuS723dc5g\n" + - "uuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAV0NLqsDAAAEAwBGMEQCIFALT043\n" + - "X5IffLsxIAGXTrWgkZHf12QKgrYKXVB629eOAiAIeci2xi3fUW6mU8tT4LwyjowV\n" + - "DkrSCw1ZMo0JApsfzTAKBggqhkjOPQQDAgNJADBGAiEA7HUxjwx0MBC+4PuPx4Z1\n" + - "WpKz7jdHOMTh1sdaoVV5hNoCIQDrnjBFUopXHTvm/rj+aMFIeYejggPqv14KJOqT\n" + - "gym+uA==\n" + - "-----END CERTIFICATE-----"; - public void runTest(ValidatePathWithParams pathValidator) throws Exception { // Validate valid pathValidator.validate(new String[]{VALID, INT}, @@ -361,19 +359,61 @@ public void runTest(ValidatePathWithParams pathValidator) throws Exception { // Validate Revoked pathValidator.validate(new String[]{REVOKED, INT}, ValidatePathWithParams.Status.REVOKED, - "Thu Nov 29 08:12:02 PST 2018", System.out); + "Wed Oct 02 06:05:57 PDT 2019", System.out); } } class ComodoUserTrustRSA { + // Owner: CN=Sectigo RSA Extended Validation Secure Server CA, O=Sectigo Limited, L=Salford, + // ST=Greater Manchester, C=GB + // Issuer: CN=USERTrust RSA Certification Authority, O=The USERTRUST Network, L=Jersey City, ST=New Jersey, C=US + // Serial number: 284e39c14b386d889c7299e58cd05a57 + // Valid from: Thu Nov 01 17:00:00 PDT 2018 until: Tue Dec 31 15:59:59 PST 2030 + private static final String INT_VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIGNDCCBBygAwIBAgIQKE45wUs4bYiccpnljNBaVzANBgkqhkiG9w0BAQwFADCB\n" + + "iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n" + + "cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n" + + "BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx\n" + + "MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBkTELMAkGA1UEBhMCR0IxGzAZBgNV\n" + + "BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE\n" + + "ChMPU2VjdGlnbyBMaW1pdGVkMTkwNwYDVQQDEzBTZWN0aWdvIFJTQSBFeHRlbmRl\n" + + "ZCBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQCaoslYBiqFev0Yc4TXPa0s9oliMcn9VaENfTUK4GVT7niB\n" + + "QXxC6Mt8kTtvyr5lU92hDQDh2WDPQsZ7oibh75t2kowT3z1S+Sy1GsUDM4NbdOde\n" + + "orcmzFm/b4bwD4G/G+pB4EX1HSfjN9eT0Hje+AGvCrd2MmnxJ+Yymv9BH9OB65jK\n" + + "rUO9Na4iHr48XWBDFvzsPCJ11Uioof6dRBVp+Lauj88Z7k2X8d606HeXn43h6acp\n" + + "LLURWyqXM0CrzedVWBzuXKuBEaqD6w/1VpLJvSU+wl3ScvXSLFp82DSRJVJONXWl\n" + + "dp9gjJioPGRByeZw11k3galbbF5gFK9xSnbDx29LAgMBAAGjggGNMIIBiTAfBgNV\n" + + "HSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQULGn/gMmHkK40\n" + + "4bTnTJOFmUDpp7IwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw\n" + + "HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDoGA1UdIAQzMDEwLwYEVR0g\n" + + "ADAnMCUGCCsGAQUFBwIBFhlodHRwczovL2Nwcy51c2VydHJ1c3QuY29tMFAGA1Ud\n" + + "HwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RS\n" + + "U0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYI\n" + + "KwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FB\n" + + "ZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0\n" + + "LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAQ4AzPxVypLyy3IjUUmVl7FaxrHsXQq2z\n" + + "Zt2gKnHQShuA+5xpRPNndjvhHk4D08PZXUe6Im7E5knqxtyl5aYdldb+HI/7f+zd\n" + + "W/1ub2N4Vq4ZYUjcZ1ECOFK7Z2zoNicDmU+Fe/TreXPuPsDicTG/tMcWEVM558OQ\n" + + "TJkB2LK3ZhGukWM/RTMRcRdXaXOX8Lh0ylzRO1O0ObXytvOFpkkkD92HGsfS06i7\n" + + "NLDPJEeZXqzHE5Tqj7VSAj+2luwfaXaPLD8lQEVci8xmsPGOn0mXE1ZzsChEPhVq\n" + + "FYQUsbiRJRhidKauhd+G2CkRTcR5fpsuz+iStB9s5Fks9lKoXnn0hv78VYjvR78C\n" + + "Cvj5FW/ounHjWTWMb3il9S5ngbFGcelB1l/MQkR63+1ybdi2OpjNWJCftxOWUpkC\n" + + "xaRdnOnSj7GQY0NLn8Gtq9FcSZydtkVgXpouSFZkXNS/MYwbcCCcRKBbrk8ss0SI\n" + + "Xg1gTURjh9VP1OHm0OktYcUw9e90wHIDn7h0qA+bWOsZquSRzT4s2crF3ZSA3tuV\n" + + "/UJ33mjdVO8wBD8aI5y10QreSPJvZHHNDyCmoyjXvNhR+u3arXUoHWxO+MZBeXbi\n" + + "iF7Nwn/IEmQvWBW8l6D26CXIavcY1kAJcfyzHkrPbLo+fAOa/KFl3lIU+0biEVNk\n" + + "Q9zXE6hC6X4=\n" + + "-----END CERTIFICATE-----"; + // Owner: CN=USERTrust RSA Extended Validation Secure Server CA, // O=The USERTRUST Network, L=Jersey City, ST=New Jersey, C=US // Issuer: CN=USERTrust RSA Certification Authority, O=The USERTRUST Network, // L=Jersey City, ST=New Jersey, C=US // Serial number: f6bb751efa7d2e8368e606407334f83 // Valid from: Sat Feb 11 16:00:00 PST 2012 until: Thu Feb 11 15:59:59 PST 2027 - private static final String INT = "-----BEGIN CERTIFICATE-----\n" + private static final String INT_REVOKED = "-----BEGIN CERTIFICATE-----\n" + "MIIGGTCCBAGgAwIBAgIQD2u3Ue+n0ug2jmBkBzNPgzANBgkqhkiG9w0BAQwFADCB\n" + "iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n" + "cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n" @@ -409,15 +449,69 @@ class ComodoUserTrustRSA { + "4fokbdNREXoShKClNIPbB5iY+WdSzb9CKLyb96g=\n" + "-----END CERTIFICATE-----"; - // Owner: CN=usertrustrsacertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, - // O=Sectigo Limited, STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, - // L=Salford, ST=Greater Manchester, OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, + // Owner: CN=usertrustrsacertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, O=Sectigo Limited, + // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, ST=Manchester, + // OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.3=GB, + // SERIALNUMBER=04058690 + // Issuer: CN=Sectigo RSA Extended Validation Secure Server CA, O=Sectigo Limited, L=Salford, + // ST=Greater Manchester, C=GB + // Serial number: b07fd164b5790c9d5d1fddff5819cdb2 + // Valid from: Sun Sep 29 17:00:00 PDT 2019 until: Tue Dec 28 15:59:59 PST 2021 + private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIH5TCCBs2gAwIBAgIRALB/0WS1eQydXR/d/1gZzbIwDQYJKoZIhvcNAQELBQAw\n" + + "gZExCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO\n" + + "BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE5MDcGA1UE\n" + + "AxMwU2VjdGlnbyBSU0EgRXh0ZW5kZWQgVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVy\n" + + "IENBMB4XDTE5MDkzMDAwMDAwMFoXDTIxMTIyODIzNTk1OVowggFWMREwDwYDVQQF\n" + + "EwgwNDA1ODY5MDETMBEGCysGAQQBgjc8AgEDEwJHQjEdMBsGA1UEDxMUUHJpdmF0\n" + + "ZSBPcmdhbml6YXRpb24xCzAJBgNVBAYTAkdCMQ8wDQYDVQQREwZNNSAzRVExEzAR\n" + + "BgNVBAgTCk1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxFjAUBgNVBAkTDVRy\n" + + "YWZmb3JkIFJvYWQxFjAUBgNVBAkTDUV4Y2hhbmdlIFF1YXkxJTAjBgNVBAkTHDNy\n" + + "ZCBGbG9vciwgMjYgT2ZmaWNlIFZpbGxhZ2UxGDAWBgNVBAoTD1NlY3RpZ28gTGlt\n" + + "aXRlZDEaMBgGA1UECxMRQ09NT0RPIEVWIFNHQyBTU0wxOzA5BgNVBAMTMnVzZXJ0\n" + + "cnVzdHJzYWNlcnRpZmljYXRpb25hdXRob3JpdHktZXYuY29tb2RvY2EuY29tMIIB\n" + + "IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnh/rxeiYwpLa651eLvGnR+RE\n" + + "rhDWkTZtqZcHw9Oy7JL2uELyEPbM+v0az40cBHS0bQZJZbWmXNukMUMSwIb4z7t8\n" + + "OXlxz9uvxEufvlqBl4qeC/z3LpFBRRHEero3yGKVwkoe1aP2Pq7Udi+7i7eVZZdA\n" + + "1ticxZWo/UBU9mwbIOYqf/4xzZ6G891hKb+NAuuEfxG52vXZl8odMThfHuDlkfS7\n" + + "nZMQBaO40KJeSEBhr+5TIS7d7tWWye/F6oEQ0+dHBiF9PyZ1dXoO8aue/80mP+0F\n" + + "MYTmRFsKHge6ZjojfH9cLlR5kTqtP5Tqh5GBQ4zp3uyIBBU6ylKp9PNHkewGUQID\n" + + "AQABo4IDbjCCA2owHwYDVR0jBBgwFoAULGn/gMmHkK404bTnTJOFmUDpp7IwHQYD\n" + + "VR0OBBYEFHz7cvDn1LYe2M+z4plwQn7rt938MA4GA1UdDwEB/wQEAwIFoDAMBgNV\n" + + "HRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBJBgNVHSAE\n" + + "QjBAMDUGDCsGAQQBsjEBAgEFATAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3Rp\n" + + "Z28uY29tL0NQUzAHBgVngQwBATBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3Js\n" + + "LnNlY3RpZ28uY29tL1NlY3RpZ29SU0FFeHRlbmRlZFZhbGlkYXRpb25TZWN1cmVT\n" + + "ZXJ2ZXJDQS5jcmwwgYYGCCsGAQUFBwEBBHoweDBRBggrBgEFBQcwAoZFaHR0cDov\n" + + "L2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNBRXh0ZW5kZWRWYWxpZGF0aW9uU2Vj\n" + + "dXJlU2VydmVyQ0EuY3J0MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdv\n" + + "LmNvbTA9BgNVHREENjA0gjJ1c2VydHJ1c3Ryc2FjZXJ0aWZpY2F0aW9uYXV0aG9y\n" + + "aXR5LWV2LmNvbW9kb2NhLmNvbTCCAX4GCisGAQQB1nkCBAIEggFuBIIBagFoAHYA\n" + + "7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFtgzv54wAABAMARzBF\n" + + "AiB5PmhsK3zU3XdKvyxw/wWHMmLI7apHLa1yKdjkA8H+ggIhALdUx7Tl8aeWhK6z\n" + + "lh+PHvMAdCcAJK6w9qBJGQtSrYO5AHUAVYHUwhaQNgFK6gubVzxT8MDkOHhwJQgX\n" + + "L6OqHQcT0wwAAAFtgzv5zgAABAMARjBEAiBumSwAUamibqJXTN2cf/H3mjd0T35/\n" + + "UK9w2hu9gFobxgIgSXTLndHyqFUmcmquu3It0WC1yl6YMceGixbQL1e8BQcAdwC7\n" + + "2d+8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAW2DO/nXAAAEAwBIMEYC\n" + + "IQDHRs10oYoXE5yq6WsiksjdQsUWZNpbSsrmz0u+KlxTVQIhAJ4rvHItKSeJLkaN\n" + + "S3YpVZnkN8tOwuxPsYeyVx/BtaNpMA0GCSqGSIb3DQEBCwUAA4IBAQAPFIsUFymo\n" + + "VTp0vntHrZpBApBQzDeriQv7Bi7tmou/Ng47RtXW3DjGdrePGSfOdl7h62k8qprU\n" + + "JeLyloDqhvmT/CG/hdwrfZ3Sv3N2xpetGcnW5S3oEi3m+/M1ls9eD+x1vybqV9Kd\n" + + "lcjuV7SYDlbvAS9w7TcygudhdW0cI8XTCvesGKohBkAlqaQ/MWYpt4WvsxHjbWgn\n" + + "5ZlIYR6A1ZFEjADifViH/5AA79lgGhAskkIWPjvRFalEVKTKtjhRK76eCfZs4Frr\n" + + "CEOpon+BeNKk+x/K/r10dSoWe0SV2uGVxTD83zkP++eREwo1hTgn8bXn7ftlnA3j\n" + + "7ml+Usz6udaD\n" + + "-----END CERTIFICATE-----"; + + // Owner: CN=usertrustrsacertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, O=Sectigo Limited, + // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, + // ST=Greater Manchester, OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, // OID.1.3.6.1.4.1.311.60.2.1.3=GB, SERIALNUMBER=04058690 // Issuer: CN=USERTrust RSA Extended Validation Secure Server CA, O=The USERTRUST Network, L=Jersey City, // ST=New Jersey, C=US // Serial number: d3c204e8df6a1539568cf15e97e57b1d // Valid from: Wed Nov 28 16:00:00 PST 2018 until: Fri Feb 26 15:59:59 PST 2021 - private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + "MIIIADCCBuigAwIBAgIRANPCBOjfahU5VozxXpflex0wDQYJKoZIhvcNAQELBQAw\n" + "gZUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK\n" + "ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMTswOQYD\n" + @@ -463,81 +557,56 @@ class ComodoUserTrustRSA { "3Ld31zbQaywKdpCsT74/hEBMfcDiP02mmtyrlqHD4R3tdYne\n" + "-----END CERTIFICATE-----"; - // Owner: CN=usertrustrsacertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, O=COMODO CA Limited, - // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, - // ST=Greater Manchester, OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, - // OID.1.3.6.1.4.1.311.60.2.1.3=GB, SERIALNUMBER=04058690 - // Issuer: CN=USERTrust RSA Extended Validation Secure Server CA, O=The USERTRUST Network, L=Jersey City, - // ST=New Jersey, C=US - // Serial number: ffcada019c9fb1155a32300083cb99c9 - // Valid from: Mon Jul 03 17:00:00 PDT 2017 until: Thu Oct 03 16:59:59 PDT 2019 - private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + - "MIIIATCCBumgAwIBAgIRAP/K2gGcn7EVWjIwAIPLmckwDQYJKoZIhvcNAQELBQAw\n" + - "gZUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK\n" + - "ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMTswOQYD\n" + - "VQQDEzJVU0VSVHJ1c3QgUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNl\n" + - "cnZlciBDQTAeFw0xNzA3MDQwMDAwMDBaFw0xOTEwMDMyMzU5NTlaMIIBYDERMA8G\n" + - "A1UEBRMIMDQwNTg2OTAxEzARBgsrBgEEAYI3PAIBAxMCR0IxHTAbBgNVBA8TFFBy\n" + - "aXZhdGUgT3JnYW5pemF0aW9uMQswCQYDVQQGEwJHQjEPMA0GA1UEERMGTTUgM0VR\n" + - "MRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQx\n" + - "FjAUBgNVBAkTDVRyYWZmb3JkIFJvYWQxFjAUBgNVBAkTDUV4Y2hhbmdlIFF1YXkx\n" + - "JTAjBgNVBAkTHDNyZCBGbG9vciwgMjYgT2ZmaWNlIFZpbGxhZ2UxGjAYBgNVBAoT\n" + - "EUNPTU9ETyBDQSBMaW1pdGVkMRowGAYDVQQLExFDT01PRE8gRVYgU0dDIFNTTDE7\n" + - "MDkGA1UEAxMydXNlcnRydXN0cnNhY2VydGlmaWNhdGlvbmF1dGhvcml0eS1ldi5j\n" + - "b21vZG9jYS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCeH+vF\n" + - "6JjCktrrnV4u8adH5ESuENaRNm2plwfD07Lskva4QvIQ9sz6/RrPjRwEdLRtBkll\n" + - "taZc26QxQxLAhvjPu3w5eXHP26/ES5++WoGXip4L/PcukUFFEcR6ujfIYpXCSh7V\n" + - "o/Y+rtR2L7uLt5Vll0DW2JzFlaj9QFT2bBsg5ip//jHNnobz3WEpv40C64R/Ebna\n" + - "9dmXyh0xOF8e4OWR9LudkxAFo7jQol5IQGGv7lMhLt3u1ZbJ78XqgRDT50cGIX0/\n" + - "JnV1eg7xq57/zSY/7QUxhOZEWwoeB7pmOiN8f1wuVHmROq0/lOqHkYFDjOne7IgE\n" + - "FTrKUqn080eR7AZRAgMBAAGjggN8MIIDeDAfBgNVHSMEGDAWgBQvgU/iZvq8aL+Z\n" + - "Q4RSiSA6gvOkpTAdBgNVHQ4EFgQUfPty8OfUth7Yz7PimXBCfuu33fwwDgYDVR0P\n" + - "AQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG\n" + - "AQUFBwMCMEsGA1UdIAREMEIwNwYMKwYBBAGyMQECAQUBMCcwJQYIKwYBBQUHAgEW\n" + - "GWh0dHBzOi8vY3BzLnVzZXJ0cnVzdC5jb20wBwYFZ4EMAQEwWgYDVR0fBFMwUTBP\n" + - "oE2gS4ZJaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUV4dGVu\n" + - "ZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCBjQYIKwYBBQUHAQEEgYAw\n" + - "fjBVBggrBgEFBQcwAoZJaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVz\n" + - "dFJTQUV4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAlBggrBgEF\n" + - "BQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTA9BgNVHREENjA0gjJ1c2Vy\n" + - "dHJ1c3Ryc2FjZXJ0aWZpY2F0aW9uYXV0aG9yaXR5LWV2LmNvbW9kb2NhLmNvbTCC\n" + - "AX8GCisGAQQB1nkCBAIEggFvBIIBawFpAHYApLkJkLQYWBSHuxOizGdwCjw1mAT5\n" + - "G9+443fNDsgN3BAAAAFdDU2iYQAABAMARzBFAiB0o4GnVHD8MeVQ32D0XYu+EQQW\n" + - "jvN78rmCfk0OEBxyFAIhAKgyctIn0IaDJiZzsrtAiqEnkcMtuh8o+R0Rqw1ygAjk\n" + - "AHcAVhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0AAAFdDU2gFgAABAMA\n" + - "SDBGAiEA7mcmZ8H5uHuNCdI0CVxsqDZQcZX/gVk94KckePkzQoACIQCHwm5hcvNC\n" + - "M8vNmFkboQN79DglRctHrlh143A6mUTk8QB2AO5Lvbd1zmC64UJpH6vhnmajD35f\n" + - "sHLYgwDEe4l6qP3LAAABXQ1NojoAAAQDAEcwRQIhAPqwijgE0Fr6uJ+yF+TvyXco\n" + - "Hduv9h7R5WWwJfghXiMyAiBB4+fJm4rIcOnJBZmOqFnRpIjPN0jwDqJT0nDHxaXA\n" + - "nDANBgkqhkiG9w0BAQsFAAOCAQEACXitF1bTEvV1HX11WrT/XuoMhsoPK4TS16rs\n" + - "FqztV4iXKlA1/h5qbsjYY1gVrM+/6kQkmEs5qrxsek2WNxY80NO3WAzroRJ3H9Sd\n" + - "mPn0No2P8LZ5Fs5hvaD/PfWO5xxey80c3kGyvWOej90P3IrL/1RiULyh95TrXBjI\n" + - "ddCBsZ28904wsQUrPBPMpiu0DKl1HR/em9WkcipMi+onJxxFWjucssz5PW/BzGYF\n" + - "jfWLDEI0tN5L4CWV3iVXFXOURY1Mwhtsey9jvlEyxSsys55QdKF40yGgtV9VC+os\n" + - "7hJP33+qA0cvCTaRytiPP6z/l2G/KSIXTyv6SxzGhsTFfzLAOg==\n" + - "-----END CERTIFICATE-----"; - public void runTest(ValidatePathWithParams pathValidator) throws Exception { // Validate valid - pathValidator.validate(new String[]{VALID, INT}, + pathValidator.validate(new String[]{VALID, INT_VALID}, ValidatePathWithParams.Status.GOOD, null, System.out); // Validate Revoked - pathValidator.validate(new String[]{REVOKED, INT}, + pathValidator.validate(new String[]{REVOKED, INT_REVOKED}, ValidatePathWithParams.Status.REVOKED, - "Thu Nov 29 10:58:13 PST 2018", System.out); + "Wed Oct 02 06:07:12 PDT 2019", System.out); } } class ComodoUserTrustECC { + // Owner: CN=Sectigo ECC Extended Validation Secure Server CA, O=Sectigo Limited, L=Salford, + // ST=Greater Manchester, C=GB + // Issuer: CN=USERTrust ECC Certification Authority, O=The USERTRUST Network, L=Jersey City, ST=New Jersey, C=US + // Serial number: 80f5606d3a162b143adc12fbe8c2066f + // Valid from: Thu Nov 01 17:00:00 PDT 2018 until: Tue Dec 31 15:59:59 PST 2030 + private static final String INT_VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIDyTCCA0+gAwIBAgIRAID1YG06FisUOtwS++jCBm8wCgYIKoZIzj0EAwMwgYgx\n" + + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz\n" + + "ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQD\n" + + "EyVVU0VSVHJ1c3QgRUNDIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE4MTEw\n" + + "MjAwMDAwMFoXDTMwMTIzMTIzNTk1OVowgZExCzAJBgNVBAYTAkdCMRswGQYDVQQI\n" + + "ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoT\n" + + "D1NlY3RpZ28gTGltaXRlZDE5MDcGA1UEAxMwU2VjdGlnbyBFQ0MgRXh0ZW5kZWQg\n" + + "VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" + + "AQcDQgAEAyJ5Ca9JyXq8bO+krLVWysbtm7fdMSJ54uFD23t0x6JAC4IjxevfQJzW\n" + + "z4T6yY+FybTBqtOa++ijJFnkB5wKy6OCAY0wggGJMB8GA1UdIwQYMBaAFDrhCYbU\n" + + "zxnClnZ0SXbc4DXGY2OaMB0GA1UdDgQWBBTvwSqVDDLa+3Mw3IoT2BVL9xPo+DAO\n" + + "BgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggr\n" + + "BgEFBQcDAQYIKwYBBQUHAwIwOgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUH\n" + + "AgEWGWh0dHBzOi8vY3BzLnVzZXJ0cnVzdC5jb20wUAYDVR0fBEkwRzBFoEOgQYY/\n" + + "aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0NlcnRpZmljYXRp\n" + + "b25BdXRob3JpdHkuY3JsMHYGCCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0\n" + + "cDovL2NydC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdEVDQ0FkZFRydXN0Q0EuY3J0\n" + + "MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMAoGCCqGSM49\n" + + "BAMDA2gAMGUCMQCjHztBDL90GCRXHlGqm0H7kzP04hd0MxwakKjWzOmstXNFLONj\n" + + "RFa0JqI/iKUJMFcCMCbLgyzcFW7DihtY5XE0XCLCw+git0NjxiFB6FaOFIlyDdqT\n" + + "j+Th+DJ92JLvICVD/g==\n" + + "-----END CERTIFICATE-----"; + // Owner: CN=USERTrust ECC Extended Validation Secure Server CA, O=The USERTRUST Network, // L=Jersey City, ST=New Jersey, C=US // Issuer: CN=USERTrust ECC Certification Authority, O=The USERTRUST Network, // L=Jersey City, ST=New Jersey, C=US // Serial number: 3d09b24f5c08a7ce8eb85a51d3c1aa52 // Valid from: Sun Apr 14 17:00:00 PDT 2013 until: Fri Apr 14 16:59:59 PDT 2028 - private static final String INT = "-----BEGIN CERTIFICATE-----\n" + private static final String INT_REVOKED = "-----BEGIN CERTIFICATE-----\n" + "MIIDwTCCA0igAwIBAgIQPQmyT1wIp86OuFpR08GqUjAKBggqhkjOPQQDAzCBiDEL\n" + "MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl\n" + "eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT\n" @@ -561,6 +630,51 @@ class ComodoUserTrustECC { + "s1rWGRU=\n" + "-----END CERTIFICATE-----"; + // Owner: CN=usertrustecccertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, O=Sectigo Limited, + // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, + // OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.3=GB, + // SERIALNUMBER=04058690 + // Issuer: CN=Sectigo ECC Extended Validation Secure Server CA, O=Sectigo Limited, L=Salford, + // ST=Greater Manchester, C=GB + // Serial number: 8b72489b7f505a55e2a22659c90ed2ab + // Valid from: Sun Sep 29 17:00:00 PDT 2019 until: Tue Dec 28 15:59:59 PST 2021 + private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + "MIIGRTCCBeugAwIBAgIRAItySJt/UFpV4qImWckO0qswCgYIKoZIzj0EAwIwgZEx\n" + + "CzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNV\n" + + "BAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE5MDcGA1UEAxMw\n" + + "U2VjdGlnbyBFQ0MgRXh0ZW5kZWQgVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB\n" + + "MB4XDTE5MDkzMDAwMDAwMFoXDTIxMTIyODIzNTk1OVowggFBMREwDwYDVQQFEwgw\n" + + "NDA1ODY5MDETMBEGCysGAQQBgjc8AgEDEwJHQjEdMBsGA1UEDxMUUHJpdmF0ZSBP\n" + + "cmdhbml6YXRpb24xCzAJBgNVBAYTAkdCMQ8wDQYDVQQREwZNNSAzRVExEDAOBgNV\n" + + "BAcTB1NhbGZvcmQxFjAUBgNVBAkTDVRyYWZmb3JkIFJvYWQxFjAUBgNVBAkTDUV4\n" + + "Y2hhbmdlIFF1YXkxJTAjBgNVBAkTHDNyZCBGbG9vciwgMjYgT2ZmaWNlIFZpbGxh\n" + + "Z2UxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEaMBgGA1UECxMRQ09NT0RPIEVW\n" + + "IFNHQyBTU0wxOzA5BgNVBAMTMnVzZXJ0cnVzdGVjY2NlcnRpZmljYXRpb25hdXRo\n" + + "b3JpdHktZXYuY29tb2RvY2EuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\n" + + "LTJfEd92Wlg+h/AVtPsMmwX9Puvi+WGCv3sgFRpur8Iy2kGVpXHRQTCn2j9aky4t\n" + + "FQGm7OG2klJA/MEeevKVaaOCA28wggNrMB8GA1UdIwQYMBaAFO/BKpUMMtr7czDc\n" + + "ihPYFUv3E+j4MB0GA1UdDgQWBBSzrWHzmiHwx2Rrm7SjRC0UegNrKzAOBgNVHQ8B\n" + + "Af8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB\n" + + "BQUHAwIwSQYDVR0gBEIwQDA1BgwrBgEEAbIxAQIBBQEwJTAjBggrBgEFBQcCARYX\n" + + "aHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwBwYFZ4EMAQEwVgYDVR0fBE8wTTBLoEmg\n" + + "R4ZFaHR0cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdvRUNDRXh0ZW5kZWRWYWxp\n" + + "ZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGGBggrBgEFBQcBAQR6MHgwUQYIKwYB\n" + + "BQUHMAKGRWh0dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb0VDQ0V4dGVuZGVk\n" + + "VmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAjBggrBgEFBQcwAYYXaHR0cDov\n" + + "L29jc3Auc2VjdGlnby5jb20wPQYDVR0RBDYwNIIydXNlcnRydXN0ZWNjY2VydGlm\n" + + "aWNhdGlvbmF1dGhvcml0eS1ldi5jb21vZG9jYS5jb20wggF/BgorBgEEAdZ5AgQC\n" + + "BIIBbwSCAWsBaQB2AO5Lvbd1zmC64UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAAB\n" + + "bYL/SJoAAAQDAEcwRQIhAL7EJt/Rgz6NBnx2v8Hevux3Gpcxy64kaeyLVgFeNqFk\n" + + "AiBRf+OWLOtZzEav/oERljrk8hgZB4CR1nj/Tn98cmRrwwB2AFWB1MIWkDYBSuoL\n" + + "m1c8U/DA5Dh4cCUIFy+jqh0HE9MMAAABbYL/SIgAAAQDAEcwRQIgVtZZaiBMC2lu\n" + + "atBzUHQmOq4qrUQP7nS83cd3VzPhToECIQDnlpOCdaxJwr8C0MtkvYpKSabwBPFL\n" + + "ASEkwmOpjuQErAB3ALvZ37wfinG1k5Qjl6qSe0c4V5UKq1LoGpCWZDaOHtGFAAAB\n" + + "bYL/SJoAAAQDAEgwRgIhAI8OgzP/kzF1bOJRHU2S/ewij/6HpGPy7Mbm7Hyuv3IU\n" + + "AiEAxDmX2FmORlgeerQmQ+ar3D9/TwA9RQckVDu5IrgweREwCgYIKoZIzj0EAwID\n" + + "SAAwRQIhAPwQWGWd3oR7YJ7ngCDQ9TAbdPgND51SiR34WfEgaTQtAiAxD4umKm02\n" + + "59GEMj5NpyF2ZQEq5mEGcjJNojrn+PC4zg==\n" + + "-----END CERTIFICATE-----"; + // Owner: CN=usertrustecccertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, O=Sectigo Limited, // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, // ST=Greater Manchester, OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, @@ -569,7 +683,7 @@ class ComodoUserTrustECC { // ST=New Jersey, C=US // Serial number: ab1455f9833ae7783f95de8744181f6a // Valid from: Wed Nov 28 16:00:00 PST 2018 until: Fri Feb 26 15:59:59 PST 2021 - private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + + private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + "MIIGhjCCBiygAwIBAgIRAKsUVfmDOud4P5Xeh0QYH2owCgYIKoZIzj0EAwIwgZUx\n" + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz\n" + "ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMTswOQYDVQQD\n" + @@ -607,60 +721,14 @@ class ComodoUserTrustECC { "11EPtBSCEhUCIBcyI0yl5dRff6+4x8IeCrLiAOYsfzM7Y/a5uRKFnbYz\n" + "-----END CERTIFICATE-----"; - // Owner: CN=usertrustecccertificationauthority-ev.comodoca.com, OU=COMODO EV SGC SSL, O=COMODO CA Limited, - // STREET="3rd Floor, 26 Office Village", STREET=Exchange Quay, STREET=Trafford Road, L=Salford, - // ST=Greater Manchester, OID.2.5.4.17=M5 3EQ, C=GB, OID.2.5.4.15=Private Organization, - // OID.1.3.6.1.4.1.311.60.2.1.3=GB, SERIALNUMBER=04058690 - // Issuer: CN=USERTrust ECC Extended Validation Secure Server CA, O=The USERTRUST Network, L=Jersey City, - // ST=New Jersey, C=US - // Serial number: 9bd0c93cac9ca2edc1a7dd923316b3c6 - // Valid from: Mon Jul 03 17:00:00 PDT 2017 until: Thu Oct 03 16:59:59 PDT 2019 - private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + - "MIIGhzCCBi2gAwIBAgIRAJvQyTysnKLtwafdkjMWs8YwCgYIKoZIzj0EAwIwgZUx\n" + - "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJz\n" + - "ZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMTswOQYDVQQD\n" + - "EzJVU0VSVHJ1c3QgRUNDIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl\n" + - "ciBDQTAeFw0xNzA3MDQwMDAwMDBaFw0xOTEwMDMyMzU5NTlaMIIBYDERMA8GA1UE\n" + - "BRMIMDQwNTg2OTAxEzARBgsrBgEEAYI3PAIBAxMCR0IxHTAbBgNVBA8TFFByaXZh\n" + - "dGUgT3JnYW5pemF0aW9uMQswCQYDVQQGEwJHQjEPMA0GA1UEERMGTTUgM0VRMRsw\n" + - "GQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxFjAU\n" + - "BgNVBAkTDVRyYWZmb3JkIFJvYWQxFjAUBgNVBAkTDUV4Y2hhbmdlIFF1YXkxJTAj\n" + - "BgNVBAkTHDNyZCBGbG9vciwgMjYgT2ZmaWNlIFZpbGxhZ2UxGjAYBgNVBAoTEUNP\n" + - "TU9ETyBDQSBMaW1pdGVkMRowGAYDVQQLExFDT01PRE8gRVYgU0dDIFNTTDE7MDkG\n" + - "A1UEAxMydXNlcnRydXN0ZWNjY2VydGlmaWNhdGlvbmF1dGhvcml0eS1ldi5jb21v\n" + - "ZG9jYS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtMl8R33ZaWD6H8BW0\n" + - "+wybBf0+6+L5YYK/eyAVGm6vwjLaQZWlcdFBMKfaP1qTLi0VAabs4baSUkD8wR56\n" + - "8pVpo4IDjjCCA4owHwYDVR0jBBgwFoAUKpxa+U6hMNpASyvpS/H1nNwC+S4wHQYD\n" + - "VR0OBBYEFLOtYfOaIfDHZGubtKNELRR6A2srMA4GA1UdDwEB/wQEAwIFgDAMBgNV\n" + - "HRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBQBgNVHSAE\n" + - "STBHMDwGDCsGAQQBsjEBAgEFATAsMCoGCCsGAQUFBwIBFh5odHRwczovL2Nwcy50\n" + - "cnVzdC1wcm92aWRlci5jb20wBwYFZ4EMAQEwXwYDVR0fBFgwVjBUoFKgUIZOaHR0\n" + - "cDovL2NybC50cnVzdC1wcm92aWRlci5jb20vVVNFUlRydXN0RUNDRXh0ZW5kZWRW\n" + - "YWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3JsMIGYBggrBgEFBQcBAQSBizCBiDBa\n" + - "BggrBgEFBQcwAoZOaHR0cDovL2NydC50cnVzdC1wcm92aWRlci5jb20vVVNFUlRy\n" + - "dXN0RUNDRXh0ZW5kZWRWYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0MCoGCCsG\n" + - "AQUFBzABhh5odHRwOi8vb2NzcC50cnVzdC1wcm92aWRlci5jb20wPQYDVR0RBDYw\n" + - "NIIydXNlcnRydXN0ZWNjY2VydGlmaWNhdGlvbmF1dGhvcml0eS1ldi5jb21vZG9j\n" + - "YS5jb20wggF8BgorBgEEAdZ5AgQCBIIBbASCAWgBZgB1AKS5CZC0GFgUh7sTosxn\n" + - "cAo8NZgE+RvfuON3zQ7IDdwQAAABXQ0/jQ0AAAQDAEYwRAIgPbaNWgoi6OfyNwL2\n" + - "+jiySsoLrkx+0d4NJE1WnZQcfzwCICW4yvsXaMxoOXpQp3EPgrYk5Ajfvy/dY3Ui\n" + - "0/dbQtHxAHYAVhQGmi/XwuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0AAAFdDT+K\n" + - "xwAABAMARzBFAiB3GQasrX+akoHX02ZvXCcvhWCqv6qQOhLCUqflPoRbuAIhALwe\n" + - "hrQo8S1Tm5vbMcxGiViq5ZcawxENWhxZ9hS0BZweAHUA7ku9t3XOYLrhQmkfq+Ge\n" + - "ZqMPfl+wctiDAMR7iXqo/csAAAFdDT+M4AAABAMARjBEAiAjvp8w/fdTVW1VGE0T\n" + - "I0YcCIXTYFDgzUMsEUiKHANAgwIgETQUcac7Hiis2fgQ+GdGF9yuh+xMo2Z8QXNu\n" + - "1Cknf+8wCgYIKoZIzj0EAwIDSAAwRQIgQ5UiUI7xodmmMYNs3CmqlZHw/04BQRAR\n" + - "4gRm7blZSIMCIQDHvIWTaPzSO6vwVzs6wSD6FqebLiFxoddC6aZG8Nm0wQ==\n" + - "-----END CERTIFICATE-----"; - public void runTest(ValidatePathWithParams pathValidator) throws Exception { // Validate valid - pathValidator.validate(new String[]{VALID, INT}, + pathValidator.validate(new String[]{VALID, INT_VALID}, ValidatePathWithParams.Status.GOOD, null, System.out); // Validate Revoked - pathValidator.validate(new String[]{REVOKED, INT}, + pathValidator.validate(new String[]{REVOKED, INT_REVOKED}, ValidatePathWithParams.Status.REVOKED, - "Thu Nov 29 10:06:00 PST 2018", System.out); + "Wed Oct 02 06:06:50 PDT 2019", System.out); } } diff --git a/test/jdk/sun/java2d/marlin/FlipBitTest.java b/test/jdk/sun/java2d/marlin/FlipBitTest.java new file mode 100644 index 00000000000..d966f701f6f --- /dev/null +++ b/test/jdk/sun/java2d/marlin/FlipBitTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; + + +/** + * Tests calculating user space line with a negative determinant (flip). + * + * @test + * @summary verify that flipped transformed lines are properly rasterized + * @bug 8230728 + */ +public class FlipBitTest { + + static final boolean SAVE_IMAGE = false; + + public static void main(final String[] args) { + + final int size = 100; + + // First display which renderer is tested: + // JDK9 only: + System.setProperty("sun.java2d.renderer.verbose", "true"); + + System.out.println("FlipBitTest: size = " + size); + + final BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); + + final Graphics2D g2d = (Graphics2D) image.getGraphics(); + try { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE); + + final AffineTransform at = new AffineTransform(); + at.setToScale(1, -1.01); + g2d.setTransform(at); + + g2d.translate(0, -image.getHeight()); + g2d.setPaint(Color.WHITE); + g2d.fill(new Rectangle(image.getWidth(), image.getHeight())); + + g2d.setPaint(Color.BLACK); + g2d.setStroke(new BasicStroke(0.1f)); + g2d.draw(new Ellipse2D.Double(25, 25, 50, 50)); + + if (SAVE_IMAGE) { + try { + final File file = new File("FlipBitTest.png"); + + System.out.println("Writing file: " + file.getAbsolutePath()); + ImageIO.write(image, "PNG", file); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + boolean nonWhitePixelFound = false; + for (int x = 0; x < image.getWidth(); ++x) { + if (image.getRGB(x, 50) != Color.WHITE.getRGB()) { + nonWhitePixelFound = true; + break; + } + } + if (!nonWhitePixelFound) { + throw new IllegalStateException("The ellipse was not drawn"); + } + } finally { + g2d.dispose(); + } + } +} diff --git a/test/jdk/sun/security/krb5/auto/KDC.java b/test/jdk/sun/security/krb5/auto/KDC.java index 4868fac67ba..3465f3ac45f 100644 --- a/test/jdk/sun/security/krb5/auto/KDC.java +++ b/test/jdk/sun/security/krb5/auto/KDC.java @@ -163,6 +163,14 @@ public class KDC { private TreeMap s2kparamses = new TreeMap<> (String.CASE_INSENSITIVE_ORDER); + // Alias for referrals. + private TreeMap aliasReferrals = new TreeMap<> + (String.CASE_INSENSITIVE_ORDER); + + // Alias for local resolution. + private TreeMap alias2Principals = new TreeMap<> + (String.CASE_INSENSITIVE_ORDER); + // Realm name private String realm; // KDC @@ -551,6 +559,29 @@ public int getPort() { return port; } + /** + * Register an alias name to be referred to a different KDC for + * resolution, according to RFC 6806. + * @param alias Alias name (i.e. user@REALM.COM). + * @param referredKDC KDC to which the alias is referred for resolution. + */ + public void registerAlias(String alias, KDC referredKDC) { + aliasReferrals.remove(alias); + aliasReferrals.put(alias, referredKDC); + } + + /** + * Register an alias to be resolved to a Principal Name locally, + * according to RFC 6806. + * @param alias Alias name (i.e. user@REALM.COM). + * @param user Principal Name to which the alias is resolved. + */ + public void registerAlias(String alias, String user) + throws RealmException { + alias2Principals.remove(alias); + alias2Principals.put(alias, new PrincipalName(user)); + } + // Private helper methods /** @@ -776,6 +807,17 @@ protected byte[] processTgsReq(byte[] in) throws Exception { PrincipalName cname = null; boolean allowForwardable = true; + if (body.kdcOptions.get(KDCOptions.CANONICALIZE)) { + KDC referral = aliasReferrals.get(body.sname.getNameString()); + if (referral != null) { + service = new PrincipalName( + PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + + referral.getRealm(), PrincipalName.KRB_NT_SRV_INST, + this.getRealm()); + } + } + if (pas == null || pas.length == 0) { throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP); } else { @@ -962,7 +1004,8 @@ protected byte[] processTgsReq(byte[] in) throws Exception { from, till, renewTill, service, - body.addresses + body.addresses, + null ); EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY); @@ -1006,6 +1049,7 @@ protected byte[] processTgsReq(byte[] in) throws Exception { */ protected byte[] processAsReq(byte[] in) throws Exception { ASReq asReq = new ASReq(in); + byte[] asReqbytes = asReq.asn1Encode(); int[] eTypes = null; List outPAs = new ArrayList<>(); @@ -1028,6 +1072,24 @@ protected byte[] processAsReq(byte[] in) throws Exception { } int eType = eTypes[0]; + if (body.kdcOptions.get(KDCOptions.CANONICALIZE) && + body.cname.getNameType() == PrincipalName.KRB_NT_ENTERPRISE) { + PrincipalName principal = alias2Principals.get( + body.cname.getNameString()); + if (principal != null) { + body.cname = principal; + } else { + KDC referral = aliasReferrals.get(body.cname.getNameString()); + if (referral != null) { + body.cname = new PrincipalName( + PrincipalName.TGS_DEFAULT_SRV_NAME, + PrincipalName.KRB_NT_SRV_INST, + referral.getRealm()); + throw new KrbException(Krb5.KRB_ERR_WRONG_REALM); + } + } + } + EncryptionKey ckey = keyForUser(body.cname, eType, false); EncryptionKey skey = keyForUser(service, eType, true); @@ -1209,17 +1271,18 @@ protected byte[] processAsReq(byte[] in) throws Exception { } PAData[] inPAs = KDCReqDotPAData(asReq); + List enc_outPAs = new ArrayList<>(); if (inPAs == null || inPAs.length == 0) { Object preauth = options.get(Option.PREAUTH_REQUIRED); if (preauth == null || preauth.equals(Boolean.TRUE)) { throw new KrbException(Krb5.KDC_ERR_PREAUTH_REQUIRED); } } else { + EncryptionKey pakey = null; try { EncryptedData data = newEncryptedData( new DerValue(inPAs[0].getValue())); - EncryptionKey pakey - = keyForUser(body.cname, data.getEType(), false); + pakey = keyForUser(body.cname, data.getEType(), false); data.decrypt(pakey, KeyUsage.KU_PA_ENC_TS); } catch (Exception e) { KrbException ke = new KrbException(Krb5.KDC_ERR_PREAUTH_FAILED); @@ -1227,6 +1290,17 @@ protected byte[] processAsReq(byte[] in) throws Exception { throw ke; } bFlags[Krb5.TKT_OPTS_PRE_AUTHENT] = true; + for (PAData pa : inPAs) { + if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) { + Checksum ckSum = new Checksum( + Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128, + asReqbytes, ckey, KeyUsage.KU_AS_REQ); + enc_outPAs.add(new PAData(Krb5.PA_REQ_ENC_PA_REP, + ckSum.asn1Encode())); + bFlags[Krb5.TKT_OPTS_ENC_PA_REP] = true; + break; + } + } } TicketFlags tFlags = new TicketFlags(bFlags); @@ -1257,7 +1331,8 @@ protected byte[] processAsReq(byte[] in) throws Exception { from, till, rtime, service, - body.addresses + body.addresses, + enc_outPAs.toArray(new PAData[enc_outPAs.size()]) ); EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), KeyUsage.KU_ENC_AS_REP_PART); @@ -1305,8 +1380,10 @@ protected byte[] processAsReq(byte[] in) throws Exception { if (kerr == null) { if (ke.returnCode() == Krb5.KDC_ERR_PREAUTH_REQUIRED || ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) { + outPAs.add(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0])); + } + if (outPAs.size() > 0) { DerOutputStream bytes = new DerOutputStream(); - bytes.write(new PAData(Krb5.PA_ENC_TIMESTAMP, new byte[0]).asn1Encode()); for (PAData p: outPAs) { bytes.write(p.asn1Encode()); } diff --git a/test/jdk/sun/security/krb5/auto/ReferralsTest.java b/test/jdk/sun/security/krb5/auto/ReferralsTest.java new file mode 100644 index 00000000000..81455229c4a --- /dev/null +++ b/test/jdk/sun/security/krb5/auto/ReferralsTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. + * 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 8215032 + * @library /test/lib + * @run main/othervm/timeout=120 -Dsun.security.krb5.debug=true ReferralsTest + * @summary Test Kerberos cross-realm referrals (RFC 6806) + */ + +import java.io.File; +import sun.security.krb5.Credentials; +import sun.security.krb5.internal.CredentialsUtil; +import sun.security.krb5.KrbAsReqBuilder; +import sun.security.krb5.PrincipalName; + +public class ReferralsTest { + private static final boolean DEBUG = true; + private static final String krbConfigName = "krb5-localkdc.conf"; + private static final String realmKDC1 = "RABBIT.HOLE"; + private static final String realmKDC2 = "DEV.RABBIT.HOLE"; + private static final char[] password = "123qwe@Z".toCharArray(); + private static final String clientName = "test"; + + private static final String clientAlias = clientName + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1; + + private static final String clientKDC1QueryName = clientAlias.replaceAll( + PrincipalName.NAME_REALM_SEPARATOR_STR, "\\\\" + + PrincipalName.NAME_REALM_SEPARATOR_STR) + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1; + private static PrincipalName clientKDC1QueryPrincipal = null; + static { + try { + clientKDC1QueryPrincipal = new PrincipalName( + clientKDC1QueryName, PrincipalName.KRB_NT_ENTERPRISE, + null); + } catch (Throwable t) {} + } + + private static final String clientKDC2Name = clientName + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2; + + private static final String serviceName = "http" + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + + "server.dev.rabbit.hole"; + + private static Credentials tgt; + private static Credentials tgs; + + public static void main(String[] args) throws Exception { + try { + initializeKDCs(); + getTGT(); + getTGS(); + } finally { + cleanup(); + } + } + + private static void initializeKDCs() throws Exception { + KDC kdc1 = KDC.create(realmKDC1, "localhost", 0, true); + kdc1.addPrincipalRandKey(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC1); + kdc1.addPrincipal(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC1 + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC2, + password); + kdc1.addPrincipal(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC2, + password); + + KDC kdc2 = KDC.create(realmKDC2, "localhost", 0, true); + kdc2.addPrincipalRandKey(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC2); + kdc2.addPrincipal(clientKDC2Name, password); + kdc2.addPrincipal(serviceName, password); + kdc2.addPrincipal(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC1, + password); + kdc2.addPrincipal(PrincipalName.TGS_DEFAULT_SRV_NAME + + PrincipalName.NAME_COMPONENT_SEPARATOR_STR + realmKDC2 + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1, + password); + + kdc1.registerAlias(clientAlias, kdc2); + kdc1.registerAlias(serviceName, kdc2); + kdc2.registerAlias(clientAlias, clientKDC2Name); + + KDC.saveConfig(krbConfigName, kdc1, kdc2, + "forwardable=true"); + System.setProperty("java.security.krb5.conf", krbConfigName); + } + + private static void cleanup() { + File f = new File(krbConfigName); + if (f.exists()) { + f.delete(); + } + } + + private static void getTGT() throws Exception { + KrbAsReqBuilder builder = new KrbAsReqBuilder(clientKDC1QueryPrincipal, + password); + tgt = builder.action().getCreds(); + builder.destroy(); + if (DEBUG) { + System.out.println("TGT"); + System.out.println("----------------------"); + System.out.println(tgt); + System.out.println("----------------------"); + } + if (tgt == null) { + throw new Exception("TGT is null"); + } + if (!tgt.getClient().getName().equals(clientKDC2Name)) { + throw new Exception("Unexpected TGT client"); + } + String[] tgtServerNames = tgt.getServer().getNameStrings(); + if (tgtServerNames.length != 2 || !tgtServerNames[0].equals( + PrincipalName.TGS_DEFAULT_SRV_NAME) || + !tgtServerNames[1].equals(realmKDC2) || + !tgt.getServer().getRealmString().equals(realmKDC2)) { + throw new Exception("Unexpected TGT server"); + } + } + + private static void getTGS() throws Exception { + tgs = CredentialsUtil.acquireServiceCreds(serviceName + + PrincipalName.NAME_REALM_SEPARATOR_STR + realmKDC1, tgt); + if (DEBUG) { + System.out.println("TGS"); + System.out.println("----------------------"); + System.out.println(tgs); + System.out.println("----------------------"); + } + if (tgs == null) { + throw new Exception("TGS is null"); + } + if (!tgs.getClient().getName().equals(clientKDC2Name)) { + throw new Exception("Unexpected TGS client"); + } + if (!tgs.getServer().getNameString().equals(serviceName) || + !tgs.getServer().getRealmString().equals(realmKDC2)) { + throw new Exception("Unexpected TGS server"); + } + } +} diff --git a/test/jdk/sun/security/pkcs11/fips/SunJSSEFIPSInit.java b/test/jdk/sun/security/pkcs11/fips/SunJSSEFIPSInit.java new file mode 100644 index 00000000000..eda705a0857 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/fips/SunJSSEFIPSInit.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. + * + * 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 8230923 + * @requires (jdk.version.major == 11) & (os.family == "linux") & (os.arch == "amd64" | os.arch == "x86_64") + * @modules java.base/com.sun.net.ssl.internal.ssl + * @library /test/lib + * @run main/othervm/timeout=30 SunJSSEFIPSInit + * @author Martin Balao (mbalao@redhat.com) + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.security.Security; +import java.util.ArrayList; +import java.util.List; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class SunJSSEFIPSInit { + private static String lineSep = System.lineSeparator(); + private static String javaBinPath = System.getProperty("java.home", ".") + + File.separator + "bin" + File.separator + "java"; + private static String nssConfigFileName = "nss.cfg"; + private static String javaSecConfigFileName = "java.security"; + private static Path tmpDirPath; + public static void main(String[] args) throws Throwable { + tmpDirPath = Files.createTempDirectory("tmpdir"); + try { + deployConfigFiles(); + List cmds = new ArrayList<>(); + cmds.add(javaBinPath); + cmds.add("-cp"); + cmds.add(System.getProperty("test.classes", ".")); + cmds.add("-Djava.security.properties=" + tmpDirPath + + File.separator + javaSecConfigFileName); + cmds.add(SunJSSEFIPSInitClient.class.getName()); + OutputAnalyzer out = ProcessTools.executeCommand( + cmds.toArray(new String[cmds.size()])); + out.stdoutShouldContain("SunJSSE.isFIPS(): true"); + System.out.println("TEST PASS - OK"); + } finally { + deleteDir(tmpDirPath); + } + } + + private static void deployConfigFiles() throws IOException { + deployJavaSecurityFile(); + deployNssConfigFile(); + } + + private static void deployJavaSecurityFile() throws IOException { + int numberOfProviders = Security.getProviders().length; + StringBuilder sb = new StringBuilder(); + sb.append("security.provider.1=SunPKCS11 " + tmpDirPath + + File.separator + nssConfigFileName + lineSep); + sb.append("security.provider.2=com.sun.net.ssl.internal.ssl.Provider" + + " SunPKCS11-NSS" + lineSep); + for (int i = 3; i <= numberOfProviders; i++) { + sb.append("security.provider." + i + "=\"\"" + lineSep); + } + writeFile(javaSecConfigFileName, sb.toString()); + } + + private static void deployNssConfigFile() throws IOException { + StringBuilder sb = new StringBuilder(); + sb.append("name = NSS" + lineSep); + sb.append("nssLibraryDirectory = /usr/lib64" + lineSep); + sb.append("nssDbMode = noDb" + lineSep); + sb.append("nssModule = crypto" + lineSep); + writeFile(nssConfigFileName, sb.toString()); + } + + private static void writeFile(String fileName, String fileContent) + throws IOException { + try (FileOutputStream fos = new FileOutputStream(new File(tmpDirPath + + File.separator + fileName))) { + fos.write(fileContent.getBytes()); + } + } + + private static void deleteDir(Path directory) throws IOException { + Files.walkFileTree(directory, new SimpleFileVisitor() { + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) + throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } +} + diff --git a/test/jdk/sun/security/pkcs11/fips/SunJSSEFIPSInitClient.java b/test/jdk/sun/security/pkcs11/fips/SunJSSEFIPSInitClient.java new file mode 100644 index 00000000000..4bb8efe8c01 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/fips/SunJSSEFIPSInitClient.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.security.Provider; +import java.security.Security; + +public class SunJSSEFIPSInitClient { + public static void main(String[] args) throws Exception { + boolean isSunJSSEFIPS = false; + Provider[] provs = Security.getProviders(); + for (Provider p : provs) { + if (p.getName().equals("SunJSSE") && + p instanceof com.sun.net.ssl.internal.ssl.Provider) { + isSunJSSEFIPS = ((com.sun.net.ssl.internal.ssl.Provider)p).isFIPS(); + break; + } + } + System.out.println("SunJSSE.isFIPS(): " + isSunJSSEFIPS); + } +} + diff --git a/test/jdk/sun/text/resources/LocaleData b/test/jdk/sun/text/resources/LocaleData index b71bc3ac9ef..123928c0803 100644 --- a/test/jdk/sun/text/resources/LocaleData +++ b/test/jdk/sun/text/resources/LocaleData @@ -8322,7 +8322,15 @@ CurrencyNames//mru=Mauritanian Ouguiya # bug #8208746 CurrencyNames//ves=Venezuelan Bol\u00edvar Soberano -# bug# 8206879 +# bug #8206879 # For Peru decimal separator is changed to dot(.) and grouping separator is changed to comma(,) FormatData/es_PE/NumberElements/0=. FormatData/es_PE/NumberElements/1=, + +# bug #8227127 +FormatData/ja/short.Eras/0=\u7d00\u5143\u524d +FormatData/ja/short.Eras/1=\u897f\u66a6 +FormatData/zh/short.Eras/0=\u516c\u5143\u524d +FormatData/zh/short.Eras/1=\u516c\u5143 +FormatData/zh_TW/short.Eras/0=\u897f\u5143\u524d +FormatData/zh_TW/short.Eras/1=\u897f\u5143 diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index 54c5b5b7bb7..910f2ad4c39 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -39,7 +39,7 @@ * 8017142 8037343 8055222 8042126 8074791 8075173 8080774 8129361 8134916 * 8145136 8145952 8164784 8037111 8081643 7037368 8178872 8185841 8190918 * 8187946 8195478 8181157 8179071 8193552 8202026 8204269 8202537 8208746 - * 8209775 + * 8209775 8227127 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata diff --git a/test/jdk/tools/jimage/JImageExtractTest.java b/test/jdk/tools/jimage/JImageExtractTest.java index 3b636e698fa..4895fdf218e 100644 --- a/test/jdk/tools/jimage/JImageExtractTest.java +++ b/test/jdk/tools/jimage/JImageExtractTest.java @@ -27,7 +27,7 @@ * @library /test/lib * @modules jdk.jlink/jdk.tools.jimage * @build jdk.test.lib.Asserts - * @run main/othervm JImageExtractTest + * @run main/othervm/timeout=300 JImageExtractTest */ import java.io.IOException; diff --git a/test/jdk/tools/launcher/HelpFlagsTest.java b/test/jdk/tools/launcher/HelpFlagsTest.java index b19042fde85..5d7ed9b7191 100644 --- a/test/jdk/tools/launcher/HelpFlagsTest.java +++ b/test/jdk/tools/launcher/HelpFlagsTest.java @@ -140,6 +140,7 @@ private static class ToolHelpSpec { new ToolHelpSpec("jdb", 1, 1, 1, 0, 1, 1, 0), // -?, -h, --help -help, Documents -help new ToolHelpSpec("jdeprscan", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help new ToolHelpSpec("jdeps", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented. + new ToolHelpSpec("jfr", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help new ToolHelpSpec("jhsdb", 0, 0, 0, 0, 0, 0, 0), // none, prints help message anyways. new ToolHelpSpec("jimage", 1, 1, 1, 0, 0, 0, 2), // -?, -h, --help new ToolHelpSpec("jinfo", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help @@ -224,6 +225,7 @@ static boolean findFlagInLine(String line, String flag) { line.charAt(posAfter) != ',' && line.charAt(posAfter) != '[' && // jar line.charAt(posAfter) != ']' && // jarsigner + line.charAt(posAfter) != ')' && // jfr line.charAt(posAfter) != '|' && // jstatd line.charAt(posAfter) != ':' && // jps line.charAt(posAfter) != '"') { // keytool diff --git a/test/jdk/tools/launcher/VersionCheck.java b/test/jdk/tools/launcher/VersionCheck.java index 4bb2dc72d10..148ecee651e 100644 --- a/test/jdk/tools/launcher/VersionCheck.java +++ b/test/jdk/tools/launcher/VersionCheck.java @@ -88,6 +88,7 @@ public class VersionCheck extends TestHelper { "jcontrol", "jdeprscan", "jdeps", + "jfr", "jimage", "jinfo", "jlink", diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index dbef9d77e82..84d5a559ddb 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -45,6 +45,7 @@ import sun.hotspot.gc.GC; import sun.hotspot.WhiteBox; import jdk.test.lib.Platform; +import jdk.test.lib.Container; /** * The Class to be invoked by jtreg prior Test Suite execution to @@ -84,7 +85,7 @@ public Map call() { map.put("vm.hasJFR", vmHasJFR()); map.put("vm.cpu.features", cpuFeatures()); map.put("vm.rtm.cpu", vmRTMCPU()); - map.put("vm.rtm.os", vmRTMOS()); + map.put("vm.rtm.compiler", vmRTMCompiler()); map.put("vm.aot", vmAOT()); // vm.cds is true if the VM is compiled with cds support. map.put("vm.cds", vmCDS()); @@ -131,8 +132,6 @@ else if (arch.contains("86")) { } } - - /** * @return VM type value extracted from the "java.vm.name" property. */ @@ -215,7 +214,22 @@ protected String vmDebug() { */ protected String vmJvmci() { // builds with jvmci have this flag - return "" + (WB.getBooleanVMFlag("EnableJVMCI") != null); + if (WB.getBooleanVMFlag("EnableJVMCI") == null) { + return "false"; + } + + switch (GC.selected()) { + case Serial: + case Parallel: + case G1: + // These GCs are supported with JVMCI + return "true"; + default: + break; + } + + // Every other GC is not supported + return "false"; } /** @@ -301,24 +315,16 @@ protected String vmHasJFR() { } /** - * @return true if VM runs RTM supported OS and false otherwise. + * @return true if compiler in use supports RTM and false otherwise. */ - protected String vmRTMOS() { - boolean isRTMOS = true; - - if (Platform.isAix()) { - // Actually, this works since AIX 7.1.3.30, but os.version property - // is set to 7.1. - isRTMOS = (Platform.getOsVersionMajor() > 7) || - (Platform.getOsVersionMajor() == 7 && Platform.getOsVersionMinor() > 1); - - } else if (Platform.isLinux()) { - if (Platform.isPPC()) { - isRTMOS = (Platform.getOsVersionMajor() > 4) || - (Platform.getOsVersionMajor() == 4 && Platform.getOsVersionMinor() > 1); - } + protected String vmRTMCompiler() { + boolean isRTMCompiler = false; + + if (Compiler.isC2Enabled() && + (Platform.isX86() || Platform.isX64() || Platform.isPPC())) { + isRTMCompiler = true; } - return "" + isRTMOS; + return "" + isRTMCompiler; } /** @@ -341,7 +347,24 @@ protected String vmAOT() { } else { jaotc = bin.resolve("jaotc"); } - return "" + Files.exists(jaotc); + + if (!Files.exists(jaotc)) { + // No jaotc => no AOT + return "false"; + } + + switch (GC.selected()) { + case Serial: + case Parallel: + case G1: + // These GCs are supported with AOT + return "true"; + default: + break; + } + + // Every other GC is not supported + return "false"; } /** @@ -416,7 +439,7 @@ protected String isCompiler2Enabled() { * @return true if docker is supported in a given environment */ protected String dockerSupport() { - boolean isSupported = false; + boolean isSupported = true; if (Platform.isLinux()) { // currently docker testing is only supported for Linux, // on certain platforms @@ -449,7 +472,7 @@ else if (arch.equals("ppc64le")) { } private boolean checkDockerSupport() throws IOException, InterruptedException { - ProcessBuilder pb = new ProcessBuilder("docker", "ps"); + ProcessBuilder pb = new ProcessBuilder(Container.ENGINE_COMMAND, "ps"); Process p = pb.start(); p.waitFor(10, TimeUnit.SECONDS); diff --git a/test/langtools/tools/javac/T8152616.java b/test/langtools/tools/javac/T8152616.java index 9b49f283152..e2c6d38eaf6 100644 --- a/test/langtools/tools/javac/T8152616.java +++ b/test/langtools/tools/javac/T8152616.java @@ -25,8 +25,8 @@ * @test * @bug 8152616 * @summary Unit test for corner case of PrettyPrinting when SourceOutput is false - * @run compile --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED T8152616.java - * @run main T8152616 + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.tree */ import java.io.File; diff --git a/test/lib/jdk/test/lib/Container.java b/test/lib/jdk/test/lib/Container.java new file mode 100644 index 00000000000..e0ca4851e14 --- /dev/null +++ b/test/lib/jdk/test/lib/Container.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.test.lib; + +public class Container { + // Use this property to specify docker location on your system. + // E.g.: "/usr/local/bin/docker". We define this constant here so + // that it can be used in VMProps as well which checks docker support + // via this command + public static final String ENGINE_COMMAND = + System.getProperty("jdk.test.container.command", "docker"); +} diff --git a/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java b/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java index 0c8c4b118fb..d4c2ccbcad6 100644 --- a/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java +++ b/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java @@ -23,7 +23,6 @@ package jdk.test.lib.artifacts; -import java.io.FileNotFoundException; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; @@ -35,7 +34,7 @@ public static Map resolve(Class klass) throws ArtifactResolverE String managerName = System.getProperty("jdk.test.lib.artifacts.artifactmanager"); if (managerName != null) { manager = (ArtifactManager) Class.forName(managerName).newInstance(); - } else { + } else if (System.getenv().containsKey(JibArtifactManager.JIB_HOME_ENV_NAME)) { manager = JibArtifactManager.newInstance(); } } catch (Exception e) { diff --git a/test/lib/jdk/test/lib/artifacts/JibArtifactManager.java b/test/lib/jdk/test/lib/artifacts/JibArtifactManager.java index 964c324684b..0f08e087807 100644 --- a/test/lib/jdk/test/lib/artifacts/JibArtifactManager.java +++ b/test/lib/jdk/test/lib/artifacts/JibArtifactManager.java @@ -23,26 +23,66 @@ package jdk.test.lib.artifacts; -import java.io.FileNotFoundException; +import java.io.UncheckedIOException; import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; +import java.util.stream.Stream; public class JibArtifactManager implements ArtifactManager { private static final String JIB_SERVICE_FACTORY = "com.oracle.jib.api.JibServiceFactory"; + public static final String JIB_HOME_ENV_NAME = "JIB_HOME"; private static String jibVersion = "1.0"; + private Object installerObject; + private ClassLoader classLoader; - private JibArtifactManager(Object o) { - installerObject = o; + private JibArtifactManager(Object installerObject, ClassLoader classLoader) { + this.installerObject = installerObject; + this.classLoader = classLoader; } public static JibArtifactManager newInstance() throws ClassNotFoundException { + Path jibInstallDir = Paths.get(System.getenv(JIB_HOME_ENV_NAME)); + Path libDir = jibInstallDir.resolve("lib"); + if (!Files.isDirectory(libDir)) { + throw new ClassNotFoundException(JIB_SERVICE_FACTORY); + } try { - Class jibServiceFactory = Class.forName(JIB_SERVICE_FACTORY); - Object jibArtifactInstaller = jibServiceFactory.getMethod("createJibArtifactInstaller").invoke(null); - return new JibArtifactManager(jibArtifactInstaller); + URL[] jarUrls; + try (Stream files = Files.list(libDir)) { + jarUrls = files.filter(path -> path.toString().endsWith(".jar")) + .map(path -> { + try { + return path.toUri().toURL(); + } catch (MalformedURLException e) { + throw new UncheckedIOException(e); + } + }).toArray(URL[]::new); + } + // Create a class loader using all those jars and set the parent to the + // current class loader's parent. + ClassLoader classLoader = new URLClassLoader(jarUrls, JibArtifactManager.class.getClassLoader().getParent()); + + // Temporarily replace the context classLoader + Thread currentThread = Thread.currentThread(); + ClassLoader oldContextLoader = currentThread.getContextClassLoader(); + currentThread.setContextClassLoader(classLoader); + + Class jibServiceFactory = classLoader.loadClass(JIB_SERVICE_FACTORY); + try { + Object jibArtifactInstaller = jibServiceFactory.getMethod("createJibArtifactInstaller").invoke(null); + return new JibArtifactManager(jibArtifactInstaller, classLoader); + } finally { + currentThread.setContextClassLoader(oldContextLoader); + } + } catch (Exception e) { throw new ClassNotFoundException(JIB_SERVICE_FACTORY, e); } @@ -56,9 +96,19 @@ private Path install(String jibVersion, HashMap artifactDescript return invokeInstallerMethod("install", jibVersion, artifactDescription); } - private Path invokeInstallerMethod(String methodName, String jibVersion, HashMap artifactDescription) throws Exception { - Method m = Class.forName("com.oracle.jib.api.JibArtifactInstaller").getMethod(methodName, String.class, Map.class); - return (Path)m.invoke(installerObject, jibVersion, artifactDescription); + private Path invokeInstallerMethod(String methodName, String jibVersion, + HashMap artifactDescription) throws Exception { + // Temporarily replace the context classLoader + Thread currentThread = Thread.currentThread(); + ClassLoader oldContextLoader = currentThread.getContextClassLoader(); + currentThread.setContextClassLoader(classLoader); + try { + Method m = classLoader.loadClass("com.oracle.jib.api.JibArtifactInstaller") + .getMethod(methodName, String.class, Map.class); + return (Path) m.invoke(installerObject, jibVersion, artifactDescription); + } finally { + currentThread.setContextClassLoader(oldContextLoader); + } } @Override @@ -89,5 +139,5 @@ public Path resolve(Artifact artifact) throws ArtifactResolverException { } } return path; - } + } } diff --git a/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java b/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java index cbd3e83a0af..5450a551d87 100644 --- a/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java +++ b/test/lib/jdk/test/lib/containers/cgroup/MetricsTester.java @@ -550,16 +550,20 @@ public void testCpuConsumption() throws IOException, InterruptedException { long newUsage = metrics.getCpuUsage(); long[] newPerCpu = metrics.getPerCpuUsage(); - if (newSysVal <= startSysVal) { + // system/user CPU usage counters may be slowly increasing. + // allow for equal values for a pass + if (newSysVal < startSysVal) { fail(SubSystem.CPU, "getCpuSystemUsage", newSysVal, startSysVal); } - if (newUserVal <= startUserVal) { + // system/user CPU usage counters may be slowly increasing. + // allow for equal values for a pass + if (newUserVal < startUserVal) { fail(SubSystem.CPU, "getCpuUserUsage", newUserVal, startUserVal); } if (newUsage <= startUsage) { - fail(SubSystem.CPU, "getCpuUserUsage", newUsage, startUsage); + fail(SubSystem.CPU, "getCpuUsage", newUsage, startUsage); } boolean success = false; @@ -578,19 +582,28 @@ public void testMemoryUsage() throws Exception { Metrics metrics = Metrics.systemMetrics(); long memoryMaxUsage = metrics.getMemoryMaxUsage(); long memoryUsage = metrics.getMemoryUsage(); + long newMemoryMaxUsage = 0, newMemoryUsage = 0; + + // allocate memory in a loop and check more than once for new values + // otherwise we might see seldom the effect of decreasing new memory values + // e.g. because the system could free up memory + byte[][] bytes = new byte[32][]; + for (int i = 0; i < 32; i++) { + bytes[i] = new byte[8*1024*1024]; + newMemoryUsage = metrics.getMemoryUsage(); + if (newMemoryUsage > memoryUsage) { + break; + } + } + newMemoryMaxUsage = metrics.getMemoryMaxUsage(); - long[] ll = new long[64*1024*1024]; // 64M - - long newMemoryMaxUsage = metrics.getMemoryMaxUsage(); - long newMemoryUsage = metrics.getMemoryUsage(); - - if(newMemoryMaxUsage < memoryMaxUsage) { - fail(SubSystem.MEMORY, "getMemoryMaxUsage", newMemoryMaxUsage, - memoryMaxUsage); + if (newMemoryMaxUsage < memoryMaxUsage) { + fail(SubSystem.MEMORY, "getMemoryMaxUsage", memoryMaxUsage, + newMemoryMaxUsage); } - if(newMemoryUsage < memoryUsage) { - fail(SubSystem.MEMORY, "getMemoryUsage", newMemoryUsage, memoryUsage); + if (newMemoryUsage < memoryUsage) { + fail(SubSystem.MEMORY, "getMemoryUsage", memoryUsage, newMemoryUsage); } } diff --git a/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java b/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java index e7da42ff780..508c17fc399 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerRunOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, 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,13 @@ // in test environment. public class DockerRunOptions { public String imageNameAndTag; - public ArrayList dockerOpts = new ArrayList(); + public ArrayList dockerOpts = new ArrayList<>(); public String command; // normally a full path to java - public ArrayList javaOpts = new ArrayList(); + public ArrayList javaOpts = new ArrayList<>(); + // more java options, but to be set AFTER the test Java options + public ArrayList javaOptsAppended = new ArrayList<>(); public String classToRun; // class or "-version" - public ArrayList classParams = new ArrayList(); + public ArrayList classParams = new ArrayList<>(); public boolean tty = true; public boolean removeContainerAfterUse = true; @@ -70,6 +72,11 @@ public DockerRunOptions addJavaOpts(String... opts) { return this; } + public DockerRunOptions addJavaOptsAppended(String... opts) { + Collections.addAll(javaOptsAppended, opts); + return this; + } + public DockerRunOptions addClassOptions(String... opts) { Collections.addAll(classParams,opts); return this; diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index ff3674fe6b2..05cf84d4c21 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -37,14 +37,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import jdk.test.lib.Container; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import jtreg.SkippedException; public class DockerTestUtils { - private static final String FS = File.separator; private static boolean isDockerEngineAvailable = false; private static boolean wasDockerEngineChecked = false; @@ -54,11 +53,6 @@ public class DockerTestUtils { // diagnostic information. private static final int MAX_LINES_TO_COPY_FOR_CHILD_STDOUT = 100; - // Use this property to specify docker location on your system. - // E.g.: "/usr/local/bin/docker". - private static final String DOCKER_COMMAND = - System.getProperty("jdk.test.docker.command", "docker"); - // Set this property to true to retain image after test. By default // images are removed after test execution completes. // Retaining the image can be useful for diagnostics and image inspection. @@ -116,7 +110,7 @@ public static boolean canTestDocker() throws Exception { */ private static boolean isDockerEngineAvailableCheck() throws Exception { try { - execute(DOCKER_COMMAND, "ps") + execute(Container.ENGINE_COMMAND, "ps") .shouldHaveExitValue(0) .shouldContain("CONTAINER") .shouldContain("IMAGE"); @@ -179,9 +173,8 @@ private static boolean isDockerEngineAvailableCheck() throws Exception { DockerfileConfig.getBaseImageVersion()); try { // Build the docker - execute(DOCKER_COMMAND, "build", "--no-cache", "--tag", imageName, buildDir.toString()) - .shouldHaveExitValue(0) - .shouldContain("Successfully built"); + execute(Container.ENGINE_COMMAND, "build", "--no-cache", "--tag", imageName, buildDir.toString()) + .shouldHaveExitValue(0); } catch (Exception e) { // If docker image building fails there is a good chance it happens due to environment and/or // configuration other than product failure. Throw jtreg skipped exception in such case @@ -192,17 +185,17 @@ private static boolean isDockerEngineAvailableCheck() throws Exception { /** - * Run Java inside the docker image with specified parameters and options. + * Build the docker command to run java inside a container * * @param DockerRunOptions optins for running docker * - * @return output of the run command + * @return command * @throws Exception */ - public static OutputAnalyzer dockerRunJava(DockerRunOptions opts) throws Exception { - ArrayList cmd = new ArrayList<>(); + public static List buildJavaCommand(DockerRunOptions opts) throws Exception { + List cmd = new ArrayList<>(); - cmd.add(DOCKER_COMMAND); + cmd.add(Container.ENGINE_COMMAND); cmd.add("run"); if (opts.tty) cmd.add("--tty=true"); @@ -217,11 +210,24 @@ public static OutputAnalyzer dockerRunJava(DockerRunOptions opts) throws Excepti if (opts.appendTestJavaOptions) { Collections.addAll(cmd, Utils.getTestJavaOpts()); } + cmd.addAll(opts.javaOptsAppended); cmd.add(opts.classToRun); cmd.addAll(opts.classParams); - return execute(cmd); + return cmd; + } + + /** + * Run Java inside the docker image with specified parameters and options. + * + * @param DockerRunOptions optins for running docker + * + * @return output of the run command + * @throws Exception + */ + public static OutputAnalyzer dockerRunJava(DockerRunOptions opts) throws Exception { + return execute(buildJavaCommand(opts)); } @@ -232,7 +238,7 @@ public static OutputAnalyzer dockerRunJava(DockerRunOptions opts) throws Excepti * @throws Exception */ public static void removeDockerImage(String imageNameAndTag) throws Exception { - execute(DOCKER_COMMAND, "rmi", "--force", imageNameAndTag); + execute(Container.ENGINE_COMMAND, "rmi", "--force", imageNameAndTag); } diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index 74c185d2514..d729ff9c10d 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -147,6 +147,7 @@ public class EventNames { // OS public final static String OSInformation = PREFIX + "OSInformation"; + public final static String VirtualizationInformation = PREFIX + "VirtualizationInformation"; public final static String CPUInformation = PREFIX + "CPUInformation"; public final static String CPULoad = PREFIX + "CPULoad"; public final static String ThreadCPULoad = PREFIX + "ThreadCPULoad"; diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 003c987bd40..034ddc5a099 100644 --- a/test/lib/sun/hotspot/WhiteBox.java +++ b/test/lib/sun/hotspot/WhiteBox.java @@ -103,6 +103,7 @@ public boolean isClassAlive(String name) { return isClassAlive0(name.replace('.', '/')); } private native boolean isClassAlive0(String name); + public native int getSymbolRefcount(String name); private native boolean isMonitorInflated0(Object obj); public boolean isMonitorInflated(Object obj) { diff --git a/test/lib/sun/hotspot/gc/GC.java b/test/lib/sun/hotspot/gc/GC.java index bfc872097a4..2cd83b69fe1 100644 --- a/test/lib/sun/hotspot/gc/GC.java +++ b/test/lib/sun/hotspot/gc/GC.java @@ -69,4 +69,16 @@ public boolean isSelected() { public static boolean isSelectedErgonomically() { return WB.isGCSelectedErgonomically(); } + + /** + * @return the selected GC. + */ + public static GC selected() { + for (GC gc : values()) { + if (gc.isSelected()) { + return gc; + } + } + throw new IllegalStateException("No selected GC found"); + } }

    Event setting names and their purpose.