OpenJDK / jdk / jdk12
changeset 28861:d795a84f0d6a
Merge
author | ctornqvi |
---|---|
date | Wed, 04 Feb 2015 18:23:09 -0800 |
parents | 1bd6abc33423 0e2d88aaff6f |
children | 1e61b751d07c |
files | jdk/test/java/util/ResourceBundle/Bug6287579.java |
diffstat | 249 files changed, 8082 insertions(+), 2289 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Tue Feb 03 16:46:05 2015 +0100 +++ b/.hgtags Wed Feb 04 18:23:09 2015 -0800 @@ -290,3 +290,4 @@ bfc24ae2b900187585079bb11e66e459d1e525fe jdk9-b45 722378bc599e38d9a1dd484de30f10dfd7b21438 jdk9-b46 8327024a99559982b848e9c2191da9c0bf8838fd jdk9-b47 +b2f9702efbe95527ea3a991474fda23987ff1c5c jdk9-b48
--- a/.hgtags-top-repo Tue Feb 03 16:46:05 2015 +0100 +++ b/.hgtags-top-repo Wed Feb 04 18:23:09 2015 -0800 @@ -290,3 +290,4 @@ 3dd628fde2086218d548841022ee8436b6b88185 jdk9-b45 12f1e276447bcc81516e85367d53e4f08897049d jdk9-b46 b6cca3e6175a69f39e5799b7349ddb0176630291 jdk9-b47 +0064e246d83f6f9fc245c19b6d05041ecaf4b6d4 jdk9-b48
--- a/common/autoconf/basics.m4 Tue Feb 03 16:46:05 2015 +0100 +++ b/common/autoconf/basics.m4 Wed Feb 04 18:23:09 2015 -0800 @@ -987,3 +987,26 @@ IS_RECONFIGURE=no fi ]) + +# Check for support for specific options in bash +AC_DEFUN_ONCE([BASIC_CHECK_BASH_OPTIONS], +[ + # Test if bash supports pipefail. + AC_MSG_CHECKING([if bash supports pipefail]) + if ${BASH} -c 'set -o pipefail'; then + BASH_ARGS="$BASH_ARGS -o pipefail" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + AC_MSG_CHECKING([if bash supports errexit (-e)]) + if ${BASH} -e -c 'true'; then + BASH_ARGS="$BASH_ARGS -e" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + AC_SUBST(BASH_ARGS) +])
--- a/common/autoconf/bootcycle-spec.gmk.in Tue Feb 03 16:46:05 2015 +0100 +++ b/common/autoconf/bootcycle-spec.gmk.in Wed Feb 04 18:23:09 2015 -0800 @@ -46,8 +46,12 @@ BOOT_JDK := $(JDK_IMAGE_DIR) # The bootcycle build has a different output directory -BUILD_OUTPUT:=@BUILD_OUTPUT@/bootcycle-build -SJAVAC_SERVER_DIR:=$(subst @BUILD_OUTPUT@,$(BUILD_OUTPUT),$(SJAVAC_SERVER_DIR)) +OLD_BUILD_OUTPUT:=@BUILD_OUTPUT@ +BUILD_OUTPUT:=$(OLD_BUILD_OUTPUT)/bootcycle-build +# The HOTSPOT_DIST dir is not defined relative to BUILD_OUTPUT in spec.gmk. Must not +# use space in this patsubst to avoid leading space in HOTSPOT_DIST. +HOTSPOT_DIST:=$(patsubst $(OLD_BUILD_OUTPUT)%,$(BUILD_OUTPUT)%,$(HOTSPOT_DIST)) +SJAVAC_SERVER_DIR:=$(patsubst $(OLD_BUILD_OUTPUT)%, $(BUILD_OUTPUT)%, $(SJAVAC_SERVER_DIR)) JAVA_CMD:=$(BOOT_JDK)/bin/java JAVAC_CMD:=$(BOOT_JDK)/bin/javac
--- a/common/autoconf/configure.ac Tue Feb 03 16:46:05 2015 +0100 +++ b/common/autoconf/configure.ac Wed Feb 04 18:23:09 2015 -0800 @@ -113,6 +113,7 @@ # Setup tools that requires more complex handling, or that is not needed by the configure script. BASIC_SETUP_COMPLEX_TOOLS +BASIC_CHECK_BASH_OPTIONS # Check if pkg-config is available. PKG_PROG_PKG_CONFIG
--- a/common/autoconf/generated-configure.sh Tue Feb 03 16:46:05 2015 +0100 +++ b/common/autoconf/generated-configure.sh Wed Feb 04 18:23:09 2015 -0800 @@ -853,6 +853,7 @@ OS_VERSION_MINOR OS_VERSION_MAJOR PKG_CONFIG +BASH_ARGS CODESIGN XATTR DSYMUTIL @@ -3522,6 +3523,9 @@ +# Check for support for specific options in bash + + # # Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -4329,7 +4333,7 @@ #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1420811523 +DATE_WHEN_GENERATED=1421247827 ############################################################################### # @@ -19609,6 +19613,32 @@ fi + # Test if bash supports pipefail. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if bash supports pipefail" >&5 +$as_echo_n "checking if bash supports pipefail... " >&6; } + if ${BASH} -c 'set -o pipefail'; then + BASH_ARGS="$BASH_ARGS -o pipefail" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if bash supports errexit (-e)" >&5 +$as_echo_n "checking if bash supports errexit (-e)... " >&6; } + if ${BASH} -e -c 'true'; then + BASH_ARGS="$BASH_ARGS -e" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + + + # Check if pkg-config is available. @@ -27408,8 +27438,8 @@ # The trailing space for everyone except PATH is no typo, but is needed due # to trailing \ in the Windows paths. These will be stripped later. $ECHO "$WINPATH_BASH -c 'echo VS_PATH="'\"$PATH\" > set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE - $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE\;$include \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE - $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB\;$lib \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE $ECHO "$WINPATH_BASH -c 'echo VCINSTALLDIR="'\"$VCINSTALLDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE $ECHO "$WINPATH_BASH -c 'echo WindowsSdkDir="'\"$WindowsSdkDir \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE $ECHO "$WINPATH_BASH -c 'echo WINDOWSSDKDIR="'\"$WINDOWSSDKDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE
--- a/common/autoconf/spec.gmk.in Tue Feb 03 16:46:05 2015 +0100 +++ b/common/autoconf/spec.gmk.in Wed Feb 04 18:23:09 2015 -0800 @@ -78,6 +78,11 @@ OUTPUT_SYNC_SUPPORTED:=@OUTPUT_SYNC_SUPPORTED@ OUTPUT_SYNC:=@OUTPUT_SYNC@ +# Override the shell with bash +BASH:=@BASH@ +BASH_ARGS:=@BASH_ARGS@ +SHELL:=$(BASH) $(BASH_ARGS) + # The "human readable" name of this configuration CONF_NAME:=@CONF_NAME@ @@ -243,7 +248,7 @@ HOTSPOT_OUTPUTDIR=$(BUILD_OUTPUT)/hotspot JDK_OUTPUTDIR=$(BUILD_OUTPUT)/jdk IMAGES_OUTPUTDIR=$(BUILD_OUTPUT)/images -TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/testmake +TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/test-make MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/make-support HOTSPOT_DIST=@HOTSPOT_DIST@ @@ -495,7 +500,6 @@ # Tools adhering to a minimal and common standard of posix compliance. AWK:=@AWK@ BASENAME:=@BASENAME@ -BASH:=@BASH@ CAT:=@CAT@ CCACHE:=@CCACHE@ # CD is going away, but remains to cater for legacy makefiles.
--- a/corba/.hgtags Tue Feb 03 16:46:05 2015 +0100 +++ b/corba/.hgtags Wed Feb 04 18:23:09 2015 -0800 @@ -290,3 +290,4 @@ 9e3f2bed80c0e5a84a256ce41f1d10c5ade48466 jdk9-b45 326f2068b4a4c05e2fa27d6acf93eba7b54b090d jdk9-b46 ee8447ca632e1d39180b4767c749db101bff7314 jdk9-b47 +a13c49c5f2899b702652a460ed7aa73123e671e6 jdk9-b48
--- a/hotspot/.hgtags Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/.hgtags Wed Feb 04 18:23:09 2015 -0800 @@ -450,3 +450,4 @@ 5dc8184af1e2bb30b0103113d1f1a58a21a80c37 jdk9-b45 a184ee1d717297bd35b7c3e35393e137921a3ed2 jdk9-b46 3b241fb72b8925b75941d612db762a6d5da66d02 jdk9-b47 +cc775a4a24c7f5d9e624b4205e9fbd48a17331f6 jdk9-b48
--- a/hotspot/make/aix/Makefile Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/aix/Makefile Wed Feb 04 18:23:09 2015 -0800 @@ -246,8 +246,7 @@ XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \
--- a/hotspot/make/aix/makefiles/xlc.make Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/aix/makefiles/xlc.make Wed Feb 04 18:23:09 2015 -0800 @@ -74,6 +74,12 @@ # no xlc counterpart for -fcheck-new # CFLAGS += -fcheck-new +# We need to define this on the command line if we want to use the the +# predefined format specifiers from "inttypes.h". Otherwise system headrs +# can indirectly include inttypes.h before we define __STDC_FORMAT_MACROS +# in globalDefinitions.hpp +CFLAGS += -D__STDC_FORMAT_MACROS + ARCHFLAG = -q64 CFLAGS += $(ARCHFLAG)
--- a/hotspot/make/bsd/Makefile Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/bsd/Makefile Wed Feb 04 18:23:09 2015 -0800 @@ -240,8 +240,7 @@ XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \
--- a/hotspot/make/bsd/makefiles/dtrace.make Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/bsd/makefiles/dtrace.make Wed Feb 04 18:23:09 2015 -0800 @@ -179,23 +179,23 @@ # $@.tmp is created first to avoid an empty $(JVMOFFS).h if an error occurs. $(JVMOFFS).h: $(GENOFFS) $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -header > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1 ; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS)Index.h: $(GENOFFS) $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -index > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1 ; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS).cpp: $(GENOFFS) $(JVMOFFS).h $(JVMOFFS)Index.h $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -table > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS.o): $(JVMOFFS).h $(JVMOFFS).cpp
--- a/hotspot/make/bsd/makefiles/universal.gmk Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/bsd/makefiles/universal.gmk Wed Feb 04 18:23:09 2015 -0800 @@ -59,7 +59,7 @@ # Package built libraries in a universal binary $(UNIVERSAL_LIPO_LIST): - BUILT_LIPO_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`"; \ + BUILT_LIPO_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_LIPO_FILES}" ]; then \ $(MKDIR) -p $(shell dirname $@); \ lipo -create -output $@ $${BUILT_LIPO_FILES}; \ @@ -70,7 +70,7 @@ # - copies directories; including empty dirs # - copies files, symlinks, other non-directory files $(UNIVERSAL_COPY_LIST): - BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) -prune 2>/dev/null`"; \ + BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) -prune 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_COPY_FILES}" ]; then \ for i in $${BUILT_COPY_FILES}; do \ $(MKDIR) -p $(shell dirname $@); \
--- a/hotspot/make/linux/Makefile Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/linux/Makefile Wed Feb 04 18:23:09 2015 -0800 @@ -246,8 +246,7 @@ XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \
--- a/hotspot/make/linux/makefiles/vm.make Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/linux/makefiles/vm.make Wed Feb 04 18:23:09 2015 -0800 @@ -334,10 +334,8 @@ rm -f $@.1; ln -s $@ $@.1; \ if [ \"$(CROSS_COMPILE_ARCH)\" = \"\" ] ; then \ if [ -x /usr/sbin/selinuxenabled ] ; then \ - /usr/sbin/selinuxenabled; \ - if [ $$? = 0 ] ; then \ - /usr/bin/chcon -t textrel_shlib_t $@; \ - if [ $$? != 0 ]; then \ + if /usr/sbin/selinuxenabled; then \ + if ! /usr/bin/chcon -t textrel_shlib_t $@; then \ echo "ERROR: Cannot chcon $@"; \ fi \ fi \
--- a/hotspot/make/sa.files Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/sa.files Wed Feb 04 18:23:09 2015 -0800 @@ -39,6 +39,7 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/c1/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/ci/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/classfile/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/code/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/compiler/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/*.java \ @@ -49,8 +50,10 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/dummy/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/sparc/*.java \ @@ -71,6 +74,7 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/win32/coff/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/amd64/*.java \ @@ -101,6 +105,8 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/x86/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/jcore/*.java \
--- a/hotspot/make/solaris/Makefile Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/solaris/Makefile Wed Feb 04 18:23:09 2015 -0800 @@ -190,8 +190,7 @@ XSLT_CHECK = $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \
--- a/hotspot/make/solaris/makefiles/dtrace.make Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/make/solaris/makefiles/dtrace.make Wed Feb 04 18:23:09 2015 -0800 @@ -171,11 +171,11 @@ ./lib$(GENOFFS).so CONDITIONALLY_UPDATE_JVMOFFS_TARGET = \ - cmp -s $@ $@.tmp; \ - case $$? in \ - 0) rm -f $@.tmp;; \ - *) rm -f $@ && mv $@.tmp $@ && echo Updated $@;; \ - esac + if cmp -s $@ $@.tmp; then \ + rm -f $@.tmp; \ + else \ + rm -f $@ && mv $@.tmp $@ && echo Updated $@; \ + fi # $@.tmp is created first to avoid an empty $(JVMOFFS).h if an error occurs. $(JVMOFFS).h: $(GENOFFS)
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -567,16 +567,21 @@ inline void load_with_trap_null_check(Register d, int si16, Register s1); // Load heap oop and decompress. Loaded oop may not be null. - inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg); + // Specify tmp to save one cycle. + inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg, + Register tmp = noreg); + // Store heap oop and decompress. Decompressed oop may not be null. + // Specify tmp register if d should not be changed. inline void store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, - /*specify if d must stay uncompressed*/ Register tmp = noreg); + Register tmp = noreg); // Null allowed. inline void load_heap_oop(Register d, RegisterOrConstant offs, Register s1 = noreg); // Encode/decode heap oop. Oop may not be null, else en/decoding goes wrong. + // src == d allowed. inline Register encode_heap_oop_not_null(Register d, Register src = noreg); - inline void decode_heap_oop_not_null(Register d); + inline Register decode_heap_oop_not_null(Register d, Register src = noreg); // Null allowed. inline void decode_heap_oop(Register d);
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -311,11 +311,14 @@ ld(d, si16, s1); } -inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1) { +inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) { if (UseCompressedOops) { - lwz(d, offs, s1); + // In disjoint mode decoding can save a cycle if src != dst. + Register narrowOop = (tmp != noreg && Universe::narrow_oop_base_disjoint()) ? tmp : d; + lwz(narrowOop, offs, s1); // Attention: no null check here! - decode_heap_oop_not_null(d); + Register res = decode_heap_oop_not_null(d, narrowOop); + assert(res == d, "caller will not consume loaded value"); } else { ld(d, offs, s1); } @@ -340,26 +343,36 @@ } inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register src) { - Register current = (src!=noreg) ? src : d; // Compressed oop is in d if no src provided. - if (Universe::narrow_oop_base() != NULL) { + Register current = (src != noreg) ? src : d; // Oop to be compressed is in d if no src provided. + if (Universe::narrow_oop_base_overlaps()) { sub(d, current, R30); current = d; } if (Universe::narrow_oop_shift() != 0) { - srdi(d, current, LogMinObjAlignmentInBytes); + rldicl(d, current, 64-Universe::narrow_oop_shift(), 32); // Clears the upper bits. current = d; } return current; // Encoded oop is in this register. } -inline void MacroAssembler::decode_heap_oop_not_null(Register d) { +inline Register MacroAssembler::decode_heap_oop_not_null(Register d, Register src) { + if (Universe::narrow_oop_base_disjoint() && src != noreg && src != d && + Universe::narrow_oop_shift() != 0) { + mr(d, R30); + rldimi(d, src, Universe::narrow_oop_shift(), 32-Universe::narrow_oop_shift()); + return d; + } + + Register current = (src != noreg) ? src : d; // Compressed oop is in d if no src provided. if (Universe::narrow_oop_shift() != 0) { - assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - sldi(d, d, LogMinObjAlignmentInBytes); + sldi(d, current, Universe::narrow_oop_shift()); + current = d; } if (Universe::narrow_oop_base() != NULL) { - add(d, d, R30); + add(d, current, R30); + current = d; } + return current; // Decoded oop is in this register. } inline void MacroAssembler::decode_heap_oop(Register d) { @@ -368,13 +381,7 @@ cmpwi(CCR0, d, 0); beq(CCR0, isNull); } - if (Universe::narrow_oop_shift() != 0) { - assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - sldi(d, d, LogMinObjAlignmentInBytes); - } - if (Universe::narrow_oop_base() != NULL) { - add(d, d, R30); - } + decode_heap_oop_not_null(d); bind(isNull); }
--- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -172,15 +172,15 @@ // Load the invoker, as MH -> MH.form -> LF.vmentry __ verify_oop(recv); - __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), recv); + __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), recv, temp2); __ verify_oop(method_temp); - __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp); + __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp, temp2); __ verify_oop(method_temp); - // the following assumes that a Method* is normally compressed in the vmtarget field: + // The following assumes that a Method* is normally compressed in the vmtarget field: __ ld(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()), method_temp); if (VerifyMethodHandles && !for_compiler_entry) { - // make sure recv is already on stack + // Make sure recv is already on stack. __ ld(temp2, in_bytes(Method::const_offset()), method_temp); __ load_sized_value(temp2, in_bytes(ConstMethod::size_of_parameters_offset()), temp2, sizeof(u2), /*is_signed*/ false); @@ -259,8 +259,9 @@ } if (TraceMethodHandles) { - if (tmp_mh != noreg) + if (tmp_mh != noreg) { __ mr(R23_method_handle, tmp_mh); // make stub happy + } trace_method_handle_interpreter_entry(_masm, iid); } @@ -332,7 +333,7 @@ if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) { Label L_ok; Register temp2_defc = temp2; - __ load_heap_oop_not_null(temp2_defc, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg); + __ load_heap_oop_not_null(temp2_defc, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg, temp3); load_klass_from_Class(_masm, temp2_defc, temp3, temp4); __ verify_klass_ptr(temp2_defc); __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, temp4, L_ok); @@ -407,7 +408,7 @@ } Register temp2_intf = temp2; - __ load_heap_oop_not_null(temp2_intf, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg); + __ load_heap_oop_not_null(temp2_intf, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg, temp3); load_klass_from_Class(_masm, temp2_intf, temp3, temp4); __ verify_klass_ptr(temp2_intf); @@ -464,7 +465,7 @@ strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH const char* mh_reg_name = has_mh ? "R23_method_handle" : "G23"; tty->print_cr("MH %s %s="INTPTR_FORMAT " sp=" INTPTR_FORMAT, - adaptername, mh_reg_name, (intptr_t) mh, (intptr_t) entry_sp); + adaptername, mh_reg_name, (intptr_t) mh, entry_sp); if (Verbose) { tty->print_cr("Registers:"); @@ -535,23 +536,22 @@ BLOCK_COMMENT("trace_method_handle {"); - int nbytes_save = 10 * 8; // 10 volatile gprs - __ save_LR_CR(R0); - __ mr(R0, R1_SP); // saved_sp - assert(Assembler::is_simm(-nbytes_save, 16), "Overwriting R0"); - // Push_frame_reg_args only uses R0 if nbytes_save is wider than 16 bit. - __ push_frame_reg_args(nbytes_save, R0); - __ save_volatile_gprs(R1_SP, frame::abi_reg_args_size); // Except R0. + const Register tmp = R11; // Will be preserved. + const int nbytes_save = 11*8; // volatile gprs except R0 + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ save_LR_CR(tmp); // save in old frame - __ load_const(R3_ARG1, (address)adaptername); + __ mr(R5_ARG3, R1_SP); // saved_sp + __ push_frame_reg_args(nbytes_save, tmp); + + __ load_const_optimized(R3_ARG1, (address)adaptername, tmp); __ mr(R4_ARG2, R23_method_handle); - __ mr(R5_ARG3, R0); // saved_sp __ mr(R6_ARG4, R1_SP); __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub)); - __ restore_volatile_gprs(R1_SP, 112); // Except R0. __ pop_frame(); - __ restore_LR_CR(R0); + __ restore_LR_CR(tmp); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 BLOCK_COMMENT("} trace_method_handle"); }
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/ppc/vm/ppc.ad Wed Feb 04 18:23:09 2015 -0800 @@ -1,6 +1,6 @@ // -// Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. -// Copyright 2012, 2014 SAP AG. All rights reserved. +// Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +// Copyright 2012, 2015 SAP AG. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -2698,7 +2698,7 @@ const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else if (constant_reloc == relocInfo::metadata_type) { - AddressLiteral a = __ allocate_metadata_address((Metadata *)val); + AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else { @@ -2727,7 +2727,7 @@ const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else if (constant_reloc == relocInfo::metadata_type) { - AddressLiteral a = __ allocate_metadata_address((Metadata *)val); + AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else { // non-oop pointers, e.g. card mark base, heap top @@ -6029,6 +6029,20 @@ ins_pipe(pipe_class_default); %} +// Optimize DecodeN for disjoint base. +// Load base of compressed oops into a register +instruct loadBase(iRegLdst dst) %{ + effect(DEF dst); + + format %{ "MR $dst, r30_heapbase" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_or); + __ mr($dst$$Register, R30); + %} + ins_pipe(pipe_class_default); +%} + // Loading ConN must be postalloc expanded so that edges between // the nodes are safe. They may not interfere with a safepoint. // GL TODO: This needs three instructions: better put this into the constant pool. @@ -6724,13 +6738,12 @@ ins_pipe(pipe_class_default); %} -// base != 0 -// 32G aligned narrow oop base. -instruct encodeP_32GAligned(iRegNdst dst, iRegPsrc src) %{ +// Disjoint narrow oop base. +instruct encodeP_Disjoint(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodeP src)); - predicate(false /* TODO: PPC port Universe::narrow_oop_base_disjoint()*/); - - format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with 32G aligned base" %} + predicate(Universe::narrow_oop_base_disjoint()); + + format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with disjoint base" %} size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_rldicl); @@ -6745,7 +6758,7 @@ effect(TEMP crx); predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull && Universe::narrow_oop_shift() != 0 && - true /* TODO: PPC port Universe::narrow_oop_base_overlaps()*/); + Universe::narrow_oop_base_overlaps()); format %{ "EncodeP $dst, $crx, $src \t// postalloc expanded" %} postalloc_expand( postalloc_expand_encode_oop(dst, src, crx)); @@ -6756,7 +6769,7 @@ match(Set dst (EncodeP src)); predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull && Universe::narrow_oop_shift() != 0 && - true /* TODO: PPC port Universe::narrow_oop_base_overlaps()*/); + Universe::narrow_oop_base_overlaps()); format %{ "EncodeP $dst, $src\t// $src != Null, postalloc expanded" %} postalloc_expand( postalloc_expand_encode_oop_not_null(dst, src) ); @@ -6876,6 +6889,7 @@ n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && Universe::narrow_oop_shift() != 0 && Universe::narrow_oop_base() != 0); + ins_cost(4 * DEFAULT_COST); // Should be more expensive than decodeN_Disjoint_isel_Ex. effect(TEMP crx); format %{ "DecodeN $dst, $src \t// Kills $crx, postalloc expanded" %} @@ -6897,6 +6911,106 @@ ins_pipe(pipe_class_default); %} +// Optimize DecodeN for disjoint base. +// Shift narrow oop and or it into register that already contains the heap base. +// Base == dst must hold, and is assured by construction in postaloc_expand. +instruct decodeN_mergeDisjoint(iRegPdst dst, iRegNsrc src, iRegLsrc base) %{ + match(Set dst (DecodeN src)); + effect(TEMP base); + predicate(false); + + format %{ "RLDIMI $dst, $src, shift, 32-shift \t// DecodeN (disjoint base)" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_rldimi); + __ rldimi($dst$$Register, $src$$Register, Universe::narrow_oop_shift(), 32-Universe::narrow_oop_shift()); + %} + ins_pipe(pipe_class_default); +%} + +// Optimize DecodeN for disjoint base. +// This node requires only one cycle on the critical path. +// We must postalloc_expand as we can not express use_def effects where +// the used register is L and the def'ed register P. +instruct decodeN_Disjoint_notNull_Ex(iRegPdst dst, iRegNsrc src) %{ + match(Set dst (DecodeN src)); + effect(TEMP_DEF dst); + predicate((n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull || + n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && + Universe::narrow_oop_base_disjoint()); + ins_cost(DEFAULT_COST); + + format %{ "MOV $dst, R30 \t\n" + "RLDIMI $dst, $src, shift, 32-shift \t// decode with disjoint base" %} + postalloc_expand %{ + loadBaseNode *n1 = new loadBaseNode(); + n1->add_req(NULL); + n1->_opnds[0] = op_dst; + + decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); + n2->add_req(n_region, n_src, n1); + n2->_opnds[0] = op_dst; + n2->_opnds[1] = op_src; + n2->_opnds[2] = op_dst; + n2->_bottom_type = _bottom_type; + + ra_->set_pair(n1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + + nodes->push(n1); + nodes->push(n2); + %} +%} + +instruct decodeN_Disjoint_isel_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ + match(Set dst (DecodeN src)); + effect(TEMP_DEF dst, TEMP crx); + predicate((n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && + n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && + Universe::narrow_oop_base_disjoint() && VM_Version::has_isel()); + ins_cost(3 * DEFAULT_COST); + + format %{ "DecodeN $dst, $src \t// decode with disjoint base using isel" %} + postalloc_expand %{ + loadBaseNode *n1 = new loadBaseNode(); + n1->add_req(NULL); + n1->_opnds[0] = op_dst; + + cmpN_reg_imm0Node *n_compare = new cmpN_reg_imm0Node(); + n_compare->add_req(n_region, n_src); + n_compare->_opnds[0] = op_crx; + n_compare->_opnds[1] = op_src; + n_compare->_opnds[2] = new immN_0Oper(TypeNarrowOop::NULL_PTR); + + decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); + n2->add_req(n_region, n_src, n1); + n2->_opnds[0] = op_dst; + n2->_opnds[1] = op_src; + n2->_opnds[2] = op_dst; + n2->_bottom_type = _bottom_type; + + cond_set_0_ptrNode *n_cond_set = new cond_set_0_ptrNode(); + n_cond_set->add_req(n_region, n_compare, n2); + n_cond_set->_opnds[0] = op_dst; + n_cond_set->_opnds[1] = op_crx; + n_cond_set->_opnds[2] = op_dst; + n_cond_set->_bottom_type = _bottom_type; + + assert(ra_->is_oop(this) == true, "A decodeN node must produce an oop!"); + ra_->set_oop(n_cond_set, true); + + ra_->set_pair(n1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); + ra_->set_pair(n2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_cond_set->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + + nodes->push(n1); + nodes->push(n_compare); + nodes->push(n2); + nodes->push(n_cond_set); + %} +%} + // src != 0, shift != 0, base != 0 instruct decodeN_notNull_addBase_Ex(iRegPdst dst, iRegNsrc src) %{ match(Set dst (DecodeN src)); @@ -6904,6 +7018,7 @@ n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && Universe::narrow_oop_shift() != 0 && Universe::narrow_oop_base() != 0); + ins_cost(2 * DEFAULT_COST); format %{ "DecodeN $dst, $src \t// $src != NULL, postalloc expanded" %} postalloc_expand( postalloc_expand_decode_oop_not_null(dst, src)); @@ -6973,13 +7088,12 @@ ins_pipe(pipe_class_default); %} -// base != 0 -// 32G aligned narrow oop base. -instruct encodePKlass_32GAligned(iRegNdst dst, iRegPsrc src) %{ +// Disjoint narrow oop base. +instruct encodePKlass_Disjoint(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodePKlass src)); predicate(false /* TODO: PPC port Universe::narrow_klass_base_disjoint()*/); - format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with 32G aligned base" %} + format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with disjoint base" %} size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_rldicl); @@ -7486,7 +7600,7 @@ ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ cmpxchgd($crx$$CondRegister, R0, $oldVal$$Register, $newVal$$Register, $mem_ptr$$Register, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + MacroAssembler::MemBarAcq, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, NULL, true); %} ins_pipe(pipe_class_default); @@ -10476,7 +10590,7 @@ match(Set crx (CmpN src1 src2)); size(4); - ins_cost(DEFAULT_COST); + ins_cost(2); format %{ "CMPLW $crx, $src1, $src2 \t// compressed ptr" %} ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_cmpl); @@ -10488,7 +10602,7 @@ instruct cmpN_reg_imm0(flagsReg crx, iRegNsrc src1, immN_0 src2) %{ match(Set crx (CmpN src1 src2)); // Make this more expensive than zeroCheckN_iReg_imm0. - ins_cost(DEFAULT_COST); + ins_cost(2); format %{ "CMPLWI $crx, $src1, $src2 \t// compressed ptr" %} size(4); @@ -10508,6 +10622,7 @@ _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne && _leaf->as_If()->_prob >= PROB_LIKELY_MAG(4) && Matcher::branches_to_uncommon_trap(_leaf)); + ins_cost(1); // Should not be cheaper than zeroCheckN. ins_is_TrapBasedCheckNode(true); @@ -10889,7 +11004,7 @@ instruct partialSubtypeCheck(iRegPdst result, iRegP_N2P subklass, iRegP_N2P superklass, iRegPdst tmp_klass, iRegPdst tmp_arrayptr) %{ match(Set result (PartialSubtypeCheck subklass superklass)); - effect(TEMP result, TEMP tmp_klass, TEMP tmp_arrayptr); + effect(TEMP_DEF result, TEMP tmp_klass, TEMP tmp_arrayptr); ins_cost(DEFAULT_COST*10); format %{ "PartialSubtypeCheck $result = ($subklass instanceOf $superklass) tmp: $tmp_klass, $tmp_arrayptr" %} @@ -11000,7 +11115,7 @@ predicate(SpecialStringIndexOf); // type check implicit by parameter type, See Matcher::match_rule_supported match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); - effect(TEMP result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1); ins_cost(150); format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" @@ -11037,7 +11152,7 @@ iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0, flagsRegCR1 cr1) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); - effect(USE_KILL needle, /* TDEF needle, */ TEMP result, + effect(USE_KILL needle, /* TDEF needle, */ TEMP_DEF result, TEMP tmp1, TEMP tmp2); // Required for EA: check if it is still a type_array. predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && @@ -11084,7 +11199,7 @@ iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); - effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP result, + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6); // Required for EA: check if it is still a type_array. predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && @@ -11118,7 +11233,7 @@ flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ - TEMP result, + TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6); predicate(SpecialStringIndexOf); // See Matcher::match_rule_supported. ins_cost(300); @@ -11142,7 +11257,7 @@ iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0, flagsRegCR6 cr6, regCTR ctr) %{ match(Set result (StrEquals (Binary str1 str2) cntImm)); - effect(TEMP result, TEMP tmp1, TEMP tmp2, + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr6, KILL ctr); predicate(SpecialStringEquals); // See Matcher::match_rule_supported. ins_cost(250); @@ -11165,7 +11280,7 @@ iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, iRegPdst tmp4, iRegPdst tmp5, flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(TEMP result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); predicate(SpecialStringEquals); // See Matcher::match_rule_supported. ins_cost(300); @@ -11188,7 +11303,7 @@ instruct string_compare(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, iRegPdst tmp, flagsRegCR0 cr0, regCTR ctr) %{ match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(USE_KILL cnt1, USE_KILL cnt2, USE_KILL str1, USE_KILL str2, TEMP result, TEMP tmp, KILL cr0, KILL ctr); + effect(USE_KILL cnt1, USE_KILL cnt2, USE_KILL str1, USE_KILL str2, TEMP_DEF result, TEMP tmp, KILL cr0, KILL ctr); ins_cost(300); ins_alignment(8); // 'compute_padding()' gets called, up to this number-1 nops will get inserted.
--- a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -483,15 +483,6 @@ } -jbyte* G1PostBarrierStub::_byte_map_base = NULL; - -jbyte* G1PostBarrierStub::byte_map_base_slow() { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->is_a(BarrierSet::G1SATBCTLogging), - "Must be if we're using this."); - return ((G1SATBCardTableModRefBS*)bs)->byte_map_base; -} - void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ bind(_entry);
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1374,6 +1374,7 @@ } void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, + Register method_counters, Register Rtmp, Label &profile_continue) { assert(ProfileInterpreter, "must be profiling interpreter"); @@ -1386,9 +1387,8 @@ br_notnull_short(ImethodDataPtr, Assembler::pn, done); // Test to see if we should create a method data oop - AddressLiteral profile_limit((address) &InvocationCounter::InterpreterProfileLimit); - sethi(profile_limit, Rtmp); - ld(Rtmp, profile_limit.low10(), Rtmp); + Address profile_limit(method_counters, MethodCounters::interpreter_profile_limit_offset()); + ld(profile_limit, Rtmp); cmp(invocation_count, Rtmp); // Use long branches because call_VM() code and following code generated by // test_backedge_count_for_osr() is large in debug VM. @@ -2375,6 +2375,7 @@ #ifndef CC_INTERP void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_count, + Register method_counters, Register branch_bcp, Register Rtmp ) { Label did_not_overflow; @@ -2382,8 +2383,8 @@ assert_different_registers(backedge_count, Rtmp, branch_bcp); assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr"); - AddressLiteral limit(&InvocationCounter::InterpreterBackwardBranchLimit); - load_contents(limit, Rtmp); + Address limit(method_counters, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset())); + ld(limit, Rtmp); cmp_and_br_short(backedge_count, Rtmp, Assembler::lessUnsigned, Assembler::pt, did_not_overflow); // When ProfileInterpreter is on, the backedge_count comes from the @@ -2500,17 +2501,13 @@ // Jump if ((*counter_addr += increment) & mask) satisfies the condition. void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask_addr, Register scratch1, Register scratch2, Condition cond, Label *where) { ld(counter_addr, scratch1); add(scratch1, increment, scratch1); - if (is_simm13(mask)) { - andcc(scratch1, mask, G0); - } else { - set(mask, scratch2); - andcc(scratch1, scratch2, G0); - } + ld(mask_addr, scratch2); + andcc(scratch1, scratch2, G0); br(cond, false, Assembler::pn, *where); delayed()->st(scratch1, counter_addr); }
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -267,7 +267,7 @@ void increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); void increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); #ifndef CC_INTERP - void test_backedge_count_for_osr( Register backedge_count, Register branch_bcp, Register Rtmp ); + void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register branch_bcp, Register Rtmp ); #endif /* CC_INTERP */ // Object locking @@ -280,7 +280,7 @@ void set_method_data_pointer_for_bcp(); void test_method_data_pointer(Label& zero_continue); void verify_method_data_pointer(); - void test_invocation_counter_for_mdp(Register invocation_count, Register Rtmp, Label &profile_continue); + void test_invocation_counter_for_mdp(Register invocation_count, Register method_counters, Register Rtmp, Label &profile_continue); void set_mdp_data_at(int constant, Register value); void increment_mdp_data_at(Address counter, Register bumped_count, @@ -291,7 +291,7 @@ Register bumped_count, Register scratch2, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask_addr, Register scratch1, Register scratch2, Condition cond, Label *where); void set_mdp_flag_at(int flag_constant, Register scratch);
--- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -282,12 +282,11 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { // Note: In tiered we increment either counters in MethodCounters* or in // MDO depending if we're profiling or not. - const Register Rcounters = G3_scratch; + const Register G3_method_counters = G3_scratch; Label done; if (TieredCompilation) { const int increment = InvocationCounter::count_increment; - const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // If no method data exists, go to profile_continue. @@ -297,6 +296,7 @@ Address mdo_invocation_counter(G4_scratch, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G4_scratch, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, G3_scratch, Lscratch, Assembler::zero, overflow); @@ -305,20 +305,21 @@ // Increment counter in MethodCounters* __ bind(no_mdo); - Address invocation_counter(Rcounters, + Address invocation_counter(G3_method_counters, in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); - __ get_method_counters(Lmethod, Rcounters, done); + __ get_method_counters(Lmethod, G3_method_counters, done); + Address mask(G3_method_counters, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, G4_scratch, Lscratch, Assembler::zero, overflow); __ bind(done); - } else { + } else { // not TieredCompilation // Update standard invocation counters - __ get_method_counters(Lmethod, Rcounters, done); - __ increment_invocation_counter(Rcounters, O0, G4_scratch); + __ get_method_counters(Lmethod, G3_method_counters, done); + __ increment_invocation_counter(G3_method_counters, O0, G4_scratch); if (ProfileInterpreter) { - Address interpreter_invocation_counter(Rcounters, + Address interpreter_invocation_counter(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_counter_offset())); __ ld(interpreter_invocation_counter, G4_scratch); __ inc(G4_scratch); @@ -327,16 +328,16 @@ if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - AddressLiteral profile_limit((address)&InvocationCounter::InterpreterProfileLimit); - __ load_contents(profile_limit, G3_scratch); - __ cmp_and_br_short(O0, G3_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue); + Address profile_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_profile_limit_offset())); + __ ld(profile_limit, G1_scratch); + __ cmp_and_br_short(O0, G1_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(*profile_method); } - AddressLiteral invocation_limit((address)&InvocationCounter::InterpreterInvocationLimit); - __ load_contents(invocation_limit, G3_scratch); + Address invocation_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_limit_offset())); + __ ld(invocation_limit, G3_scratch); __ cmp(O0, G3_scratch); __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); // Far distance __ delayed()->nop();
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1599,13 +1599,12 @@ // Bump bytecode pointer by displacement (take the branch) __ delayed()->add( O1_disp, Lbcp, Lbcp ); // add to bc addr - const Register Rcounters = G3_scratch; - __ get_method_counters(Lmethod, Rcounters, Lforward); + const Register G3_method_counters = G3_scratch; + __ get_method_counters(Lmethod, G3_method_counters, Lforward); if (TieredCompilation) { Label Lno_mdo, Loverflow; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // If no method data exists, go to profile_continue. __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch); @@ -1614,6 +1613,7 @@ // Increment backedge counter in the MDO Address mdo_backedge_counter(G4_scratch, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G4_scratch, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, O0, Assembler::notZero, &Lforward); __ ba_short(Loverflow); @@ -1621,9 +1621,10 @@ // If there's no MDO, increment counter in MethodCounters* __ bind(Lno_mdo); - Address backedge_counter(Rcounters, + Address backedge_counter(G3_method_counters, in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G3_method_counters, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(backedge_counter, increment, mask, G4_scratch, O0, Assembler::notZero, &Lforward); __ bind(Loverflow); @@ -1663,18 +1664,19 @@ __ jmp(O2, G0); __ delayed()->nop(); - } else { + } else { // not TieredCompilation // Update Backedge branch separately from invocations const Register G4_invoke_ctr = G4; - __ increment_backedge_counter(Rcounters, G4_invoke_ctr, G1_scratch); + __ increment_backedge_counter(G3_method_counters, G4_invoke_ctr, G1_scratch); if (ProfileInterpreter) { - __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_scratch, Lforward); + __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_method_counters, G1_scratch, Lforward); if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(O2_bumped_count, l_cur_bcp, G3_scratch); + + __ test_backedge_count_for_osr(O2_bumped_count, G3_method_counters, l_cur_bcp, G1_scratch); } } else { if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(G4_invoke_ctr, l_cur_bcp, G3_scratch); + __ test_backedge_count_for_osr(G4_invoke_ctr, G3_method_counters, l_cur_bcp, G1_scratch); } } }
--- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -541,15 +541,6 @@ } -jbyte* G1PostBarrierStub::_byte_map_base = NULL; - -jbyte* G1PostBarrierStub::byte_map_base_slow() { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->is_a(BarrierSet::G1SATBCTLogging), - "Must be if we're using this."); - return ((G1SATBCardTableModRefBS*)bs)->byte_map_base; -} - void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); assert(addr()->is_register(), "Precondition.");
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1360,7 +1360,7 @@ // Jump if ((*counter_addr += increment) & mask) satisfies the condition. void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where) { if (!preloaded) {
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -182,7 +182,7 @@ void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant);
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1426,7 +1426,7 @@ // Jump if ((*counter_addr += increment) & mask) satisfies the condition. void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where) { if (!preloaded) {
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -191,7 +191,7 @@ void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant);
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -346,7 +346,6 @@ // depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -356,6 +355,7 @@ // Increment counter in the MDO const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ jmp(done); } @@ -366,11 +366,12 @@ InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); + const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ bind(done); - } else { - const Address backedge_counter (rax, + } else { // not TieredCompilation + const Address backedge_counter(rax, MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); const Address invocation_counter(rax, @@ -400,16 +401,16 @@ if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(rax, *profile_method); } - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset()))); __ jcc(Assembler::aboveEqual, *overflow); __ bind(done); }
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -299,7 +299,6 @@ // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -309,6 +308,7 @@ // Increment counter in the MDO const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ jmp(done); } @@ -318,10 +318,11 @@ MethodCounters::invocation_counter_offset() + InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); + const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ bind(done); - } else { + } else { // not TieredCompilation const Address backedge_counter(rax, MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); @@ -350,14 +351,16 @@ if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(rax, *profile_method); } - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset()))); __ jcc(Assembler::aboveEqual, *overflow); __ bind(done); }
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1621,7 +1621,6 @@ if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -1630,6 +1629,7 @@ // Increment the MDO backedge counter const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); __ jmp(dispatch); @@ -1637,9 +1637,10 @@ __ bind(no_mdo); // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); + const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); - } else { + } else { // not TieredCompilation // increment counter __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter @@ -1653,8 +1654,7 @@ if (ProfileInterpreter) { // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, dispatch); // if no method data exists, go to profile method @@ -1662,8 +1662,7 @@ if (UseOnStackReplacement) { // check for overflow against rbx, which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rbx, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::below, dispatch); // When ProfileInterpreter is on, the backedge_count comes from the @@ -1678,8 +1677,7 @@ } else { if (UseOnStackReplacement) { // check for overflow against rax, which is the sum of the counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::aboveEqual, backedge_counter_overflow); }
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1642,7 +1642,6 @@ if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -1651,6 +1650,7 @@ // Increment the MDO backedge counter const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); __ jmp(dispatch); @@ -1658,9 +1658,10 @@ __ bind(no_mdo); // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); + const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); - } else { + } else { // not TieredCompilation // increment counter __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter @@ -1674,8 +1675,7 @@ if (ProfileInterpreter) { // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, dispatch); // if no method data exists, go to profile method @@ -1683,8 +1683,7 @@ if (UseOnStackReplacement) { // check for overflow against ebx which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rbx, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::below, dispatch); // When ProfileInterpreter is on, the backedge_count comes @@ -1702,8 +1701,7 @@ if (UseOnStackReplacement) { // check for overflow against eax, which is the sum of the // counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::aboveEqual, backedge_counter_overflow); }
--- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -31,6 +31,7 @@ #include "os_aix.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/perfMemory.hpp" +#include "services/memTracker.hpp" #include "utilities/exceptions.hpp" // put OS-includes here @@ -196,12 +197,37 @@ return pid; } +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + return false; + } + return true; +} -// check if the given path is considered a secure directory for + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. -// static bool is_directory_secure(const char* path) { struct stat statbuf; int result = 0; @@ -211,38 +237,276 @@ return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + +// (Taken over from Solaris to support the O_NOFOLLOW case on AIX.) +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { + return false; + } +} + +// Helper functions for open without O_NOFOLLOW which is not present on AIX 5.3/6.1. +// We use the jdk6 implementation here. +#ifndef O_NOFOLLOW +// The O_NOFOLLOW oflag doesn't exist before solaris 5.10, this is to simulate that behaviour +// was done in jdk 5/6 hotspot by Oracle this way +static int open_o_nofollow_impl(const char* path, int oflag, mode_t mode, bool use_mode) { + struct stat orig_st; + struct stat new_st; + bool create; + int error; + int fd; + + create = false; + + if (lstat(path, &orig_st) != 0) { + if (errno == ENOENT && (oflag & O_CREAT) != 0) { + // File doesn't exist, but_we want to create it, add O_EXCL flag + // to make sure no-one creates it (or a symlink) before us + // This works as we expect with symlinks, from posix man page: + // 'If O_EXCL and O_CREAT are set, and path names a symbolic + // link, open() shall fail and set errno to [EEXIST]'. + oflag |= O_EXCL; + create = true; + } else { + // File doesn't exist, and we are not creating it. + return OS_ERR; } + } else { + // Lstat success, check if existing file is a link. + if ((orig_st.st_mode & S_IFMT) == S_IFLNK) { + // File is a symlink. + errno = ELOOP; + return OS_ERR; + } + } + + if (use_mode == true) { + fd = open(path, oflag, mode); + } else { + fd = open(path, oflag); + } + + if (fd == OS_ERR) { + return fd; + } + + // Can't do inode checks on before/after if we created the file. + if (create == false) { + if (fstat(fd, &new_st) != 0) { + // Keep errno from fstat, in case close also fails. + error = errno; + ::close(fd); + errno = error; + return OS_ERR; + } + + if (orig_st.st_dev != new_st.st_dev || orig_st.st_ino != new_st.st_ino) { + // File was tampered with during race window. + ::close(fd); + errno = EEXIST; + if (PrintMiscellaneous && Verbose) { + warning("possible file tampering attempt detected when opening %s", path); + } + return OS_ERR; + } + } + + return fd; +} + +static int open_o_nofollow(const char* path, int oflag, mode_t mode) { + return open_o_nofollow_impl(path, oflag, mode, true); +} + +static int open_o_nofollow(const char* path, int oflag) { + return open_o_nofollow_impl(path, oflag, 0, false); +} +#endif + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case. +#ifdef O_NOFOLLOW + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); +#else + // workaround (jdk6 coding) + RESTARTABLE(::open_o_nofollow(dirname, O_RDONLY), result); +#endif + + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } + } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirp->dd_fd)) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirp->dd_fd; + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - -// return the user name for the given user id +// Return the user name for the given user id. // -// the caller is expected to free the allocated memory. -// +// The caller is expected to free the allocated memory. static char* get_user_name(uid_t uid) { struct passwd pwent; - // determine the max pwbuf size from sysconf, and hardcode + // Determine the max pwbuf size from sysconf, and hardcode // a default if this not available through sysconf. - // long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (bufsize == -1) bufsize = 1024; @@ -344,7 +608,8 @@ strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // Open the user directory. + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name); @@ -464,28 +729,7 @@ } } - -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path); -} - - -// cleanup stale shared memory resources +// Cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in // the named user temporary directory. It scans the named directory @@ -493,33 +737,26 @@ // process id is extracted from the file name and a test is run to // determine if the process is alive. If the process is not alive, // any stale file resources are removed. -// static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // Open the directory. + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup + // Directory doesn't exist or is insecure, so there is nothing to cleanup. return; } - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory - os::closedir(dirp); - return; - } - - // for each entry in the directory that matches the expected file + // For each entry in the directory that matches the expected file // name pattern, determine if the file resources are stale and if // so, remove the file resources. Note, instrumented HotSpot processes // for this user may start and/or terminate during this search and // remove or create new files in this directory. The behavior of this // loop under these conditions is dependent upon the implementation of // opendir/readdir. - // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -529,56 +766,55 @@ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + // Attempt to remove all unexpected files, except "." and "..". + unlink(entry->d_name); } errno = 0; continue; } - // we now have a file name that converts to a valid integer + // We now have a file name that converts to a valid integer // that could represent a process id . if this process id // matches the current process id or the process is not running, // then remove the stale file resources. // - // process liveness is detected by sending signal number 0 to + // Process liveness is detected by sending signal number 0 to // the process id (see kill(2)). if kill determines that the // process does not exist, then the file resources are removed. // if kill determines that that we don't have permission to // signal the process, then the file resources are assumed to // be stale and are removed because the resources for such a // process should be in a different user specific directory. - // if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); - FREE_C_HEAP_ARRAY(char, dbuf); + + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } -// make the user specific temporary directory. Returns true if +// Make the user specific temporary directory. Returns true if // the directory exists and is secure upon return. Returns false // if the directory exists but is either a symlink, is otherwise // insecure, or if an error occurred. -// static bool make_user_tmp_dir(const char* dirname) { - // create the directory with 0755 permissions. note that the directory + // Create the directory with 0755 permissions. note that the directory // will be owned by euid::egid, which may not be the same as uid::gid. - // if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) { if (errno == EEXIST) { // The directory already exists and was probably created by another // JVM instance. However, this could also be the result of a // deliberate symlink. Verify that the existing directory is safe. - // if (!is_directory_secure(dirname)) { - // directory is not secure + // Directory is not secure. if (PrintMiscellaneous && Verbose) { warning("%s directory is insecure\n", dirname); } @@ -614,19 +850,63 @@ return -1; } + int saved_cwd_fd; + // Open the directory and set the current working directory to it. + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. + return -1; + } + + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. int result; - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case. +#ifdef O_NOFOLLOW + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); +#else + // workaround function (jdk6 code) + RESTARTABLE(::open_o_nofollow(filename, O_RDWR|O_CREAT, S_IREAD|S_IWRITE), result); +#endif + if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } } + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + return -1; } + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); // save the file descriptor int fd = result; + // Check to see if the file is secure. + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // Truncate the file to get rid of any existing data. + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -648,7 +928,14 @@ // open the file int result; + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case +#ifdef O_NOFOLLOW RESTARTABLE(::open(filename, oflags), result); +#else + RESTARTABLE(::open_o_nofollow(filename, oflags), result); +#endif + if (result == OS_ERR) { if (errno == ENOENT) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), @@ -662,8 +949,15 @@ THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); } } + int fd = result; - return result; + // Check to see if the file is secure. + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -695,13 +989,21 @@ char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // Get the short filename. + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name); FREE_C_HEAP_ARRAY(char, dirname); @@ -733,6 +1035,9 @@ // clear the shared memory region (void)::memset((void*) mapAddress, 0, size); + // It does not go through os api, the operation has to record from here. + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal); + return mapAddress; } @@ -807,7 +1112,7 @@ char* mapAddress; int result; int fd; - size_t size; + size_t size = 0; const char* luser = NULL; int mmap_prot; @@ -819,12 +1124,18 @@ // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open. +#ifdef O_NOFOLLOW + file_flags = O_RDONLY | O_NOFOLLOW; +#else file_flags = O_RDONLY; +#endif } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode"); @@ -853,9 +1164,9 @@ // store file, we don't follow them when attaching either. // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); + FREE_C_HEAP_ARRAY(char, dirname, mtInternal); if (luser != user) { - FREE_C_HEAP_ARRAY(char, luser); + FREE_C_HEAP_ARRAY(char, luser, mtInternal); } THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); @@ -901,6 +1212,9 @@ "Could not map PerfMemory"); } + // It does not go through os api, the operation has to record from here. + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal); + *addr = mapAddress; *sizep = size;
--- a/hotspot/src/os/windows/vm/os_windows.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -428,9 +428,9 @@ } // Diagnostic code to investigate JDK-6573254 - int res = 50115; // non-java thread + int res = 30115; // non-java thread if (thread->is_Java_thread()) { - res = 40115; // java thread + res = 20115; // java thread } // Install a win32 structured exception handler around every thread created @@ -3791,6 +3791,7 @@ static INIT_ONCE init_once_crit_sect = INIT_ONCE_STATIC_INIT; static CRITICAL_SECTION crit_sect; + static volatile jint process_exiting = 0; int i, j; DWORD res; HANDLE hproc, hthr; @@ -3798,10 +3799,10 @@ // The first thread that reached this point, initializes the critical section. if (!InitOnceExecuteOnce(&init_once_crit_sect, init_crit_sect_call, &crit_sect, NULL)) { warning("crit_sect initialization failed in %s: %d\n", __FILE__, __LINE__); - } else { + } else if (OrderAccess::load_acquire(&process_exiting) == 0) { EnterCriticalSection(&crit_sect); - if (what == EPT_THREAD) { + if (what == EPT_THREAD && OrderAccess::load_acquire(&process_exiting) == 0) { // Remove from the array those handles of the threads that have completed exiting. for (i = 0, j = 0; i < handle_count; ++i) { res = WaitForSingleObject(handles[i], 0 /* don't wait */); @@ -3856,7 +3857,7 @@ // The current exiting thread has stored its handle in the array, and now // should leave the critical section before calling _endthreadex(). - } else { // what != EPT_THREAD + } else if (what != EPT_THREAD) { if (handle_count > 0) { // Before ending the process, make sure all the threads that had called // _endthreadex() completed. @@ -3882,24 +3883,28 @@ handle_count = 0; } - // End the process, not leaving critical section. - // This makes sure no other thread executes exit-related code at the same - // time, thus a race is avoided. - if (what == EPT_PROCESS) { - ::exit(exit_code); - } else { - _exit(exit_code); - } + OrderAccess::release_store(&process_exiting, 1); } LeaveCriticalSection(&crit_sect); } + + if (what == EPT_THREAD) { + while (OrderAccess::load_acquire(&process_exiting) != 0) { + // Some other thread is about to call exit(), so we + // don't let the current thread proceed to _endthreadex() + SuspendThread(GetCurrentThread()); + // Avoid busy-wait loop, if SuspendThread() failed. + Sleep(EXIT_TIMEOUT); + } + } } // We are here if either // - there's no 'race at exit' bug on this OS release; // - initialization of the critical section failed (unlikely); - // - the current thread has stored its handle and left the critical section. + // - the current thread has stored its handle and left the critical section; + // - the process-exiting thread has raised the flag and left the critical section. if (what == EPT_THREAD) { _endthreadex((unsigned)exit_code); } else if (what == EPT_PROCESS) {
--- a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -601,15 +601,6 @@ LIR_Opr _addr; LIR_Opr _new_val; - static jbyte* _byte_map_base; - static jbyte* byte_map_base_slow(); - static jbyte* byte_map_base() { - if (_byte_map_base == NULL) { - _byte_map_base = byte_map_base_slow(); - } - return _byte_map_base; - } - public: // addr (the address of the object head) and new_val must be registers. G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { }
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -32,6 +32,7 @@ #include "ci/ciArrayKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObjArray.hpp" +#include "runtime/arguments.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/vm_version.hpp" @@ -3351,7 +3352,12 @@ if (!x->inlinee()->is_accessor()) { CodeEmitInfo* info = state_for(x, x->state(), true); // Notify the runtime very infrequently only to take care of counter overflows - increment_event_counter_impl(info, x->inlinee(), (1 << Tier23InlineeNotifyFreqLog) - 1, InvocationEntryBci, false, true); + int freq_log = Tier23InlineeNotifyFreqLog; + double scale; + if (_method->has_option_value("CompileThresholdScaling", scale)) { + freq_log = Arguments::scaled_freq_log(freq_log, scale); + } + increment_event_counter_impl(info, x->inlinee(), right_n_bits(freq_log), InvocationEntryBci, false, true); } } @@ -3366,7 +3372,11 @@ ShouldNotReachHere(); } // Increment the appropriate invocation/backedge counter and notify the runtime. - increment_event_counter_impl(info, info->scope()->method(), (1 << freq_log) - 1, bci, backedge, true); + double scale; + if (_method->has_option_value("CompileThresholdScaling", scale)) { + freq_log = Arguments::scaled_freq_log(freq_log, scale); + } + increment_event_counter_impl(info, info->scope()->method(), right_n_bits(freq_log), bci, backedge, true); } void LIRGenerator::decrement_age(CodeEmitInfo* info) {
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,6 +221,30 @@ return (const char*)end; } +template <class T, class N> void CompactHashtable<T, N>::symbols_do(SymbolClosure *cl) { + assert(!DumpSharedSpaces, "run-time only"); + for (juint i = 0; i < _bucket_count; i ++) { + juint bucket_info = _buckets[i]; + juint bucket_offset = BUCKET_OFFSET(bucket_info); + int bucket_type = BUCKET_TYPE(bucket_info); + juint* bucket = _buckets + bucket_offset; + juint* bucket_end = _buckets; + + Symbol* sym; + if (bucket_type == COMPACT_BUCKET_TYPE) { + sym = (Symbol*)((void*)(_base_address + bucket[0])); + cl->do_symbol(&sym); + } else { + bucket_end += BUCKET_OFFSET(_buckets[i + 1]); + while (bucket < bucket_end) { + sym = (Symbol*)((void*)(_base_address + bucket[1])); + cl->do_symbol(&sym); + bucket += 2; + } + } + } +} + // Explicitly instantiate these types template class CompactHashtable<Symbol*, char>;
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,9 @@ } return NULL; } + + // iterate over symbols + void symbols_do(SymbolClosure *cl); }; ////////////////////////////////////////////////////////////////////////
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,10 @@ // Call function for all symbols in the symbol table. void SymbolTable::symbols_do(SymbolClosure *cl) { + // all symbols from shared table + _shared_table.symbols_do(cl); + + // all symbols from the dynamic table const int n = the_table()->table_size(); for (int i = 0; i < n; i++) { for (HashtableEntry<Symbol*, mtSymbol>* p = the_table()->bucket(i);
--- a/hotspot/src/share/vm/classfile/verifier.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1546,10 +1546,15 @@ no_control_flow = true; break; case Bytecodes::_getstatic : case Bytecodes::_putstatic : + // pass TRUE, operand can be an array type for getstatic/putstatic. + verify_field_instructions( + &bcs, ¤t_frame, cp, true, CHECK_VERIFY(this)); + no_control_flow = false; break; case Bytecodes::_getfield : case Bytecodes::_putfield : + // pass FALSE, operand can't be an array type for getfield/putfield. verify_field_instructions( - &bcs, ¤t_frame, cp, CHECK_VERIFY(this)); + &bcs, ¤t_frame, cp, false, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_invokevirtual : case Bytecodes::_invokespecial : @@ -2107,6 +2112,7 @@ void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, StackMapFrame* current_frame, constantPoolHandle cp, + bool allow_arrays, TRAPS) { u2 index = bcs->get_index_u2(); verify_cp_type(bcs->bci(), index, cp, @@ -2126,8 +2132,8 @@ // Get referenced class type VerificationType ref_class_type = cp_ref_index_to_type( index, cp, CHECK_VERIFY(this)); - if (!ref_class_type.is_object()) { - /* Unreachable? Class file parser verifies Fieldref contents */ + if (!ref_class_type.is_object() && + (!allow_arrays || !ref_class_type.is_array())) { verify_error(ErrorContext::bad_type(bcs->bci(), TypeOrigin::cp(index, ref_class_type)), "Expecting reference to class in class %s at constant pool index %d",
--- a/hotspot/src/share/vm/classfile/verifier.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/classfile/verifier.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -297,7 +297,7 @@ void verify_field_instructions( RawBytecodeStream* bcs, StackMapFrame* current_frame, - constantPoolHandle cp, TRAPS); + constantPoolHandle cp, bool allow_arrays, TRAPS); void verify_invoke_init( RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type,
--- a/hotspot/src/share/vm/code/codeCache.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -233,8 +233,8 @@ ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size) { // Determine alignment const size_t page_size = os::can_execute_large_page_memory() ? - MIN2(os::page_size_for_region(InitialCodeCacheSize, 8), - os::page_size_for_region(size, 8)) : + MIN2(os::page_size_for_region_aligned(InitialCodeCacheSize, 8), + os::page_size_for_region_aligned(size, 8)) : os::vm_page_size(); const size_t granularity = os::vm_allocation_granularity(); const size_t r_align = MAX2(page_size, granularity);
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1470,7 +1470,9 @@ // The method may be explicitly excluded by the user. bool quietly; - if (CompilerOracle::should_exclude(method, quietly)) { + double scale; + if (CompilerOracle::should_exclude(method, quietly) + || (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) { if (!quietly) { // This does not happen quietly... ResourceMark rm;
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -162,8 +162,8 @@ "we should have already filtered out humongous regions"); assert(_end == orig_end(), "we should have already filtered out humongous regions"); - - _in_collection_set = false; + assert(!_in_collection_set, + err_msg("Should not clear heap region %u in the collection set", hrm_index())); set_allocation_context(AllocationContext::system()); set_young_index_in_cset(-1);
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1194,8 +1194,10 @@ return real_forwardee(old); } - new_obj = _next_gen->par_promote(par_scan_state->thread_num(), - old, m, sz); + if (!_promotion_failed) { + new_obj = _next_gen->par_promote(par_scan_state->thread_num(), + old, m, sz); + } if (new_obj == NULL) { // promotion failed, forward to self
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -61,9 +61,9 @@ void GenerationSizer::initialize_size_info() { trace_gen_sizes("ps heap raw"); - const size_t max_page_sz = os::page_size_for_region(_max_heap_byte_size, 8); + const size_t max_page_sz = os::page_size_for_region_aligned(_max_heap_byte_size, 8); const size_t min_pages = 4; // 1 for eden + 1 for each survivor + 1 for old - const size_t min_page_sz = os::page_size_for_region(_min_heap_byte_size, min_pages); + const size_t min_page_sz = os::page_size_for_region_aligned(_min_heap_byte_size, min_pages); const size_t page_sz = MIN2(max_page_sz, min_page_sz); // Can a page size be something else than a power of two?
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -41,7 +41,7 @@ const size_t words = bits / BitsPerWord; const size_t raw_bytes = words * sizeof(idx_t); - const size_t page_sz = os::page_size_for_region(raw_bytes, 10); + const size_t page_sz = os::page_size_for_region_aligned(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity));
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -403,7 +403,7 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) { const size_t raw_bytes = count * element_size; - const size_t page_sz = os::page_size_for_region(raw_bytes, 10); + const size_t page_sz = os::page_size_for_region_aligned(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity));
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -53,7 +53,7 @@ /* * USELABELS - If using GCC, then use labels for the opcode dispatching * rather -then a switch statement. This improves performance because it - * gives us the oportunity to have the instructions that calculate the + * gives us the opportunity to have the instructions that calculate the * next opcode to jump to be intermixed with the rest of the instructions * that implement the opcode (see UPDATE_PC_AND_TOS_AND_CONTINUE macro). */
--- a/hotspot/src/share/vm/interpreter/invocationCounter.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/interpreter/invocationCounter.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -36,7 +36,7 @@ // Implementation notes: For space reasons, state & counter are both encoded in one word, // The state is encoded using some of the least significant bits, the counter is using the // more significant bits. The counter is incremented before a method is activated and an -// action is triggered when when count() > limit(). +// action is triggered when count() > limit(). class InvocationCounter VALUE_OBJ_CLASS_SPEC { friend class VMStructs; @@ -48,7 +48,6 @@ number_of_state_bits = 2, number_of_carry_bits = 1, number_of_noncount_bits = number_of_state_bits + number_of_carry_bits, - number_of_count_bits = BitsPerInt - number_of_noncount_bits, state_limit = nth_bit(number_of_state_bits), count_grain = nth_bit(number_of_state_bits + number_of_carry_bits), carry_mask = right_n_bits(number_of_carry_bits) << number_of_state_bits, @@ -68,6 +67,7 @@ count_increment = count_grain, // use this value to increment the 32bit _counter word count_mask_value = count_mask, // use this value to mask the backedge counter count_shift = number_of_noncount_bits, + number_of_count_bits = BitsPerInt - number_of_noncount_bits, count_limit = nth_bit(number_of_count_bits - 1) };
--- a/hotspot/src/share/vm/memory/heap.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/memory/heap.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -104,8 +104,8 @@ size_t page_size = os::vm_page_size(); if (os::can_execute_large_page_memory()) { const size_t min_pages = 8; - page_size = MIN2(os::page_size_for_region(committed_size, min_pages), - os::page_size_for_region(rs.size(), min_pages)); + page_size = MIN2(os::page_size_for_region_aligned(committed_size, min_pages), + os::page_size_for_region_aligned(rs.size(), min_pages)); } const size_t granularity = os::vm_allocation_granularity();
--- a/hotspot/src/share/vm/oops/method.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/oops/method.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -412,15 +412,14 @@ } methodHandle mh(m); - ClassLoaderData* loader_data = mh->method_holder()->class_loader_data(); - MethodCounters* counters = MethodCounters::allocate(loader_data, THREAD); + MethodCounters* counters = MethodCounters::allocate(mh, THREAD); if (HAS_PENDING_EXCEPTION) { CompileBroker::log_metaspace_failure(); ClassLoaderDataGraph::set_metaspace_oom(true); return NULL; // return the exception (which is cleared) } if (!mh->init_method_counters(counters)) { - MetadataFactory::free_metadata(loader_data, counters); + MetadataFactory::free_metadata(mh->method_holder()->class_loader_data(), counters); } return mh->method_counters(); }
--- a/hotspot/src/share/vm/oops/methodCounters.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/oops/methodCounters.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -23,10 +23,11 @@ */ #include "precompiled.hpp" #include "oops/methodCounters.hpp" -#include "runtime/thread.inline.hpp" +#include "runtime/handles.inline.hpp" -MethodCounters* MethodCounters::allocate(ClassLoaderData* loader_data, TRAPS) { - return new(loader_data, size(), false, MetaspaceObj::MethodCountersType, THREAD) MethodCounters(); +MethodCounters* MethodCounters::allocate(methodHandle mh, TRAPS) { + ClassLoaderData* loader_data = mh->method_holder()->class_loader_data(); + return new(loader_data, size(), false, MetaspaceObj::MethodCountersType, THREAD) MethodCounters(mh); } void MethodCounters::clear_counters() {
--- a/hotspot/src/share/vm/oops/methodCounters.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/oops/methodCounters.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -26,7 +26,9 @@ #define SHARE_VM_OOPS_METHODCOUNTERS_HPP #include "oops/metadata.hpp" +#include "compiler/compilerOracle.hpp" #include "interpreter/invocationCounter.hpp" +#include "runtime/arguments.hpp" class MethodCounters: public MetaspaceObj { friend class VMStructs; @@ -45,7 +47,11 @@ // 3. (INT_MIN..0] - method is hot and will deopt and get // recompiled without the counters int _nmethod_age; - + int _interpreter_invocation_limit; // per-method InterpreterInvocationLimit + int _interpreter_backward_branch_limit; // per-method InterpreterBackwardBranchLimit + int _interpreter_profile_limit; // per-method InterpreterProfileLimit + int _invoke_mask; // per-method Tier0InvokeNotifyFreqLog + int _backedge_mask; // per-method Tier0BackedgeNotifyFreqLog #ifdef TIERED float _rate; // Events (invocation and backedge counter increments) per millisecond jlong _prev_time; // Previous time the rate was acquired @@ -53,15 +59,15 @@ u1 _highest_osr_comp_level; // Same for OSR level #endif - MethodCounters() : _interpreter_invocation_count(0), - _interpreter_throwout_count(0), - _number_of_breakpoints(0), - _nmethod_age(INT_MAX) + MethodCounters(methodHandle mh) : _interpreter_invocation_count(0), + _interpreter_throwout_count(0), + _number_of_breakpoints(0), + _nmethod_age(INT_MAX) #ifdef TIERED - , _rate(0), - _prev_time(0), - _highest_comp_level(0), - _highest_osr_comp_level(0) + , _rate(0), + _prev_time(0), + _highest_comp_level(0), + _highest_osr_comp_level(0) #endif { invocation_counter()->init(); @@ -70,10 +76,28 @@ if (StressCodeAging) { set_nmethod_age(HotMethodDetectionLimit); } + + // Set per-method thresholds. + double scale = 1.0; + CompilerOracle::has_option_value(mh, "CompileThresholdScaling", scale); + + int compile_threshold = Arguments::scaled_compile_threshold(CompileThreshold, scale); + _interpreter_invocation_limit = compile_threshold << InvocationCounter::count_shift; + if (ProfileInterpreter) { + // If interpreter profiling is enabled, the backward branch limit + // is compared against the method data counter rather than an invocation + // counter, therefore no shifting of bits is required. + _interpreter_backward_branch_limit = (compile_threshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100; + } else { + _interpreter_backward_branch_limit = ((compile_threshold * OnStackReplacePercentage) / 100) << InvocationCounter::count_shift; + } + _interpreter_profile_limit = ((compile_threshold * InterpreterProfilePercentage) / 100) << InvocationCounter::count_shift; + _invoke_mask = right_n_bits(Arguments::scaled_freq_log(Tier0InvokeNotifyFreqLog, scale)) << InvocationCounter::count_shift; + _backedge_mask = right_n_bits(Arguments::scaled_freq_log(Tier0BackedgeNotifyFreqLog, scale)) << InvocationCounter::count_shift; } public: - static MethodCounters* allocate(ClassLoaderData* loader_data, TRAPS); + static MethodCounters* allocate(methodHandle mh, TRAPS); void deallocate_contents(ClassLoaderData* loader_data) {} DEBUG_ONLY(bool on_stack() { return false; }) // for template @@ -161,5 +185,24 @@ return offset_of(MethodCounters, _interpreter_invocation_count); } + static ByteSize interpreter_invocation_limit_offset() { + return byte_offset_of(MethodCounters, _interpreter_invocation_limit); + } + + static ByteSize interpreter_backward_branch_limit_offset() { + return byte_offset_of(MethodCounters, _interpreter_backward_branch_limit); + } + + static ByteSize interpreter_profile_limit_offset() { + return byte_offset_of(MethodCounters, _interpreter_profile_limit); + } + + static ByteSize invoke_mask_offset() { + return byte_offset_of(MethodCounters, _invoke_mask); + } + + static ByteSize backedge_mask_offset() { + return byte_offset_of(MethodCounters, _backedge_mask); + } }; #endif //SHARE_VM_OOPS_METHODCOUNTERS_HPP
--- a/hotspot/src/share/vm/oops/methodData.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/oops/methodData.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -31,6 +31,7 @@ #include "memory/heapInspection.hpp" #include "oops/methodData.hpp" #include "prims/jvmtiRedefineClasses.hpp" +#include "runtime/arguments.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" @@ -1131,6 +1132,13 @@ _backedge_counter.init(); _invocation_counter_start = 0; _backedge_counter_start = 0; + + // Set per-method invoke- and backedge mask. + double scale = 1.0; + CompilerOracle::has_option_value(_method, "CompileThresholdScaling", scale); + _invoke_mask = right_n_bits(Arguments::scaled_freq_log(Tier0InvokeNotifyFreqLog, scale)) << InvocationCounter::count_shift; + _backedge_mask = right_n_bits(Arguments::scaled_freq_log(Tier0BackedgeNotifyFreqLog, scale)) << InvocationCounter::count_shift; + _tenure_traps = 0; _num_loops = 0; _num_blocks = 0;
--- a/hotspot/src/share/vm/oops/methodData.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/oops/methodData.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -2088,6 +2088,8 @@ int _invocation_counter_start; int _backedge_counter_start; uint _tenure_traps; + int _invoke_mask; // per-method Tier0InvokeNotifyFreqLog + int _backedge_mask; // per-method Tier0BackedgeNotifyFreqLog #if INCLUDE_RTM_OPT // State of RTM code generation during compilation of the method @@ -2447,10 +2449,19 @@ static ByteSize invocation_counter_offset() { return byte_offset_of(MethodData, _invocation_counter); } + static ByteSize backedge_counter_offset() { return byte_offset_of(MethodData, _backedge_counter); } + static ByteSize invoke_mask_offset() { + return byte_offset_of(MethodData, _invoke_mask); + } + + static ByteSize backedge_mask_offset() { + return byte_offset_of(MethodData, _backedge_mask); + } + static ByteSize parameters_type_data_di_offset() { return byte_offset_of(MethodData, _parameters_type_data_di); }
--- a/hotspot/src/share/vm/opto/chaitin.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/chaitin.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -582,6 +582,9 @@ // Peephole remove copies post_allocate_copy_removal(); + // Merge multidefs if multiple defs representing the same value are used in a single block. + merge_multidefs(); + #ifdef ASSERT // Veify the graph after RA. verify(&live_arena);
--- a/hotspot/src/share/vm/opto/chaitin.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/chaitin.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -681,6 +681,32 @@ // Extend the node to LRG mapping void add_reference( const Node *node, const Node *old_node); + // Record the first use of a def in the block for a register. + class RegDefUse { + Node* _def; + Node* _first_use; + public: + RegDefUse() : _def(NULL), _first_use(NULL) { } + Node* def() const { return _def; } + Node* first_use() const { return _first_use; } + + void update(Node* def, Node* use) { + if (_def != def) { + _def = def; + _first_use = use; + } + } + void clear() { + _def = NULL; + _first_use = NULL; + } + }; + typedef GrowableArray<RegDefUse> RegToDefUseMap; + int possibly_merge_multidef(Node *n, uint k, Block *block, RegToDefUseMap& reg2defuse); + + // Merge nodes that are a part of a multidef lrg and produce the same value within a block. + void merge_multidefs(); + private: static int _final_loads, _final_stores, _final_copies, _final_memoves;
--- a/hotspot/src/share/vm/opto/doCall.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/doCall.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -94,7 +94,7 @@ if (log != NULL) { int rid = (receiver_count >= 0)? log->identify(profile.receiver(0)): -1; int r2id = (rid != -1 && profile.has_receiver(1))? log->identify(profile.receiver(1)):-1; - log->begin_elem("call method='%d' count='%d' prof_factor='%g'", + log->begin_elem("call method='%d' count='%d' prof_factor='%f'", log->identify(callee), site_count, prof_factor); if (call_does_dispatch) log->print(" virtual='1'"); if (allow_inline) log->print(" inline='1'");
--- a/hotspot/src/share/vm/opto/escape.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/escape.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -2010,14 +2010,9 @@ bt = field->layout_type(); } else { // Check for unsafe oop field access - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - int opcode = n->fast_out(i)->Opcode(); - if (opcode == Op_StoreP || opcode == Op_LoadP || - opcode == Op_StoreN || opcode == Op_LoadN) { - bt = T_OBJECT; - (*unsafe) = true; - break; - } + if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN)) { + bt = T_OBJECT; + (*unsafe) = true; } } } else if (adr_type->isa_aryptr()) { @@ -2031,13 +2026,8 @@ } } else if (adr_type->isa_rawptr() || adr_type->isa_klassptr()) { // Allocation initialization, ThreadLocal field access, unsafe access - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - int opcode = n->fast_out(i)->Opcode(); - if (opcode == Op_StoreP || opcode == Op_LoadP || - opcode == Op_StoreN || opcode == Op_LoadN) { - bt = T_OBJECT; - break; - } + if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN)) { + bt = T_OBJECT; } } } @@ -3092,13 +3082,7 @@ continue; } else if (n->Opcode() == Op_EncodeISOArray) { // get the memory projection - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node *use = n->fast_out(i); - if (use->Opcode() == Op_SCMemProj) { - n = use; - break; - } - } + n = n->find_out_with(Op_SCMemProj); assert(n->Opcode() == Op_SCMemProj, "memory projection required"); } else { assert(n->is_Mem(), "memory node required."); @@ -3122,13 +3106,7 @@ continue; // don't push users } else if (n->is_LoadStore()) { // get the memory projection - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node *use = n->fast_out(i); - if (use->Opcode() == Op_SCMemProj) { - n = use; - break; - } - } + n = n->find_out_with(Op_SCMemProj); assert(n->Opcode() == Op_SCMemProj, "memory projection required"); } }
--- a/hotspot/src/share/vm/opto/ifg.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/ifg.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -535,12 +535,8 @@ // The method add_input_to_liveout() keeps such nodes alive (put them on liveout list) // when it sees SCMemProj node in a block. Unfortunately SCMemProj node could be placed // in block in such order that KILL MachProj nodes are processed first. - uint cnt = def->outcnt(); - for (uint i = 0; i < cnt; i++) { - Node* proj = def->raw_out(i); - if (proj->Opcode() == Op_SCMemProj) { - return false; - } + if (def->has_out_with(Op_SCMemProj)) { + return false; } } b->remove_node(location);
--- a/hotspot/src/share/vm/opto/loopTransform.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -2057,10 +2057,9 @@ } Node *main_cmp = main_bol->in(1); if( main_cmp->outcnt() > 1 ) { // CmpNode shared? - _igvn.hash_delete(main_bol); main_cmp = main_cmp->clone();// Clone a private CmpNode register_new_node( main_cmp, main_cle->in(0) ); - main_bol->set_req(1,main_cmp); + _igvn.replace_input_of(main_bol, 1, main_cmp); } // Hack the now-private loop bounds _igvn.replace_input_of(main_cmp, 2, main_limit);
--- a/hotspot/src/share/vm/opto/machnode.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/machnode.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -616,6 +616,29 @@ #endif }; +// MachMergeNode is similar to a PhiNode in a sense it merges multiple values, +// however it doesn't have a control input and is more like a MergeMem. +// It is inserted after the register allocation is done to ensure that nodes use single +// definition of a multidef lrg in a block. +class MachMergeNode : public MachIdealNode { +public: + MachMergeNode(Node *n1) { + init_class_id(Class_MachMerge); + add_req(NULL); + add_req(n1); + } + virtual const RegMask &out_RegMask() const { return in(1)->out_RegMask(); } + virtual const RegMask &in_RegMask(uint idx) const { return in(1)->in_RegMask(idx); } + virtual const class Type *bottom_type() const { return in(1)->bottom_type(); } + virtual uint ideal_reg() const { return bottom_type()->ideal_reg(); } + virtual uint oper_input_base() const { return 1; } + virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } + virtual uint size(PhaseRegAlloc *ra_) const { return 0; } +#ifndef PRODUCT + virtual const char *Name() const { return "MachMerge"; } +#endif +}; + //------------------------------MachBranchNode-------------------------------- // Abstract machine branch Node class MachBranchNode : public MachIdealNode {
--- a/hotspot/src/share/vm/opto/macro.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/macro.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -258,14 +258,7 @@ // Search for CastP2X->Xor->URShift->Cmp path which // checks if the store done to a different from the value's region. // And replace Cmp with #0 (false) to collapse G1 post barrier. - Node* xorx = NULL; - for (DUIterator_Fast imax, i = p2x->fast_outs(imax); i < imax; i++) { - Node* u = p2x->fast_out(i); - if (u->Opcode() == Op_XorX) { - xorx = u; - break; - } - } + Node* xorx = p2x->find_out_with(Op_XorX); assert(xorx != NULL, "missing G1 post barrier"); Node* shift = xorx->unique_out(); Node* cmpx = shift->unique_out();
--- a/hotspot/src/share/vm/opto/memnode.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/memnode.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -2609,7 +2609,6 @@ return false; // if not a distinct instance, there may be aliases of the address for (DUIterator_Fast imax, i = adr->fast_outs(imax); i < imax; i++) { Node *use = adr->fast_out(i); - int opc = use->Opcode(); if (use->is_Load() || use->is_LoadStore()) { return false; }
--- a/hotspot/src/share/vm/opto/node.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/node.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -881,6 +881,34 @@ return (Node*) this; } +// Find out of current node that matches opcode. +Node* Node::find_out_with(int opcode) { + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + Node* use = fast_out(i); + if (use->Opcode() == opcode) { + return use; + } + } + return NULL; +} + +// Return true if the current node has an out that matches opcode. +bool Node::has_out_with(int opcode) { + return (find_out_with(opcode) != NULL); +} + +// Return true if the current node has an out that matches any of the opcodes. +bool Node::has_out_with(int opcode1, int opcode2, int opcode3, int opcode4) { + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + int opcode = fast_out(i)->Opcode(); + if (opcode == opcode1 || opcode == opcode2 || opcode == opcode3 || opcode == opcode4) { + return true; + } + } + return false; +} + + //---------------------------uncast_helper------------------------------------- Node* Node::uncast_helper(const Node* p) { #ifdef ASSERT
--- a/hotspot/src/share/vm/opto/node.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/node.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -98,6 +98,7 @@ class MachSafePointNode; class MachSpillCopyNode; class MachTempNode; +class MachMergeNode; class Matcher; class MemBarNode; class MemBarStoreStoreNode; @@ -436,6 +437,13 @@ return (this->uncast() == n->uncast()); } + // Find out of current node that matches opcode. + Node* find_out_with(int opcode); + // Return true if the current node has an out that matches opcode. + bool has_out_with(int opcode); + // Return true if the current node has an out that matches any of the opcodes. + bool has_out_with(int opcode1, int opcode2, int opcode3, int opcode4); + private: static Node* uncast_helper(const Node* n); @@ -507,18 +515,25 @@ //----------------- Other Node Properties - // Generate class id for some ideal nodes to avoid virtual query - // methods is_<Node>(). - // Class id is the set of bits corresponded to the node class and all its - // super classes so that queries for super classes are also valid. - // Subclasses of the same super class have different assigned bit - // (the third parameter in the macro DEFINE_CLASS_ID). - // Classes with deeper hierarchy are declared first. - // Classes with the same hierarchy depth are sorted by usage frequency. + // Generate class IDs for (some) ideal nodes so that it is possible to determine + // the type of a node using a non-virtual method call (the method is_<Node>() below). // - // The query method masks the bits to cut off bits of subclasses - // and then compare the result with the class id - // (see the macro DEFINE_CLASS_QUERY below). + // A class ID of an ideal node is a set of bits. In a class ID, a single bit determines + // the type of the node the ID represents; another subset of an ID's bits are reserved + // for the superclasses of the node represented by the ID. + // + // By design, if A is a supertype of B, A.is_B() returns true and B.is_A() + // returns false. A.is_A() returns true. + // + // If two classes, A and B, have the same superclass, a different bit of A's class id + // is reserved for A's type than for B's type. That bit is specified by the third + // parameter in the macro DEFINE_CLASS_ID. + // + // By convention, classes with deeper hierarchy are declared first. Moreover, + // classes with the same hierarchy depth are sorted by usage frequency. + // + // The query method masks the bits to cut off bits of subclasses and then compares + // the result with the class id (see the macro DEFINE_CLASS_QUERY below). // // Class_MachCall=30, ClassMask_MachCall=31 // 12 8 4 0 @@ -592,6 +607,7 @@ DEFINE_CLASS_ID(MachTemp, Mach, 3) DEFINE_CLASS_ID(MachConstantBase, Mach, 4) DEFINE_CLASS_ID(MachConstant, Mach, 5) + DEFINE_CLASS_ID(MachMerge, Mach, 6) DEFINE_CLASS_ID(Type, Node, 2) DEFINE_CLASS_ID(Phi, Type, 0) @@ -763,6 +779,7 @@ DEFINE_CLASS_QUERY(MachSafePoint) DEFINE_CLASS_QUERY(MachSpillCopy) DEFINE_CLASS_QUERY(MachTemp) + DEFINE_CLASS_QUERY(MachMerge) DEFINE_CLASS_QUERY(Mem) DEFINE_CLASS_QUERY(MemBar) DEFINE_CLASS_QUERY(MemBarStoreStore)
--- a/hotspot/src/share/vm/opto/parse1.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/parse1.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -441,7 +441,7 @@ CompileLog* log = C->log(); if (log != NULL) { - log->begin_head("parse method='%d' uses='%g'", + log->begin_head("parse method='%d' uses='%f'", log->identify(parse_method), expected_uses); if (depth() == 1 && C->is_osr_compilation()) { log->print(" osr_bci='%d'", C->entry_bci());
--- a/hotspot/src/share/vm/opto/parse2.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/parse2.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -832,7 +832,7 @@ sprintf(prob_str_buf, "%g", prob); prob_str = prob_str_buf; } - C->log()->elem("branch target_bci='%d' taken='%d' not_taken='%d' cnt='%g' prob='%s'", + C->log()->elem("branch target_bci='%d' taken='%d' not_taken='%d' cnt='%f' prob='%s'", iter().get_dest(), taken, not_taken, cnt, prob_str); } return prob;
--- a/hotspot/src/share/vm/opto/phase.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/phase.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -110,6 +110,7 @@ tty->print_cr (" Compute Liveness: %7.3f s", timers[_t_computeLive].seconds()); tty->print_cr (" Regalloc Split: %7.3f s", timers[_t_regAllocSplit].seconds()); tty->print_cr (" Postalloc Copy Rem: %7.3f s", timers[_t_postAllocCopyRemoval].seconds()); + tty->print_cr (" Merge multidefs: %7.3f s", timers[_t_mergeMultidefs].seconds()); tty->print_cr (" Fixup Spills: %7.3f s", timers[_t_fixupSpills].seconds()); tty->print_cr (" Compact: %7.3f s", timers[_t_chaitinCompact].seconds()); tty->print_cr (" Coalesce 1: %7.3f s", timers[_t_chaitinCoalesce1].seconds()); @@ -126,6 +127,7 @@ timers[_t_computeLive].seconds() + timers[_t_regAllocSplit].seconds() + timers[_t_postAllocCopyRemoval].seconds() + + timers[_t_mergeMultidefs].seconds() + timers[_t_fixupSpills].seconds() + timers[_t_chaitinCompact].seconds() + timers[_t_chaitinCoalesce1].seconds() +
--- a/hotspot/src/share/vm/opto/phase.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/phase.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -88,6 +88,7 @@ _t_computeLive, _t_regAllocSplit, _t_postAllocCopyRemoval, + _t_mergeMultidefs, _t_fixupSpills, _t_chaitinCompact, _t_chaitinCoalesce1,
--- a/hotspot/src/share/vm/opto/postaloc.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/postaloc.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -263,20 +263,6 @@ // intermediate copies might be illegal, i.e., value is stored down to stack // then reloaded BUT survives in a register the whole way. Node *val = skip_copies(n->in(k)); - - if (val == x && nk_idx != 0 && - regnd[nk_reg] != NULL && regnd[nk_reg] != x && - _lrg_map.live_range_id(x) == _lrg_map.live_range_id(regnd[nk_reg])) { - // When rematerialzing nodes and stretching lifetimes, the - // allocator will reuse the original def for multidef LRG instead - // of the current reaching def because it can't know it's safe to - // do so. After allocation completes if they are in the same LRG - // then it should use the current reaching def instead. - n->set_req(k, regnd[nk_reg]); - blk_adjust += yank_if_dead(val, current_block, &value, ®nd); - val = skip_copies(n->in(k)); - } - if (val == x) return blk_adjust; // No progress? int n_regs = RegMask::num_registers(val->ideal_reg()); @@ -382,6 +368,94 @@ return false; } +// The algorithms works as follows: +// We traverse the block top to bottom. possibly_merge_multidef() is invoked for every input edge k +// of the instruction n. We check to see if the input is a multidef lrg. If it is, we record the fact that we've +// seen a definition (coming as an input) and add that fact to the reg2defuse array. The array maps registers to their +// current reaching definitions (we track only multidefs though). With each definition we also associate the first +// instruction we saw use it. If we encounter the situation when we observe an def (an input) that is a part of the +// same lrg but is different from the previous seen def we merge the two with a MachMerge node and substitute +// all the uses that we've seen so far to use the merge. After that we keep replacing the new defs in the same lrg +// as they get encountered with the merge node and keep adding these defs to the merge inputs. +void PhaseChaitin::merge_multidefs() { + Compile::TracePhase tp("mergeMultidefs", &timers[_t_mergeMultidefs]); + ResourceMark rm; + // Keep track of the defs seen in registers and collect their uses in the block. + RegToDefUseMap reg2defuse(_max_reg, _max_reg, RegDefUse()); + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); + for (uint j = 1; j < block->number_of_nodes(); j++) { + Node* n = block->get_node(j); + if (n->is_Phi()) continue; + for (uint k = 1; k < n->req(); k++) { + j += possibly_merge_multidef(n, k, block, reg2defuse); + } + // Null out the value produced by the instruction itself, since we're only interested in defs + // implicitly defined by the uses. We are actually interested in tracking only redefinitions + // of the multidef lrgs in the same register. For that matter it's enough to track changes in + // the base register only and ignore other effects of multi-register lrgs and fat projections. + // It is also ok to ignore defs coming from singledefs. After an implicit overwrite by one of + // those our register is guaranteed to be used by another lrg and we won't attempt to merge it. + uint lrg = _lrg_map.live_range_id(n); + if (lrg > 0 && lrgs(lrg).is_multidef()) { + OptoReg::Name reg = lrgs(lrg).reg(); + reg2defuse.at(reg).clear(); + } + } + // Clear reg->def->use tracking for the next block + for (int j = 0; j < reg2defuse.length(); j++) { + reg2defuse.at(j).clear(); + } + } +} + +int PhaseChaitin::possibly_merge_multidef(Node *n, uint k, Block *block, RegToDefUseMap& reg2defuse) { + int blk_adjust = 0; + + uint lrg = _lrg_map.live_range_id(n->in(k)); + if (lrg > 0 && lrgs(lrg).is_multidef()) { + OptoReg::Name reg = lrgs(lrg).reg(); + + Node* def = reg2defuse.at(reg).def(); + if (def != NULL && lrg == _lrg_map.live_range_id(def) && def != n->in(k)) { + // Same lrg but different node, we have to merge. + MachMergeNode* merge; + if (def->is_MachMerge()) { // is it already a merge? + merge = def->as_MachMerge(); + } else { + merge = new MachMergeNode(def); + + // Insert the merge node into the block before the first use. + uint use_index = block->find_node(reg2defuse.at(reg).first_use()); + block->insert_node(merge, use_index++); + + // Let the allocator know about the new node, use the same lrg + _lrg_map.extend(merge->_idx, lrg); + blk_adjust++; + + // Fixup all the uses (there is at least one) that happened between the first + // use and before the current one. + for (; use_index < block->number_of_nodes(); use_index++) { + Node* use = block->get_node(use_index); + if (use == n) { + break; + } + use->replace_edge(def, merge); + } + } + if (merge->find_edge(n->in(k)) == -1) { + merge->add_req(n->in(k)); + } + n->set_req(k, merge); + } + + // update the uses + reg2defuse.at(reg).update(n->in(k), n); + } + + return blk_adjust; +} + //------------------------------post_allocate_copy_removal--------------------- // Post-Allocation peephole copy removal. We do this in 1 pass over the
--- a/hotspot/src/share/vm/opto/stringopts.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/opto/stringopts.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1507,10 +1507,12 @@ } case StringConcat::StringMode: { const Type* type = kit.gvn().type(arg); + Node* count = NULL; if (type == TypePtr::NULL_PTR) { // replace the argument with the null checked version arg = null_string; sc->set_argument(argi, arg); + count = kit.load_String_length(kit.control(), arg); } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) { // s = s != null ? s : "null"; // length = length + (s.count - s.offset); @@ -1533,10 +1535,13 @@ // replace the argument with the null checked version arg = phi; sc->set_argument(argi, arg); + count = kit.load_String_length(kit.control(), arg); + } else { + // A corresponding nullcheck will be connected during IGVN MemNode::Ideal_common_DU_postCCP + // kit.control might be a different test, that can be hoisted above the actual nullcheck + // in case, that the control input is not null, Ideal_common_DU_postCCP will not look for a nullcheck. + count = kit.load_String_length(NULL, arg); } - - Node* count = kit.load_String_length(kit.control(), arg); - length = __ AddI(length, count); string_sizes->init_req(argi, NULL); break;
--- a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -68,11 +68,11 @@ ~JvmtiConstantPoolReconstituter() { if (_symmap != NULL) { - os::free(_symmap); + delete _symmap; _symmap = NULL; } if (_classmap != NULL) { - os::free(_classmap); + delete _classmap; _classmap = NULL; } }
--- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1046,10 +1046,16 @@ { assert(str->klass() == SystemDictionary::String_klass(), "not a string"); + typeArrayOop s_value = java_lang_String::value(str); + + // JDK-6584008: the value field may be null if a String instance is + // partially constructed. + if (s_value == NULL) { + return 0; + } // get the string value and length // (string value may be offset from the base) int s_len = java_lang_String::length(str); - typeArrayOop s_value = java_lang_String::value(str); int s_offset = java_lang_String::offset(str); jchar* value; if (s_len > 0) {
--- a/hotspot/src/share/vm/prims/perf.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/prims/perf.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -100,6 +100,11 @@ PerfWrapper("Perf_Detach"); + if (!UsePerfData) { + // With -XX:-UsePerfData, detach is just a NOP + return; + } + void* address = 0; jlong capacity = 0;
--- a/hotspot/src/share/vm/prims/unsafe.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/prims/unsafe.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1104,43 +1104,6 @@ -UNSAFE_ENTRY(void, Unsafe_MonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj)) - UnsafeWrapper("Unsafe_MonitorEnter"); - { - if (jobj == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - Handle obj(thread, JNIHandles::resolve_non_null(jobj)); - ObjectSynchronizer::jni_enter(obj, CHECK); - } -UNSAFE_END - - -UNSAFE_ENTRY(jboolean, Unsafe_TryMonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj)) - UnsafeWrapper("Unsafe_TryMonitorEnter"); - { - if (jobj == NULL) { - THROW_(vmSymbols::java_lang_NullPointerException(), JNI_FALSE); - } - Handle obj(thread, JNIHandles::resolve_non_null(jobj)); - bool res = ObjectSynchronizer::jni_try_enter(obj, CHECK_0); - return (res ? JNI_TRUE : JNI_FALSE); - } -UNSAFE_END - - -UNSAFE_ENTRY(void, Unsafe_MonitorExit(JNIEnv *env, jobject unsafe, jobject jobj)) - UnsafeWrapper("Unsafe_MonitorExit"); - { - if (jobj == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - Handle obj(THREAD, JNIHandles::resolve_non_null(jobj)); - ObjectSynchronizer::jni_exit(obj(), CHECK); - } -UNSAFE_END - - UNSAFE_ENTRY(void, Unsafe_ThrowException(JNIEnv *env, jobject unsafe, jthrowable thr)) UnsafeWrapper("Unsafe_ThrowException"); { @@ -1365,8 +1328,6 @@ {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)} }; @@ -1411,8 +1372,6 @@ {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)} }; @@ -1461,8 +1420,6 @@ {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, @@ -1515,9 +1472,6 @@ {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, - {CC"tryMonitorEnter", CC"("OBJ")Z", FN_PTR(Unsafe_TryMonitorEnter)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, @@ -1571,9 +1525,6 @@ {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, - {CC"tryMonitorEnter", CC"("OBJ")Z", FN_PTR(Unsafe_TryMonitorEnter)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)},
--- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -155,7 +155,7 @@ if (mdo != NULL) { int i = mdo->invocation_count_delta(); int b = mdo->backedge_count_delta(); - return call_predicate_helper<CompLevel_full_profile>(i, b, 1); + return call_predicate_helper<CompLevel_full_profile>(i, b, 1, method); } return false; } @@ -229,32 +229,32 @@ // Tier?LoadFeedback is basically a coefficient that determines of // how many methods per compiler thread can be in the queue before // the threshold values double. -bool AdvancedThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level) { +bool AdvancedThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return loop_predicate_helper<CompLevel_none>(i, b, k); + return loop_predicate_helper<CompLevel_none>(i, b, k, method); } case CompLevel_full_profile: { double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); - return loop_predicate_helper<CompLevel_full_profile>(i, b, k); + return loop_predicate_helper<CompLevel_full_profile>(i, b, k, method); } default: return true; } } -bool AdvancedThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level) { +bool AdvancedThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return call_predicate_helper<CompLevel_none>(i, b, k); + return call_predicate_helper<CompLevel_none>(i, b, k, method); } case CompLevel_full_profile: { double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); - return call_predicate_helper<CompLevel_full_profile>(i, b, k); + return call_predicate_helper<CompLevel_full_profile>(i, b, k, method); } default: return true; @@ -271,7 +271,7 @@ int i = method->invocation_count(); int b = method->backedge_count(); double k = Tier0ProfilingStartPercentage / 100.0; - return call_predicate_helper<CompLevel_none>(i, b, k) || loop_predicate_helper<CompLevel_none>(i, b, k); + return call_predicate_helper<CompLevel_none>(i, b, k, method) || loop_predicate_helper<CompLevel_none>(i, b, k, method); } return false; } @@ -348,7 +348,7 @@ // If we were at full profile level, would we switch to full opt? if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; - } else if ((this->*p)(i, b, cur_level)) { + } else if ((this->*p)(i, b, cur_level, method)) { // C1-generated fully profiled code is about 30% slower than the limited profile // code that has only invocation and backedge counters. The observation is that // if C2 queue is large enough we can spend too much time in the fully profiled code @@ -374,7 +374,7 @@ if (mdo->would_profile()) { if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - (this->*p)(i, b, cur_level))) { + (this->*p)(i, b, cur_level, method))) { next_level = CompLevel_full_profile; } } else { @@ -390,7 +390,7 @@ if (mdo->would_profile()) { int mdo_i = mdo->invocation_count_delta(); int mdo_b = mdo->backedge_count_delta(); - if ((this->*p)(mdo_i, mdo_b, cur_level)) { + if ((this->*p)(mdo_i, mdo_b, cur_level, method)) { next_level = CompLevel_full_optimization; } } else {
--- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -84,7 +84,7 @@ * invocation and backedge notifications. Basically every n-th invocation or backedge a mutator thread * makes a call into the runtime. * - * - Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control + * - Tier?InvocationThreshold, Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control * compilation thresholds. * Level 2 thresholds are not used and are provided for option-compatibility and potential future use. * Other thresholds work as follows: @@ -100,7 +100,9 @@ * The same predicate is used to control the transition from level 3 to level 4 (C2). It should be * noted though that the thresholds are relative. Moreover i and b for the 0->3 transition come * from Method* and for 3->4 transition they come from MDO (since profiled invocations are - * counted separately). + * counted separately). Finally, if a method does not contain anything worth profiling, a transition + * from level 3 to level 4 occurs without considering thresholds (e.g., with fewer invocations than + * what is specified by Tier4InvocationThreshold). * * OSR transitions are controlled simply with b > TierXBackEdgeThreshold * s predicates. * @@ -164,9 +166,9 @@ // Call and loop predicates determine whether a transition to a higher compilation // level should be performed (pointers to predicate functions are passed to common(). // Predicates also take compiler load into account. - typedef bool (AdvancedThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level); - bool call_predicate(int i, int b, CompLevel cur_level); - bool loop_predicate(int i, int b, CompLevel cur_level); + typedef bool (AdvancedThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method); + bool call_predicate(int i, int b, CompLevel cur_level, Method* method); + bool loop_predicate(int i, int b, CompLevel cur_level, Method* method); // Common transition function. Given a predicate determines if a method should transition to another level. CompLevel common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback = false); // Transition functions.
--- a/hotspot/src/share/vm/runtime/arguments.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1126,16 +1126,35 @@ } #endif -// Returns threshold scaled with CompileThresholdScaling -intx Arguments::get_scaled_compile_threshold(intx threshold) { - return (intx)(threshold * CompileThresholdScaling); +intx Arguments::scaled_compile_threshold(intx threshold, double scale) { + if (scale == 1.0 || scale < 0.0) { + return threshold; + } else { + return (intx)(threshold * scale); + } } // Returns freq_log scaled with CompileThresholdScaling -intx Arguments::get_scaled_freq_log(intx freq_log) { - intx scaled_freq = get_scaled_compile_threshold((intx)1 << freq_log); - if (scaled_freq == 0) { - return 0; +intx Arguments::scaled_freq_log(intx freq_log, double scale) { + // Check if scaling is necessary or negative value was specified. + if (scale == 1.0 || scale < 0.0) { + return freq_log; + } + + // Check value to avoid calculating log2 of 0. + if (scale == 0.0) { + return 1; + } + + intx scaled_freq = scaled_compile_threshold((intx)1 << freq_log, scale); + // Determine the maximum notification frequency value currently supported. + // The largest mask value that the interpreter/C1 can handle is + // of length InvocationCounter::number_of_count_bits. Mask values are always + // one bit shorter then the value of the notification frequency. Set + // max_freq_bits accordingly. + intx max_freq_bits = InvocationCounter::number_of_count_bits + 1; + if (scaled_freq > nth_bit(max_freq_bits)) { + return max_freq_bits; } else { return log2_intptr(scaled_freq); } @@ -1180,31 +1199,36 @@ Tier3InvokeNotifyFreqLog = 0; Tier4InvocationThreshold = 0; } + + if (CompileThresholdScaling < 0) { + vm_exit_during_initialization("Negative value specified for CompileThresholdScaling", NULL); + } + // Scale tiered compilation thresholds if (!FLAG_IS_DEFAULT(CompileThresholdScaling)) { - FLAG_SET_ERGO(intx, Tier0InvokeNotifyFreqLog, get_scaled_freq_log(Tier0InvokeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier0BackedgeNotifyFreqLog, get_scaled_freq_log(Tier0BackedgeNotifyFreqLog)); - - FLAG_SET_ERGO(intx, Tier3InvocationThreshold, get_scaled_compile_threshold(Tier3InvocationThreshold)); - FLAG_SET_ERGO(intx, Tier3MinInvocationThreshold, get_scaled_compile_threshold(Tier3MinInvocationThreshold)); - FLAG_SET_ERGO(intx, Tier3CompileThreshold, get_scaled_compile_threshold(Tier3CompileThreshold)); - FLAG_SET_ERGO(intx, Tier3BackEdgeThreshold, get_scaled_compile_threshold(Tier3BackEdgeThreshold)); + FLAG_SET_ERGO(intx, Tier0InvokeNotifyFreqLog, scaled_freq_log(Tier0InvokeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier0BackedgeNotifyFreqLog, scaled_freq_log(Tier0BackedgeNotifyFreqLog)); + + FLAG_SET_ERGO(intx, Tier3InvocationThreshold, scaled_compile_threshold(Tier3InvocationThreshold)); + FLAG_SET_ERGO(intx, Tier3MinInvocationThreshold, scaled_compile_threshold(Tier3MinInvocationThreshold)); + FLAG_SET_ERGO(intx, Tier3CompileThreshold, scaled_compile_threshold(Tier3CompileThreshold)); + FLAG_SET_ERGO(intx, Tier3BackEdgeThreshold, scaled_compile_threshold(Tier3BackEdgeThreshold)); // Tier2{Invocation,MinInvocation,Compile,Backedge}Threshold should be scaled here // once these thresholds become supported. - FLAG_SET_ERGO(intx, Tier2InvokeNotifyFreqLog, get_scaled_freq_log(Tier2InvokeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier2BackedgeNotifyFreqLog, get_scaled_freq_log(Tier2BackedgeNotifyFreqLog)); - - FLAG_SET_ERGO(intx, Tier3InvokeNotifyFreqLog, get_scaled_freq_log(Tier3InvokeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier3BackedgeNotifyFreqLog, get_scaled_freq_log(Tier3BackedgeNotifyFreqLog)); - - FLAG_SET_ERGO(intx, Tier23InlineeNotifyFreqLog, get_scaled_freq_log(Tier23InlineeNotifyFreqLog)); - - FLAG_SET_ERGO(intx, Tier4InvocationThreshold, get_scaled_compile_threshold(Tier4InvocationThreshold)); - FLAG_SET_ERGO(intx, Tier4MinInvocationThreshold, get_scaled_compile_threshold(Tier4MinInvocationThreshold)); - FLAG_SET_ERGO(intx, Tier4CompileThreshold, get_scaled_compile_threshold(Tier4CompileThreshold)); - FLAG_SET_ERGO(intx, Tier4BackEdgeThreshold, get_scaled_compile_threshold(Tier4BackEdgeThreshold)); + FLAG_SET_ERGO(intx, Tier2InvokeNotifyFreqLog, scaled_freq_log(Tier2InvokeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier2BackedgeNotifyFreqLog, scaled_freq_log(Tier2BackedgeNotifyFreqLog)); + + FLAG_SET_ERGO(intx, Tier3InvokeNotifyFreqLog, scaled_freq_log(Tier3InvokeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier3BackedgeNotifyFreqLog, scaled_freq_log(Tier3BackedgeNotifyFreqLog)); + + FLAG_SET_ERGO(intx, Tier23InlineeNotifyFreqLog, scaled_freq_log(Tier23InlineeNotifyFreqLog)); + + FLAG_SET_ERGO(intx, Tier4InvocationThreshold, scaled_compile_threshold(Tier4InvocationThreshold)); + FLAG_SET_ERGO(intx, Tier4MinInvocationThreshold, scaled_compile_threshold(Tier4MinInvocationThreshold)); + FLAG_SET_ERGO(intx, Tier4CompileThreshold, scaled_compile_threshold(Tier4CompileThreshold)); + FLAG_SET_ERGO(intx, Tier4BackEdgeThreshold, scaled_compile_threshold(Tier4BackEdgeThreshold)); } } @@ -3456,7 +3480,7 @@ } if ((TieredCompilation && CompileThresholdScaling == 0) - || (!TieredCompilation && get_scaled_compile_threshold(CompileThreshold) == 0)) { + || (!TieredCompilation && scaled_compile_threshold(CompileThreshold) == 0)) { set_mode_flags(_int); } @@ -3896,7 +3920,7 @@ } // Scale CompileThreshold if (!FLAG_IS_DEFAULT(CompileThresholdScaling)) { - FLAG_SET_ERGO(intx, CompileThreshold, get_scaled_compile_threshold(CompileThreshold)); + FLAG_SET_ERGO(intx, CompileThreshold, scaled_compile_threshold(CompileThreshold)); } }
--- a/hotspot/src/share/vm/runtime/arguments.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/arguments.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -328,9 +328,6 @@ static bool _ClipInlining; static bool _CIDynamicCompilePriority; - // Scale compile thresholds - static intx get_scaled_compile_threshold(intx threshold); - static intx get_scaled_freq_log(intx freq_log); // Tiered static void set_tiered_flags(); static int get_min_number_of_compiler_threads(); @@ -452,6 +449,18 @@ static char* SharedArchivePath; public: + // Scale compile thresholds + // Returns threshold scaled with CompileThresholdScaling + static intx scaled_compile_threshold(intx threshold, double scale); + static intx scaled_compile_threshold(intx threshold) { + return scaled_compile_threshold(threshold, CompileThresholdScaling); + } + // Returns freq_log scaled with CompileThresholdScaling + static intx scaled_freq_log(intx freq_log, double scale); + static intx scaled_freq_log(intx freq_log) { + return scaled_freq_log(freq_log, CompileThresholdScaling); + } + // Parses the arguments, first phase static jint parse(const JavaVMInitArgs* args); // Apply ergonomics
--- a/hotspot/src/share/vm/runtime/globals.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -2477,7 +2477,7 @@ "Number of compiler threads to run") \ \ product(intx, CompilationPolicyChoice, 0, \ - "which compilation policy (0/1)") \ + "which compilation policy (0-3)") \ \ develop(bool, UseStackBanging, true, \ "use stack banging for stack overflow checks (required for " \ @@ -3528,7 +3528,16 @@ \ product(double, CompileThresholdScaling, 1.0, \ "Factor to control when first compilation happens " \ - "(both with and without tiered compilation)") \ + "(both with and without tiered compilation): " \ + "values greater than 1.0 delay counter overflow, " \ + "values between 0 and 1.0 rush counter overflow, " \ + "value of 1.0 leave compilation thresholds unchanged " \ + "value of 0.0 is equivalent to -Xint. " \ + "" \ + "Flag can be set as per-method option. " \ + "If a value is specified for a method, compilation thresholds " \ + "for that method are scaled by both the value of the global flag "\ + "and the value of the per-method flag.") \ \ product(intx, Tier0InvokeNotifyFreqLog, 7, \ "Interpreter (tier 0) invocation notification frequency") \
--- a/hotspot/src/share/vm/runtime/os.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1401,15 +1401,17 @@ return (sp > (stack_limit + reserved_area)); } -size_t os::page_size_for_region(size_t region_size, size_t min_pages) { +size_t os::page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned) { assert(min_pages > 0, "sanity"); if (UseLargePages) { const size_t max_page_size = region_size / min_pages; for (size_t i = 0; _page_sizes[i] != 0; ++i) { const size_t page_size = _page_sizes[i]; - if (page_size <= max_page_size && is_size_aligned(region_size, page_size)) { - return page_size; + if (page_size <= max_page_size) { + if (!must_be_aligned || is_size_aligned(region_size, page_size)) { + return page_size; + } } } } @@ -1417,6 +1419,14 @@ return vm_page_size(); } +size_t os::page_size_for_region_aligned(size_t region_size, size_t min_pages) { + return page_size_for_region(region_size, min_pages, true); +} + +size_t os::page_size_for_region_unaligned(size_t region_size, size_t min_pages) { + return page_size_for_region(region_size, min_pages, false); +} + #ifndef PRODUCT void os::trace_page_sizes(const char* str, const size_t* page_sizes, int count) { @@ -1665,17 +1675,17 @@ static size_t large_page_size() { const size_t large_page_size_example = 4 * M; - return os::page_size_for_region(large_page_size_example, 1); + return os::page_size_for_region_aligned(large_page_size_example, 1); } - static void test_page_size_for_region() { + static void test_page_size_for_region_aligned() { if (UseLargePages) { const size_t small_page = small_page_size(); const size_t large_page = large_page_size(); if (large_page > small_page) { size_t num_small_pages_in_large = large_page / small_page; - size_t page = os::page_size_for_region(large_page, num_small_pages_in_large); + size_t page = os::page_size_for_region_aligned(large_page, num_small_pages_in_large); assert_eq(page, small_page); } @@ -1688,21 +1698,53 @@ const size_t large_page = large_page_size(); if (large_page > small_page) { const size_t unaligned_region = large_page + 17; - size_t page = os::page_size_for_region(unaligned_region, 1); + size_t page = os::page_size_for_region_aligned(unaligned_region, 1); assert_eq(page, small_page); const size_t num_pages = 5; const size_t aligned_region = large_page * num_pages; - page = os::page_size_for_region(aligned_region, num_pages); + page = os::page_size_for_region_aligned(aligned_region, num_pages); assert_eq(page, large_page); } } } + static void test_page_size_for_region_unaligned() { + if (UseLargePages) { + // Given exact page size, should return that page size. + for (size_t i = 0; os::_page_sizes[i] != 0; i++) { + size_t expected = os::_page_sizes[i]; + size_t actual = os::page_size_for_region_unaligned(expected, 1); + assert_eq(expected, actual); + } + + // Given slightly larger size than a page size, return the page size. + for (size_t i = 0; os::_page_sizes[i] != 0; i++) { + size_t expected = os::_page_sizes[i]; + size_t actual = os::page_size_for_region_unaligned(expected + 17, 1); + assert_eq(expected, actual); + } + + // Given a slightly smaller size than a page size, + // return the next smaller page size. + if (os::_page_sizes[1] > os::_page_sizes[0]) { + size_t expected = os::_page_sizes[0]; + size_t actual = os::page_size_for_region_unaligned(os::_page_sizes[1] - 17, 1); + assert_eq(actual, expected); + } + + // Return small page size for values less than a small page. + size_t small_page = small_page_size(); + size_t actual = os::page_size_for_region_unaligned(small_page - 17, 1); + assert_eq(small_page, actual); + } + } + public: static void run_tests() { - test_page_size_for_region(); + test_page_size_for_region_aligned(); test_page_size_for_region_alignment(); + test_page_size_for_region_unaligned(); } };
--- a/hotspot/src/share/vm/runtime/os.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/os.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -148,6 +148,7 @@ static void pd_free_memory(char *addr, size_t bytes, size_t alignment_hint); static void pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint); + static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned); public: static void init(void); // Called before command line parsing @@ -267,8 +268,13 @@ // Returns the page size to use for a region of memory. // region_size / min_pages will always be greater than or equal to the - // returned value. - static size_t page_size_for_region(size_t region_size, size_t min_pages); + // returned value. The returned value will divide region_size. + static size_t page_size_for_region_aligned(size_t region_size, size_t min_pages); + + // Returns the page size to use for a region of memory. + // region_size / min_pages will always be greater than or equal to the + // returned value. The returned value might not divide region_size. + static size_t page_size_for_region_unaligned(size_t region_size, size_t min_pages); // Return the largest page size that can be used static size_t max_page_size() {
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -257,28 +257,28 @@ // Call and loop predicates determine whether a transition to a higher // compilation level should be performed (pointers to predicate functions // are passed to common() transition function). -bool SimpleThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level) { +bool SimpleThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { - return loop_predicate_helper<CompLevel_none>(i, b, 1.0); + return loop_predicate_helper<CompLevel_none>(i, b, 1.0, method); } case CompLevel_full_profile: { - return loop_predicate_helper<CompLevel_full_profile>(i, b, 1.0); + return loop_predicate_helper<CompLevel_full_profile>(i, b, 1.0, method); } default: return true; } } -bool SimpleThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level) { +bool SimpleThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { - return call_predicate_helper<CompLevel_none>(i, b, 1.0); + return call_predicate_helper<CompLevel_none>(i, b, 1.0, method); } case CompLevel_full_profile: { - return call_predicate_helper<CompLevel_full_profile>(i, b, 1.0); + return call_predicate_helper<CompLevel_full_profile>(i, b, 1.0, method); } default: return true; @@ -293,8 +293,8 @@ int i = mdo->invocation_count(); int b = mdo->backedge_count(); double k = ProfileMaturityPercentage / 100.0; - return call_predicate_helper<CompLevel_full_profile>(i, b, k) || - loop_predicate_helper<CompLevel_full_profile>(i, b, k); + return call_predicate_helper<CompLevel_full_profile>(i, b, k, method) || + loop_predicate_helper<CompLevel_full_profile>(i, b, k, method); } return false; } @@ -313,7 +313,7 @@ // If we were at full profile level, would we switch to full opt? if (common(p, method, CompLevel_full_profile) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; - } else if ((this->*p)(i, b, cur_level)) { + } else if ((this->*p)(i, b, cur_level, method)) { next_level = CompLevel_full_profile; } break; @@ -325,7 +325,7 @@ if (mdo->would_profile()) { int mdo_i = mdo->invocation_count_delta(); int mdo_b = mdo->backedge_count_delta(); - if ((this->*p)(mdo_i, mdo_b, cur_level)) { + if ((this->*p)(mdo_i, mdo_b, cur_level, method)) { next_level = CompLevel_full_optimization; } } else {
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -43,9 +43,9 @@ // Call and loop predicates determine whether a transition to a higher compilation // level should be performed (pointers to predicate functions are passed to common_TF(). // Predicates also take compiler load into account. - typedef bool (SimpleThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level); - bool call_predicate(int i, int b, CompLevel cur_level); - bool loop_predicate(int i, int b, CompLevel cur_level); + typedef bool (SimpleThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method); + bool call_predicate(int i, int b, CompLevel cur_level, Method* method); + bool loop_predicate(int i, int b, CompLevel cur_level, Method* method); // Common transition function. Given a predicate determines if a method should transition to another level. CompLevel common(Predicate p, Method* method, CompLevel cur_level); // Transition functions. @@ -76,8 +76,8 @@ // Predicate helpers are used by .*_predicate() methods as well as others. // They check the given counter values, multiplied by the scale against the thresholds. - template<CompLevel level> static inline bool call_predicate_helper(int i, int b, double scale); - template<CompLevel level> static inline bool loop_predicate_helper(int i, int b, double scale); + template<CompLevel level> static inline bool call_predicate_helper(int i, int b, double scale, Method* method); + template<CompLevel level> static inline bool loop_predicate_helper(int i, int b, double scale, Method* method); // Get a compilation level for a given method. static CompLevel comp_level(Method* method) {
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -25,8 +25,14 @@ #ifndef SHARE_VM_RUNTIME_SIMPLETHRESHOLDPOLICY_INLINE_HPP #define SHARE_VM_RUNTIME_SIMPLETHRESHOLDPOLICY_INLINE_HPP +#include "compiler/compilerOracle.hpp" + template<CompLevel level> -bool SimpleThresholdPolicy::call_predicate_helper(int i, int b, double scale) { +bool SimpleThresholdPolicy::call_predicate_helper(int i, int b, double scale, Method* method) { + double threshold_scaling; + if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { + scale *= threshold_scaling; + } switch(level) { case CompLevel_none: case CompLevel_limited_profile: @@ -40,7 +46,11 @@ } template<CompLevel level> -bool SimpleThresholdPolicy::loop_predicate_helper(int i, int b, double scale) { +bool SimpleThresholdPolicy::loop_predicate_helper(int i, int b, double scale, Method* method) { + double threshold_scaling; + if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { + scale *= threshold_scaling; + } switch(level) { case CompLevel_none: case CompLevel_limited_profile:
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -276,18 +276,6 @@ THREAD->set_current_pending_monitor_is_from_java(true); } -// NOTE: must use heavy weight monitor to handle jni monitor enter -bool ObjectSynchronizer::jni_try_enter(Handle obj, Thread* THREAD) { - if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); - assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); - } - - ObjectMonitor* monitor = ObjectSynchronizer::inflate_helper(obj()); - return monitor->try_enter(THREAD); -} - - // NOTE: must use heavy weight monitor to handle jni monitor exit void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) { TEVENT(jni_exit);
--- a/hotspot/src/share/vm/runtime/synchronizer.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/synchronizer.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,6 @@ // Used only to handle jni locks or other unmatched monitor enter/exit // Internally they will use heavy weight monitor. static void jni_enter(Handle obj, TRAPS); - static bool jni_try_enter(Handle obj, Thread* THREAD); // Implements Unsafe.tryMonitorEnter static void jni_exit(oop obj, Thread* THREAD); // Handle all interpreter, compiler and jni cases
--- a/hotspot/src/share/vm/runtime/virtualspace.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -38,7 +38,8 @@ } ReservedSpace::ReservedSpace(size_t size) { - size_t page_size = os::page_size_for_region(size, 1); + // Want to use large pages where possible and pad with small pages. + size_t page_size = os::page_size_for_region_unaligned(size, 1); bool large_pages = page_size != (size_t)os::vm_page_size(); // Don't force the alignment to be large page aligned, // since that will waste memory. @@ -617,7 +618,7 @@ bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { - const size_t max_commit_granularity = os::page_size_for_region(rs.size(), 1); + const size_t max_commit_granularity = os::page_size_for_region_unaligned(rs.size(), 1); return initialize_with_granularity(rs, committed_size, max_commit_granularity); } @@ -1239,7 +1240,7 @@ case Disable: return vs.initialize_with_granularity(rs, 0, os::vm_page_size()); case Commit: - return vs.initialize_with_granularity(rs, 0, os::page_size_for_region(rs.size(), 1)); + return vs.initialize_with_granularity(rs, 0, os::page_size_for_region_unaligned(rs.size(), 1)); } }
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Feb 04 18:23:09 2015 -0800 @@ -351,11 +351,18 @@ nonstatic_field(MethodData, _arg_stack, intx) \ nonstatic_field(MethodData, _arg_returned, intx) \ nonstatic_field(MethodData, _tenure_traps, uint) \ + nonstatic_field(MethodData, _invoke_mask, int) \ + nonstatic_field(MethodData, _backedge_mask, int) \ nonstatic_field(DataLayout, _header._struct._tag, u1) \ nonstatic_field(DataLayout, _header._struct._flags, u1) \ nonstatic_field(DataLayout, _header._struct._bci, u2) \ nonstatic_field(DataLayout, _cells[0], intptr_t) \ nonstatic_field(MethodCounters, _nmethod_age, int) \ + nonstatic_field(MethodCounters, _interpreter_invocation_limit, int) \ + nonstatic_field(MethodCounters, _interpreter_backward_branch_limit, int) \ + nonstatic_field(MethodCounters, _interpreter_profile_limit, int) \ + nonstatic_field(MethodCounters, _invoke_mask, int) \ + nonstatic_field(MethodCounters, _backedge_mask, int) \ nonstatic_field(MethodCounters, _interpreter_invocation_count, int) \ nonstatic_field(MethodCounters, _interpreter_throwout_count, u2) \ nonstatic_field(MethodCounters, _number_of_breakpoints, u2) \
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Wed Feb 04 18:23:09 2015 -0800 @@ -1142,17 +1142,18 @@ return ((x != NoLongBits) && (mask_long_bits(x, x - 1) == NoLongBits)); } -//* largest i such that 2^i <= x -// A negative value of 'x' will return '31' +// Returns largest i such that 2^i <= x. +// If x < 0, the function returns 31 on a 32-bit machine and 63 on a 64-bit machine. +// If x == 0, the function returns -1. inline int log2_intptr(intptr_t x) { int i = -1; - uintptr_t p = 1; + uintptr_t p = 1; while (p != 0 && p <= (uintptr_t)x) { // p = 2^(i+1) && p <= x (i.e., 2^(i+1) <= x) i++; p *= 2; } // p = 2^(i+1) && x < p (i.e., 2^i <= x < 2^(i+1)) - // (if p = 0 then overflow occurred and i = 31) + // If p = 0, overflow has occurred and i = 31 or i = 63 (depending on the machine word size). return i; }
--- a/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java Wed Feb 04 18:23:09 2015 -0800 @@ -54,7 +54,7 @@ // // Tier0InvokeNotifyFreqLog, Tier0BackedgeNotifyFreqLog, // Tier3InvocationThreshold, Tier3MinInvocationThreshold, - // Tier3CompileThreshold, and Tier3BackEdgeThreshold, + // Tier3CompileThreshold, Tier3BackEdgeThreshold, // Tier2InvokeNotifyFreqLog, Tier2BackedgeNotifyFreqLog, // Tier3InvokeNotifyFreqLog, Tier3BackedgeNotifyFreqLog, // Tier23InlineeNotifyFreqLog, Tier4InvocationThreshold,
--- a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Wed Feb 04 18:23:09 2015 -0800 @@ -98,11 +98,13 @@ return false; }); for (BlobType bt : BlobType.getAvailable()) { - int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0; - Asserts.assertEQ(counters.get(bt.getMemoryPool().getName()).get(), - expectedNotificationsAmount, String.format("Unexpected " - + "amount of notifications for pool: %s", - bt.getMemoryPool().getName())); + if (CodeCacheUtils.isCodeHeapPredictable(bt)) { + int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0; + Asserts.assertEQ(counters.get(bt.getMemoryPool().getName()).get(), + expectedNotificationsAmount, String.format("Unexpected " + + "amount of notifications for pool: %s", + bt.getMemoryPool().getName())); + } } try { ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
--- a/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java Wed Feb 04 18:23:09 2015 -0800 @@ -52,7 +52,9 @@ public static void main(String[] args) { for (BlobType bt : BlobType.getAvailable()) { - new ThresholdNotificationsTest(bt).runTest(); + if (CodeCacheUtils.isCodeHeapPredictable(bt)) { + new ThresholdNotificationsTest(bt).runTest(); + } } }
--- a/hotspot/test/compiler/loopopts/7052494/Test7052494.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/compiler/loopopts/7052494/Test7052494.java Wed Feb 04 18:23:09 2015 -0800 @@ -25,7 +25,6 @@ /** * @test * @bug 7052494 - * @ignore 7154567 * @summary Eclipse test fails on JDK 7 b142 * * @run main/othervm -Xbatch Test7052494
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/stringopts/TestOptimizeStringConcat.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright 2015 SAP AG. All Rights Reserved. + * 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 8068909 + * @key regression + * @summary test that string optimizations produce code, that doesn't lead to a crash. + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestOptimizeStringConcat + * @author axel.siebenborn@sap.com + */ +public class TestOptimizeStringConcat { + + static boolean checkArgumentSyntax(String value, String allowedchars, String notallowedchars, String logmsg) { + String rc = null; + + int maxchar = 99999; + int minchar = 1; + if ((allowedchars != null && notallowedchars != null) || minchar > maxchar) { + rc = "internal error"; + } else { + if (value == null) { + rc = "the value null is not allowed, it is missing"; + } else if (value != null && minchar > 0 && value.trim().equals("")) { + rc = "the value must not be empty"; + } else if (value != null) { + if (value.length() < minchar || value.length() > maxchar) { + if (rc == null) { + rc = "the value length must be between +minchar+ and +maxchar"; + } + } + char[] _value = value.toCharArray(); + boolean dotfound = false; + int i = 1; + if (_value[i] == '.' && !dotfound) { + dotfound = true; + } else if (allowedchars != null && allowedchars.indexOf(_value[i]) == -1) { + if (rc == null) { + rc = "the value contains an illegal character: '" + _value[i] + "', only following characters are allowed: '+allowedchars+'"; + } else { + rc += " / the value contains an illegal character: '" + _value[i] + "', only following characters are allowed: '+allowedchars+'"; + } + } else if (notallowedchars != null && notallowedchars.indexOf(_value[i]) != -1) { + if (rc == null) { + rc = "the value contains an illegal character: '" + _value[i] + "', following characters are not allowed '+notallowedchars+'"; + } else { + rc += " / the value contains an illegal character: '" + _value[i] + "', following characters are not allowed '+notallowedchars+'"; + } + } + } + } + + if (rc != null) { + System.out.println(logmsg + " ==> " + rc); + return false; + } + return true; + } + + public static void main(String[] args) { + boolean failed = false; + for (int i = 0; i < 10000; i++) { + failed |= !checkArgumentSyntax("theName", null, "\"<&", "Error consistencyCheck: name in component definition"); + failed |= !checkArgumentSyntax(null, null, "\"<&", "Error consistencyCheck: name in component definition"); + failed |= !checkArgumentSyntax("42", "0123456789.", null, "Error consistencyCheck: counter in component definition"); + } + System.out.println(failed); + } +}
--- a/hotspot/test/compiler/testlibrary/rtm/BusyLock.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/compiler/testlibrary/rtm/BusyLock.java Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,6 @@ package rtm; -import com.oracle.java.testlibrary.Utils; -import sun.misc.Unsafe; - import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; @@ -42,7 +39,6 @@ // Following field have to be static in order to avoid escape analysis. @SuppressWarnings("UnsuedDeclaration") private static int field = 0; - private static final Unsafe UNSAFE = Utils.getUnsafe(); protected final Object monitor; protected final int timeout; @@ -59,18 +55,9 @@ @Override public void run() { try { - // wait until forceAbort leave monitor - barrier.await(); - if (UNSAFE.tryMonitorEnter(monitor)) { - try { - barrier.await(); - Thread.sleep(timeout); - } finally { - UNSAFE.monitorExit(monitor); - } - } else { - throw new RuntimeException("Monitor should be entered by " + - "::run() first."); + synchronized (monitor) { + barrier.await(); + Thread.sleep(timeout); } } catch (InterruptedException | BrokenBarrierException e) { throw new RuntimeException("Synchronization error happened.", e); @@ -79,7 +66,6 @@ public void syncAndTest() { try { - barrier.await(); // wait until monitor is locked by a ::run method barrier.await(); } catch (InterruptedException | BrokenBarrierException e) {
--- a/hotspot/test/gc/TestNUMAPageSize.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/gc/TestNUMAPageSize.java Wed Feb 04 18:23:09 2015 -0800 @@ -25,6 +25,7 @@ * @test TestNUMAPageSize * @summary Make sure that start up with NUMA support does not cause problems. * @bug 8061467 + * @requires (vm.opt.AggressiveOpts == null) | (vm.opt.AggressiveOpts == false) * @key gc * @key regression * @run main/othervm -Xmx8M -XX:+UseNUMA TestNUMAPageSize
--- a/hotspot/test/gc/TestSmallHeap.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/gc/TestSmallHeap.java Wed Feb 04 18:23:09 2015 -0800 @@ -25,6 +25,7 @@ * @test TestSmallHeap * @bug 8067438 * @requires vm.gc=="null" + * @requires (vm.opt.AggressiveOpts=="null") | (vm.opt.AggressiveOpts=="false") * @summary Verify that starting the VM with a small heap works * @library /testlibrary /../../test/lib * @build TestSmallHeap @@ -33,8 +34,9 @@ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseSerialGC TestSmallHeap * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseG1GC TestSmallHeap * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseConcMarkSweepGC TestSmallHeap - * - * Note: It would be nice to verify the minimal supported heap size (2m) here, + */ + +/* Note: It would be nice to verify the minimal supported heap size (2m) here, * but we align the heap size based on the card table size. And the card table * size is aligned based on the minimal pages size provided by the os. This * means that on most platforms, where the minimal page size is 4k, we get a
--- a/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java Wed Feb 04 18:23:09 2015 -0800 @@ -116,7 +116,14 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(finalargs.toArray(new String[0])); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); + try { + output.shouldHaveExitValue(0); + } catch (RuntimeException e) { + // It's ok if there is no client vm in the jdk. + if (output.firstMatch("Unrecognized option: -client") == null) { + throw e; + } + } return output; }
--- a/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-Xmx64m", "-XX:-TransmitErrorReport", Crasher.class.getName()); + "-Xmx64m", "-XX:-TransmitErrorReport", "-XX:-CreateMinidumpOnCrash", Crasher.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotMatch("error occurred during error reporting \\(printing problematic frame\\)"); }
--- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java Tue Feb 03 16:46:05 2015 +0100 +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java Wed Feb 04 18:23:09 2015 -0800 @@ -25,6 +25,7 @@ * @test CompilerQueueTest * @bug 8054889 * @library .. + * @ignore 8069160 * @build DcmdUtil CompilerQueueTest * @run main CompilerQueueTest * @run main/othervm -XX:-TieredCompilation CompilerQueueTest
--- a/jaxp/.hgtags Tue Feb 03 16:46:05 2015 +0100 +++ b/jaxp/.hgtags Wed Feb 04 18:23:09 2015 -0800 @@ -290,3 +290,4 @@ 0dab3e848229127c7aca4c58b98e2d90ba70372f jdk9-b45 74eaf7ad986576c792df4dbff05eed63e5727695 jdk9-b46 e391de88e69b59d7c618387e3cf91032f6991ce9 jdk9-b47 +833051855168a973780fafeb6fc59e7370bcf400 jdk9-b48
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java Tue Feb 03 16:46:05 2015 +0100 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java Wed Feb 04 18:23:09 2015 -0800 @@ -270,8 +270,8 @@ if (Double.isNaN(start)) return(EMPTYSTRING); - final int strlen = value.length(); - int istart = (int)Math.round(start) - 1; + final int strlen = value.length(); + int istart = (int)Math.round(start) - 1; if (istart > strlen) return(EMPTYSTRING); @@ -292,10 +292,11 @@ public static String substringF(String value, double start, double length) { if (Double.isInfinite(start) || Double.isNaN(start) || - Double.isNaN(length)) + Double.isNaN(length) || + length < 0) return(EMPTYSTRING); - int istart = (int)Math.round(start) - 1; + int istart = (int)Math.round(start) - 1; final int isum; if (Double.isInfinite(length)) isum = Integer.MAX_VALUE;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java Tue Feb 03 16:46:05 2015 +0100 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java Wed Feb 04 18:23:09 2015 -0800 @@ -1,15 +1,15 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. */ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,36 +17,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// $Id: XPathExpressionImpl.java,v 1.3 2005/09/27 09:40:43 sunithareddy Exp $ package com.sun.org.apache.xpath.internal.jaxp; -import com.sun.org.apache.xpath.internal.*; +import com.sun.org.apache.xalan.internal.utils.FeatureManager; +import com.sun.org.apache.xpath.internal.objects.XObject; +import javax.xml.namespace.QName; import javax.xml.transform.TransformerException; - -import com.sun.org.apache.xpath.internal.objects.XObject; -import com.sun.org.apache.xml.internal.dtm.DTM; -import com.sun.org.apache.xml.internal.utils.PrefixResolver; -import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; -import com.sun.org.apache.xalan.internal.res.XSLMessages; -import com.sun.org.apache.xalan.internal.utils.FactoryImpl; -import com.sun.org.apache.xalan.internal.utils.FeatureManager; - -import javax.xml.namespace.NamespaceContext; -import javax.xml.namespace.QName; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathEvaluationResult; +import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; -import javax.xml.xpath.XPathConstants; - +import org.w3c.dom.Document; import org.w3c.dom.Node; -import org.w3c.dom.Document; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.traversal.NodeIterator; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.DocumentBuilder; - import org.xml.sax.InputSource; /** @@ -54,22 +39,10 @@ * * @author Ramesh Mandava */ -public class XPathExpressionImpl implements javax.xml.xpath.XPathExpression{ +public class XPathExpressionImpl extends XPathImplUtil implements XPathExpression { - private XPathFunctionResolver functionResolver; - private XPathVariableResolver variableResolver; - private JAXPPrefixResolver prefixResolver; private com.sun.org.apache.xpath.internal.XPath xpath; - // By default Extension Functions are allowed in XPath Expressions. If - // Secure Processing Feature is set on XPathFactory then the invocation of - // extensions function need to throw XPathFunctionException - private boolean featureSecureProcessing = false; - - private boolean useServicesMechanism = true; - - private final FeatureManager featureManager; - /** Protected constructor to prevent direct instantiation; use compile() * from the context. */ @@ -81,7 +54,7 @@ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, JAXPPrefixResolver prefixResolver, XPathFunctionResolver functionResolver, - XPathVariableResolver variableResolver ) { + XPathVariableResolver variableResolver) { this(xpath, prefixResolver, functionResolver, variableResolver, false, true, new FeatureManager()); }; @@ -89,291 +62,108 @@ protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver, XPathVariableResolver variableResolver, boolean featureSecureProcessing, - boolean useServicesMechanism, FeatureManager featureManager ) { + boolean useServiceMechanism, FeatureManager featureManager) { this.xpath = xpath; this.prefixResolver = prefixResolver; this.functionResolver = functionResolver; this.variableResolver = variableResolver; this.featureSecureProcessing = featureSecureProcessing; - this.useServicesMechanism = useServicesMechanism; + this.useServiceMechanism = useServiceMechanism; this.featureManager = featureManager; }; - public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath ) { + public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath) { this.xpath = xpath; } public Object eval(Object item, QName returnType) throws javax.xml.transform.TransformerException { - XObject resultObject = eval ( item ); - return getResultAsType( resultObject, returnType ); + XObject resultObject = eval(item, xpath); + return getResultAsType(resultObject, returnType); } - private XObject eval ( Object contextItem ) - throws javax.xml.transform.TransformerException { - com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null; - if ( functionResolver != null ) { - JAXPExtensionsProvider jep = new JAXPExtensionsProvider( - functionResolver, featureSecureProcessing, featureManager ); - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep ); - } else { - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); - } - - xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); - XObject xobj = null; - - Node contextNode = (Node)contextItem; - // We always need to have a ContextNode with Xalan XPath implementation - // To allow simple expression evaluation like 1+1 we are setting - // dummy Document as Context Node - - if ( contextNode == null ) - xobj = xpath.execute(xpathSupport, DTM.NULL, prefixResolver); - else - xobj = xpath.execute(xpathSupport, contextNode, prefixResolver); - - return xobj; - } - - - /** - * <p>Evaluate the compiled XPath expression in the specified context and - * return the result as the specified type.</p> - * - * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> - * - * <p>If <code>returnType</code> is not one of the types defined - * in {@link XPathConstants}, - * then an <code>IllegalArgumentException</code> is thrown.</p> - * - * <p>If a <code>null</code> value is provided for - * <code>item</code>, an empty document will be used for the - * context. - * If <code>returnType</code> is <code>null</code>, then a - * <code>NullPointerException</code> is thrown.</p> - * - * @param item The starting context (node or node list, for example). - * @param returnType The desired return type. - * - * @return The <code>Object</code> that is the result of evaluating the - * expression and converting the result to - * <code>returnType</code>. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If <code>returnType</code> is not one - * of the types defined in {@link XPathConstants}. - * @throws NullPointerException If <code>returnType</code> is - * <code>null</code>. - */ + @Override public Object evaluate(Object item, QName returnType) throws XPathExpressionException { - //Validating parameters to enforce constraints defined by JAXP spec - if ( returnType == null ) { - //Throwing NullPointerException as defined in spec - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException( fmsg ); - } - // Checking if requested returnType is supported. returnType need to be - // defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + isSupported(returnType); try { - return eval( item, returnType); - } catch ( java.lang.NullPointerException npe ) { + return eval(item, returnType); + } catch (java.lang.NullPointerException npe) { // If VariableResolver returns null Or if we get // NullPointerException at this stage for some other reason // then we have to reurn XPathException - throw new XPathExpressionException ( npe ); - } catch ( javax.xml.transform.TransformerException te ) { + throw new XPathExpressionException (npe); + } catch (javax.xml.transform.TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { // For any other exceptions we need to throw - // XPathExpressionException ( as per spec ) - throw new XPathExpressionException( te); + // XPathExpressionException (as per spec) + throw new XPathExpressionException(te); } } - - } - - /** - * <p>Evaluate the compiled XPath expression in the specified context and - * return the result as a <code>String</code>.</p> - * - * <p>This method calls {@link #evaluate(Object item, QName returnType)} - * with a <code>returnType</code> of - * {@link XPathConstants#STRING}.</p> - * - * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> - * - * <p>If a <code>null</code> value is provided for - * <code>item</code>, an empty document will be used for the - * context. - * - * @param item The starting context (node or node list, for example). - * - * @return The <code>String</code> that is the result of evaluating the - * expression and converting the result to a - * <code>String</code>. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - */ - public String evaluate(Object item) - throws XPathExpressionException { - return (String)this.evaluate( item, XPathConstants.STRING ); - } - - - - static DocumentBuilderFactory dbf = null; - static DocumentBuilder db = null; - static Document d = null; - - /** - * <p>Evaluate the compiled XPath expression in the context of the - * specified <code>InputSource</code> and return the result as the - * specified type.</p> - * - * <p>This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(Object item, QName returnType)} on the resulting - * document object.</p> - * - * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> - * - * <p>If <code>returnType</code> is not one of the types defined in - * {@link XPathConstants}, - * then an <code>IllegalArgumentException</code> is thrown.</p> - * - *<p>If <code>source</code> or <code>returnType</code> is <code>null</code>, - * then a <code>NullPointerException</code> is thrown.</p> - * - * @param source The <code>InputSource</code> of the document to evaluate - * over. - * @param returnType The desired return type. - * - * @return The <code>Object</code> that is the result of evaluating the - * expression and converting the result to - * <code>returnType</code>. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If <code>returnType</code> is not one - * of the types defined in {@link XPathConstants}. - * @throws NullPointerException If <code>source</code> or - * <code>returnType</code> is <code>null</code>. - */ - public Object evaluate(InputSource source, QName returnType) - throws XPathExpressionException { - if ( ( source == null ) || ( returnType == null ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_SOURCE_RETURN_TYPE_CANNOT_BE_NULL, - null ); - throw new NullPointerException ( fmsg ); - } - // Checking if requested returnType is supported. returnType need to be - // defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } - try { - if ( dbf == null ) { - dbf = FactoryImpl.getDOMFactory(useServicesMechanism); - dbf.setNamespaceAware( true ); - dbf.setValidating( false ); - } - db = dbf.newDocumentBuilder(); - Document document = db.parse( source ); - return eval( document, returnType ); - } catch ( Exception e ) { - throw new XPathExpressionException ( e ); - } } - /** - * <p>Evaluate the compiled XPath expression in the context of the specified <code>InputSource</code> and return the result as a - * <code>String</code>.</p> - * - * <p>This method calls {@link #evaluate(InputSource source, QName returnType)} with a <code>returnType</code> of - * {@link XPathConstants#STRING}.</p> - * - * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> - * - * <p>If <code>source</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p> - * - * @param source The <code>InputSource</code> of the document to evaluate over. - * - * @return The <code>String</code> that is the result of evaluating the expression and converting the result to a - * <code>String</code>. - * - * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws NullPointerException If <code>source</code> is <code>null</code>. - */ + + @Override + public String evaluate(Object item) + throws XPathExpressionException { + return (String)this.evaluate(item, XPathConstants.STRING); + } + + @Override + public Object evaluate(InputSource source, QName returnType) + throws XPathExpressionException { + isSupported (returnType); + try { + Document document = getDocument(source); + return eval(document, returnType); + } catch (TransformerException e) { + throw new XPathExpressionException(e); + } + } + + @Override public String evaluate(InputSource source) throws XPathExpressionException { - return (String)this.evaluate( source, XPathConstants.STRING ); + return (String)this.evaluate(source, XPathConstants.STRING); } - private boolean isSupported( QName returnType ) { - // XPathConstants.STRING - if ( ( returnType.equals( XPathConstants.STRING ) ) || - ( returnType.equals( XPathConstants.NUMBER ) ) || - ( returnType.equals( XPathConstants.BOOLEAN ) ) || - ( returnType.equals( XPathConstants.NODE ) ) || - ( returnType.equals( XPathConstants.NODESET ) ) ) { + @Override + public <T>T evaluateExpression(Object item, Class<T> type) + throws XPathExpressionException { + isSupportedClassType(type); - return true; + try { + XObject resultObject = eval(item, xpath); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + return getXPathResult(resultObject, type); + } else { + return XPathResultImpl.getValue(resultObject, type); + } + + } catch (javax.xml.transform.TransformerException te) { + throw new XPathExpressionException(te); } - return false; - } - - private Object getResultAsType( XObject resultObject, QName returnType ) - throws javax.xml.transform.TransformerException { - // XPathConstants.STRING - if ( returnType.equals( XPathConstants.STRING ) ) { - return resultObject.str(); - } - // XPathConstants.NUMBER - if ( returnType.equals( XPathConstants.NUMBER ) ) { - return new Double ( resultObject.num()); - } - // XPathConstants.BOOLEAN - if ( returnType.equals( XPathConstants.BOOLEAN ) ) { - return new Boolean( resultObject.bool()); - } - // XPathConstants.NODESET ---ORdered, UNOrdered??? - if ( returnType.equals( XPathConstants.NODESET ) ) { - return resultObject.nodelist(); - } - // XPathConstants.NODE - if ( returnType.equals( XPathConstants.NODE ) ) { - NodeIterator ni = resultObject.nodeset(); - //Return the first node, or null - return ni.nextNode(); - } - // If isSupported check is already done then the execution path - // shouldn't come here. Being defensive - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString()}); - throw new IllegalArgumentException ( fmsg ); } + @Override + public XPathEvaluationResult<?> evaluateExpression(Object item) + throws XPathExpressionException { + return evaluateExpression(item, XPathEvaluationResult.class); + } + + @Override + public <T>T evaluateExpression(InputSource source, Class<T> type) + throws XPathExpressionException { + Document document = getDocument(source); + return evaluateExpression(document, type); + } + + @Override + public XPathEvaluationResult<?> evaluateExpression(InputSource source) + throws XPathExpressionException { + return evaluateExpression(source, XPathEvaluationResult.class); + } }
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java Tue Feb 03 16:46:05 2015 +0100 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java Wed Feb 04 18:23:09 2015 -0800 @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2004 The Apache Software Foundation. @@ -28,55 +27,37 @@ import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; import javax.xml.xpath.XPathExpression; - -import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xpath.internal.*; import com.sun.org.apache.xpath.internal.objects.XObject; -import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; -import com.sun.org.apache.xalan.internal.res.XSLMessages; -import com.sun.org.apache.xalan.internal.utils.FactoryImpl; import com.sun.org.apache.xalan.internal.utils.FeatureManager; - -import org.w3c.dom.Node; import org.w3c.dom.Document; -import org.w3c.dom.traversal.NodeIterator; - import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import javax.xml.parsers.*; - -import java.io.IOException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathEvaluationResult; /** * The XPathImpl class provides implementation for the methods defined in - * javax.xml.xpath.XPath interface. This provide simple access to the results + * javax.xml.xpath.XPath interface. This provides simple access to the results * of an XPath expression. * + * @author Ramesh Mandava * - * @author Ramesh Mandava + * Updated 12/04/2014: + * New methods: evaluateExpression + * Refactored to share code with XPathExpressionImpl. */ -public class XPathImpl implements javax.xml.xpath.XPath { +public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { // Private variables - private XPathVariableResolver variableResolver; - private XPathFunctionResolver functionResolver; private XPathVariableResolver origVariableResolver; private XPathFunctionResolver origFunctionResolver; private NamespaceContext namespaceContext=null; - private JAXPPrefixResolver prefixResolver; - // By default Extension Functions are allowed in XPath Expressions. If - // Secure Processing Feature is set on XPathFactory then the invocation of - // extensions function need to throw XPathFunctionException - private boolean featureSecureProcessing = false; - private boolean useServiceMechanism = true; - private final FeatureManager featureManager; - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr ) { + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr) { this(vr, fr, false, true, new FeatureManager()); } - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr, + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr, boolean featureSecureProcessing, boolean useServiceMechanism, FeatureManager featureManager) { this.origVariableResolver = this.variableResolver = vr; @@ -86,451 +67,173 @@ this.featureManager = featureManager; } - /** - * <p>Establishes a variable resolver.</p> - * - * @param resolver Variable Resolver - */ + + //-Override- public void setXPathVariableResolver(XPathVariableResolver resolver) { - if ( resolver == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPathVariableResolver"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(resolver, "XPathVariableResolver"); this.variableResolver = resolver; } - /** - * <p>Returns the current variable resolver.</p> - * - * @return Current variable resolver - */ + //-Override- public XPathVariableResolver getXPathVariableResolver() { return variableResolver; } - /** - * <p>Establishes a function resolver.</p> - * - * @param resolver XPath function resolver - */ + //-Override- public void setXPathFunctionResolver(XPathFunctionResolver resolver) { - if ( resolver == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPathFunctionResolver"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(resolver, "XPathFunctionResolver"); this.functionResolver = resolver; } - /** - * <p>Returns the current function resolver.</p> - * - * @return Current function resolver - */ + //-Override- public XPathFunctionResolver getXPathFunctionResolver() { return functionResolver; } - /** - * <p>Establishes a namespace context.</p> - * - * @param nsContext Namespace context to use - */ + //-Override- public void setNamespaceContext(NamespaceContext nsContext) { - if ( nsContext == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"NamespaceContext"} ); - throw new NullPointerException( fmsg ); - } + requireNonNull(nsContext, "NamespaceContext"); this.namespaceContext = nsContext; - this.prefixResolver = new JAXPPrefixResolver ( nsContext ); + this.prefixResolver = new JAXPPrefixResolver (nsContext); } - /** - * <p>Returns the current namespace context.</p> - * - * @return Current Namespace context - */ + //-Override- public NamespaceContext getNamespaceContext() { return namespaceContext; } - private static Document d = null; + /** + * Evaluate an {@code XPath} expression in the specified context. + * @param expression The XPath expression. + * @param contextItem The starting context. + * @return an XObject as the result of evaluating the expression + * @throws TransformerException if evaluating fails + */ + private XObject eval(String expression, Object contextItem) + throws TransformerException { + requireNonNull(expression, "XPath expression"); + com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath(expression, + null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT); - private DocumentBuilder getParser() { - try { - // we'd really like to cache those DocumentBuilders, but we can't because: - // 1. thread safety. parsers are not thread-safe, so at least - // we need one instance per a thread. - // 2. parsers are non-reentrant, so now we are looking at having a - // pool of parsers. - // 3. then the class loading issue. The look-up procedure of - // DocumentBuilderFactory.newInstance() depends on context class loader - // and system properties, which may change during the execution of JVM. - // - // so we really have to create a fresh DocumentBuilder every time we need one - // - KK - DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(useServiceMechanism); - dbf.setNamespaceAware( true ); - dbf.setValidating( false ); - return dbf.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - // this should never happen with a well-behaving JAXP implementation. - throw new Error(e); - } + return eval(contextItem, xpath); } - - private XObject eval(String expression, Object contextItem) - throws javax.xml.transform.TransformerException { - com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath( expression, - null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); - com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null; - if ( functionResolver != null ) { - JAXPExtensionsProvider jep = new JAXPExtensionsProvider( - functionResolver, featureSecureProcessing, featureManager ); - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext( jep ); - } else { - xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); - } - - XObject xobj = null; - - xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); - - // If item is null, then we will create a a Dummy contextNode - if ( contextItem instanceof Node ) { - xobj = xpath.execute (xpathSupport, (Node)contextItem, - prefixResolver ); - } else { - xobj = xpath.execute ( xpathSupport, DTM.NULL, prefixResolver ); - } - - return xobj; - } - - /** - * <p>Evaluate an <code>XPath</code> expression in the specified context and return the result as the specified type.</p> - * - * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and <code>QName</code> resolution and return type conversion.</p> - * - * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants} ( - * {@link XPathConstants#NUMBER NUMBER}, - * {@link XPathConstants#STRING STRING}, - * {@link XPathConstants#BOOLEAN BOOLEAN}, - * {@link XPathConstants#NODE NODE} or - * {@link XPathConstants#NODESET NODESET}) - * then an <code>IllegalArgumentException</code> is thrown.</p> - * - * <p>If a <code>null</code> value is provided for - * <code>item</code>, an empty document will be used for the - * context. - * If <code>expression</code> or <code>returnType</code> is <code>null</code>, then a - * <code>NullPointerException</code> is thrown.</p> - * - * @param expression The XPath expression. - * @param item The starting context (node or node list, for example). - * @param returnType The desired return type. - * - * @return Result of evaluating an XPath expression as an <code>Object</code> of <code>returnType</code>. - * - * @throws XPathExpressionException If <code>expression</code> cannot be evaluated. - * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If <code>expression</code> or <code>returnType</code> is <code>null</code>. - */ + //-Override- public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException { - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } - if ( returnType == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException ( fmsg ); - } - // Checking if requested returnType is supported. returnType need to - // be defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + //this check is necessary before calling eval to maintain binary compatibility + requireNonNull(expression, "XPath expression"); + isSupported(returnType); try { - XObject resultObject = eval( expression, item ); - return getResultAsType( resultObject, returnType ); - } catch ( java.lang.NullPointerException npe ) { + XObject resultObject = eval(expression, item); + return getResultAsType(resultObject, returnType); + } catch (java.lang.NullPointerException npe) { // If VariableResolver returns null Or if we get // NullPointerException at this stage for some other reason // then we have to reurn XPathException - throw new XPathExpressionException ( npe ); - } catch ( javax.xml.transform.TransformerException te ) { + throw new XPathExpressionException (npe); + } catch (TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { // For any other exceptions we need to throw - // XPathExpressionException ( as per spec ) - throw new XPathExpressionException ( te ); + // XPathExpressionException (as per spec) + throw new XPathExpressionException (te); } } } - private boolean isSupported( QName returnType ) { - if ( ( returnType.equals( XPathConstants.STRING ) ) || - ( returnType.equals( XPathConstants.NUMBER ) ) || - ( returnType.equals( XPathConstants.BOOLEAN ) ) || - ( returnType.equals( XPathConstants.NODE ) ) || - ( returnType.equals( XPathConstants.NODESET ) ) ) { - - return true; - } - return false; - } - - private Object getResultAsType( XObject resultObject, QName returnType ) - throws javax.xml.transform.TransformerException { - // XPathConstants.STRING - if ( returnType.equals( XPathConstants.STRING ) ) { - return resultObject.str(); - } - // XPathConstants.NUMBER - if ( returnType.equals( XPathConstants.NUMBER ) ) { - return new Double ( resultObject.num()); - } - // XPathConstants.BOOLEAN - if ( returnType.equals( XPathConstants.BOOLEAN ) ) { - return new Boolean( resultObject.bool()); - } - // XPathConstants.NODESET ---ORdered, UNOrdered??? - if ( returnType.equals( XPathConstants.NODESET ) ) { - return resultObject.nodelist(); - } - // XPathConstants.NODE - if ( returnType.equals( XPathConstants.NODE ) ) { - NodeIterator ni = resultObject.nodeset(); - //Return the first node, or null - return ni.nextNode(); - } - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString()}); - throw new IllegalArgumentException( fmsg ); + //-Override- + public String evaluate(String expression, Object item) + throws XPathExpressionException { + return (String)this.evaluate(expression, item, XPathConstants.STRING); } - - - /** - * <p>Evaluate an XPath expression in the specified context and return the result as a <code>String</code>.</p> - * - * <p>This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a <code>returnType</code> of - * {@link XPathConstants#STRING}.</p> - * - * <p>See "Evaluation of XPath Expressions" of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> - * - * <p>If a <code>null</code> value is provided for - * <code>item</code>, an empty document will be used for the - * context. - * If <code>expression</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p> - * - * @param expression The XPath expression. - * @param item The starting context (node or node list, for example). - * - * @return The <code>String</code> that is the result of evaluating the expression and - * converting the result to a <code>String</code>. - * - * @throws XPathExpressionException If <code>expression</code> cannot be evaluated. - * @throws NullPointerException If <code>expression</code> is <code>null</code>. - */ - public String evaluate(String expression, Object item) - throws XPathExpressionException { - return (String)this.evaluate( expression, item, XPathConstants.STRING ); - } - - /** - * <p>Compile an XPath expression for later evaluation.</p> - * - * <p>If <code>expression</code> contains any {@link XPathFunction}s, - * they must be available via the {@link XPathFunctionResolver}. - * An {@link XPathExpressionException} will be thrown if the <code>XPathFunction</code> - * cannot be resovled with the <code>XPathFunctionResolver</code>.</p> - * - * <p>If <code>expression</code> is <code>null</code>, a <code>NullPointerException</code> is thrown.</p> - * - * @param expression The XPath expression. - * - * @return Compiled XPath expression. - - * @throws XPathExpressionException If <code>expression</code> cannot be compiled. - * @throws NullPointerException If <code>expression</code> is <code>null</code>. - */ + //-Override- public XPathExpression compile(String expression) throws XPathExpressionException { - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } + requireNonNull(expression, "XPath expression"); try { com.sun.org.apache.xpath.internal.XPath xpath = new XPath (expression, null, - prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); + prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT); // Can have errorListener XPathExpressionImpl ximpl = new XPathExpressionImpl (xpath, prefixResolver, functionResolver, variableResolver, - featureSecureProcessing, useServiceMechanism, featureManager ); + featureSecureProcessing, useServiceMechanism, featureManager); return ximpl; - } catch ( javax.xml.transform.TransformerException te ) { - throw new XPathExpressionException ( te ) ; + } catch (TransformerException te) { + throw new XPathExpressionException (te) ; } } - - /** - * <p>Evaluate an XPath expression in the context of the specified <code>InputSource</code> - * and return the result as the specified type.</p> - * - * <p>This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object.</p> - * - * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> - * - * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants}, - * then an <code>IllegalArgumentException</code> is thrown.</p> - * - * <p>If <code>expression</code>, <code>source</code> or <code>returnType</code> is <code>null</code>, - * then a <code>NullPointerException</code> is thrown.</p> - * - * @param expression The XPath expression. - * @param source The input source of the document to evaluate over. - * @param returnType The desired return type. - * - * @return The <code>Object</code> that encapsulates the result of evaluating the expression. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If <code>expression</code>, <code>source</code> or <code>returnType</code> - * is <code>null</code>. - */ + //-Override- public Object evaluate(String expression, InputSource source, QName returnType) throws XPathExpressionException { - // Checking validity of different parameters - if( source== null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"source"} ); - throw new NullPointerException ( fmsg ); - } - if ( expression == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"XPath expression"} ); - throw new NullPointerException ( fmsg ); - } - if ( returnType == null ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, - new Object[] {"returnType"} ); - throw new NullPointerException ( fmsg ); - } - - //Checking if requested returnType is supported. - //returnType need to be defined in XPathConstants - if ( !isSupported ( returnType ) ) { - String fmsg = XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, - new Object[] { returnType.toString() } ); - throw new IllegalArgumentException ( fmsg ); - } + isSupported(returnType); try { - - Document document = getParser().parse( source ); - - XObject resultObject = eval( expression, document ); - return getResultAsType( resultObject, returnType ); - } catch ( SAXException e ) { - throw new XPathExpressionException ( e ); - } catch( IOException e ) { - throw new XPathExpressionException ( e ); - } catch ( javax.xml.transform.TransformerException te ) { + Document document = getDocument(source); + XObject resultObject = eval(expression, document); + return getResultAsType(resultObject, returnType); + } catch (TransformerException te) { Throwable nestedException = te.getException(); - if ( nestedException instanceof javax.xml.xpath.XPathFunctionException ) { + if (nestedException instanceof javax.xml.xpath.XPathFunctionException) { throw (javax.xml.xpath.XPathFunctionException)nestedException; } else { - throw new XPathExpressionException ( te ); + throw new XPathExpressionException (te); } } - } - - - - /** - * <p>Evaluate an XPath expression in the context of the specified <code>InputSource</code> - * and return the result as a <code>String</code>.</p> - * - * <p>This method calls {@link #evaluate(String expression, InputSource source, QName returnType)} with a - * <code>returnType</code> of {@link XPathConstants#STRING}.</p> - * - * <p>See "Evaluation of XPath Expressions" section of JAXP 1.3 spec - * for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> - * - * <p>If <code>expression</code> or <code>source</code> is <code>null</code>, - * then a <code>NullPointerException</code> is thrown.</p> - * - * @param expression The XPath expression. - * @param source The <code>InputSource</code> of the document to evaluate over. - * - * @return The <code>String</code> that is the result of evaluating the expression and - * converting the result to a <code>String</code>. - * - * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If <code>expression</code> or <code>source</code> is <code>null</code>. - */ + //-Override- public String evaluate(String expression, InputSource source) throws XPathExpressionException { - return (String)this.evaluate( expression, source, XPathConstants.STRING ); + return (String)this.evaluate(expression, source, XPathConstants.STRING); } - /** - * <p>Reset this <code>XPath</code> to its original configuration.</p> - * - * <p><code>XPath</code> is reset to the same state as when it was created with - * {@link XPathFactory#newXPath()}. - * <code>reset()</code> is designed to allow the reuse of existing <code>XPath</code>s - * thus saving resources associated with the creation of new <code>XPath</code>s.</p> - * - * <p>The reset <code>XPath</code> is not guaranteed to have the same - * {@link XPathFunctionResolver}, {@link XPathVariableResolver} - * or {@link NamespaceContext} <code>Object</code>s, e.g. {@link Object#equals(Object obj)}. - * It is guaranteed to have a functionally equal <code>XPathFunctionResolver</code>, - * <code>XPathVariableResolver</code> - * and <code>NamespaceContext</code>.</p> - */ + //-Override- public void reset() { this.variableResolver = this.origVariableResolver; this.functionResolver = this.origFunctionResolver; this.namespaceContext = null; } + //-Override- + public <T> T evaluateExpression(String expression, Object item, Class<T> type) + throws XPathExpressionException { + isSupportedClassType(type); + try { + XObject resultObject = eval(expression, item); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + return getXPathResult(resultObject, type); + } else { + return XPathResultImpl.getValue(resultObject, type); + } + } catch (TransformerException te) { + throw new XPathExpressionException (te); + } + } + + //-Override- + public XPathEvaluationResult<?> evaluateExpression(String expression, Object item) + throws XPathExpressionException { + return evaluateExpression(expression, item, XPathEvaluationResult.class); + } + + //-Override- + public <T> T evaluateExpression(String expression, InputSource source, Class<T> type) + throws XPathExpressionException { + Document document = getDocument(source); + return evaluateExpression(expression, document, type); + } + + //-Override- + public XPathEvaluationResult<?> evaluateExpression(String expression, InputSource source) + throws XPathExpressionException { + return evaluateExpression(expression, source, XPathEvaluationResult.class); + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 com.sun.org.apache.xpath.internal.jaxp; + +import com.sun.org.apache.xalan.internal.res.XSLMessages; +import com.sun.org.apache.xalan.internal.utils.FactoryImpl; +import com.sun.org.apache.xalan.internal.utils.FeatureManager; +import com.sun.org.apache.xml.internal.dtm.DTM; +import com.sun.org.apache.xpath.internal.objects.XObject; +import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; +import java.io.IOException; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathEvaluationResult; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFunctionResolver; +import javax.xml.xpath.XPathNodes; +import javax.xml.xpath.XPathVariableResolver; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeIterator; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * This class contains several utility methods used by XPathImpl and + * XPathExpressionImpl + */ +class XPathImplUtil { + XPathFunctionResolver functionResolver; + XPathVariableResolver variableResolver; + JAXPPrefixResolver prefixResolver; + boolean useServiceMechanism = true; + // By default Extension Functions are allowed in XPath Expressions. If + // Secure Processing Feature is set on XPathFactory then the invocation of + // extensions function need to throw XPathFunctionException + boolean featureSecureProcessing = false; + FeatureManager featureManager; + + /** + * Evaluate an XPath context using the internal XPath engine + * @param contextItem The XPath context + * @param xpath The internal XPath engine + * @return an XObject + * @throws javax.xml.transform.TransformerException If the expression cannot be evaluated. + */ + XObject eval(Object contextItem, com.sun.org.apache.xpath.internal.XPath xpath) + throws javax.xml.transform.TransformerException { + com.sun.org.apache.xpath.internal.XPathContext xpathSupport; + if (functionResolver != null) { + JAXPExtensionsProvider jep = new JAXPExtensionsProvider( + functionResolver, featureSecureProcessing, featureManager); + xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(jep); + } else { + xpathSupport = new com.sun.org.apache.xpath.internal.XPathContext(); + } + + xpathSupport.setVarStack(new JAXPVariableStack(variableResolver)); + XObject xobj; + + Node contextNode = (Node)contextItem; + // We always need to have a ContextNode with Xalan XPath implementation + // To allow simple expression evaluation like 1+1 we are setting + // dummy Document as Context Node + if (contextNode == null) { + xobj = xpath.execute(xpathSupport, DTM.NULL, prefixResolver); + } else { + xobj = xpath.execute(xpathSupport, contextNode, prefixResolver); + } + + return xobj; + } + + /** + * Parse the input source and return a Document. + * @param source The {@code InputSource} of the document + * @return a DOM Document + * @throws XPathExpressionException if there is an error parsing the source. + */ + Document getDocument(InputSource source) + throws XPathExpressionException { + requireNonNull(source, "Source"); + try { + // we'd really like to cache those DocumentBuilders, but we can't because: + // 1. thread safety. parsers are not thread-safe, so at least + // we need one instance per a thread. + // 2. parsers are non-reentrant, so now we are looking at having a + // pool of parsers. + // 3. then the class loading issue. The look-up procedure of + // DocumentBuilderFactory.newInstance() depends on context class loader + // and system properties, which may change during the execution of JVM. + // + // so we really have to create a fresh DocumentBuilder every time we need one + // - KK + DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(useServiceMechanism); + dbf.setNamespaceAware(true); + dbf.setValidating(false); + return dbf.newDocumentBuilder().parse(source); + } catch (ParserConfigurationException | SAXException | IOException e) { + throw new XPathExpressionException (e); + } + } + + /** + * Get result depending on the QName type defined in XPathConstants + * @param resultObject the result of an evaluation + * @param returnType the return type + * @return result per the return type + * @throws TransformerException if the result can not be converted to + * the specified return type. + */ + Object getResultAsType(XObject resultObject, QName returnType) + throws TransformerException { + // XPathConstants.STRING + if (returnType.equals(XPathConstants.STRING)) { + return resultObject.str(); + } + // XPathConstants.NUMBER + if (returnType.equals(XPathConstants.NUMBER)) { + return resultObject.num(); + } + // XPathConstants.BOOLEAN + if (returnType.equals(XPathConstants.BOOLEAN)) { + return resultObject.bool(); + } + // XPathConstants.NODESET ---ORdered, UNOrdered??? + if (returnType.equals(XPathConstants.NODESET)) { + return resultObject.nodelist(); + } + // XPathConstants.NODE + if (returnType.equals(XPathConstants.NODE)) { + NodeIterator ni = resultObject.nodeset(); + //Return the first node, or null + return ni.nextNode(); + } + // If isSupported check is already done then the execution path + // shouldn't come here. Being defensive + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, + new Object[] { returnType.toString()}); + throw new IllegalArgumentException (fmsg); + } + + /** + * Construct an XPathExpressionResult object based on the result of the + * evaluation and cast to the specified class type. + * @param <T> The class type + * @param resultObject the result of an evaluation + * @param type The class type expected to be returned by the XPath expression. + * @return an instance of the specified type or null if the XObject returned + * an UNKNOWN object type. + * @throws TransformerException if there is an error converting the result + * to the specified type. It's unlikely to happen. This is mostly needed + * by the internal XPath engine. + */ + <T> T getXPathResult(XObject resultObject, Class<T> type) + throws TransformerException { + int resultType = resultObject.getType(); + + switch (resultType) { + case XObject.CLASS_BOOLEAN : + return type.cast(new XPathResultImpl<>(resultObject, Boolean.class)); + case XObject.CLASS_NUMBER : + return type.cast(new XPathResultImpl<>(resultObject, Double.class)); + case XObject.CLASS_STRING : + return type.cast(new XPathResultImpl<>(resultObject, String.class)); + case XObject.CLASS_NODESET : + return type.cast(new XPathResultImpl<>(resultObject, XPathNodes.class)); + case XObject.CLASS_RTREEFRAG : //NODE + return type.cast(new XPathResultImpl<>(resultObject, Node.class)); + } + + return null; + } + + /** + * Check whether or not the specified type is supported + * @param <T> The class type + * @param type The type to be checked + * @throws IllegalArgumentException if the type is not supported + */ + <T> void isSupportedClassType(Class<T> type) { + requireNonNull(type, "The class type"); + if (type.isAssignableFrom(Boolean.class) || + type.isAssignableFrom(Double.class) || + type.isAssignableFrom(Integer.class) || + type.isAssignableFrom(Long.class) || + type.isAssignableFrom(String.class) || + type.isAssignableFrom(XPathNodes.class) || + type.isAssignableFrom(Node.class) || + type.isAssignableFrom(XPathEvaluationResult.class)) { + return; + } + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, + new Object[] { type.toString() }); + throw new IllegalArgumentException (fmsg); + } + + /** + * Check if the requested returnType is supported. + * @param returnType the return type + * @throws IllegalArgumentException if the return type is not supported + */ + void isSupported(QName returnType) { + requireNonNull(returnType, "returnType"); + if (returnType.equals(XPathConstants.STRING) || + returnType.equals(XPathConstants.NUMBER) || + returnType.equals(XPathConstants.BOOLEAN) || + returnType.equals(XPathConstants.NODE) || + returnType.equals(XPathConstants.NODESET)) { + return; + } + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_UNSUPPORTED_RETURN_TYPE, + new Object[] { returnType.toString() }); + throw new IllegalArgumentException (fmsg); + } + + /** + * Checks that the specified parameter is not {@code null}. + * + * @param <T> the type of the reference + * @param param the parameter to check for nullity + * @param paramName the parameter name + * @throws NullPointerException if {@code param} is {@code null} + */ + <T> void requireNonNull(T param, String paramName) { + if (param == null) { + String fmsg = XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_ARG_CANNOT_BE_NULL, + new Object[] {paramName}); + throw new NullPointerException (fmsg); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 com.sun.org.apache.xpath.internal.jaxp; + +import java.util.Iterator; +import javax.xml.xpath.XPathException; +import javax.xml.xpath.XPathNodes; +import javax.xml.xpath.XPathEvaluationResult.XPathResultType; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * This class implements XPathNodes that represents a set of nodes selected by + * evaluating an expression. + */ +public class XPathNodesImpl implements XPathNodes { + Class<Node> elementType; + NodeList nodeList = null; + + public XPathNodesImpl(NodeList nodeList, Class<Node> elementType) { + this.nodeList = nodeList; + this.elementType = elementType; + } + + @Override + public Iterator<Node> iterator() { + return new NodeSetIterator<>(elementType); + } + + class NodeSetIterator<E> implements Iterator<E> { + int currentIndex; + Class<E> elementType; + NodeSetIterator(Class<E> elementType) { + this.elementType = elementType; + } + public boolean hasNext() { + if (nodeList != null) { + return currentIndex < nodeList.getLength(); + } + + return false; + } + + public E next() { + if (nodeList != null && nodeList.getLength() > 0) { + return elementType.cast(nodeList.item(currentIndex++)); + } + return null; + } + } + + @Override + public int size() { + if (nodeList != null) { + return nodeList.getLength(); + } + return 0; + } + + @Override + public Node get(int index) throws XPathException { + if (index <0 || index >= size()) { + throw new IndexOutOfBoundsException("Index " + index + " is out of bounds"); + } + if (nodeList != null) { + return nodeList.item(index); + } + return null; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathResultImpl.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 com.sun.org.apache.xpath.internal.jaxp; + +import com.sun.org.apache.xpath.internal.objects.XObject; +import java.util.Objects; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathNodes; +import javax.xml.xpath.XPathEvaluationResult; +import javax.xml.xpath.XPathEvaluationResult.XPathResultType; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.traversal.NodeIterator; + + +/** + * This is the implementation of XPathEvaluationResult that represents the + * result of the evaluation of an XPath expression within the context of a + * particular node. + */ +class XPathResultImpl<T> implements XPathEvaluationResult<T> { + + XObject resultObject; + int resultType; + Class<T> type; + XPathResultType mapToType; + NodeList nodeList = null; + int currentIndex; + Node currentNode; + + boolean boolValue = false; + Node node = null; + double numValue; + String strValue; + + /** + * Construct an XPathEvaluationResult object. + * + * @param resultObject internal XPath result object + * @param type class type + * @throws TransformerException if there is an error reading the XPath + * result. + */ + public XPathResultImpl(XObject resultObject, Class<T> type) + throws TransformerException { + this.resultObject = resultObject; + resultType = resultObject.getType(); + this.type = type; + getResult(resultObject); + } + + /** + * Return the result type as an enum specified by {@code XPathResultType} + * @return the result type + */ + @Override + public XPathResultType type() { + return mapToType; + } + + /** + * Returns the value of the result as the type <T> specified for the class. + * + * @return The value of the result. + */ + @Override + public T value() { + Objects.requireNonNull(type); + try { + return getValue(resultObject, type); + } catch (TransformerException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Read the XObject and set values in accordance with the result type + * @param resultObject internal XPath result object + * @throws TransformerException if there is an error reading the XPath + * result. + */ + private void getResult(XObject resultObject) throws TransformerException { + switch (resultType) { + case XObject.CLASS_BOOLEAN: + boolValue = resultObject.bool(); + mapToType = XPathResultType.BOOLEAN; + break; + case XObject.CLASS_NUMBER: + numValue = resultObject.num(); + mapToType = XPathResultType.NUMBER; + break; + case XObject.CLASS_STRING: + strValue = resultObject.str(); + mapToType = XPathResultType.STRING; + break; + case XObject.CLASS_NODESET: + mapToType = XPathResultType.NODESET; + nodeList = resultObject.nodelist(); + break; + case XObject.CLASS_RTREEFRAG: //NODE + mapToType = XPathResultType.NODE; + NodeIterator ni = resultObject.nodeset(); + //Return the first node, or null + node = ni.nextNode(); + break; + } + } + + /** + * Read the internal result object and return the value in accordance with + * the type specified. + * + * @param <T> The expected class type. + * @param resultObject internal XPath result object + * @param type the class type + * @return The value of the result, null in case of unexpected type. + * @throws TransformerException if there is an error reading the XPath + * result. + */ + static <T> T getValue(XObject resultObject, Class<T> type) throws TransformerException { + Objects.requireNonNull(type); + if (type.isAssignableFrom(XPathEvaluationResult.class)) { + return type.cast(new XPathResultImpl<T>(resultObject, type)); + } + int resultType = classToInternalType(type); + switch (resultType) { + case XObject.CLASS_BOOLEAN: + return type.cast(resultObject.bool()); + case XObject.CLASS_NUMBER: + if (Double.class.isAssignableFrom(type)) { + return type.cast(resultObject.num()); + } else if (Integer.class.isAssignableFrom(type)) { + return type.cast((int)resultObject.num()); + } else if (Long.class.isAssignableFrom(type)) { + return type.cast((long)resultObject.num()); + } + /* + This is to suppress warnings. By the current specification, + among numeric types, only Double, Integer and Long are supported. + */ + break; + case XObject.CLASS_STRING: + return type.cast(resultObject.str()); + case XObject.CLASS_NODESET: + XPathNodes nodeSet = new XPathNodesImpl(resultObject.nodelist(), + Node.class); + return type.cast(nodeSet); + case XObject.CLASS_RTREEFRAG: //NODE + NodeIterator ni = resultObject.nodeset(); + //Return the first node, or null + return type.cast(ni.nextNode()); + } + + return null; + } + + /** + * Map the specified class type to the internal result type + * + * @param <T> The expected class type. + * @param type the class type + * @return the internal XObject type. + */ + static <T> int classToInternalType(Class<T> type) { + if (type.isAssignableFrom(Boolean.class)) { + return XObject.CLASS_BOOLEAN; + } else if (Number.class.isAssignableFrom(type)) { + return XObject.CLASS_NUMBER; + } else if (type.isAssignableFrom(String.class)) { + return XObject.CLASS_STRING; + } else if (type.isAssignableFrom(XPathNodes.class)) { + return XObject.CLASS_NODESET; + } else if (type.isAssignableFrom(Node.class)) { + return XObject.CLASS_RTREEFRAG; + } + return XObject.CLASS_NULL; + } +}
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java Tue Feb 03 16:46:05 2015 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,12 @@ package javax.xml.xpath; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; import org.xml.sax.InputSource; -import javax.xml.namespace.QName; -import javax.xml.namespace.NamespaceContext; /** - * <p><code>XPath</code> provides access to the XPath evaluation environment and expressions.</p> + * {@code XPath} provides access to the XPath evaluation environment and expressions. * * <a name="XPath-evaluation"/> * <table border="1" cellpadding="2"> @@ -39,7 +39,6 @@ * <th colspan="2">Evaluation of XPath Expressions.</th> * </tr> * </thead> - * <tbody> * <tr> * <td>context</td> * <td> @@ -55,8 +54,8 @@ * If the expression contains a variable reference, its value will be found through the {@link XPathVariableResolver} * set with {@link #setXPathVariableResolver(XPathVariableResolver resolver)}. * An {@link XPathExpressionException} is raised if the variable resolver is undefined or - * the resolver returns <code>null</code> for the variable. - * The value of a variable must be immutable through the course of any single evaluation.</p> + * the resolver returns {@code null} for the variable. + * The value of a variable must be immutable through the course of any single evaluation. * </td> * </tr> * <tr> @@ -65,7 +64,7 @@ * If the expression contains a function reference, the function will be found through the {@link XPathFunctionResolver} * set with {@link #setXPathFunctionResolver(XPathFunctionResolver resolver)}. * An {@link XPathExpressionException} is raised if the function resolver is undefined or - * the function resolver returns <code>null</code> for the function.</p> + * the function resolver returns {@code null} for the function. * </td> * </tr> * <tr> @@ -80,7 +79,7 @@ * <td> * This result of evaluating an expression is converted to an instance of the desired return type. * Valid return types are defined in {@link XPathConstants}. - * Conversion to the return type follows XPath conversion rules.</p> + * Conversion to the return type follows XPath conversion rules. * </td> * </tr> * </table> @@ -88,9 +87,9 @@ * <p>An XPath object is not thread-safe and not reentrant. * In other words, it is the application's responsibility to make * sure that one {@link XPath} object is not used from - * more than one thread at any given time, and while the <code>evaluate</code> + * more than one thread at any given time, and while the {@code evaluate} * method is invoked, applications may not recursively call - * the <code>evaluate</code> method. + * the {@code evaluate} method. * <p> * * @author <a href="Norman.Walsh@Sun.com">Norman Walsh</a> @@ -100,191 +99,189 @@ */ public interface XPath { - /** - * <p>Reset this <code>XPath</code> to its original configuration.</p> - * - * <p><code>XPath</code> is reset to the same state as when it was created with - * {@link XPathFactory#newXPath()}. - * <code>reset()</code> is designed to allow the reuse of existing <code>XPath</code>s - * thus saving resources associated with the creation of new <code>XPath</code>s.</p> - * - * <p>The reset <code>XPath</code> is not guaranteed to have the same {@link XPathFunctionResolver}, {@link XPathVariableResolver} - * or {@link NamespaceContext} <code>Object</code>s, e.g. {@link Object#equals(Object obj)}. - * It is guaranteed to have a functionally equal <code>XPathFunctionResolver</code>, <code>XPathVariableResolver</code> - * and <code>NamespaceContext</code>.</p> - */ - public void reset(); /** - * <p>Establish a variable resolver.</p> + * Reset this {@code XPath} to its original configuration. * - * <p>A <code>NullPointerException</code> is thrown if <code>resolver</code> is <code>null</code>.</p> + * <p>{@code XPath} is reset to the same state as when it was created with + * {@link XPathFactory#newXPath()}. + * {@code reset()} is designed to allow the reuse of existing {@code XPath}s + * thus saving resources associated with the creation of new {@code XPath}s. + * + * <p>The reset {@code XPath} is not guaranteed to have the same + * {@link XPathFunctionResolver}, {@link XPathVariableResolver} + * or {@link NamespaceContext} {@code Object}s, e.g. {@link Object#equals(Object obj)}. + * It is guaranteed to have a functionally equal {@code XPathFunctionResolver}, + * {@code XPathVariableResolver} and {@code NamespaceContext}. + */ + public void reset(); + + /** + * Establish a variable resolver. + * + * <p>A {@code NullPointerException} is thrown if {@code resolver} is {@code null}. * * @param resolver Variable resolver. * - * @throws NullPointerException If <code>resolver</code> is <code>null</code>. + * @throws NullPointerException If {@code resolver} is {@code null}. */ public void setXPathVariableResolver(XPathVariableResolver resolver); /** - * <p>Return the current variable resolver.</p> + * Return the current variable resolver. * - * <p><code>null</code> is returned in no variable resolver is in effect.</p> + * <p>{@code null} is returned in no variable resolver is in effect. * * @return Current variable resolver. */ public XPathVariableResolver getXPathVariableResolver(); /** - * <p>Establish a function resolver.</p> + * Establish a function resolver. * - * <p>A <code>NullPointerException</code> is thrown if <code>resolver</code> is <code>null</code>.</p> + * <p>A {@code NullPointerException} is thrown if {@code resolver} is {@code null}. * * @param resolver XPath function resolver. * - * @throws NullPointerException If <code>resolver</code> is <code>null</code>. + * @throws NullPointerException If {@code resolver} is {@code null}. */ public void setXPathFunctionResolver(XPathFunctionResolver resolver); /** - * <p>Return the current function resolver.</p> - * - * <p><code>null</code> is returned in no function resolver is in effect.</p> + * Return the current function resolver. + * <p> + * {@code null} is returned in no function resolver is in effect. * * @return Current function resolver. */ public XPathFunctionResolver getXPathFunctionResolver(); /** - * <p>Establish a namespace context.</p> + * Establish a namespace context. * - * <p>A <code>NullPointerException</code> is thrown if <code>nsContext</code> is <code>null</code>.</p> + * <p>A {@code NullPointerException} is thrown if {@code nsContext} is {@code null}. * * @param nsContext Namespace context to use. * - * @throws NullPointerException If <code>nsContext</code> is <code>null</code>. + * @throws NullPointerException If {@code nsContext} is {@code null}. */ public void setNamespaceContext(NamespaceContext nsContext); /** - * <p>Return the current namespace context.</p> + * Return the current namespace context. * - * <p><code>null</code> is returned in no namespace context is in effect.</p> + * <p>{@code null} is returned in no namespace context is in effect. * * @return Current Namespace context. */ public NamespaceContext getNamespaceContext(); /** - * <p>Compile an XPath expression for later evaluation.</p> + * Compile an XPath expression for later evaluation. * - * <p>If <code>expression</code> contains any {@link XPathFunction}s, + * <p>If {@code expression} contains any {@link XPathFunction}s, * they must be available via the {@link XPathFunctionResolver}. * An {@link XPathExpressionException} will be thrown if the - * <code>XPathFunction</code> - * cannot be resovled with the <code>XPathFunctionResolver</code>.</p> + * {@code XPathFunction} + * cannot be resovled with the {@code XPathFunctionResolver}. * - * <p>If <code>expression</code> contains any variables, the + * <p>If {@code expression} contains any variables, the * {@link XPathVariableResolver} in effect - * <strong>at compile time</strong> will be used to resolve them.</p> - * - * <p>If <code>expression</code> is <code>null</code>, a <code>NullPointerException</code> is thrown.</p> + * <strong>at compile time</strong> will be used to resolve them. * * @param expression The XPath expression. * * @return Compiled XPath expression. - * @throws XPathExpressionException If <code>expression</code> cannot be compiled. - * @throws NullPointerException If <code>expression</code> is <code>null</code>. + * @throws XPathExpressionException If {@code expression} cannot be compiled. + * @throws NullPointerException If {@code expression} is {@code null}. */ public XPathExpression compile(String expression) throws XPathExpressionException; /** - * <p>Evaluate an <code>XPath</code> expression in the specified context and return the result as the specified type.</p> + * Evaluate an {@code XPath} expression in the specified context and + * return the result as the specified type. * - * <p>See <a href="#XPath-evaluation">Evaluation of XPath Expressions</a> for context item evaluation, - * variable, function and <code>QName</code> resolution and return type conversion.</p> + * <p> + * See <a href="#XPath-evaluation">Evaluation of XPath Expressions</a> + * for context item evaluation, variable, function and {@code QName} resolution + * and return type conversion. + * <p> + * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * - * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants} ( + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @param expression The XPath expression. + * @param item The context the XPath expression will be evaluated in. + * @param returnType The result type expected to be returned by the XPath expression. + * + * @return The result of evaluating an XPath expression as an {@code Object} of {@code returnType}. + * + * @throws XPathExpressionException If {@code expression} cannot be evaluated. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants} ( * {@link XPathConstants#NUMBER NUMBER}, * {@link XPathConstants#STRING STRING}, * {@link XPathConstants#BOOLEAN BOOLEAN}, * {@link XPathConstants#NODE NODE} or - * {@link XPathConstants#NODESET NODESET}) - * then an <code>IllegalArgumentException</code> is thrown.</p> - * - * <p>If a <code>null</code> value is provided for - * <code>item</code>, an empty document will be used for the - * context. - * If <code>expression</code> or <code>returnType</code> is <code>null</code>, then a - * <code>NullPointerException</code> is thrown.</p> - * - * @param expression The XPath expression. - * @param item The starting context (a node, for example). - * @param returnType The desired return type. - * - * @return Result of evaluating an XPath expression as an <code>Object</code> of <code>returnType</code>. - * - * @throws XPathExpressionException If <code>expression</code> cannot be evaluated. - * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If <code>expression</code> or <code>returnType</code> is <code>null</code>. + * {@link XPathConstants#NODESET NODESET}). + * @throws NullPointerException If {@code expression or returnType} is {@code null}. */ public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException; /** - * <p>Evaluate an XPath expression in the specified context and return the result as a <code>String</code>.</p> + * Evaluate an XPath expression in the specified context and return the result as a {@code String}. * - * <p>This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a <code>returnType</code> of - * {@link XPathConstants#STRING}.</p> + * <p>This method calls {@link #evaluate(String expression, Object item, QName returnType)} with a {@code returnType} of + * {@link XPathConstants#STRING}. * * <p>See <a href="#XPath-evaluation">Evaluation of XPath Expressions</a> for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> + * variable, function and QName resolution and return type conversion. * - * <p>If a <code>null</code> value is provided for - * <code>item</code>, an empty document will be used for the - * context. - * If <code>expression</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p> + * <p> + * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. * * @param expression The XPath expression. - * @param item The starting context (a node, for example). + * @param item The context the XPath expression will be evaluated in. * - * @return The <code>String</code> that is the result of evaluating the expression and - * converting the result to a <code>String</code>. + * @return The result of evaluating an XPath expression as a {@code String}. * - * @throws XPathExpressionException If <code>expression</code> cannot be evaluated. - * @throws NullPointerException If <code>expression</code> is <code>null</code>. + * @throws XPathExpressionException If {@code expression} cannot be evaluated. + * @throws NullPointerException If {@code expression} is {@code null}. */ public String evaluate(String expression, Object item) throws XPathExpressionException; /** - * <p>Evaluate an XPath expression in the context of the specified <code>InputSource</code> - * and return the result as the specified type.</p> + * Evaluate an XPath expression in the context of the specified {@code InputSource} + * and return the result as the specified type. * * <p>This method builds a data model for the {@link InputSource} and calls - * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object.</p> + * {@link #evaluate(String expression, Object item, QName returnType)} on the resulting document object. * * <p>See <a href="#XPath-evaluation">Evaluation of XPath Expressions</a> for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> - * - * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants}, - * then an <code>IllegalArgumentException</code> is thrown.</p> - * - * <p>If <code>expression</code>, <code>source</code> or <code>returnType</code> is <code>null</code>, - * then a <code>NullPointerException</code> is thrown.</p> + * variable, function and QName resolution and return type conversion. * * @param expression The XPath expression. * @param source The input source of the document to evaluate over. * @param returnType The desired return type. * - * @return The <code>Object</code> that encapsulates the result of evaluating the expression. + * @return The {@code Object} that encapsulates the result of evaluating the expression. * * @throws XPathExpressionException If expression cannot be evaluated. - * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If <code>expression</code>, <code>source</code> or <code>returnType</code> - * is <code>null</code>. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants}. + * @throws NullPointerException If {@code expression, source or returnType} is {@code null}. */ public Object evaluate( String expression, @@ -293,27 +290,209 @@ throws XPathExpressionException; /** - * <p>Evaluate an XPath expression in the context of the specified <code>InputSource</code> - * and return the result as a <code>String</code>.</p> + * Evaluate an XPath expression in the context of the specified {@code InputSource} + * and return the result as a {@code String}. * * <p>This method calls {@link #evaluate(String expression, InputSource source, QName returnType)} with a - * <code>returnType</code> of {@link XPathConstants#STRING}.</p> + * {@code returnType} of {@link XPathConstants#STRING}. * * <p>See <a href="#XPath-evaluation">Evaluation of XPath Expressions</a> for context item evaluation, - * variable, function and QName resolution and return type conversion.</p> - * - * <p>If <code>expression</code> or <code>source</code> is <code>null</code>, - * then a <code>NullPointerException</code> is thrown.</p> + * variable, function and QName resolution and return type conversion. * * @param expression The XPath expression. - * @param source The <code>InputSource</code> of the document to evaluate over. + * @param source The {@code InputSource} of the document to evaluate over. * - * @return The <code>String</code> that is the result of evaluating the expression and - * converting the result to a <code>String</code>. + * @return The {@code String} that is the result of evaluating the expression and + * converting the result to a {@code String}. * * @throws XPathExpressionException If expression cannot be evaluated. - * @throws NullPointerException If <code>expression</code> or <code>source</code> is <code>null</code>. + * @throws NullPointerException If {@code expression or source} is {@code null}. */ public String evaluate(String expression, InputSource source) throws XPathExpressionException; + + /** + * Evaluate an XPath expression in the specified context and return + * the result with the type specified through the {@code class type} + * + * <p> + * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + * <pre> {@code + * (T)evaluate(expression, item, + * XPathEvaluationResult.XPathResultType.getQNameType(type)); + * }</pre> + * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param <T> The class type that will be returned by the XPath expression. + * @param expression The XPath expression. + * @param item The context the XPath expression will be evaluated in. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType}, + * or XPathEvaluationResult is specified as the type but an implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. + * @throws NullPointerException If {@code expression or type} is {@code null}. + * + * @since 1.9 + */ + default <T>T evaluateExpression(String expression, Object item, Class<T> type) + throws XPathExpressionException { + return type.cast(evaluate(expression, item, + XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate an XPath expression in the specified context. This is equivalent to + * calling {@link #evaluateExpression(String expression, Object item, Class type)} + * with type {@link XPathEvaluationResult}: + * <pre> {@code + * evaluateExpression(expression, item, XPathEvaluationResult.class); + * }</pre> + * <p> + * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + * <pre> {@code + * evaluateExpression(expression, item, XPathEvaluationResult.class); + * }</pre> + * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param expression The XPath expression. + * @param item The context the XPath expression will be evaluated in. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * @throws NullPointerException If {@code expression} is {@code null}. + * + * @since 1.9 + */ + default XPathEvaluationResult<?> evaluateExpression(String expression, Object item) + throws XPathExpressionException + { + return evaluateExpression(expression, item, XPathEvaluationResult.class); + } + + /** + * Evaluate an XPath expression in the context of the specified {@code source} + * and return the result as specified. + * <p> + * This method builds a data model for the {@link InputSource} and calls + * {@link #evaluateExpression(String expression, Object item, Class type)} + * on the resulting document object. The data model is usually + * {@link org.w3c.dom.Document} + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + * <pre> {@code + (T)evaluate(expression, source, + XPathEvaluationResult.XPathResultType.getQNameType(type)); + * }</pre> + * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param <T> The class type that will be returned by the XPath expression. + * @param expression The XPath expression. + * @param source The input source of the document to evaluate over. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType + * XPathResultType}, or XPathEvaluationResult is specified as the type but an + * implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. + * @throws NullPointerException If {@code expression, source or type}is {@code null}. + * + * @since 1.9 + */ + default <T>T evaluateExpression(String expression, InputSource source, Class<T> type) + throws XPathExpressionException + { + return type.cast(evaluate(expression, source, + XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate an XPath expression in the specified context. This is equivalent to + * calling {@link #evaluateExpression(String expression, Object item, Class type)} + * with type {@link XPathEvaluationResult}: + * <pre> {@code + * evaluateExpression(expression, item, XPathEvaluationResult.class); + * }</pre> + * <p> + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + * <pre> {@code + * evaluateExpression(expression, source, XPathEvaluationResult.class); + * }</pre> + * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param expression The XPath expression. + * @param source The input source of the document to evaluate over. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * @throws NullPointerException If {@code expression or source} is {@code null}. + * + * @since 1.9 + */ + default XPathEvaluationResult<?> evaluateExpression(String expression, InputSource source) + throws XPathExpressionException + { + return evaluateExpression(expression, source, XPathEvaluationResult.class); + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 javax.xml.xpath; + +import java.util.Objects; +import javax.xml.namespace.QName; +import org.w3c.dom.Node; +/** + * The {@code XPathEvaluationResult} interface represents the result of the + * evaluation of an XPath expression within the context of a particular node. + * The evaluation of an XPath expression can result in various result types as + * defined in XML Path Language (XPath) Version 1.0. + * <p> + * + * @param <T> the object type returned by the XPath evaluation. + * @see <a href="http://www.w3.org/TR/xpath">XML Path Language (XPath) Version + * 1.0</a> + * + * @since 1.9 + */ +public interface XPathEvaluationResult<T> { + + /** + * XPathResultType represents possible return types of an XPath evaluation. + * Provided as an enum type, it allows the use of switch statement. At the + * same time, a mapping is provided between the original QName types in + * {@link XPathConstants} and class types used in the generic methods. + */ + public static enum XPathResultType { + /** + * Any type that represents any of the 5 other types listed below. + * Maps to {@link XPathEvaluationResult}. + */ + ANY(new QName("http://www.w3.org/1999/XSL/Transform", "any"), XPathEvaluationResult.class), + /** + * The XPath 1.0 boolean data type. Maps to Java {@link Boolean}. + */ + BOOLEAN(XPathConstants.BOOLEAN, Boolean.class), + /** + * The XPath 1.0 Number data type. Maps to Java {@link Number}. Of the + * subtypes of Number, only Double, Integer and Long are required. + */ + NUMBER(XPathConstants.NUMBER, Number.class), + /** + * The XPath 1.0 String data type. Maps to Java {@link String}. + */ + STRING(XPathConstants.STRING, String.class), + /** + * The XPath 1.0 NodeSet data type. Maps to {@link org.w3c.dom.NodeList}. + */ + NODESET(XPathConstants.NODESET, XPathNodes.class), + /** + * The XPath 1.0 NodeSet data type. Maps to {@link org.w3c.dom.Node}. + */ + NODE(XPathConstants.NODE, Node.class); + + final QName qnameType; + final Class<?> clsType; + XPathResultType(QName qnameType, Class<?> clsType) { + this.qnameType = qnameType; + this.clsType = clsType; + } + + /** + * Compares this type to the specified class type. + * @param clsType class type + * @return true if the argument is not null and is a class type that + * matches that this type represents, false otherwise. + */ + private boolean equalsClassType(Class<?> clsType) { + Objects.nonNull(clsType); + if (clsType.isAssignableFrom(this.clsType)) { + return true; + } + return false; + } + + /** + * Returns the QName type as specified in {@link XPathConstants} that + * corresponds to the specified class type. + * @param clsType a class type that the enum type supports + * @return the QName type that matches with the specified class type, + * null if there is no match + */ + static public QName getQNameType(Class<?> clsType) { + for (XPathResultType type : XPathResultType.values()) { + if (type.equalsClassType(clsType)) { + return type.qnameType; + } + } + return null; + } + } + + /** + * Return the result type as an enum specified by {@code XPathResultType} + * @return the result type + */ + public XPathResultType type(); + + /** + * Returns the value of the result as the type <T> specified for the class. + * + * @return The value of the result. + */ + public T value(); + +}
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java Tue Feb 03 16:46:05 2015 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java Wed Feb 04 18:23:09 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,11 @@ package javax.xml.xpath; +import javax.xml.namespace.QName; import org.xml.sax.InputSource; -import javax.xml.namespace.QName; /** - * <p><code>XPathExpression</code> provides access to compiled XPath expressions.</p> + * <p>{@code XPathExpression} provides access to compiled XPath expressions.</p> * * <a name="XPathExpression-evaluation"/> * <table border="1" cellpadding="2"> @@ -53,7 +53,7 @@ * <td> * If the expression contains a variable reference, its value will be found through the {@link XPathVariableResolver}. * An {@link XPathExpressionException} is raised if the variable resolver is undefined or - * the resolver returns <code>null</code> for the variable. + * the resolver returns {@code null} for the variable. * The value of a variable must be immutable through the course of any single evaluation.</p> * </td> * </tr> @@ -62,7 +62,7 @@ * <td> * If the expression contains a function reference, the function will be found through the {@link XPathFunctionResolver}. * An {@link XPathExpressionException} is raised if the function resolver is undefined or - * the function resolver returns <code>null</code> for the function.</p> + * the function resolver returns {@code null} for the function.</p> * </td> * </tr> * <tr> @@ -84,9 +84,9 @@ * <p>An XPath expression is not thread-safe and not reentrant. * In other words, it is the application's responsibility to make * sure that one {@link XPathExpression} object is not used from - * more than one thread at any given time, and while the <code>evaluate</code> + * more than one thread at any given time, and while the {@code evaluate} * method is invoked, applications may not recursively call - * the <code>evaluate</code> method. + * the {@code evaluate} method. * <p> * * @author <a href="mailto:Norman.Walsh@Sun.com">Norman Walsh</a> @@ -96,50 +96,56 @@ */ public interface XPathExpression { + /** * <p>Evaluate the compiled XPath expression in the specified context and return the result as the specified type.</p> * * <p>See <a href="#XPathExpression-evaluation">Evaluation of XPath Expressions</a> for context item evaluation, * variable, function and QName resolution and return type conversion.</p> * - * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants}, - * then an <code>IllegalArgumentException</code> is thrown.</p> + * <p> + * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * - * <p>If a <code>null</code> value is provided for - * <code>item</code>, an empty document will be used for the - * context. - * If <code>returnType</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p> + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. * - * @param item The starting context (a node, for example). - * @param returnType The desired return type. + * @param item The context the XPath expression will be evaluated in. + * @param returnType The result type expected to be returned by the XPath expression. * - * @return The <code>Object</code> that is the result of evaluating the expression and converting the result to - * <code>returnType</code>. + * @return The {@code Object} that is the result of evaluating the expression and converting the result to + * {@code returnType}. * * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If <code>returnType</code> is <code>null</code>. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants}. + * @throws NullPointerException If {@code returnType} is {@code null}. */ public Object evaluate(Object item, QName returnType) throws XPathExpressionException; /** - * <p>Evaluate the compiled XPath expression in the specified context and return the result as a <code>String</code>.</p> + * <p>Evaluate the compiled XPath expression in the specified context and return the result as a {@code String}.</p> * - * <p>This method calls {@link #evaluate(Object item, QName returnType)} with a <code>returnType</code> of + * <p>This method calls {@link #evaluate(Object item, QName returnType)} with a {@code returnType} of * {@link XPathConstants#STRING}.</p> * * <p>See <a href="#XPathExpression-evaluation">Evaluation of XPath Expressions</a> for context item evaluation, * variable, function and QName resolution and return type conversion.</p> * - * <p>If a <code>null</code> value is provided for - * <code>item</code>, an empty document will be used for the - * context. + * <p> + * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. * - * @param item The starting context (a node, for example). + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. * - * @return The <code>String</code> that is the result of evaluating the expression and converting the result to a - * <code>String</code>. + * @param item The context the XPath expression will be evaluated in. + * + * @return The result of evaluating an XPath expression as a {@code String}. * * @throws XPathExpressionException If the expression cannot be evaluated. */ @@ -147,7 +153,7 @@ throws XPathExpressionException; /** - * <p>Evaluate the compiled XPath expression in the context of the specified <code>InputSource</code> and return the result as the + * <p>Evaluate the compiled XPath expression in the context of the specified {@code InputSource} and return the result as the * specified type.</p> * * <p>This method builds a data model for the {@link InputSource} and calls @@ -156,45 +162,225 @@ * <p>See <a href="#XPathExpression-evaluation">Evaluation of XPath Expressions</a> for context item evaluation, * variable, function and QName resolution and return type conversion.</p> * - * <p>If <code>returnType</code> is not one of the types defined in {@link XPathConstants}, - * then an <code>IllegalArgumentException</code> is thrown.</p> + * <p>If {@code returnType} is not one of the types defined in {@link XPathConstants}, + * then an {@code IllegalArgumentException} is thrown.</p> * - * <p>If <code>source</code> or <code>returnType</code> is <code>null</code>, - * then a <code>NullPointerException</code> is thrown.</p> + * <p>If {@code source} or {@code returnType} is {@code null}, + * then a {@code NullPointerException} is thrown.</p> * - * @param source The <code>InputSource</code> of the document to evaluate over. + * @param source The {@code InputSource} of the document to evaluate over. * @param returnType The desired return type. * - * @return The <code>Object</code> that is the result of evaluating the expression and converting the result to - * <code>returnType</code>. + * @return The {@code Object} that is the result of evaluating the expression and converting the result to + * {@code returnType}. * * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws IllegalArgumentException If <code>returnType</code> is not one of the types defined in {@link XPathConstants}. - * @throws NullPointerException If <code>source</code> or <code>returnType</code> is <code>null</code>. + * @throws IllegalArgumentException If {@code returnType} is not one of the types defined in {@link XPathConstants}. + * @throws NullPointerException If {@code source or returnType} is {@code null}. */ public Object evaluate(InputSource source, QName returnType) throws XPathExpressionException; /** - * <p>Evaluate the compiled XPath expression in the context of the specified <code>InputSource</code> and return the result as a - * <code>String</code>.</p> + * <p>Evaluate the compiled XPath expression in the context of the specified {@code InputSource} and return the result as a + * {@code String}.</p> * - * <p>This method calls {@link #evaluate(InputSource source, QName returnType)} with a <code>returnType</code> of + * <p>This method calls {@link #evaluate(InputSource source, QName returnType)} with a {@code returnType} of * {@link XPathConstants#STRING}.</p> * * <p>See <a href="#XPathExpression-evaluation">Evaluation of XPath Expressions</a> for context item evaluation, * variable, function and QName resolution and return type conversion.</p> * - * <p>If <code>source</code> is <code>null</code>, then a <code>NullPointerException</code> is thrown.</p> + * <p>If {@code source} is {@code null}, then a {@code NullPointerException} is thrown.</p> * - * @param source The <code>InputSource</code> of the document to evaluate over. + * @param source The {@code InputSource} of the document to evaluate over. * - * @return The <code>String</code> that is the result of evaluating the expression and converting the result to a - * <code>String</code>. + * @return The {@code String} that is the result of evaluating the expression and converting the result to a + * {@code String}. * * @throws XPathExpressionException If the expression cannot be evaluated. - * @throws NullPointerException If <code>source</code> is <code>null</code>. + * @throws NullPointerException If {@code source} is {@code null}. */ public String evaluate(InputSource source) throws XPathExpressionException; + + /** + * Evaluate the compiled XPath expression in the specified context, and return + * the result with the type specified through the {@code class type}. + * + * <p> + * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + * <pre> {@code + * (T)evaluate(item, XPathEvaluationResult.XPathResultType.getQNameType(type)); + * }</pre> + * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param <T> The class type that will be returned by the XPath expression. + * @param item The context the XPath expression will be evaluated in. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType + * XPathResultType}, or XPathEvaluationResult is specified as the type but an + * implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type is not available. + * @throws NullPointerException If {@code type} is {@code null}. + * + * @since 1.9 + */ + default <T>T evaluateExpression(Object item, Class<T> type) + throws XPathExpressionException + { + return type.cast(evaluate(item, XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate the compiled XPath expression in the specified context. This is + * equivalent to calling {@link #evaluateExpression(Object item, Class type)} + * with type {@link XPathEvaluationResult}: + * <pre> {@code + * evaluateExpression(item, XPathEvaluationResult.class); + * }</pre> + * <p> + * The parameter {@code item} represents the context the XPath expression + * will be operated on. The type of the context is implementation-dependent. + * If the value is {@code null}, the operation must have no dependency on + * the context, otherwise an XPathExpressionException will be thrown. + * + * @implNote + * The type of the context is usually {@link org.w3c.dom.Node}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + * <pre> {@code + * evaluateExpression(item, XPathEvaluationResult.class); + * }</pre> + * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param item The context the XPath expression will be evaluated in. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * + * @since 1.9 + */ + default XPathEvaluationResult<?> evaluateExpression(Object item) + throws XPathExpressionException + { + return evaluateExpression(item, XPathEvaluationResult.class); + } + + /** + * Evaluate the compiled XPath expression in the specified context, + * and return the result with the type specified through the {@code class type} + * <p> + * This method builds a data model for the {@link InputSource} and calls + * {@link #evaluateExpression(Object item, Class type)} on the resulting + * document object. + * <P> + * By default, the JDK's data model is {@link org.w3c.dom.Document}. + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + * <pre> {@code + (T)evaluate(source, XPathEvaluationResult.XPathResultType.getQNameType(type)); + * }</pre> + * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type, specifying + * XPathEvaluationResult as the type will result in IllegalArgumentException. + * Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must override + * this method. + * + * @param <T> The class type that will be returned by the XPath expression. + * @param source The {@code InputSource} of the document to evaluate over. + * @param type The class type expected to be returned by the XPath expression. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If {@code type} is not of the types + * corresponding to the types defined in the {@link XPathEvaluationResult.XPathResultType + * XPathResultType}, or XPathEvaluationResult is specified as the type but an + * implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type + * is not available. + * @throws NullPointerException If {@code source or type} is {@code null}. + * + * @since 1.9 + */ + default <T>T evaluateExpression(InputSource source, Class<T> type) + throws XPathExpressionException + { + return type.cast(evaluate(source, XPathEvaluationResult.XPathResultType.getQNameType(type))); + } + + /** + * Evaluate the compiled XPath expression in the specified context. This is + * equivalent to calling {@link #evaluateExpression(InputSource source, Class type)} + * with type {@link XPathEvaluationResult}: + * <pre> {@code + * evaluateExpression(source, XPathEvaluationResult.class); + * }</pre> + * <p> + * + * @implSpec + * The default implementation in the XPath API is equivalent to: + * <pre> {@code + * (XPathEvaluationResult)evaluateExpression(source, XPathEvaluationResult.class); + * }</pre> + * + * Since the {@code evaluate} method does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} + * type, the default implementation of this method will always throw an + * IllegalArgumentException. Any implementation supporting the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type must therefore + * override this method. + * + * @param source The {@code InputSource} of the document to evaluate over. + * + * @return The result of evaluating the expression. + * + * @throws XPathExpressionException If the expression cannot be evaluated. + * @throws IllegalArgumentException If the implementation of this method + * does not support the + * {@link XPathEvaluationResult.XPathResultType#ANY ANY} type. + * @throws NullPointerException If {@code source} is {@code null}. + * + * @since 1.9 + */ + default XPathEvaluationResult<?> evaluateExpression(InputSource source) + throws XPathExpressionException + { + return evaluateExpression(source, XPathEvaluationResult.class); + } }
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java Tue Feb 03 16:46:05 2015 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java Wed Feb 04 18:23:09 2015 -0800 @@ -117,7 +117,7 @@ * and returns it if it is successfully created. * </li> * <li> - * ${java.home}/conf/jaxp.properties is read and the value associated with the key being the system property above is looked for. + * ${java.home}/lib/jaxp.properties is read and the value associated with the key being the system property above is looked for. * If present, the value is processed just like above. * </li> * <li>
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java Tue Feb 03 16:46:05 2015 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java Wed Feb 04 18:23:09 2015 -0800 @@ -176,9 +176,9 @@ String javah = ss.getSystemProperty( "java.home" ); String configFile = javah + File.separator + - "conf" + File.separator + "jaxp.properties"; + "lib" + File.separator + "jaxp.properties"; - // try to read from $java.home/conf/jaxp.properties + // try to read from $java.home/lib/jaxp.properties try { if(firstTime){ synchronized(cacheProps){ @@ -193,7 +193,7 @@ } } final String factoryClassName = cacheProps.getProperty(propertyName); - debugPrintln("found " + factoryClassName + " in $java.home/conf/jaxp.properties"); + debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); if (factoryClassName != null) { xpathFactory = createInstance(factoryClassName, true);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 javax.xml.xpath; + +import java.util.Iterator; +import org.w3c.dom.Node; + +/** + * XPathNodes represents a set of nodes selected by a location path as specified + * in <a href="http://www.w3.org/TR/xpath/#node-sets">XML Path Language (XPath) + * Version 1.0, 3.3 Node-sets</a>. + * + * @since 1.9 + */ +public interface XPathNodes extends Iterable<Node> { + + /** + * Returns an iterator of the Nodes. + * + * @return an Iterator. + */ + @Override + public abstract Iterator<Node> iterator(); + + /** + * Returns the number of items in the result + * + * @return The number of items in the result + */ + public abstract int size(); + + /** + * Returns a Node at the specified position + * + * @param index Index of the element to return. + * @return The Node at the specified position. + * @throws javax.xml.xpath.XPathException If the index is out of range + * (index < 0 || index >= size()) + */ + public abstract Node get(int index) + throws XPathException; +}
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html Tue Feb 03 16:46:05 2015 +0100 +++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html Wed Feb 04 18:23:09 2015 -0800 @@ -1,6 +1,8 @@ -<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<html> +<head> <!-- -Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. This code is free software; you can redistribute it and/or modify it @@ -23,35 +25,35 @@ or visit www.oracle.com if you need additional information or have any questions. --> +</head> +<body bgcolor="white"> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> -<title>javax.xml.xpath</title> -<meta name="@author" content="mailto:Ben@galbraiths.org" /> -<meta name="@author" content="mailto:Norman.Walsh@Sun.com" /> -<meta name="@author" content="mailto:Jeff.Suttor@Sun.com" /> -<meta name="@see" content="http://www.w3.org/TR/xpath" /> -<meta name="@since" content="1.5" /> -</head> - -<body> - -<p>This package provides an <em>object-model neutral</em> API for the +This package provides an <em>object-model neutral</em> API for the evaluation of XPath expressions and access to the evaluation environment. -</p> -<p>The following XML standards apply:</p> - -<ul> -<li><a href="http://www.w3.org/TR/xpath">XML Path Language (XPath) Version 1.0</a></li> -</ul> +<p> +The XPath API supports <a href="http://www.w3.org/TR/xpath"> + XML Path Language (XPath) Version 1.0</a> <hr /> -<h2>XPath Overview</h2> +<ul> + <li><a href='#XPath.Overview'>1. XPath Overview</a></li> + <li><a href='#XPath.Expressions'>2. XPath Expressions</a></li> + <li><a href='#XPath.Datatypes'>3. XPath Data Types</a> + <ul> + <li><a href='#XPath.Datatypes.QName'>3.1 QName Types</a> + <li><a href='#XPath.Datatypes.Class'>3.2 Class Types</a> + <li><a href='#XPath.Datatypes.Enum'>3.3 Enum Types</a> + </ul> + </li> + <li><a href='#XPath.Context'>4. XPath Context</a></li> + <li><a href='#XPath.Use'>5. Using the XPath API</a></li> +</ul> +<p> +<a name="XPath.Overview"></a> +<h3>1. XPath Overview</h3> <p>The XPath language provides a simple, concise syntax for selecting nodes from an XML document. XPath also provides rules for converting a @@ -67,7 +69,8 @@ replace many lines of DOM API code. </p> -<h3>XPath Expressions</h3> +<a name="XPath.Expressions"></a> +<h3>2. XPath Expressions</h3> <p>An XPath <em>expression</em> is composed of a <em>location path</em> and one or more optional <em>predicates</em>. Expressions @@ -76,18 +79,22 @@ <p>The following is an example of a simple XPath expression:</p> +<blockquote> <pre> /foo/bar </pre> +</blockquote> <p>This example would select the <code><bar></code> element in an XML document such as the following:</p> +<blockquote> <pre> <foo> -<bar/> + <bar/> </foo> </pre> +</blockquote> <p>The expression <code>/foo/bar</code> is an example of a location path. While XPath location paths resemble Unix-style file system @@ -96,30 +103,36 @@ <code><bar></code> elements in the following document would be selected by the <code>/foo/bar</code> expression:</p> +<blockquote> <pre> <foo> -<bar/> -<bar/> -<bar/> + <bar/> + <bar/> + <bar/> </foo> </pre> +</blockquote> <p>A special location path operator, <code>//</code>, selects nodes at any depth in an XML document. The following example selects all <code><bar></code> elements regardless of their location in a document:</p> +<blockquote> <pre> //bar </pre> +</blockquote> <p>A wildcard operator, *, causes all element nodes to be selected. The following example selects all children elements of a -<code><foo></code> element:</p> +<code><foo></code> element: +<blockquote> <pre> /foo/* </pre> +</blockquote> <p>In addition to element nodes, XPath location paths may also address attribute nodes, text nodes, comment nodes, and processing instruction @@ -166,35 +179,27 @@ <code><foo></code> elements that contain an <code>include</code> attribute with the value of <code>true</code>:</p> +<blockquote> <pre> //foo[@include='true'] </pre> +</blockquote> <p>Predicates may be appended to each other to further refine an expression, such as:</p> +<blockquote> <pre> //foo[@include='true'][@mode='bar'] </pre> +</blockquote> -<h3>Using the XPath API</h3> - -<p> -The following example demonstrates using the XPath API to select one -or more nodes from an XML document:</p> - -<pre> -XPath xpath = XPathFactory.newInstance().newXPath(); -String expression = "/widgets/widget"; -InputSource inputSource = new InputSource("widgets.xml"); -NodeList nodes = (NodeList) xpath.evaluate(expression, inputSource, XPathConstants.NODESET); -</pre> - -<h3>XPath Expressions and Types</h3> +<a name="XPath.Datatypes"></a> +<h3>3. XPath Data Types</h3> <p>While XPath expressions select nodes in the XML document, the XPath API allows the selected nodes to be coalesced into one of the -following other data types:</p> +following data types:</p> <ul> <li><code>Boolean</code></li> @@ -202,14 +207,10 @@ <li><code>String</code></li> </ul> -<p>The desired return type is specified by a {@link -javax.xml.namespace.QName} parameter in method call used to evaluate -the expression, which is either a call to -<code>XPathExpression.evalute(...)</code> or to one of the -<code>XPath.evaluate(...)</code> convenience methods. The allowed -QName values are specified as constants in the {@link -javax.xml.xpath.XPathConstants} class; they are:</p> - +<a name="XPath.Datatypes.QName"></a> +<h3>3.1 QName types</h3> +The XPath API defines the following {@link javax.xml.namespace.QName} types to +represent return types of an XPath evaluation: <ul> <li>{@link javax.xml.xpath.XPathConstants#NODESET}</li> <li>{@link javax.xml.xpath.XPathConstants#NODE}</li> @@ -218,26 +219,71 @@ <li>{@link javax.xml.xpath.XPathConstants#NUMBER}</li> </ul> +<p>The return type is specified by a {@link javax.xml.namespace.QName} parameter +in method call used to evaluate the expression, which is either a call to +<code>XPathExpression.evalute(...)</code> or <code>XPath.evaluate(...)</code> +methods. + <p>When a <code>Boolean</code> return type is requested, <code>Boolean.TRUE</code> is returned if one or more nodes were -selected; otherwise, <code>Boolean.FALSE</code> is returned.</p> +selected; otherwise, <code>Boolean.FALSE</code> is returned. <p>The <code>String</code> return type is a convenience for retrieving the character data from a text node, attribute node, comment node, or processing-instruction node. When used on an element node, the value of the child text nodes is returned. -</p> <p>The <code>Number</code> return type attempts to coalesce the text of a node to a <code>double</code> data type. -</p> -<h3>XPath Context</h3> +<a name="XPath.Datatypes.Class"></a> +<h3>3.2 Class types</h3> +In addition to the QName types, the XPath API supports the use of Class types +through the <code>XPathExpression.evaluteExpression(...)</code> or +<code>XPath.evaluateExpression(...)</code> methods. + +The XPath data types are mapped to Class types as follows: +<ul> +<li><code>Boolean</code> -- <code>Boolean.class</code></li> +<li><code>Number</code> -- <code>Number.class</code></li> +<li><code>String</code> -- <code>String.class</code></li> +<li><code>Nodeset</code> -- <code>XPathNodes.class</code></li> +<li><code>Node</code> -- <code>Node.class</code></li> +</ul> + +<p> +Of the subtypes of Number, only Double, Integer and Long are supported. + +<a name="XPath.Datatypes.Enum"></a> +<h3>3.3 Enum types</h3> +Enum types are defined in {@link javax.xml.xpath.XPathEvaluationResult.XPathResultType} +that provide mappings between the QName and Class types above. The result of +evaluating an expression using the <code>XPathExpression.evaluteExpression(...)</code> +or <code>XPath.evaluateExpression(...)</code> methods will be of one of these types. + +<a name="XPath.Context"></a> +<h3>4. XPath Context</h3> <p>XPath location paths may be relative to a particular node in the -document, known as the <code>context</code>. Consider the following -XML document:</p> +document, known as the <code>context</code>. A context consists of: +<ul> + <li>a node (the context node)</li> + <li>a pair of non-zero positive integers (the context position and the context size)</li> + <li>a set of variable bindings</li> + <li>a function library</li> + <li>the set of namespace declarations in scope for the expression</li> +</ul> +<p> +It is an XML document tree represented as a hierarchy of nodes, a +{@link org.w3c.dom.Node} for example, in the JDK implementation. + +<a name="XPath.Use"></a> +<h3>5. Using the XPath API</h3> + +Consider the following XML document: +<p> +<blockquote> <pre> <widgets> <widget> @@ -246,36 +292,88 @@ </widget> </widgets> </pre> +</blockquote> -<p>The <code><widget></code> element can be selected with the -following XPath API code:</p> +<p> +The <code><widget></code> element can be selected with the following process: +<blockquote> <pre> // parse the XML as a W3C Document DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = builder.parse(new File("/widgets.xml")); +//Get an XPath object and evaluate the expression XPath xpath = XPathFactory.newInstance().newXPath(); String expression = "/widgets/widget"; Node widgetNode = (Node) xpath.evaluate(expression, document, XPathConstants.NODE); + +//or using the evaluateExpression method +Node widgetNode = xpath.evaluateExpression(expression, document, Node.class); </pre> +</blockquote> <p>With a reference to the <code><widget></code> element, a -relative XPath expression can now written to select the +relative XPath expression can be written to select the <code><manufacturer></code> child element:</p> +<blockquote> <pre> XPath xpath = XPathFactory.newInstance().newXPath(); <strong>String expression = "manufacturer";</strong> Node manufacturerNode = (Node) xpath.evaluate(expression, <strong>widgetNode</strong>, XPathConstants.NODE); + +//or using the evaluateExpression method +Node manufacturerNode = xpath.evaluateExpression(expression, <strong>widgetNode</strong>, Node.class); </pre> +</blockquote> -<ul> -<li>Author <a href="mailto:Ben@galbraiths.org">Ben Galbraith</a></li> -<li>Author <a href="mailto:Norman.Walsh@Sun.com">Norman Walsh</a></li> -<li>Author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a></li> -<li>See <a href="http://www.w3.org/TR/xpath">XML Path Language (XPath) Version 1.0</a></li> -<li>Since 1.5</li> -</ul> +<p> +In the above example, the XML file is read into a DOM Document before being passed +to the XPath API. The following code demonstrates the use of InputSource to +leave it to the XPath implementation to process it: + +<blockquote> +<pre> +XPath xpath = XPathFactory.newInstance().newXPath(); +String expression = "/widgets/widget"; +InputSource inputSource = new InputSource("widgets.xml"); +NodeList nodes = (NodeList) xpath.evaluate(expression, inputSource, XPathConstants.NODESET); + +//or using the evaluateExpression method +XPathNodes nodes = xpath.evaluate(expression, inputSource, XPathNodes.class); +</pre> +</blockquote> + +<p> +In the above cases, the type of the expected results are known. In case where +the result type is unknown or any type, the {@link javax.xml.xpath.XPathEvaluationResult} +may be used to determine the return type. The following code demonstrates the usage: +<blockquote> +<pre> +XPathEvaluationResult<?> result = xpath.evaluateExpression(expression, document); +switch (result.type()) { + case NODESET: + XPathNodes nodes = (XPathNodes)result.value(); + ... + break; +} +</pre> +</blockquote> + +<p> +The XPath 1.0 Number data type is defined as a double. However, the XPath +specification also provides functions that returns Integer type. To facilitate +such operations, the XPath API allows Integer and Long to be used in +{@code evaluateExpression} method such as the following code: +<p> +<blockquote> +<pre> +int count = xpath.evaluate("count(/widgets/widget)", document, Integer.class); +</pre> +</blockquote> + +@since 1.5 + </body> </html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,297 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.xml.validation.ptests; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.validation.ptests.ValidationTestConst.XML_DIR; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertSame; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; + +/* + * @summary Class containing the test cases for SchemaFactory + */ +@Test(singleThreaded = true) +public class SchemaFactoryTest { + + @BeforeClass + public void setup() throws SAXException, IOException, ParserConfigurationException { + sf = newSchemaFactory(); + + assertNotNull(sf); + + xsd1 = Files.readAllBytes(Paths.get(XML_DIR + "test.xsd")); + xsd2 = Files.readAllBytes(Paths.get(XML_DIR + "test1.xsd")); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + DocumentBuilder db = dbf.newDocumentBuilder(); + xsdDoc1 = db.parse(newInputStream(xsd1)); + xsdDoc2 = db.parse(newInputStream(xsd2)); + + xml = Files.readAllBytes(Paths.get(XML_DIR + "test.xml")); + } + + @Test(expectedExceptions = SAXParseException.class) + public void testNewSchemaDefault() throws SAXException, IOException { + validate(sf.newSchema()); + } + + @Test + public void testNewSchemaWithFile() throws SAXException, IOException { + validate(sf.newSchema(new File(XML_DIR + "test.xsd"))); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNewSchemaWithNullFile() throws SAXException { + sf.newSchema((File) null); + } + + @DataProvider(name = "valid-source") + public Object[][] getValidSource() { + return new Object[][] { + { streamSource(xsd1) }, + { saxSource(xsd1) }, + { domSource(xsdDoc1) } }; + + } + + @Test(dataProvider = "valid-source") + public void testNewSchemaWithValidSource(Source schema) throws SAXException, IOException { + validate(sf.newSchema(schema)); + } + + @DataProvider(name = "invalid-source") + public Object[][] getInvalidSource() { + return new Object[][] { + { nullStreamSource() }, + { nullSaxSource() } }; + } + + @Test(dataProvider = "invalid-source", expectedExceptions = SAXParseException.class) + public void testNewSchemaWithInvalidSource(Source schema) throws SAXException { + sf.newSchema(schema); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNewSchemaWithNullSource() throws SAXException { + sf.newSchema((Source)null); + } + + @DataProvider(name = "valid-sources") + public Object[][] getValidSources() { + return new Object[][] { + { streamSource(xsd1), streamSource(xsd2) }, + { saxSource(xsd1), saxSource(xsd2) }, + { domSource(xsdDoc1), domSource(xsdDoc2) } }; + + } + + @Test(dataProvider = "valid-sources") + public void testNewSchemaWithValidSourceArray(Source schema1, Source schema2) throws SAXException, IOException { + validate(sf.newSchema(new Source[] { schema1, schema2 })); + } + + @DataProvider(name = "invalid-sources") + public Object[][] getInvalidSources() { + return new Object[][] { + { streamSource(xsd1), nullStreamSource() }, + { nullStreamSource(), nullStreamSource() }, + { saxSource(xsd1), nullSaxSource() }, + { nullSaxSource(), nullSaxSource() } }; + } + + @Test(dataProvider = "invalid-sources", expectedExceptions = SAXParseException.class) + public void testNewSchemaWithInvalidSourceArray(Source schema1, Source schema2) throws SAXException { + sf.newSchema(new Source[] { schema1, schema2 }); + } + + @DataProvider(name = "null-sources") + public Object[][] getNullSources() { + return new Object[][] { + { new Source[] { domSource(xsdDoc1), null } }, + { new Source[] { null, null } }, + { null } }; + + } + + @Test(dataProvider = "null-sources", expectedExceptions = NullPointerException.class) + public void testNewSchemaWithNullSourceArray(Source[] schemas) throws SAXException { + sf.newSchema(schemas); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNewSchemaWithNullUrl() throws SAXException { + sf.newSchema((URL) null); + } + + + @Test + public void testErrorHandler() { + SchemaFactory sf = newSchemaFactory(); + assertNull(sf.getErrorHandler(), "When SchemaFactory is created, initially ErrorHandler should not be set."); + + ErrorHandler handler = new MyErrorHandler(); + sf.setErrorHandler(handler); + assertSame(sf.getErrorHandler(), handler); + + sf.setErrorHandler(null); + assertNull(sf.getErrorHandler()); + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + sf.getProperty(UNRECOGNIZED_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + sf.setProperty(UNRECOGNIZED_NAME, "test"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + assertNotNull(sf); + sf.getProperty(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + assertNotNull(sf); + sf.setProperty(null, "test"); + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + sf.getFeature(UNRECOGNIZED_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + sf.setFeature(UNRECOGNIZED_NAME, true); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + assertNotNull(sf); + sf.getFeature(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + SchemaFactory sf = newSchemaFactory(); + assertNotNull(sf); + sf.setFeature(null, true); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testInvalidSchemaLanguage() { + final String INVALID_SCHEMA_LANGUAGE = "http://relaxng.org/ns/structure/1.0"; + SchemaFactory.newInstance(INVALID_SCHEMA_LANGUAGE); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullSchemaLanguage() { + SchemaFactory.newInstance(null); + } + + private void validate(Schema schema) throws SAXException, IOException { + schema.newValidator().validate(new StreamSource(new ByteArrayInputStream(xml))); + } + private InputStream newInputStream(byte[] xsd) { + return new ByteArrayInputStream(xsd); + } + + private Source streamSource(byte[] xsd) { + return new StreamSource(newInputStream(xsd)); + } + + private Source nullStreamSource() { + return new StreamSource((InputStream) null); + } + + private Source saxSource(byte[] xsd) { + return new SAXSource(new InputSource(newInputStream(xsd))); + } + + private Source nullSaxSource() { + return new SAXSource(new InputSource((InputStream) null)); + } + + private Source domSource(Document xsdDoc) { + return new DOMSource(xsdDoc); + } + + private SchemaFactory newSchemaFactory() { + return SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); + } + + private static final String UNRECOGNIZED_NAME = "http://xml.org/sax/features/namespace-prefixes"; + + private SchemaFactory sf; + private byte[] xsd1; + private byte[] xsd2; + private Document xsdDoc1; + private Document xsdDoc2; + private byte[] xml; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/TypeInfoProviderTest.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.xml.validation.ptests; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.validation.ptests.ValidationTestConst.XML_DIR; +import static jaxp.library.JAXPTestUtilities.filenameToURL; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.TypeInfoProvider; +import javax.xml.validation.ValidatorHandler; + +import jaxp.library.JAXPFileBaseTest; + +import org.testng.annotations.Test; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +/* + * @summary test ValidatorHandler.getTypeInfoProvider() + */ +public class TypeInfoProviderTest extends JAXPFileBaseTest { + + private ValidatorHandler validatorHandler; + + @Test + public void test() throws SAXException, ParserConfigurationException, IOException { + + SchemaFactory sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); + Schema schema = sf.newSchema(new File(XML_DIR + "shiporder11.xsd")); + validatorHandler = schema.newValidatorHandler(); + MyDefaultHandler myDefaultHandler = new MyDefaultHandler(); + validatorHandler.setContentHandler(myDefaultHandler); + + InputSource is = new InputSource(filenameToURL(XML_DIR + "shiporder11.xml")); + + SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + parserFactory.setNamespaceAware(true); + XMLReader xmlReader = parserFactory.newSAXParser().getXMLReader(); + xmlReader.setContentHandler(validatorHandler); + xmlReader.parse(is); + + } + + private class MyDefaultHandler extends DefaultHandler { + + public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { + TypeInfoProvider typeInfoProvider = validatorHandler.getTypeInfoProvider(); + int index = atts.getIndex("orderid"); + if (index != -1) { + System.out.println(" Index " + index); + System.out.println(" ElementType " + typeInfoProvider.getElementTypeInfo().getTypeName()); + assertEquals(typeInfoProvider.getAttributeTypeInfo(index).getTypeName(), "string"); + assertTrue(typeInfoProvider.isSpecified(index)); + assertFalse(typeInfoProvider.isIdAttribute(index)); + } + + } + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorHandlerTest.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.xml.validation.ptests; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.validation.ptests.ValidationTestConst.XML_DIR; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import java.io.File; + +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.ValidatorHandler; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.xml.sax.ContentHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.helpers.DefaultHandler; + +/* + * @summary Class containing the test cases for ValidatorHandler API + */ +public class ValidatorHandlerTest { + @BeforeClass + public void setup() throws SAXException { + schema = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI).newSchema(new File(XML_DIR + "test.xsd")); + + assertNotNull(schema); + } + + @Test + public void testErrorHandler() { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNull(validatorHandler.getErrorHandler(), "When ValidatorHandler is created, initially ErrorHandler should not be set."); + + ErrorHandler handler = new MyErrorHandler(); + validatorHandler.setErrorHandler(handler); + assertSame(validatorHandler.getErrorHandler(), handler); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + validatorHandler.getProperty(FEATURE_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + validatorHandler.setProperty(FEATURE_NAME, "test"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNotNull(validatorHandler); + validatorHandler.getProperty(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNotNull(validatorHandler); + validatorHandler.setProperty(null, "test"); + } + + public void testFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertFalse(validatorHandler.getFeature(FEATURE_NAME), "The feature should be false by default."); + + validatorHandler.setFeature(FEATURE_NAME, true); + assertTrue(validatorHandler.getFeature(FEATURE_NAME), "The feature should be false by default."); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNotNull(validatorHandler); + validatorHandler.getFeature(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNotNull(validatorHandler); + validatorHandler.setFeature(null, true); + } + + @Test + public void testContentHandler() { + ValidatorHandler validatorHandler = getValidatorHandler(); + assertNull(validatorHandler.getContentHandler(), "When ValidatorHandler is created, initially ContentHandler should not be set."); + + ContentHandler handler = new DefaultHandler(); + validatorHandler.setContentHandler(handler); + assertSame(validatorHandler.getContentHandler(), handler); + + validatorHandler.setContentHandler(null); + assertNull(validatorHandler.getContentHandler()); + + } + + private ValidatorHandler getValidatorHandler() { + return schema.newValidatorHandler(); + } + + private static final String FEATURE_NAME = "http://xml.org/sax/features/namespace-prefixes"; + + private Schema schema; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorTest.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javax.xml.validation.ptests; + +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.validation.ptests.ValidationTestConst.XML_DIR; +import static jaxp.library.JAXPTestUtilities.filenameToURL; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertSame; + +import java.io.File; +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import jaxp.library.JAXPFileBaseTest; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.helpers.DefaultHandler; + +/* + * @summary Class containing the test cases for Validator API + */ +public class ValidatorTest extends JAXPFileBaseTest { + + @BeforeClass + public void setup() throws SAXException, IOException, ParserConfigurationException { + schema = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI).newSchema(new File(XML_DIR + "test.xsd")); + + assertNotNull(schema); + + xmlFileUri = filenameToURL(XML_DIR + "test.xml"); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + xmlDoc = dbf.newDocumentBuilder().parse(xmlFileUri); + } + + @Test + public void testValidateStreamSource() throws SAXException, IOException { + Validator validator = getValidator(); + validator.setErrorHandler(new MyErrorHandler()); + validator.validate(getStreamSource()); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testValidateNullSource() throws SAXException, IOException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.validate(null); + } + + @Test + public void testErrorHandler() { + Validator validator = getValidator(); + assertNull(validator.getErrorHandler(), "When Validator is created, initially ErrorHandler should not be set."); + + ErrorHandler mh = new MyErrorHandler(); + validator.setErrorHandler(mh); + assertSame(validator.getErrorHandler(), mh); + + } + + @DataProvider(name = "source-result") + public Object[][] getSourceAndResult() { + return new Object[][] { + { getStreamSource(), null }, + { getSAXSource(), getSAXResult() }, + { getDOMSource(), getDOMResult() }, + { getSAXSource(), null }, + { getDOMSource(), null } }; + } + + @Test(dataProvider = "source-result") + public void testValidateWithResult(Source source, Result result) throws SAXException, IOException { + Validator validator = getValidator(); + validator.validate(source, result); + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + validator.getProperty(UNRECOGNIZED_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + validator.setProperty(UNRECOGNIZED_NAME, "test"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.getProperty(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullProperty() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.setProperty(null, "test"); + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testGetUnrecognizedFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + validator.getFeature(UNRECOGNIZED_NAME); + + } + + @Test(expectedExceptions = SAXNotRecognizedException.class) + public void testSetUnrecognizedFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + validator.setFeature(UNRECOGNIZED_NAME, true); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testGetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.getFeature(null); + + } + + @Test(expectedExceptions = NullPointerException.class) + public void testSetNullFeature() throws SAXNotRecognizedException, SAXNotSupportedException { + Validator validator = getValidator(); + assertNotNull(validator); + validator.setFeature(null, true); + } + + private Validator getValidator() { + return schema.newValidator(); + } + + private Source getStreamSource() { + return new StreamSource(xmlFileUri); + } + + private Source getSAXSource() { + return new SAXSource(new InputSource(xmlFileUri)); + } + + private Result getSAXResult() { + SAXResult saxResult = new SAXResult(); + saxResult.setHandler(new DefaultHandler()); + return saxResult; + } + + private Source getDOMSource() { + return new DOMSource(xmlDoc); + } + + private Result getDOMResult() { + return new DOMResult(); + } + + private static final String UNRECOGNIZED_NAME = "http://xml.org/sax/features/namespace-prefixes"; + private String xmlFileUri; + private Schema schema; + private Document xmlDoc; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xml Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> + +<shiporder orderid="889923" +xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +xsi:noNamespaceSchemaLocation="shiporder.xsd"> +<orderperson>John Smith</orderperson> +<shipto> +<name>Ola Nordmann</name> +<address>Langgt 23</address> +<city>4000 Stavanger</city> +<country>Norway</country> +</shipto> +<item> +<title>Empire Burlesque</title> +<note>Special Edition</note> +<quantity>1</quantity> +<price>10.90</price> +</item> +<item> +<title>Hide your heart</title> +<quantity>1</quantity> +<price>9.90</price> +</item> +</shiporder> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xsd Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + +<!-- definition of simple elements --> +<xs:element name="orderperson" type="xs:string"/> +<xs:element name="name" type="xs:string"/> +<xs:element name="address" type="xs:string"/> +<xs:element name="city" type="xs:string"/> +<xs:element name="country" type="xs:string"/> +<xs:element name="title" type="xs:string"/> +<xs:element name="note" type="xs:string"/> +<xs:element name="quantity" type="xs:positiveInteger"/> +<xs:element name="price" type="xs:decimal"/> + +<!-- definition of attributes --> +<xs:attribute name="orderid" type="xs:string"/> + +<!-- definition of complex elements --> +<xs:element name="shipto"> +<xs:complexType> +<xs:sequence> +<xs:element ref="name"/> +<xs:element ref="address"/> +<xs:element ref="city"/> +<xs:element ref="country"/> +</xs:sequence> +</xs:complexType> +</xs:element> +<xs:element name="item"> +<xs:complexType> +<xs:sequence> +<xs:element ref="title"/> +<xs:element ref="note" minOccurs="0"/> +<xs:element ref="quantity"/> +<xs:element ref="price"/> +</xs:sequence> +</xs:complexType> +</xs:element> + +<xs:element name="shiporder"> +<xs:complexType> +<xs:sequence> +<xs:element ref="orderperson"/> +<xs:element ref="shipto"/> +<xs:element ref="item" maxOccurs="unbounded"/> +</xs:sequence> +<xs:attribute ref="orderid" use="required"/> +</xs:complexType> +</xs:element> + +</xs:schema> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xml Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> + +<shiporder orderid="889923" +xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +xsi:noNamespaceSchemaLocation="shiporder.xsd"> +<orderperson>John Smith</orderperson> +<shipto> +<name>Ola Nordmann</name> +<address>Langgt 23</address> +<city>4000 Stavanger</city> +<country>Norway</country> +</shipto> +<item> +<title>Empire Burlesque</title> +<note>Special Edition</note> +<quantity>1</quantity> +<price>10.90</price> +</item> +<item> +<title>Hide your heart</title> +<quantity>1</quantity> +<price>9.90</price> +</item> +</shiporder> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xsd Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + +<!-- definition of simple elements --> +<xs:element name="orderperson" type="xs:string"/> +<xs:element name="name" type="xs:string"/> +<xs:element name="address" type="xs:string"/> +<xs:element name="city" type="xs:string"/> +<xs:element name="country" type="xs:string"/> +<xs:element name="title" type="xs:string"/> +<xs:element name="note" type="xs:string"/> +<xs:element name="quantity" type="xs:positiveInteger"/> +<xs:element name="price" type="xs:decimal"/> + +<!-- definition of attributes --> +<xs:attribute name="orderid" type="xs:string"/> + +<!-- definition of complex elements --> +<xs:element name="shipto"> +<xs:complexType> +<xs:sequence> +<xs:element ref="name"/> +<xs:element ref="address"/> +<xs:element ref="city"/> +<xs:element ref="country"/> +</xs:sequence> +</xs:complexType> +</xs:element> +<xs:element name="item"> +<xs:complexType> +<xs:sequence> +<xs:element ref="title"/> +<xs:element ref="note" minOccurs="0"/> +<xs:element ref="quantity"/> +<xs:element ref="price"/> +</xs:sequence> +</xs:complexType> +</xs:element> + +<xs:element name="shiporder"> +<xs:complexType> +<xs:sequence> +<xs:element ref="orderperson"/> +<xs:element ref="shipto"/> +<xs:element ref="item" maxOccurs="unbounded"/> +</xs:sequence> +<xs:attribute ref="orderid" use="required"/> +</xs:complexType> +</xs:element> + +</xs:schema> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xml Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8" ?> + <contact xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test.xsd"> +<name> John </name> +<phone>444-121-3434</phone> +</contact>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xsd Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" ?> + <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> +<xs:element name="contact"> +<xs:complexType> +<xs:sequence> + <xs:element name="name" type="xs:string"/> + <xs:element name="phone" type="xs:string"/> +</xs:sequence> +</xs:complexType> +</xs:element> +</xs:schema>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test1.xsd Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" ?> + <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> +<xs:element name="address"> +<xs:complexType> +<xs:sequence> + <xs:element name="street" type="xs:string"/> + <xs:element name="city" type="xs:string"/> +</xs:sequence> +</xs:complexType> +</xs:element> +</xs:schema>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4511326.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test.gaptest; + +import java.io.StringReader; + +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamSource; + +import jaxp.library.JAXPBaseTest; + +import org.testng.annotations.Test; + +/* + * @bug 4511326 + * @summary In forwards-compatible mode the attribute isn't ignored + */ + +public class Bug4511326 extends JAXPBaseTest { + + private static final String XSL = "<xsl:stylesheet version='2.0' " + + "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" + + "<xsl:template a='1' match='/'>" + + "<H2><xsl:value-of select='//author'/></H2>" + + "<H1><xsl:value-of select='//title'/></H1>" + + "</xsl:template>" + + "</xsl:stylesheet>"; + + + @Test + public void ignoreAttTest() throws TransformerConfigurationException { + /* Create a TransformFactory instance */ + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + + /* Create and init a StreamSource instance */ + StreamSource source = new StreamSource(new StringReader(XSL)); + + transformerFactory.newTransformer(source); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4512806.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test.gaptest; + +import static javax.xml.transform.OutputKeys.ENCODING; +import static javax.xml.transform.OutputKeys.INDENT; +import static org.testng.Assert.assertEquals; + +import java.io.StringReader; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamSource; + +import jaxp.library.JAXPBaseTest; + +import org.testng.annotations.Test; + +/* + * @bug 4512806 + * @summary test transformer.setOutputProperties(null) + */ +public class Bug4512806 extends JAXPBaseTest { + + @Test + public void testProperty() throws TransformerConfigurationException { + /* Create a transform factory instance */ + TransformerFactory tfactory = TransformerFactory.newInstance(); + + /* Create a StreamSource instance */ + StreamSource streamSource = new StreamSource(new StringReader(xslData)); + + transformer = tfactory.newTransformer(streamSource); + transformer.setOutputProperty(INDENT, "no"); + transformer.setOutputProperty(ENCODING, "UTF-16"); + + assertEquals(printPropertyValue(INDENT), "indent=no"); + assertEquals(printPropertyValue(ENCODING), "encoding=UTF-16"); + + transformer.setOutputProperties(null); + + assertEquals(printPropertyValue(INDENT), "indent=yes"); + assertEquals(printPropertyValue(ENCODING), "encoding=UTF-8"); + + } + + private String printPropertyValue(String name) { + return name + "=" + transformer.getOutputProperty(name); + } + + private Transformer transformer; + + private static final String xslData = "<?xml version='1.0'?>" + + "<xsl:stylesheet" + + " version='1.0'" + + " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'" + + ">\n" + + " <xsl:output method='xml' indent='yes'" + + " encoding='UTF-8'/>\n" + + " <xsl:template match='/'>\n" + + " Hello World! \n" + + " </xsl:template>\n" + + "</xsl:stylesheet>"; + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515047.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test.gaptest; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import jaxp.library.JAXPBaseTest; + +import org.testng.annotations.Test; + +/* + * @bug 4515047 + * @summary test transform an empty dom source + */ + +public class Bug4515047 extends JAXPBaseTest { + + @Test + public void testCreateTxDoc() throws TransformerException, ParserConfigurationException { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + + StreamResult result = new StreamResult(System.out); + DOMSource source = new DOMSource(); + + /* This should not throw an Illegal Argument Exception */ + //Test empty DOMSource + transformer.transform(source, result); + + //Test DOMSource having only an empty node + source.setNode(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()); + transformer.transform(source, result); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515660.java Wed Feb 04 18:23:09 2015 -0800 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test.gaptest; + +import static org.testng.Assert.assertTrue; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXSource; +import