Merge
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index e95f272..26c2321 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -290,3 +290,4 @@
3dd628fde2086218d548841022ee8436b6b88185 jdk9-b45
12f1e276447bcc81516e85367d53e4f08897049d jdk9-b46
b6cca3e6175a69f39e5799b7349ddb0176630291 jdk9-b47
+0064e246d83f6f9fc245c19b6d05041ecaf4b6d4 jdk9-b48
diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4
index 62d8357..800c52b 100644
--- a/common/autoconf/basics.m4
+++ b/common/autoconf/basics.m4
@@ -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)
+])
diff --git a/common/autoconf/bootcycle-spec.gmk.in b/common/autoconf/bootcycle-spec.gmk.in
index a547f34..6e68c3a 100644
--- a/common/autoconf/bootcycle-spec.gmk.in
+++ b/common/autoconf/bootcycle-spec.gmk.in
@@ -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
diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac
index 146556f..902ba47 100644
--- a/common/autoconf/configure.ac
+++ b/common/autoconf/configure.ac
@@ -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
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index 21ab1f4..11b5d33 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -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
diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in
index 1c6c1c4..d25b35b 100644
--- a/common/autoconf/spec.gmk.in
+++ b/common/autoconf/spec.gmk.in
@@ -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.
diff --git a/corba/.hgtags b/corba/.hgtags
index a6362dd..5fa0c42 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -290,3 +290,4 @@
9e3f2bed80c0e5a84a256ce41f1d10c5ade48466 jdk9-b45
326f2068b4a4c05e2fa27d6acf93eba7b54b090d jdk9-b46
ee8447ca632e1d39180b4767c749db101bff7314 jdk9-b47
+a13c49c5f2899b702652a460ed7aa73123e671e6 jdk9-b48
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index 5d7b668..a0e96ea 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -450,3 +450,4 @@
5dc8184af1e2bb30b0103113d1f1a58a21a80c37 jdk9-b45
a184ee1d717297bd35b7c3e35393e137921a3ed2 jdk9-b46
3b241fb72b8925b75941d612db762a6d5da66d02 jdk9-b47
+cc775a4a24c7f5d9e624b4205e9fbd48a17331f6 jdk9-b48
diff --git a/hotspot/make/aix/Makefile b/hotspot/make/aix/Makefile
index e015074..bbb92c9 100644
--- a/hotspot/make/aix/Makefile
+++ b/hotspot/make/aix/Makefile
@@ -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; \
diff --git a/hotspot/make/aix/makefiles/xlc.make b/hotspot/make/aix/makefiles/xlc.make
index b652532..17a71b6 100644
--- a/hotspot/make/aix/makefiles/xlc.make
+++ b/hotspot/make/aix/makefiles/xlc.make
@@ -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)
diff --git a/hotspot/make/bsd/Makefile b/hotspot/make/bsd/Makefile
index 3f0cfc3..4d45841 100644
--- a/hotspot/make/bsd/Makefile
+++ b/hotspot/make/bsd/Makefile
@@ -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; \
diff --git a/hotspot/make/bsd/makefiles/dtrace.make b/hotspot/make/bsd/makefiles/dtrace.make
index dbb4116..80eb4d9 100644
--- a/hotspot/make/bsd/makefiles/dtrace.make
+++ b/hotspot/make/bsd/makefiles/dtrace.make
@@ -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
diff --git a/hotspot/make/bsd/makefiles/universal.gmk b/hotspot/make/bsd/makefiles/universal.gmk
index 12a34d7..40868ad 100644
--- a/hotspot/make/bsd/makefiles/universal.gmk
+++ b/hotspot/make/bsd/makefiles/universal.gmk
@@ -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 $@); \
diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile
index c3ed19f..33ed65d 100644
--- a/hotspot/make/linux/Makefile
+++ b/hotspot/make/linux/Makefile
@@ -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; \
diff --git a/hotspot/make/linux/makefiles/vm.make b/hotspot/make/linux/makefiles/vm.make
index a138a16..65b11f5 100644
--- a/hotspot/make/linux/makefiles/vm.make
+++ b/hotspot/make/linux/makefiles/vm.make
@@ -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 \
diff --git a/hotspot/make/sa.files b/hotspot/make/sa.files
index fa807c3..dfe1e53 100644
--- a/hotspot/make/sa.files
+++ b/hotspot/make/sa.files
@@ -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 \
diff --git a/hotspot/make/solaris/Makefile b/hotspot/make/solaris/Makefile
index 869db69..f8fb06c 100644
--- a/hotspot/make/solaris/Makefile
+++ b/hotspot/make/solaris/Makefile
@@ -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; \
diff --git a/hotspot/make/solaris/makefiles/dtrace.make b/hotspot/make/solaris/makefiles/dtrace.make
index be6e71d..1b76dc7 100644
--- a/hotspot/make/solaris/makefiles/dtrace.make
+++ b/hotspot/make/solaris/makefiles/dtrace.make
@@ -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)
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
index 5c11898..4621678 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
@@ -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);
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp
index 84485d4..f5d19df 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp
@@ -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);
}
diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp
index 89c0344..88e0dec 100644
--- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp
@@ -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");
}
diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad
index 51a9762..a9d576c 100644
--- a/hotspot/src/cpu/ppc/vm/ppc.ad
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad
@@ -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()*/);
+ predicate(Universe::narrow_oop_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);
@@ -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.
diff --git a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp
index f3709eb..1187443 100644
--- a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp
@@ -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);
diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp
index 51f237b..153bfbd 100644
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp
@@ -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);
}
diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp
index 5ba547d..862611c 100644
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp
+++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp
@@ -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);
diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
index 93f8780..c3039d5 100644
--- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
@@ -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();
diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp
index 9424b1b..438d376 100644
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp
@@ -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);
}
}
}
diff --git a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
index 718c829..919c2a6 100644
--- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
@@ -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.");
diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp
index 181ee15..9aa4587 100644
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp
@@ -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) {
diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp
index e4d6136..2cd8e16 100644
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp
@@ -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);
diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp
index 23e3b97..76335ca 100644
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp
@@ -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) {
diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp
index a1cd446..c4ed238 100644
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp
@@ -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);
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
index 93772f3..69c8533 100644
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
@@ -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);
}
diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
index f3390c9..6318a95 100644
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
@@ -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);
}
diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp
index 2187056..d0bdc33 100644
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp
@@ -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);
}
diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp
index b1b1b00..82072f0 100644
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp
@@ -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);
}
diff --git a/hotspot/src/os/aix/vm/perfMemory_aix.cpp b/hotspot/src/os/aix/vm/perfMemory_aix.cpp
index b509cf9..c9dd76b 100644
--- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp
+++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp
@@ -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 result;
-
- RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result);
- if (result == OS_ERR) {
- if (PrintMiscellaneous && Verbose) {
- warning("could not create file %s: %s\n", filename, strerror(errno));
- }
+ 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;
+
+ // 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) {
+ 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;
diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp
index fb09815..f8f17d5 100644
--- a/hotspot/src/os/windows/vm/os_windows.cpp
+++ b/hotspot/src/os/windows/vm/os_windows.cpp
@@ -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) {
diff --git a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp
index e3a4f4d..05a8c70 100644
--- a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp
+++ b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp
@@ -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) { }
diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
index 2beb72a..8fe99af 100644
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
@@ -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) {
diff --git a/hotspot/src/share/vm/classfile/compactHashtable.cpp b/hotspot/src/share/vm/classfile/compactHashtable.cpp
index 157b168..bd19755 100644
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp
@@ -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>;
diff --git a/hotspot/src/share/vm/classfile/compactHashtable.hpp b/hotspot/src/share/vm/classfile/compactHashtable.hpp
index ac01fa7..3e32fc0 100644
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp
@@ -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);
};
////////////////////////////////////////////////////////////////////////
diff --git a/hotspot/src/share/vm/classfile/symbolTable.cpp b/hotspot/src/share/vm/classfile/symbolTable.cpp
index 4df696f..3d08364 100644
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp
@@ -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);
diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp
index a44dd5c..6797d5d 100644
--- a/hotspot/src/share/vm/classfile/verifier.cpp
+++ b/hotspot/src/share/vm/classfile/verifier.cpp
@@ -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",
diff --git a/hotspot/src/share/vm/classfile/verifier.hpp b/hotspot/src/share/vm/classfile/verifier.hpp
index 3495805..113e404 100644
--- a/hotspot/src/share/vm/classfile/verifier.hpp
+++ b/hotspot/src/share/vm/classfile/verifier.hpp
@@ -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,
diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp
index af50207..5a546f5 100644
--- a/hotspot/src/share/vm/code/codeCache.cpp
+++ b/hotspot/src/share/vm/code/codeCache.cpp
@@ -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);
diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp
index 4f0def8..71b3fc5 100644
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp
@@ -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;
diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp
index 5ead54b..d5eaf9f 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp
@@ -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);
diff --git a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp
index a56c948..30ef7ce 100644
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp
@@ -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
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp
index 29fb547..a6cef46 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp
@@ -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?
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp
index a8ab193..33e8f3f 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp
@@ -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));
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
index a546e54..28cff78 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
@@ -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));
diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
index 2bf9a20..5ec7ec8 100644
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
@@ -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).
*/
diff --git a/hotspot/src/share/vm/interpreter/invocationCounter.hpp b/hotspot/src/share/vm/interpreter/invocationCounter.hpp
index e0cb50c..0409b02 100644
--- a/hotspot/src/share/vm/interpreter/invocationCounter.hpp
+++ b/hotspot/src/share/vm/interpreter/invocationCounter.hpp
@@ -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)
};
diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp
index 5501700..67cc033 100644
--- a/hotspot/src/share/vm/memory/heap.cpp
+++ b/hotspot/src/share/vm/memory/heap.cpp
@@ -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();
diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp
index 62a1501..9e37b0b 100644
--- a/hotspot/src/share/vm/oops/method.cpp
+++ b/hotspot/src/share/vm/oops/method.cpp
@@ -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();
}
diff --git a/hotspot/src/share/vm/oops/methodCounters.cpp b/hotspot/src/share/vm/oops/methodCounters.cpp
index 25379d2..b78b6e8 100644
--- a/hotspot/src/share/vm/oops/methodCounters.cpp
+++ b/hotspot/src/share/vm/oops/methodCounters.cpp
@@ -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() {
diff --git a/hotspot/src/share/vm/oops/methodCounters.hpp b/hotspot/src/share/vm/oops/methodCounters.hpp
index a21d376..7d042bf 100644
--- a/hotspot/src/share/vm/oops/methodCounters.hpp
+++ b/hotspot/src/share/vm/oops/methodCounters.hpp
@@ -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
diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp
index ef21558..f9e187f 100644
--- a/hotspot/src/share/vm/oops/methodData.cpp
+++ b/hotspot/src/share/vm/oops/methodData.cpp
@@ -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;
diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp
index e91cffb..d069746 100644
--- a/hotspot/src/share/vm/oops/methodData.hpp
+++ b/hotspot/src/share/vm/oops/methodData.hpp
@@ -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);
}
diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp
index c03c0f4..106e228 100644
--- a/hotspot/src/share/vm/opto/chaitin.cpp
+++ b/hotspot/src/share/vm/opto/chaitin.cpp
@@ -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);
diff --git a/hotspot/src/share/vm/opto/chaitin.hpp b/hotspot/src/share/vm/opto/chaitin.hpp
index 99194cf..51915c5 100644
--- a/hotspot/src/share/vm/opto/chaitin.hpp
+++ b/hotspot/src/share/vm/opto/chaitin.hpp
@@ -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;
diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp
index 7397f9e..1697d7e 100644
--- a/hotspot/src/share/vm/opto/doCall.cpp
+++ b/hotspot/src/share/vm/opto/doCall.cpp
@@ -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'");
diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp
index 7362481..42ba126 100644
--- a/hotspot/src/share/vm/opto/escape.cpp
+++ b/hotspot/src/share/vm/opto/escape.cpp
@@ -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");
}
}
diff --git a/hotspot/src/share/vm/opto/ifg.cpp b/hotspot/src/share/vm/opto/ifg.cpp
index 61e1343..f01cd40 100644
--- a/hotspot/src/share/vm/opto/ifg.cpp
+++ b/hotspot/src/share/vm/opto/ifg.cpp
@@ -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);
diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp
index b917ee1..f61e335 100644
--- a/hotspot/src/share/vm/opto/loopTransform.cpp
+++ b/hotspot/src/share/vm/opto/loopTransform.cpp
@@ -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);
diff --git a/hotspot/src/share/vm/opto/machnode.hpp b/hotspot/src/share/vm/opto/machnode.hpp
index a557c02..e30e234 100644
--- a/hotspot/src/share/vm/opto/machnode.hpp
+++ b/hotspot/src/share/vm/opto/machnode.hpp
@@ -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 {
diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp
index b393745..93659c3 100644
--- a/hotspot/src/share/vm/opto/macro.cpp
+++ b/hotspot/src/share/vm/opto/macro.cpp
@@ -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();
diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp
index 966bcbe..3afa49c 100644
--- a/hotspot/src/share/vm/opto/memnode.cpp
+++ b/hotspot/src/share/vm/opto/memnode.cpp
@@ -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;
}
diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp
index 8ed950a..225b20c 100644
--- a/hotspot/src/share/vm/opto/node.cpp
+++ b/hotspot/src/share/vm/opto/node.cpp
@@ -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
diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp
index bcf6911..ce591dc 100644
--- a/hotspot/src/share/vm/opto/node.hpp
+++ b/hotspot/src/share/vm/opto/node.hpp
@@ -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)
diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp
index 402ccfe..35728e6 100644
--- a/hotspot/src/share/vm/opto/parse1.cpp
+++ b/hotspot/src/share/vm/opto/parse1.cpp
@@ -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());
diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp
index 8a319f8..c99ac96 100644
--- a/hotspot/src/share/vm/opto/parse2.cpp
+++ b/hotspot/src/share/vm/opto/parse2.cpp
@@ -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;
diff --git a/hotspot/src/share/vm/opto/phase.cpp b/hotspot/src/share/vm/opto/phase.cpp
index 0c9c697..9662bbc 100644
--- a/hotspot/src/share/vm/opto/phase.cpp
+++ b/hotspot/src/share/vm/opto/phase.cpp
@@ -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() +
diff --git a/hotspot/src/share/vm/opto/phase.hpp b/hotspot/src/share/vm/opto/phase.hpp
index f273947..4b5d53d 100644
--- a/hotspot/src/share/vm/opto/phase.hpp
+++ b/hotspot/src/share/vm/opto/phase.hpp
@@ -88,6 +88,7 @@
_t_computeLive,
_t_regAllocSplit,
_t_postAllocCopyRemoval,
+ _t_mergeMultidefs,
_t_fixupSpills,
_t_chaitinCompact,
_t_chaitinCoalesce1,
diff --git a/hotspot/src/share/vm/opto/postaloc.cpp b/hotspot/src/share/vm/opto/postaloc.cpp
index 35e3974..d6ac102 100644
--- a/hotspot/src/share/vm/opto/postaloc.cpp
+++ b/hotspot/src/share/vm/opto/postaloc.cpp
@@ -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
diff --git a/hotspot/src/share/vm/opto/stringopts.cpp b/hotspot/src/share/vm/opto/stringopts.cpp
index 1d9bae5..5f7da1f 100644
--- a/hotspot/src/share/vm/opto/stringopts.cpp
+++ b/hotspot/src/share/vm/opto/stringopts.cpp
@@ -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;
diff --git a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp
index be05366..b0c5a43 100644
--- a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp
+++ b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp
@@ -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;
}
}
diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp
index 89680d1..31ab6f5 100644
--- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp
@@ -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) {
diff --git a/hotspot/src/share/vm/prims/perf.cpp b/hotspot/src/share/vm/prims/perf.cpp
index 9ad0f4c..bddb1f7 100644
--- a/hotspot/src/share/vm/prims/perf.cpp
+++ b/hotspot/src/share/vm/prims/perf.cpp
@@ -100,6 +100,11 @@
PerfWrapper("Perf_Detach");
+ if (!UsePerfData) {
+ // With -XX:-UsePerfData, detach is just a NOP
+ return;
+ }
+
void* address = 0;
jlong capacity = 0;
diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp
index 68a729a..f681cce 100644
--- a/hotspot/src/share/vm/prims/unsafe.cpp
+++ b/hotspot/src/share/vm/prims/unsafe.cpp
@@ -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)},
diff --git a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp
index bd78c3d..eb83161 100644
--- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp
+++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp
@@ -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 {
diff --git a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp
index a224511..5ec4063 100644
--- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp
+++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp
@@ -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.
diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp
index 6650090..0c31c9b 100644
--- a/hotspot/src/share/vm/runtime/arguments.cpp
+++ b/hotspot/src/share/vm/runtime/arguments.cpp
@@ -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, Tier0InvokeNotifyFreqLog, scaled_freq_log(Tier0InvokeNotifyFreqLog));
+ FLAG_SET_ERGO(intx, Tier0BackedgeNotifyFreqLog, 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, 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, Tier2InvokeNotifyFreqLog, scaled_freq_log(Tier2InvokeNotifyFreqLog));
+ FLAG_SET_ERGO(intx, Tier2BackedgeNotifyFreqLog, 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, Tier3InvokeNotifyFreqLog, scaled_freq_log(Tier3InvokeNotifyFreqLog));
+ FLAG_SET_ERGO(intx, Tier3BackedgeNotifyFreqLog, scaled_freq_log(Tier3BackedgeNotifyFreqLog));
- FLAG_SET_ERGO(intx, Tier23InlineeNotifyFreqLog, get_scaled_freq_log(Tier23InlineeNotifyFreqLog));
+ FLAG_SET_ERGO(intx, Tier23InlineeNotifyFreqLog, 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, 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));
}
}
diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp
index a0edd81..ae726b8 100644
--- a/hotspot/src/share/vm/runtime/arguments.hpp
+++ b/hotspot/src/share/vm/runtime/arguments.hpp
@@ -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
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index 6d56c2f..dd01436 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -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") \
diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp
index 31cffe2..0a7f654 100644
--- a/hotspot/src/share/vm/runtime/os.cpp
+++ b/hotspot/src/share/vm/runtime/os.cpp
@@ -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();
}
};
diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp
index ecd2e24..67f2226 100644
--- a/hotspot/src/share/vm/runtime/os.hpp
+++ b/hotspot/src/share/vm/runtime/os.hpp
@@ -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() {
diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp
index 11803f1..4b17ca2 100644
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp
+++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp
@@ -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 {
diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp
index 49a9d89..87d009e 100644
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp
+++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp
@@ -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) {
diff --git a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp
index ff0a6cf..05b37c4 100644
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp
+++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp
@@ -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:
diff --git a/hotspot/src/share/vm/runtime/synchronizer.cpp b/hotspot/src/share/vm/runtime/synchronizer.cpp
index a64d5b9..7f829ba 100644
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp
@@ -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);
diff --git a/hotspot/src/share/vm/runtime/synchronizer.hpp b/hotspot/src/share/vm/runtime/synchronizer.hpp
index a823b54..f2ff4c6 100644
--- a/hotspot/src/share/vm/runtime/synchronizer.hpp
+++ b/hotspot/src/share/vm/runtime/synchronizer.hpp
@@ -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
diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp
index b659ec5..d57f1be 100644
--- a/hotspot/src/share/vm/runtime/virtualspace.cpp
+++ b/hotspot/src/share/vm/runtime/virtualspace.cpp
@@ -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));
}
}
diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp
index 182052c..5b3ca8a 100644
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp
@@ -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) \
diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp
index 784db46..652da09 100644
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp
@@ -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;
}
diff --git a/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java b/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java
index b9837c2..5e61102 100644
--- a/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java
+++ b/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java
@@ -54,7 +54,7 @@
//
// Tier0InvokeNotifyFreqLog, Tier0BackedgeNotifyFreqLog,
// Tier3InvocationThreshold, Tier3MinInvocationThreshold,
- // Tier3CompileThreshold, and Tier3BackEdgeThreshold,
+ // Tier3CompileThreshold, Tier3BackEdgeThreshold,
// Tier2InvokeNotifyFreqLog, Tier2BackedgeNotifyFreqLog,
// Tier3InvokeNotifyFreqLog, Tier3BackedgeNotifyFreqLog,
// Tier23InlineeNotifyFreqLog, Tier4InvocationThreshold,
diff --git a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java
index 04551a2..8e390c1 100644
--- a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java
+++ b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java
@@ -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()).
diff --git a/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java b/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java
index b03fbc2..fea786e 100644
--- a/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java
+++ b/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java
@@ -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();
+ }
}
}
diff --git a/hotspot/test/compiler/loopopts/7052494/Test7052494.java b/hotspot/test/compiler/loopopts/7052494/Test7052494.java
index fa45411..62aa12f 100644
--- a/hotspot/test/compiler/loopopts/7052494/Test7052494.java
+++ b/hotspot/test/compiler/loopopts/7052494/Test7052494.java
@@ -25,7 +25,6 @@
/**
* @test
* @bug 7052494
- * @ignore 7154567
* @summary Eclipse test fails on JDK 7 b142
*
* @run main/othervm -Xbatch Test7052494
diff --git a/hotspot/test/compiler/stringopts/TestOptimizeStringConcat.java b/hotspot/test/compiler/stringopts/TestOptimizeStringConcat.java
new file mode 100644
index 0000000..771ffb0
--- /dev/null
+++ b/hotspot/test/compiler/stringopts/TestOptimizeStringConcat.java
@@ -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);
+ }
+}
diff --git a/hotspot/test/compiler/testlibrary/rtm/BusyLock.java b/hotspot/test/compiler/testlibrary/rtm/BusyLock.java
index 55985b6..879edb8 100644
--- a/hotspot/test/compiler/testlibrary/rtm/BusyLock.java
+++ b/hotspot/test/compiler/testlibrary/rtm/BusyLock.java
@@ -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) {
diff --git a/hotspot/test/gc/TestNUMAPageSize.java b/hotspot/test/gc/TestNUMAPageSize.java
index 1a3b5dd..9537f0f 100644
--- a/hotspot/test/gc/TestNUMAPageSize.java
+++ b/hotspot/test/gc/TestNUMAPageSize.java
@@ -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
diff --git a/hotspot/test/gc/TestSmallHeap.java b/hotspot/test/gc/TestSmallHeap.java
index 170b539..abe6ed3 100644
--- a/hotspot/test/gc/TestSmallHeap.java
+++ b/hotspot/test/gc/TestSmallHeap.java
@@ -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
diff --git a/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java b/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java
index c4a81e2..c24b3ec 100644
--- a/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java
+++ b/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java
@@ -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;
}
diff --git a/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java b/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java
index 9ce9f76..2ad3fc1 100644
--- a/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java
+++ b/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java
@@ -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\\)");
}
diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java
index 1a96dd8..3bd7cf3 100644
--- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java
+++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java
@@ -25,6 +25,7 @@
* @test CompilerQueueTest
* @bug 8054889
* @library ..
+ * @ignore 8069160
* @build DcmdUtil CompilerQueueTest
* @run main CompilerQueueTest
* @run main/othervm -XX:-TieredCompilation CompilerQueueTest
diff --git a/jaxp/.hgtags b/jaxp/.hgtags
index c0eb212..664424c 100644
--- a/jaxp/.hgtags
+++ b/jaxp/.hgtags
@@ -290,3 +290,4 @@
0dab3e848229127c7aca4c58b98e2d90ba70372f jdk9-b45
74eaf7ad986576c792df4dbff05eed63e5727695 jdk9-b46
e391de88e69b59d7c618387e3cf91032f6991ce9 jdk9-b47
+833051855168a973780fafeb6fc59e7370bcf400 jdk9-b48
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java
index 74acd2a..8d05e9e 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/BasisLibrary.java
@@ -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;
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java
index dc64401..a87728d 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java
@@ -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 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 com.sun.org.apache.xpath.internal.objects.XObject;
import javax.xml.namespace.QName;
-import javax.xml.xpath.XPathExpressionException;
+import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathEvaluationResult;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFunctionResolver;
import javax.xml.xpath.XPathVariableResolver;
-import javax.xml.xpath.XPathConstants;
-
-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.w3c.dom.Node;
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.
- */
+
+ @Override
public String evaluate(Object item)
throws XPathExpressionException {
- return (String)this.evaluate( item, XPathConstants.STRING );
+ 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>.
- */
+ @Override
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 );
- }
+ isSupported (returnType);
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 );
+ Document document = getDocument(source);
+ return eval(document, returnType);
+ } catch (TransformerException 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(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;
- }
- return false;
- }
+ try {
+ XObject resultObject = eval(item, xpath);
+ if (type.isAssignableFrom(XPathEvaluationResult.class)) {
+ return getXPathResult(resultObject, type);
+ } else {
+ return XPathResultImpl.getValue(resultObject, type);
+ }
- private Object getResultAsType( XObject resultObject, QName returnType )
- throws javax.xml.transform.TransformerException {
- // XPathConstants.STRING
- if ( returnType.equals( XPathConstants.STRING ) ) {
- return resultObject.str();
+ } catch (javax.xml.transform.TransformerException te) {
+ throw new XPathExpressionException(te);
}
- // 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);
+ }
}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java
index ebd6b2c..1bbfef4 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java
@@ -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
+ *
+ * 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;
-
- 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);
- }
- }
-
-
- 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>
- *
+ * Evaluate an {@code XPath} expression in the specified context.
* @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>.
+ * @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);
+
+ return eval(contextItem, xpath);
+ }
+
+ //-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 );
- }
-
-
-
- /**
- * <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>.
- */
+ //-Override-
public String evaluate(String expression, Object item)
throws XPathExpressionException {
- return (String)this.evaluate( expression, item, XPathConstants.STRING );
+ 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);
+ }
}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java
new file mode 100644
index 0000000..da4cdfc
--- /dev/null
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImplUtil.java
@@ -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);
+ }
+ }
+}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java
new file mode 100644
index 0000000..14c291f
--- /dev/null
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java
@@ -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;
+ }
+}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathResultImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathResultImpl.java
new file mode 100644
index 0000000..4953702
--- /dev/null
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathResultImpl.java
@@ -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;
+ }
+}
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java
index 90ba4fe..6e77e23 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPath.java
@@ -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 org.xml.sax.InputSource;
-import javax.xml.namespace.QName;
import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import org.xml.sax.InputSource;
/**
- * <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);
+ }
}
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java
new file mode 100644
index 0000000..7454739
--- /dev/null
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathEvaluationResult.java
@@ -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();
+
+}
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java
index 0f980f6..a7625ec 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathExpression.java
@@ -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 org.xml.sax.InputSource;
import javax.xml.namespace.QName;
+import org.xml.sax.InputSource;
/**
- * <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);
+ }
}
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java
index ce2074b..ea7370e 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactory.java
@@ -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>
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java
index 282f0b0..bceeda8 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java
@@ -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);
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java
new file mode 100644
index 0000000..6f1db4e
--- /dev/null
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathNodes.java
@@ -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;
+}
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html b/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html
index 82415a2..af0d152 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/package.html
@@ -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.
-->
-
-<!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 bgcolor="white">
-<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);
-</pre>
-<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>
+//or using the evaluateExpression method
+Node manufacturerNode = xpath.evaluateExpression(expression, <strong>widgetNode</strong>, Node.class);
+</pre>
+</blockquote>
+
+<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>
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java
new file mode 100644
index 0000000..de285f2
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/SchemaFactoryTest.java
@@ -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;
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/TypeInfoProviderTest.java b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/TypeInfoProviderTest.java
new file mode 100644
index 0000000..d34c708
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/TypeInfoProviderTest.java
@@ -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));
+ }
+
+ }
+
+ }
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorHandlerTest.java b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorHandlerTest.java
new file mode 100644
index 0000000..3b48a21
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorHandlerTest.java
@@ -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;
+
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorTest.java b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorTest.java
new file mode 100644
index 0000000..c455f07
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/ptests/ValidatorTest.java
@@ -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;
+
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xml b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xml
new file mode 100644
index 0000000..0a00dbd
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xml
@@ -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
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xsd b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xsd
new file mode 100644
index 0000000..7281dbd
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder11.xsd
@@ -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
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xml b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xml
new file mode 100644
index 0000000..0a00dbd
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xml
@@ -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
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xsd b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xsd
new file mode 100644
index 0000000..7281dbd
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/shiporder12.xsd
@@ -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
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xml b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xml
new file mode 100644
index 0000000..8ad2861
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xml
@@ -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>
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xsd b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xsd
new file mode 100644
index 0000000..1671283
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test.xsd
@@ -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>
diff --git a/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test1.xsd b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test1.xsd
new file mode 100644
index 0000000..9f172d2
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/javax/xml/validation/xmlfiles/test1.xsd
@@ -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>
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4511326.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4511326.java
new file mode 100644
index 0000000..fec94a1
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4511326.java
@@ -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);
+ }
+
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4512806.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4512806.java
new file mode 100644
index 0000000..631b091
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4512806.java
@@ -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>";
+
+
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515047.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515047.java
new file mode 100644
index 0000000..0b822c8
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515047.java
@@ -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);
+ }
+
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515660.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515660.java
new file mode 100644
index 0000000..6f2c314
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4515660.java
@@ -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 javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+
+import jaxp.library.JAXPBaseTest;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.XMLFilterImpl;
+
+/*
+ * @bug 4515660
+ * @summary verify property org.xml.sax.driver is used by SAXTransformerFactory
+ */
+@Test(singleThreaded = true)
+public class Bug4515660 extends JAXPBaseTest {
+
+ @BeforeClass
+ public void setSaxDrier() {
+ setSystemProperty("org.xml.sax.driver", ReaderStub.class.getName());
+ }
+
+ @AfterClass
+ public void clearSaxDrier() {
+ setSystemProperty("org.xml.sax.driver", null);
+ }
+
+ @Test
+ public void testTransformer() throws TransformerException {
+ String xml = "<?xml version='1.0'?><root/>";
+ ReaderStub.used = false;
+
+ TransformerFactory transFactory = TransformerFactory.newInstance();
+ Transformer transformer = transFactory.newTransformer();
+ InputSource in = new InputSource(new StringReader(xml));
+ SAXSource source = new SAXSource(in);
+ StreamResult result = new StreamResult(new StringWriter());
+
+ transformer.transform(source, result);
+
+ assertTrue(ReaderStub.used);
+
+ }
+
+ @Test
+ public void testSAXTransformerFactory() throws TransformerConfigurationException {
+ final String xsl = "<?xml version='1.0'?>\n" + "<xsl:stylesheet" + " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'" + " version='1.0'>\n"
+ + " <xsl:template match='/'>Hello World!</xsl:template>\n" + "</xsl:stylesheet>\n";
+
+ ReaderStub.used = false;
+
+ TransformerFactory transFactory = TransformerFactory.newInstance();
+ assertTrue(transFactory.getFeature(SAXTransformerFactory.FEATURE));
+
+ InputSource in = new InputSource(new StringReader(xsl));
+ SAXSource source = new SAXSource(in);
+
+ transFactory.newTransformer(source);
+ assertTrue(ReaderStub.used);
+
+ }
+
+ public static class ReaderStub extends XMLFilterImpl {
+ static boolean used = false;
+
+ public ReaderStub() throws ParserConfigurationException, SAXException {
+ super();
+ super.setParent(SAXParserFactory.newInstance().newSAXParser().getXMLReader());
+ used = true;
+ }
+
+ public void parse(InputSource input) throws SAXException, IOException {
+ used = true;
+ super.parse(input);
+ }
+
+ public void parse(String systemId) throws SAXException, IOException {
+ used = true;
+ super.parse(systemId);
+ }
+ }
+
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4693341.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4693341.java
new file mode 100644
index 0000000..d7d586b
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4693341.java
@@ -0,0 +1,79 @@
+/*
+ * 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 java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static jaxp.library.JAXPTestUtilities.USER_DIR;
+import static jaxp.library.JAXPTestUtilities.compareDocumentWithGold;
+import static org.testng.Assert.assertTrue;
+import static test.gaptest.GapTestConst.GOLDEN_DIR;
+import static test.gaptest.GapTestConst.XML_DIR;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import jaxp.library.JAXPFileBaseTest;
+
+import org.testng.annotations.Test;
+import org.xml.sax.SAXException;
+
+/*
+ * @bug 4693341
+ * @summary test transforming to stream with external dtd
+ */
+
+public class Bug4693341 extends JAXPFileBaseTest {
+
+ @Test
+ public void test() throws TransformerException, ParserConfigurationException, SAXException, IOException {
+
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+
+ String out = USER_DIR + File.separator + "Bug4693341.out";
+ StreamResult result = new StreamResult(new File(out));
+
+ String in = XML_DIR + "Bug4693341.xml";
+ String golden = GOLDEN_DIR + "Bug4693341.xml";
+ File file = new File(in);
+ StreamSource source = new StreamSource(file);
+ System.out.println(source.getSystemId());
+
+ Files.copy(Paths.get(XML_DIR + "Bug4693341.dtd"),
+ Paths.get(USER_DIR + File.separator + "Bug4693341.dtd"), REPLACE_EXISTING);
+
+ transformer.transform(source, result);
+
+ assertTrue(compareDocumentWithGold(golden, out));
+ }
+
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4848653.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4848653.java
new file mode 100644
index 0000000..f4de775
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4848653.java
@@ -0,0 +1,80 @@
+/*
+ * 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 jaxp.library.JAXPTestUtilities.filenameToURL;
+import static test.gaptest.GapTestConst.XML_DIR;
+
+import java.io.IOException;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import jaxp.library.JAXPFileBaseTest;
+
+import org.testng.annotations.Test;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+
+/*
+ * @bug 4848653
+ * @summary Verify JAXP schemaLanguage property is ignored if setValidating(false)
+ */
+
+public class Bug4848653 extends JAXPFileBaseTest {
+
+ @Test
+ public void test() throws IOException, SAXException, ParserConfigurationException {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setValidating(false);
+ SAXParser parser = factory.newSAXParser();
+ parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", XMLConstants.W3C_XML_SCHEMA_NS_URI);
+
+ String filename = XML_DIR + "Bug4848653.xml";
+ InputSource is = new InputSource(filenameToURL(filename));
+ XMLReader xmlReader = parser.getXMLReader();
+ xmlReader.setErrorHandler(new MyErrorHandler());
+ xmlReader.parse(is);
+ }
+
+ class MyErrorHandler implements ErrorHandler {
+ public void error(SAXParseException exception) throws SAXParseException {
+ throw exception;
+ }
+
+ public void warning(SAXParseException exception) throws SAXParseException {
+ throw exception;
+ }
+
+ public void fatalError(SAXParseException exception) throws SAXParseException {
+ throw exception;
+ }
+
+ }
+
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4858685.java b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4858685.java
new file mode 100644
index 0000000..5dd5401
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/Bug4858685.java
@@ -0,0 +1,246 @@
+/*
+ * 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 jaxp.library.JAXPTestUtilities.filenameToURL;
+import static org.testng.Assert.assertEquals;
+import static test.gaptest.GapTestConst.GOLDEN_DIR;
+import static test.gaptest.GapTestConst.XML_DIR;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.stream.StreamSource;
+
+import jaxp.library.JAXPFileBaseTest;
+
+import org.testng.annotations.Test;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/*
+ * @bug 4858685 4894410
+ * @summary test transforming text node
+ */
+
+public class Bug4858685 extends JAXPFileBaseTest {
+ @Test
+ public void test() throws TransformerException, IOException {
+ String uri = XML_DIR + "certificate.xml";
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+
+ Transformer transformer = transformerFactory.newTransformer();
+
+ // use URI as a StreamSource
+ StreamSource streamSource = new StreamSource(filenameToURL(uri));
+
+ DOMResult domResult = new DOMResult();
+
+ // StreamSource -> DOMResult
+ transformer.transform(streamSource, domResult);
+
+ // dump DOM in a human readable form
+ String gotString = DOMDump.dumpDom(domResult.getNode());
+
+ String goldenString = new String(Files.readAllBytes(Paths.get(GOLDEN_DIR + "Bug4858685.txt")));
+
+ assertEquals(gotString, goldenString);
+
+ }
+
+ /**
+ * DOMDump: dump a DOM to a String in human readable form. method dumpDOM()
+ * is static for easy calling:
+ */
+ private static class DOMDump {
+
+ /**
+ * the maximum level to indent with blanks
+ */
+ private static final int BLANKS_LEN = 64;
+
+ /**
+ * each level of the tree will be indented with blanks for readability
+ */
+ private static final String BLANKS = " ";
+
+ /**
+ * dumpDOM will dump the DOM into a String for human readability
+ *
+ * @param domNode
+ * the DOM Node to dump
+ * @return human readabile DOM as a String
+ */
+ public static String dumpDom(Node domNode) {
+ return dumpInternal(domNode, 0);
+ }
+
+ /**
+ * dumpInternal is used internaly to recursively dump DOM Nodes
+ *
+ * @param domNode
+ * to dump
+ * @param indent
+ * level
+ * @return domNode as human readable String
+ */
+ private static String dumpInternal(Node domNode, int indent) {
+
+ String result = "";
+
+ // indent for readability
+ result += indentBlanks(indent);
+ indent += 2;
+
+ // protect against null
+ if (domNode == null) {
+ result = result + "[null]" + "\n";
+ return result;
+ }
+
+ // what to output depends on NodeType
+ short type = domNode.getNodeType();
+ switch (type) {
+ case Node.ATTRIBUTE_NODE: {
+ result += "[attribute] " + domNode.getNodeName() + "=\"" + domNode.getNodeValue() + "\"";
+ break;
+ }
+ case Node.CDATA_SECTION_NODE: {
+ result += "[cdata] " + domNode.getNodeValue();
+ break;
+ }
+ case Node.COMMENT_NODE: {
+ result += "[comment] " + domNode.getNodeValue();
+ break;
+ }
+ case Node.DOCUMENT_FRAGMENT_NODE: {
+ result += "[document fragment]";
+ break;
+ }
+ case Node.DOCUMENT_NODE: {
+ result += "[document]";
+ break;
+ }
+ case Node.DOCUMENT_TYPE_NODE: {
+ result += "[document type] " + domNode.getNodeName();
+ break;
+ }
+ case Node.ELEMENT_NODE: {
+ result += "[element] " + domNode.getNodeName();
+ // output all attributes for Element
+ if (domNode.hasAttributes()) {
+ NamedNodeMap attributes = domNode.getAttributes();
+ for (int onAttribute = 0; onAttribute < attributes.getLength(); onAttribute++) {
+
+ // seprate each attribute with a space
+ result += " ";
+
+ Node attribute = attributes.item(onAttribute);
+ String namespaceURI = attribute.getNamespaceURI();
+ String prefix = attribute.getPrefix();
+ String localName = attribute.getLocalName();
+ String name = attribute.getNodeName();
+ String value = attribute.getNodeValue();
+
+ // using Namespaces?
+ if (namespaceURI != null) {
+ result += "{" + namespaceURI + "}";
+ }
+ if (prefix != null) {
+ result += prefix + ":";
+ }
+
+ // name="value"
+ result += attribute.getNodeName() + "=\"" + attribute.getNodeValue() + "\"";
+ }
+ }
+
+ break;
+ }
+ case Node.ENTITY_NODE: {
+ result += "[entity] " + domNode.getNodeName();
+ break;
+ }
+ case Node.ENTITY_REFERENCE_NODE: {
+ result += "[entity reference] " + domNode.getNodeName();
+ break;
+ }
+ case Node.NOTATION_NODE: {
+ result += "[notation] " + domNode.getNodeName();
+ break;
+ }
+ case Node.PROCESSING_INSTRUCTION_NODE: {
+ result += "[pi] target=\"" + domNode.getNodeName() + "\" content=\"" + domNode.getNodeValue() + "\"";
+ break;
+ }
+ case Node.TEXT_NODE: {
+ result += "[text] " + domNode.getNodeValue();
+ break;
+ }
+ default: {
+ result += "[unknown]";
+ break;
+ }
+ }
+
+ // humans read in lines
+ result += "\n";
+
+ // process children
+ NodeList children = domNode.getChildNodes();
+ for (int onChild = 0; onChild < children.getLength(); onChild++) {
+ Node child = children.item(onChild);
+ result += dumpInternal(child, indent);
+ }
+
+ // return human readable DOM as String
+ return result;
+ }
+
+ /**
+ * indentBlanks will return a String of indent blanks
+ *
+ * @param indent
+ * level
+ * @return String of blanks
+ */
+ private static String indentBlanks(int indent) {
+ if (indent == 0) {
+ return "";
+ }
+
+ if (indent > BLANKS_LEN) {
+ return BLANKS;
+ }
+
+ return BLANKS.substring(0, indent + 1);
+ }
+
+ }
+}
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.dtd b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.dtd
new file mode 100644
index 0000000..23e6411
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.dtd
@@ -0,0 +1,39 @@
+<!ELEMENT SupplierOrder (OrderId, OrderDate, ShippingAddress, LineItems)>
+
+<!ELEMENT OrderId (#PCDATA)>
+
+<!ELEMENT OrderDate (#PCDATA)>
+
+<!ELEMENT ShippingAddress (FirstName, LastName, Street, City, State, Country, ZipCode, Email, Phone)>
+
+<!ELEMENT FirstName (#PCDATA)>
+
+<!ELEMENT LastName (#PCDATA)>
+
+<!ELEMENT Street (#PCDATA)>
+
+<!ELEMENT City (#PCDATA)>
+
+<!ELEMENT State (#PCDATA)>
+
+<!ELEMENT Country (#PCDATA)>
+
+<!ELEMENT ZipCode (#PCDATA)>
+
+<!ELEMENT Email (#PCDATA)>
+
+<!ELEMENT Phone (#PCDATA)>
+
+<!ELEMENT LineItems (LineItem+)>
+
+<!ELEMENT LineItem EMPTY>
+
+<!ATTLIST LineItem
+ categoryId CDATA #REQUIRED
+ productId CDATA #REQUIRED
+ itemId CDATA #REQUIRED
+ lineNo CDATA #REQUIRED
+ quantity CDATA #REQUIRED
+ unitPrice CDATA #REQUIRED
+>
+
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.xml b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.xml
new file mode 100644
index 0000000..96fad23
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4693341.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE SupplierOrder SYSTEM "Bug4693341.dtd" >
+<SupplierOrder>
+<OrderId>10016</OrderId>
+<OrderDate>Wed May 29 12:45:00 PDT 2002</OrderDate>
+<ShippingAddress>
+<FirstName>ABC</FirstName>
+<LastName>XYZ</LastName>
+<Street>1234 Anywhere Street</Street>
+<City>Palo Alto</City>
+<State>California</State>
+<Country>USA</Country>
+<ZipCode>94303</ZipCode>
+<Email>NULL</Email>
+<Phone>NULL</Phone>
+</ShippingAddress>
+<LineItems>
+<LineItem categoryId="BIRDS" itemId="EST-18" lineNo="0" productId="AV-CB-01" quantity="1" unitPrice="193.5"/>
+</LineItems>
+</SupplierOrder>
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4848653.xml b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4848653.xml
new file mode 100644
index 0000000..d80a5e2
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/Bug4848653.xml
@@ -0,0 +1 @@
+<a/>
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/certificate.xml b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/certificate.xml
new file mode 100644
index 0000000..e56e16a
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/certificate.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<env:Envelope xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:ns0="http://headertest.org/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <env:Body>
+ <ds:X509Certificate xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
+MIIDVjCCAxICBD6kKrMwCwYHKoZIzjgEAwUAMIGPMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
+FDASBgNVBAcTC1NhbnRhIENsYXJhMR8wHQYDVQQKExZTdW4gTWljcm9zeXN0ZW1zLCBJbmMuMR4w
+HAYDVQQLExVKYXZhIGFuZCBYTUwgU29mdHdhcmUxHDAaBgNVBAMTE0pXUy1TZWN1cml0eSBDbGll
+bnQwHhcNMDMwNDIxMTczMDI3WhcNMDMwNzIwMTczMDI3WjCBjzELMAkGA1UEBhMCVVMxCzAJBgNV
+BAgTAkNBMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEfMB0GA1UEChMWU3VuIE1pY3Jvc3lzdGVtcywg
+SW5jLjEeMBwGA1UECxMVSmF2YSBhbmQgWE1MIFNvZnR3YXJlMRwwGgYDVQQDExNKV1MtU2VjdXJp
+dHkgQ2xpZW50MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E
+AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up
+1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUj
+C8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZ
+T+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7
+zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAV3R+bUfh+u0yaPBV75umKvFB
+ucv37ETDak889b7k72kZdGoHz3oDmp69tiNDg5r7IvKtjHGbZ6C3Nv0ycNR7Sed1QPOF4nn/tgUl
+j+BvtVW3iiIRgBJ82KP+28QtwPkkxSp7n5HG0v7bE29E/juLduuhKBQTaaCvajuCFxiBrmAwCwYH
+KoZIzjgEAwUAAzEAMC4CFQCCuDNmMKjgY6MV1SmAcCdnhuT6VwIVAJBOiPDnDWp2WlKAERF6nOAf
+vKz9
+ </ds:X509Certificate>
+ </env:Body>
+</env:Envelope>
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.dtd b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.dtd
new file mode 100644
index 0000000..23e6411
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.dtd
@@ -0,0 +1,39 @@
+<!ELEMENT SupplierOrder (OrderId, OrderDate, ShippingAddress, LineItems)>
+
+<!ELEMENT OrderId (#PCDATA)>
+
+<!ELEMENT OrderDate (#PCDATA)>
+
+<!ELEMENT ShippingAddress (FirstName, LastName, Street, City, State, Country, ZipCode, Email, Phone)>
+
+<!ELEMENT FirstName (#PCDATA)>
+
+<!ELEMENT LastName (#PCDATA)>
+
+<!ELEMENT Street (#PCDATA)>
+
+<!ELEMENT City (#PCDATA)>
+
+<!ELEMENT State (#PCDATA)>
+
+<!ELEMENT Country (#PCDATA)>
+
+<!ELEMENT ZipCode (#PCDATA)>
+
+<!ELEMENT Email (#PCDATA)>
+
+<!ELEMENT Phone (#PCDATA)>
+
+<!ELEMENT LineItems (LineItem+)>
+
+<!ELEMENT LineItem EMPTY>
+
+<!ATTLIST LineItem
+ categoryId CDATA #REQUIRED
+ productId CDATA #REQUIRED
+ itemId CDATA #REQUIRED
+ lineNo CDATA #REQUIRED
+ quantity CDATA #REQUIRED
+ unitPrice CDATA #REQUIRED
+>
+
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.xml b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.xml
new file mode 100644
index 0000000..96fad23
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4693341.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE SupplierOrder SYSTEM "Bug4693341.dtd" >
+<SupplierOrder>
+<OrderId>10016</OrderId>
+<OrderDate>Wed May 29 12:45:00 PDT 2002</OrderDate>
+<ShippingAddress>
+<FirstName>ABC</FirstName>
+<LastName>XYZ</LastName>
+<Street>1234 Anywhere Street</Street>
+<City>Palo Alto</City>
+<State>California</State>
+<Country>USA</Country>
+<ZipCode>94303</ZipCode>
+<Email>NULL</Email>
+<Phone>NULL</Phone>
+</ShippingAddress>
+<LineItems>
+<LineItem categoryId="BIRDS" itemId="EST-18" lineNo="0" productId="AV-CB-01" quantity="1" unitPrice="193.5"/>
+</LineItems>
+</SupplierOrder>
diff --git a/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4858685.txt b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4858685.txt
new file mode 100644
index 0000000..91ee2de
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/functional/test/gaptest/xmlfiles/out/Bug4858685.txt
@@ -0,0 +1,30 @@
+[document]
+ [element] env:Envelope {http://www.w3.org/2000/xmlns/}xmlns:xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:ns0="http://headertest.org/" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:xsd="http://www.w3.org/2001/XMLSchema" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ [text]
+
+ [element] env:Body
+ [text]
+
+ [element] ds:X509Certificate xmlns="" {http://www.w3.org/2000/xmlns/}xmlns:xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ [text]
+MIIDVjCCAxICBD6kKrMwCwYHKoZIzjgEAwUAMIGPMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex
+FDASBgNVBAcTC1NhbnRhIENsYXJhMR8wHQYDVQQKExZTdW4gTWljcm9zeXN0ZW1zLCBJbmMuMR4w
+HAYDVQQLExVKYXZhIGFuZCBYTUwgU29mdHdhcmUxHDAaBgNVBAMTE0pXUy1TZWN1cml0eSBDbGll
+bnQwHhcNMDMwNDIxMTczMDI3WhcNMDMwNzIwMTczMDI3WjCBjzELMAkGA1UEBhMCVVMxCzAJBgNV
+BAgTAkNBMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEfMB0GA1UEChMWU3VuIE1pY3Jvc3lzdGVtcywg
+SW5jLjEeMBwGA1UECxMVSmF2YSBhbmQgWE1MIFNvZnR3YXJlMRwwGgYDVQQDExNKV1MtU2VjdXJp
+dHkgQ2xpZW50MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E
+AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up
+1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUj
+C8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZ
+T+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7
+zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAV3R+bUfh+u0yaPBV75umKvFB
+ucv37ETDak889b7k72kZdGoHz3oDmp69tiNDg5r7IvKtjHGbZ6C3Nv0ycNR7Sed1QPOF4nn/tgUl
+j+BvtVW3iiIRgBJ82KP+28QtwPkkxSp7n5HG0v7bE29E/juLduuhKBQTaaCvajuCFxiBrmAwCwYH
+KoZIzjgEAwUAAzEAMC4CFQCCuDNmMKjgY6MV1SmAcCdnhuT6VwIVAJBOiPDnDWp2WlKAERF6nOAf
+vKz9
+
+ [text]
+
+ [text]
+
diff --git a/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/MyErrorHandler.java b/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/MyErrorHandler.java
new file mode 100644
index 0000000..1efbf95
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/MyErrorHandler.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * 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 org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXParseException;
+
+class MyErrorHandler implements ErrorHandler {
+ public void error(SAXParseException exception) throws SAXParseException {
+ throw exception;
+ }
+
+ public void warning(SAXParseException exception) throws SAXParseException {
+ throw exception;
+ }
+
+ public void fatalError(SAXParseException exception) throws SAXParseException {
+ throw exception;
+ }
+}
diff --git a/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/ValidationTestConst.java b/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/ValidationTestConst.java
new file mode 100644
index 0000000..50f4c86
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/libs/javax/xml/validation/ptests/ValidationTestConst.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ *
+ * 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 jaxp.library.JAXPTestUtilities.FILE_SEP;
+import static jaxp.library.JAXPTestUtilities.getPathByClassName;
+
+/**
+ * This class defines the path constant
+ */
+public class ValidationTestConst {
+ /**
+ * XML source file directory.
+ */
+ public static final String XML_DIR = getPathByClassName(ValidationTestConst.class,
+ ".." + FILE_SEP + "xmlfiles");
+
+ /**
+ * Golden validation files directory.
+ */
+ public static final String GOLDEN_DIR = getPathByClassName(ValidationTestConst.class,
+ ".." + FILE_SEP + "xmlfiles" + FILE_SEP + "out");
+}
diff --git a/jaxp/test/javax/xml/jaxp/libs/test/gaptest/GapTestConst.java b/jaxp/test/javax/xml/jaxp/libs/test/gaptest/GapTestConst.java
new file mode 100644
index 0000000..237d0ac
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/libs/test/gaptest/GapTestConst.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ * 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 jaxp.library.JAXPTestUtilities.FILE_SEP;
+import static jaxp.library.JAXPTestUtilities.getPathByClassName;
+
+/**
+ * This class defines the path constant
+ */
+public class GapTestConst {
+ /**
+ * XML source file directory.
+ */
+ public static final String XML_DIR = getPathByClassName(GapTestConst.class, "xmlfiles");
+
+ /**
+ * Golden validation files directory.
+ */
+ public static final String GOLDEN_DIR = getPathByClassName(GapTestConst.class, "xmlfiles" + FILE_SEP + "out");
+}
diff --git a/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathAnyTypeTest.java b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathAnyTypeTest.java
new file mode 100644
index 0000000..ef56ca9
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathAnyTypeTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ *
+ * 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.io.File;
+import javax.xml.xpath.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import org.testng.annotations.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/*
+ * @bug 8054196
+ * @summary Test for the project XPath: support any type. This test covers the new
+ * evaluateExpression methods of XPath, as well as XPathNodes and XPathEvaluationResult.
+ */
+public class XPathAnyTypeTest extends XPathTestBase {
+ /*
+ Test for resolveFunction(QName functionName,int arity); evaluate throws
+ NPE if functionName is null.
+ */
+
+ @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class)
+ public void testCheckXPathFunctionResolver02(XPath xpath) throws XPathExpressionException {
+ xpath.setXPathFunctionResolver((functionName, arity) -> null);
+ assertEquals(xpath.evaluate(null, "5"), "2");
+ }
+ /*
+ Check that NPE is thrown when expression is null.
+ */
+
+ @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class)
+ public void test01(XPath xpath) throws XPathExpressionException {
+ double result = xpath.evaluateExpression(null, (Object) null, Double.class);
+ }
+
+ /*
+ Check that NPE is thrown when the class type is null.
+ */
+ @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class)
+ public void test02(XPath xpath) throws XPathExpressionException {
+ double result = xpath.evaluateExpression("1+1", (Object) null, null);
+ }
+
+ /*
+ Parameter item can be null when the expression does not depends on the
+ context.
+ */
+ @Test(dataProvider = "xpath")
+ public void test03(XPath xpath) throws XPathExpressionException {
+ int result = xpath.evaluateExpression("1+1", (Object) null, Integer.class);
+ assertTrue(result == 2);
+ }
+
+ /*
+ * Test return type: boolean.
+ */
+ @Test(dataProvider = "document")
+ public void test04(XPath xpath, Document doc) throws XPathExpressionException {
+ boolean result1 = xpath.evaluateExpression("boolean(/Customers/Customer[@id=3])", doc, Boolean.class);
+ assertTrue(result1);
+ }
+
+ /*
+ * Test return type: numeric. Subtypes supported: Double, Integer and Long
+ */
+ @Test(dataProvider = "document")
+ public void test05(XPath xpath, Document doc) throws XPathExpressionException {
+ double result1 = xpath.evaluateExpression("count(/Customers/Customer)", doc, Double.class);
+ assertTrue(result1 == 3.0);
+ int result2 = xpath.evaluateExpression("count(/Customers/Customer)", doc, Integer.class);
+ assertTrue(result2 == 3);
+ long result3 = xpath.evaluateExpression("count(/Customers/Customer)", doc, Long.class);
+ assertTrue(result3 == 3);
+ }
+
+ /*
+ * Test return type: numeric. Of the subtypes of Number, only Double,
+ * Integer and Long are required.
+ */
+ @Test(dataProvider = "invalidNumericTypes", expectedExceptions = IllegalArgumentException.class)
+ public void test06(XPath xpath, Class<Number> type) throws XPathExpressionException {
+ xpath.evaluateExpression("1+1", (Object) null, type);
+ }
+
+ /*
+ * Test return type: String.
+ */
+ @Test(dataProvider = "document")
+ public void test07(XPath xpath, Document doc) throws XPathExpressionException {
+ String result1 = xpath.evaluateExpression("string(/Customers/Customer[@id=3]/Phone/text())", doc, String.class);
+ assertTrue(result1.equals("3333333333"));
+ }
+
+ /*
+ * Test return type: NodeSet.
+ */
+ @Test(dataProvider = "document")
+ public void test08(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathNodes nodes = xpath.evaluateExpression("/Customers/Customer", doc, XPathNodes.class);
+ assertTrue(nodes.size() == 3);
+ for (Node n : nodes) {
+ assertEquals(n.getLocalName(), "Customer");
+ }
+ }
+
+ /*
+ * Test return type: Node.
+ */
+ @Test(dataProvider = "document")
+ public void test09(XPath xpath, Document doc) throws XPathExpressionException {
+ Node n = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc, Node.class);
+ assertEquals(n.getLocalName(), "Customer");
+ }
+
+ /*
+ * Test return type: Unsupported type.
+ */
+ @Test(dataProvider = "document", expectedExceptions = IllegalArgumentException.class)
+ public void test10(XPath xpath, Document doc) throws XPathExpressionException {
+ File n = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc, File.class);
+ }
+
+ /*
+ * Test return type: Any::Boolean.
+ */
+ @Test(dataProvider = "document")
+ public void test11(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathEvaluationResult<?> result = xpath.evaluateExpression("boolean(/Customers/Customer[@id=3])", doc);
+ verifyResult(result, true);
+ }
+
+ /*
+ * Test return type: Any::Number.
+ */
+ @Test(dataProvider = "document")
+ public void test12(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathEvaluationResult<?> result = xpath.evaluateExpression("count(/Customers/Customer)", doc);
+ verifyResult(result, 3.0);
+ }
+
+ /*
+ * Test return type: Any::String.
+ */
+ @Test(dataProvider = "document")
+ public void test13(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathEvaluationResult<?> result = xpath.evaluateExpression(
+ "string(/Customers/Customer[@id=3]/Phone/text())", doc, XPathEvaluationResult.class);
+ verifyResult(result, "3333333333");
+ }
+
+ /*
+ * Test return type: Any::Nodeset.
+ */
+ @Test(dataProvider = "document")
+ public void test14(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathEvaluationResult<?> result = xpath.evaluateExpression("/Customers/Customer", doc);
+ verifyResult(result, "Customer");
+ }
+
+ /*
+ * Test return type: Any::Node.
+ */
+ @Test(dataProvider = "document")
+ public void test15(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathEvaluationResult<?> result = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc);
+ verifyResult(result, "Customer");
+ }
+}
diff --git a/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathExpAnyTypeTest.java b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathExpAnyTypeTest.java
new file mode 100644
index 0000000..0eb8047
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathExpAnyTypeTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ *
+ * 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.io.File;
+import javax.xml.xpath.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import org.testng.annotations.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/*
+ * @bug 8054196
+ * @summary Test for the project XPath: support any type. This test covers the new
+ * evaluateExpression methods of XPathExpression.
+ */
+public class XPathExpAnyTypeTest extends XPathTestBase {
+
+ /*
+ * Check that NPE is thrown when the class type is null.
+ */
+ @Test(dataProvider = "xpath", expectedExceptions = NullPointerException.class)
+ public void test02(XPath xpath) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("1+1");
+ double result = exp.evaluateExpression((Object)null, null);
+ }
+
+ /*
+ * Parameter item can be null when the expression does not depends on the
+ * context.
+ */
+ @Test(dataProvider = "xpath")
+ public void test03(XPath xpath) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("1+1");
+ int result = exp.evaluateExpression((Object)null, Integer.class);
+ assertTrue(result == 2);
+ }
+
+ /*
+ * Test return type: boolean.
+ */
+ @Test(dataProvider = "document")
+ public void test04(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=3])");
+ boolean result1 = exp.evaluateExpression(doc, Boolean.class);
+ assertTrue(result1);
+ }
+
+ /*
+ * Test return type: numeric.
+ */
+ @Test(dataProvider = "document")
+ public void test05(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("count(/Customers/Customer)");
+ double result1 = exp.evaluateExpression(doc, Double.class);
+ assertTrue(result1 == 3.0);
+
+ int result2 = exp.evaluateExpression(doc, Integer.class);
+ assertTrue(result2 == 3);
+ }
+
+ /*
+ * Test return type: String.
+ */
+ @Test(dataProvider = "document")
+ public void test06(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=3]/Phone/text())");
+ String result1 = exp.evaluateExpression(doc, String.class);
+ assertTrue(result1.equals("3333333333"));
+ }
+
+ /*
+ * Test return type: NodeSet.
+ */
+ @Test(dataProvider = "document")
+ public void test07(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("/Customers/Customer");
+ XPathNodes nodes = exp.evaluateExpression(doc, XPathNodes.class);
+ assertTrue(nodes.size() == 3);
+ for (Node n : nodes) {
+ assertEquals(n.getLocalName(), "Customer");
+ }
+ }
+
+ /*
+ * Test return type: Node.
+ */
+ @Test(dataProvider = "document")
+ public void test08(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]");
+ Node n = exp.evaluateExpression(doc, Node.class);
+ assertEquals(n.getLocalName(), "Customer");
+ }
+
+ /*
+ * Test return type: Unsupported type.
+ */
+ @Test(dataProvider = "document", expectedExceptions = IllegalArgumentException.class)
+ public void test09(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]");
+ File n = exp.evaluateExpression(doc, File.class);
+ }
+
+ /*
+ * Test return type: Any::Boolean.
+ */
+ @Test(dataProvider = "document")
+ public void test10(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=3])");
+ XPathEvaluationResult<?> result = exp.evaluateExpression(doc);
+ verifyResult(result, true);
+ }
+
+ /*
+ * Test return type: Any::Number.
+ */
+ @Test(dataProvider = "document")
+ public void test11(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("count(/Customers/Customer)");
+ XPathEvaluationResult<?> result = exp.evaluateExpression(doc);
+ verifyResult(result, 3.0);
+ }
+
+ /*
+ * Test return type: Any::String.
+ */
+ @Test(dataProvider = "document")
+ public void test12(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=3]/Phone/text())");
+ XPathEvaluationResult<?> result = exp.evaluateExpression(doc, XPathEvaluationResult.class);
+ verifyResult(result, "3333333333");
+ }
+
+ /*
+ * Test return type: Any::Nodeset.
+ */
+ @Test(dataProvider = "document")
+ public void test13(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("/Customers/Customer");
+ XPathEvaluationResult<?> result = exp.evaluateExpression(doc);
+ verifyResult(result, "Customer");
+ }
+
+ /*
+ * Test return type: Any::Node.
+ */
+ @Test(dataProvider = "document")
+ public void test14(XPath xpath, Document doc) throws XPathExpressionException {
+ XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]");
+ XPathEvaluationResult<?> result = exp.evaluateExpression(doc);
+ verifyResult(result, "Customer");
+ }
+
+}
diff --git a/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathTestBase.java b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathTestBase.java
new file mode 100644
index 0000000..0f06242
--- /dev/null
+++ b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/xpath/XPathTestBase.java
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ *
+ * 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.io.ByteArrayInputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.xml.parsers.DocumentBuilderFactory;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import org.testng.annotations.DataProvider;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/*
+ * Base class for XPath test
+ */
+class XPathTestBase {
+
+ static final String rawXML
+ = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+ + "<Customers>"
+ + " <Customer id=\"1\">"
+ + " <Name>name1</Name>"
+ + " <Phone>1111111111</Phone>"
+ + " <Email>123@xyz.com</Email>"
+ + " <Address>"
+ + " <Street>1111 111st ave</Street>"
+ + " <City>The City</City>"
+ + " <State>The State</State>"
+ + " </Address>"
+ + " </Customer>"
+ + " <Customer id=\"2\">"
+ + " <Name>name1</Name>"
+ + " <Phone>2222222222</Phone>"
+ + " <Email>123@xyz.com</Email>"
+ + " <Address>"
+ + " <Street>2222 222nd ave</Street>"
+ + " <City>The City</City>"
+ + " <State>The State</State>"
+ + " </Address>"
+ + " </Customer>"
+ + " <Customer id=\"3\">"
+ + " <Name>name1</Name>"
+ + " <Phone>3333333333</Phone>"
+ + " <Email>123@xyz.com</Email>"
+ + " <Address>"
+ + " <Street>3333 333rd ave</Street>"
+ + " <City>The City</City>"
+ + " <State>The State</State>"
+ + " </Address>"
+ + " </Customer>"
+ + "</Customers>";
+
+ void verifyResult(XPathEvaluationResult<?> result, Object expected) {
+ switch (result.type()) {
+ case BOOLEAN:
+ assertTrue(((Boolean) result.value()).equals(expected));
+ return;
+ case NUMBER:
+ assertTrue(((Double) result.value()).equals(expected));
+ return;
+ case STRING:
+ assertTrue(((String) result.value()).equals(expected));
+ return;
+ case NODESET:
+ XPathNodes nodes = (XPathNodes) result.value();
+ for (Node n : nodes) {
+ assertEquals(n.getLocalName(), expected);
+ }
+ return;
+ case NODE:
+ assertTrue(((Node) result.value()).getLocalName().equals(expected));
+ return;
+ }
+ assertFalse(true, "Unsupported type");
+ }
+
+ /*
+ * DataProvider: XPath object
+ */
+ @DataProvider(name = "xpath")
+ Object[][] getXPath() {
+ return new Object[][]{{XPathFactory.newInstance().newXPath()}};
+ }
+
+ /*
+ * DataProvider: Numeric types not supported
+ */
+ @DataProvider(name = "invalidNumericTypes")
+ Object[][] getInvalidNumericTypes() {
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ return new Object[][]{{xpath, AtomicInteger.class},
+ {xpath, AtomicInteger.class},
+ {xpath, AtomicLong.class},
+ {xpath, BigDecimal.class},
+ {xpath, BigInteger.class},
+ {xpath, Byte.class},
+ {xpath, Float.class},
+ {xpath, Short.class}
+ };
+ }
+
+ /*
+ * DataProvider: XPath and Document objects
+ */
+ @DataProvider(name = "document")
+ Object[][] getDocument() throws Exception {
+ DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance();
+ dBF.setValidating(false);
+ dBF.setNamespaceAware(true);
+ Document doc = dBF.newDocumentBuilder().parse(
+ new ByteArrayInputStream(rawXML.getBytes("UTF-8")));
+
+ return new Object[][]{{XPathFactory.newInstance().newXPath(), doc}};
+ }
+}
diff --git a/jaxws/.hgtags b/jaxws/.hgtags
index 2f346d3..aab4c76 100644
--- a/jaxws/.hgtags
+++ b/jaxws/.hgtags
@@ -293,3 +293,4 @@
e529374fbe526dbd668e5e98fc047b42b3bc6d33 jdk9-b45
64ca52b0bda8028636e4ccafbe1107befcdda47d jdk9-b46
6c17d648d03e4bf4729c3645f8db55d34115e0b7 jdk9-b47
+33e7e699804892c0496adf60ad67cc12855aeb61 jdk9-b48
diff --git a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ap/SchemaGenerator.java b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ap/SchemaGenerator.java
index eef5caf..a15b145 100644
--- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ap/SchemaGenerator.java
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ap/SchemaGenerator.java
@@ -135,7 +135,7 @@
private void filterClass(List<Reference> classes, Collection<? extends Element> elements) {
for (Element element : elements) {
- if (element.getKind().equals(ElementKind.CLASS)) {
+ if (element.getKind().equals(ElementKind.CLASS) || element.getKind().equals(ElementKind.ENUM)) {
classes.add(new Reference((TypeElement) element, processingEnv));
filterClass(classes, ElementFilter.typesIn(element.getEnclosedElements()));
}
diff --git a/jdk/.hgtags b/jdk/.hgtags
index e5ebdf4..c5a3e91 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -290,3 +290,4 @@
9acaa4f57b0b9e3757a7b4576ca9418a75ea8287 jdk9-b45
efedac7f44ed41cea2b1038138047271f55aacba jdk9-b46
b641c14730ac05d9ec8b4f66e6fca3dc21adb403 jdk9-b47
+ebb2eb7f1aec78eb6d8cc4c96f018afa11093cde jdk9-b48
diff --git a/jdk/make/Tools.gmk b/jdk/make/Tools.gmk
index 55273f6..32174ef 100644
--- a/jdk/make/Tools.gmk
+++ b/jdk/make/Tools.gmk
@@ -34,28 +34,23 @@
include NativeCompilation.gmk
include SetupJavaCompilers.gmk
-# The exception handling of swing beaninfo which have the own tool directory
-ifeq (, $(BUILD_TOOLS_JDK))
- $(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \
- SETUP := GENERATE_OLDBYTECODE, \
- ADD_JAVAC_FLAGS := "-Xbootclasspath/p:$(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes", \
- SRC := $(JDK_TOPDIR)/make/src/classes, \
- BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \
- COPY := boot.modules ext.modules))
-endif
+################################################################################
-$(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources/%.template: \
- $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/%.template
- $(call install-file)
+$(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \
+ SETUP := GENERATE_OLDBYTECODE, \
+ ADD_JAVAC_FLAGS := "-Xbootclasspath/p:$(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes", \
+ SRC := $(JDK_TOPDIR)/make/src/classes, \
+ BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \
+ COPY := boot.modules ext.modules))
-BUILD_TOOLS_JDK += $(foreach i, $(wildcard $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template), $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources/$(notdir $i))
+$(eval $(call SetupCopyFiles,COPY_NIMBUS_TEMPLATES, \
+ SRC := $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus, \
+ DEST := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources, \
+ FILES := $(wildcard $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template)))
-# Resource used by CheckDeps tool
-$(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/deps/refs.allowed: \
- $(JDK_TOPDIR)/make/data/checkdeps/refs.allowed
- $(call install-file)
+BUILD_TOOLS_JDK += $(COPY_NIMBUS_TEMPLATES)
-BUILD_TOOLS_JDK += $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/deps/refs.allowed
+################################################################################
# Add a checksum ("jsum") to the end of a text file. Prevents trivial tampering with class lists.
TOOL_ADDJSUM = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
@@ -130,10 +125,6 @@
TOOL_CLDRCONVERTER = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
build.tools.cldrconverter.CLDRConverter
-TOOL_CHECKDEPS = $(JAVA_SMALL) -Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR) \
- -cp "$(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes$(PATH_SEP)$(JDK_OUTPUTDIR)" \
- build.tools.deps.CheckDeps
-
TOOL_GENMODULESXML = $(JAVA_SMALL) -Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR) \
-cp "$(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes$(PATH_SEP)$(JDK_OUTPUTDIR)" \
build.tools.module.GenJdepsModulesXml
@@ -161,25 +152,25 @@
# Tools needed on solaris because OBJCOPY is broken.
ifeq ($(OPENJDK_TARGET_OS), solaris)
-$(eval $(call SetupNativeCompilation,ADD_GNU_DEBUGLINK, \
- SRC := $(JDK_TOPDIR)/make/src/native/add_gnu_debuglink, \
- LANG := C, \
- CC := $(BUILD_CC), \
- LDEXE := $(BUILD_LD), \
- LDFLAGS := -lelf, \
- OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/add_gnu_debuglink, \
- OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \
- PROGRAM := add_gnu_debuglink))
+ $(eval $(call SetupNativeCompilation,ADD_GNU_DEBUGLINK, \
+ SRC := $(JDK_TOPDIR)/make/src/native/add_gnu_debuglink, \
+ LANG := C, \
+ CC := $(BUILD_CC), \
+ LDEXE := $(BUILD_LD), \
+ LDFLAGS := -lelf, \
+ OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/add_gnu_debuglink, \
+ OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \
+ PROGRAM := add_gnu_debuglink))
-$(eval $(call SetupNativeCompilation,FIX_EMPTY_SEC_HDR_FLAGS, \
- SRC := $(JDK_TOPDIR)/make/src/native/fix_empty_sec_hdr_flags, \
- LANG := C, \
- CC := $(BUILD_CC), \
- LDEXE := $(BUILD_LD), \
- LDFLAGS := -lelf, \
- OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/fix_empty_sec_hdr_flags, \
- OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \
- PROGRAM := fix_empty_sec_hdr_flags))
+ $(eval $(call SetupNativeCompilation,FIX_EMPTY_SEC_HDR_FLAGS, \
+ SRC := $(JDK_TOPDIR)/make/src/native/fix_empty_sec_hdr_flags, \
+ LANG := C, \
+ CC := $(BUILD_CC), \
+ LDEXE := $(BUILD_LD), \
+ LDFLAGS := -lelf, \
+ OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/fix_empty_sec_hdr_flags, \
+ OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \
+ PROGRAM := fix_empty_sec_hdr_flags))
endif
$(BUILD_TOOLS_JDK): $(BUILD_INTERIM_JIMAGE)
diff --git a/jdk/make/data/checkdeps/refs.allowed b/jdk/make/data/checkdeps/refs.allowed
deleted file mode 100644
index 7c15a04..0000000
--- a/jdk/make/data/checkdeps/refs.allowed
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# This properties-formatted file contains the names of the non-existent types
-# that are allowed to be referenced from classes in a profiles image.
-#
-# The property key is a type that does not exist. The property value is one or
-# more types that reference the missing type. The property value also encodes
-# the names of the profiles where this reference is allowed.
-
-# jsse.jar is not subsetted by the profiles build. For compact1 and compact2
-# then this means that there are references to Kerberos types that do not
-# exist. These references are harmless.
-#
-javax.security.auth.kerberos.KerberosKey=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2
-javax.security.auth.kerberos.KerberosPrincipal=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2
-javax.security.auth.kerberos.KerberosTicket=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-javax.security.auth.kerberos.KeyTab=sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2
-javax.security.auth.kerberos.ServicePermission=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2
-sun.security.jgss.GSSCaller=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2
-sun.security.jgss.krb5.Krb5Util=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,sun.security.ssl.krb5.Krb5ProxyImpl,compact1,compact2
-sun.security.jgss.krb5.ServiceCreds=sun.security.ssl.krb5.Krb5ProxyImpl,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-sun.security.krb5.EncryptedData= sun.security.ssl.krb5.KerberosPreMasterSecret,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-sun.security.krb5.EncryptionKey=sun.security.ssl.krb5.KerberosPreMasterSecret,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-sun.security.krb5.internal.crypto.KeyUsage=sun.security.ssl.krb5.KerberosPreMasterSecret,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-sun.security.krb5.internal.EncTicketPart=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-sun.security.krb5.internal.Krb5=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-sun.security.krb5.internal.Ticket=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-sun.security.krb5.KrbException=sun.security.ssl.krb5.KerberosPreMasterSecret,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-sun.security.krb5.PrincipalName=sun.security.ssl.krb5.Krb5ProxyImpl,sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-sun.security.krb5.Realm=sun.security.ssl.krb5.KerberosClientKeyExchangeImpl,compact1,compact2
-
-# Residual references to java.beans.
-# The RemoveMethods tool does not yet purge the constant pool.
-#
-java.beans.PropertyChangeListener=java.util.logging.LogManager,compact1,compact2,compact3
diff --git a/jdk/make/gensrc/GensrcMisc.gmk b/jdk/make/gensrc/GensrcMisc.gmk
index f8ed6b1..c0489f3 100644
--- a/jdk/make/gensrc/GensrcMisc.gmk
+++ b/jdk/make/gensrc/GensrcMisc.gmk
@@ -28,6 +28,13 @@
# string and the runtime name into the Version.java file.
# To be printed by java -version
+# These dependencies should ideally be added to prerequesites for Version.java
+# but skip for now until we have better incremental build for java.
+# $(call DependOnVariable, LAUNCHER_NAME) \
+# $(call DependOnVariable, RELEASE) \
+# $(call DependOnVariable, FULL_VERSION) \
+# $(call DependOnVariable, RUNTIME_VERSION)
+
$(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/misc/Version.java: \
$(JDK_TOPDIR)/src/java.base/share/classes/sun/misc/Version.java.template
$(MKDIR) -p $(@D)
diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk
index 30e3284..026a687 100644
--- a/jdk/make/lib/CoreLibraries.gmk
+++ b/jdk/make/lib/CoreLibraries.gmk
@@ -74,8 +74,6 @@
##########################################################################################
-BUILD_LIBVERIFY_SRC := check_code.c check_format.c
-
ifeq ($(OPENJDK_TARGET_OS), solaris)
ifneq ($(OPENJDK_TARGET_CPU), x86_64)
BUILD_LIBVERIFY_REORDER := $(JDK_TOPDIR)/make/mapfiles/libverify/reorder-$(OPENJDK_TARGET_CPU)
@@ -116,10 +114,6 @@
LIBJAVA_SRC_DIRS := $(call FindSrcDirsForLib, java.base, java)
-ifeq ($(OPENJDK_TARGET_OS), macosx)
- LIBJAVA_EXCLUDE_FILES += $(JDK_TOPDIR)/src/java.base/unix/native/libjava/HostLocaleProviderAdapter_md.c
-endif
-
LIBJAVA_CFLAGS := $(addprefix -I, $(LIBJAVA_SRC_DIRS)) \
-I$(JDK_TOPDIR)/src/java.base/share/native/libfdlibm \
-I$(SUPPORT_OUTPUTDIR)/headers/java.base \
@@ -134,9 +128,7 @@
LIBJAVA_CFLAGS += -DJDK_UPDATE_VERSION='"$(JDK_UPDATE_VERSION)"'
endif
-ifneq ($(OPENJDK_TARGET_OS), macosx)
- LIBJAVA_EXCLUDE_FILES += java_props_macosx.c
-else
+ifeq ($(OPENJDK_TARGET_OS), macosx)
BUILD_LIBJAVA_java_props_md.c_CFLAGS := -x objective-c
BUILD_LIBJAVA_java_props_macosx.c_CFLAGS := -x objective-c
endif
@@ -151,8 +143,6 @@
LIBRARY := java, \
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
SRC := $(LIBJAVA_SRC_DIRS), \
- EXCLUDES := fdlibm/src zip prefs, \
- EXCLUDE_FILES := $(LIBJAVA_EXCLUDE_FILES), \
LANG := C, \
OPTIMIZATION := HIGH, \
CFLAGS := $(CFLAGS_JDKLIB) \
@@ -247,19 +237,10 @@
##########################################################################################
-BUILD_LIBJLI_SRC_DIRS := $(JDK_TOPDIR)/src/java.base/share/native/libjli \
- $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli
+LIBJLI_SRC_DIRS := $(call FindSrcDirsForLib, java.base, jli)
LIBJLI_CFLAGS := $(CFLAGS_JDKLIB)
-BUILD_LIBJLI_FILES := \
- java.c \
- splashscreen_stubs.c \
- parse_manifest.c \
- version_comp.c \
- wildcard.c \
- jli_util.c
-
ifeq ($(JVM_VARIANT_ZERO), true)
ERGO_FAMILY := zero
else
@@ -269,68 +250,55 @@
ERGO_FAMILY := $(OPENJDK_TARGET_CPU_ARCH)
endif
endif
+LIBJLI_ALL_ERGO := $(wildcard $(addsuffix /ergo_*.c, $(LIBJLI_SRC_DIRS)))
+LIBJLI_EXCLUDE_ERGO := $(filter-out %/ergo_$(ERGO_FAMILY).c, $(LIBJLI_ALL_ERGO))
+# If all specialized ergo files are excluded, use generic ergo
+ifeq ($(LIBJLI_ALL_ERGO), $(LIBJLI_EXCLUDE_ERGO))
+ LIBJLI_CFLAGS += -DUSE_GENERIC_ERGO
+endif
+LIBJLI_EXCLUDE_FILES += $(notdir $(LIBJLI_EXCLUDE_ERGO))
ifeq ($(OPENJDK_TARGET_OS), macosx)
- BUILD_LIBJLI_SRC_DIRS += $(JDK_TOPDIR)/src/java.base/macosx/native/libjli
- BUILD_LIBJLI_FILES += java_md_common.c java_md_macosx.c
+ LIBJLI_EXCLUDE_FILES += java_md_solinux.c ergo.c
BUILD_LIBJLI_java_md_macosx.c_CFLAGS := -x objective-c
BUILD_LIBJLI_STATIC_java_md_macosx.c_CFLAGS := -x objective-c
-endif
-ifeq ($(OPENJDK_TARGET_OS), windows)
- BUILD_LIBJLI_FILES += java_md.c \
- cmdtoargs.c
- # Staticically link with c runtime on windows.
- LIBJLI_CFLAGS := $(filter-out -MD, $(LIBJLI_CFLAGS))
-else ifneq ($(OPENJDK_TARGET_OS), macosx)
-
- BUILD_LIBJLI_FILES += java_md_common.c
- BUILD_LIBJLI_FILES += java_md_solinux.c ergo.c
-
- ERGO_ARCH_FILE = ergo_$(ERGO_FAMILY).c
-
- # if the architecture specific ergo file exists then
- # use it, else use the generic definitions from ergo.c
- ifneq ($(wildcard $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli/$(ERGO_ARCH_FILE)), )
- BUILD_LIBJLI_FILES += $(ERGO_ARCH_FILE)
- else # !ERGO_ARCH_FILE
- LIBJLI_CFLAGS += -DUSE_GENERIC_ERGO
- endif # ERGO_ARCH_FILE
-endif #WINDOWS
-
-LIBJLI_CFLAGS += $(foreach dir, $(BUILD_LIBJLI_SRC_DIRS), -I$(dir))
-
-# Append defines depending on target platform
-LIBJLI_CFLAGS += $(OPENJDK_TARGET_CPU_JLI_CFLAGS)
-
-ifeq ($(OPENJDK_TARGET_OS), macosx)
LIBJLI_CFLAGS += -DPACKAGE_PATH=\"$(PACKAGE_PATH)\"
endif
-ifneq ($(USE_EXTERNAL_LIBZ), true)
- BUILD_LIBJLI_SRC_DIRS += $(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8
- LIBJLI_CFLAGS += $(ZLIB_CPPFLAGS)
- BUILD_LIBJLI_FILES += \
- inflate.c \
- inftrees.c \
- inffast.c \
- zadler32.c \
- zcrc32.c \
- zutil.c
-endif
-
ifeq ($(OPENJDK_TARGET_OS), windows)
+ # Staticically link with c runtime on windows.
+ LIBJLI_CFLAGS := $(filter-out -MD, $(LIBJLI_CFLAGS))
LIBJLI_OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE)
else
LIBJLI_OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE)/jli
endif
+LIBJLI_CFLAGS += $(addprefix -I, $(LIBJLI_SRC_DIRS))
+
+# Append defines depending on target platform
+LIBJLI_CFLAGS += $(OPENJDK_TARGET_CPU_JLI_CFLAGS)
+
+ifneq ($(USE_EXTERNAL_LIBZ), true)
+ LIBJLI_CFLAGS += $(ZLIB_CPPFLAGS)
+ LIBJLI_EXTRA_FILES += \
+ $(addprefix $(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8/, \
+ inflate.c \
+ inftrees.c \
+ inffast.c \
+ zadler32.c \
+ zcrc32.c \
+ zutil.c \
+ )
+endif
+
$(eval $(call SetupNativeCompilation,BUILD_LIBJLI, \
LIBRARY := jli, \
OUTPUT_DIR := $(LIBJLI_OUTPUT_DIR), \
- SRC := $(BUILD_LIBJLI_SRC_DIRS), \
- INCLUDE_FILES := $(BUILD_LIBJLI_FILES), \
+ SRC := $(LIBJLI_SRC_DIRS), \
+ EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \
+ EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \
LANG := C, \
OPTIMIZATION := HIGH, \
CFLAGS := $(LIBJLI_CFLAGS), \
@@ -376,8 +344,9 @@
$(eval $(call SetupNativeCompilation,BUILD_LIBJLI_STATIC, \
STATIC_LIBRARY := jli_static, \
OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE), \
- SRC := $(BUILD_LIBJLI_SRC_DIRS), \
- INCLUDE_FILES := $(BUILD_LIBJLI_FILES), \
+ SRC := $(LIBJLI_SRC_DIRS), \
+ EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \
+ EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \
LANG := C, \
OPTIMIZATION := HIGH, \
CFLAGS := $(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS), \
@@ -395,8 +364,9 @@
$(eval $(call SetupNativeCompilation,BUILD_LIBJLI_STATIC, \
LIBRARY := jli_static, \
OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE), \
- SRC := $(BUILD_LIBJLI_SRC_DIRS), \
- INCLUDE_FILES := $(BUILD_LIBJLI_FILES), \
+ SRC := $(LIBJLI_SRC_DIRS), \
+ EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \
+ EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \
LANG := C, \
OPTIMIZATION := HIGH, \
CFLAGS := $(CFLAGS_JDKLIB) $(LIBJLI_CFLAGS), \
@@ -411,16 +381,17 @@
else ifeq ($(OPENJDK_TARGET_OS), aix)
# AIX also requires a static libjli because the compiler doesn't support '-rpath'
- $(eval $(call SetupNativeCompilation,BUILD_LIBJLI_STATIC,\
- STATIC_LIBRARY:=jli_static,\
- OUTPUT_DIR:=$(SUPPORT_OUTPUTDIR)/native/$(MODULE),\
- SRC:=$(BUILD_LIBJLI_SRC_DIRS),\
- INCLUDE_FILES:=$(BUILD_LIBJLI_FILES),\
- LANG:=C,\
- OPTIMIZATION:=HIGH, \
- CFLAGS:=$(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS),\
- ARFLAGS:=$(ARFLAGS),\
- OBJECT_DIR:=$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static))
+ $(eval $(call SetupNativeCompilation,BUILD_LIBJLI_STATIC, \
+ STATIC_LIBRARY := jli_static, \
+ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE), \
+ SRC := $(LIBJLI_SRC_DIRS), \
+ EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \
+ EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \
+ LANG := C, \
+ OPTIMIZATION := HIGH, \
+ CFLAGS := $(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS), \
+ ARFLAGS := $(ARFLAGS), \
+ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static))
TARGETS += $(BUILD_LIBJLI_STATIC)
diff --git a/jdk/make/lib/Lib-jdk.attach.gmk b/jdk/make/lib/Lib-jdk.attach.gmk
index 046bd2e..3950b4a 100644
--- a/jdk/make/lib/Lib-jdk.attach.gmk
+++ b/jdk/make/lib/Lib-jdk.attach.gmk
@@ -31,7 +31,7 @@
$(eval $(call SetupNativeCompilation,BUILD_LIBATTACH, \
LIBRARY := attach, \
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
- SRC := $(JDK_TOPDIR)/src/jdk.attach/$(OPENJDK_TARGET_OS)/native/libattach, \
+ SRC := $(call FindSrcDirsForLib, jdk.attach, attach), \
LANG := C, \
OPTIMIZATION := LOW, \
CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) \
diff --git a/jdk/make/lib/Lib-jdk.security.auth.gmk b/jdk/make/lib/Lib-jdk.security.auth.gmk
index cab72eb..80f05da 100644
--- a/jdk/make/lib/Lib-jdk.security.auth.gmk
+++ b/jdk/make/lib/Lib-jdk.security.auth.gmk
@@ -28,9 +28,7 @@
################################################################################
LIBJAAS_MAPFILE :=
-ifneq ($(OPENJDK_TARGET_OS), solaris)
- LIBJAAS_EXCLUDE_FILES := Solaris.c
-else
+ifeq ($(OPENJDK_TARGET_OS), solaris)
# only on solaris...wonder why
LIBJAAS_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjaas/mapfile-vers
endif
@@ -43,7 +41,7 @@
$(eval $(call SetupNativeCompilation,BUILD_LIBJAAS, \
LIBRARY := $(LIBJAAS_NAME), \
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
- SRC := $(JDK_TOPDIR)/src/jdk.security.auth/$(OPENJDK_TARGET_OS_TYPE)/native/libjaas, \
+ SRC := $(call FindSrcDirsForLib, jdk.security.auth, jaas), \
LANG := C, \
OPTIMIZATION := LOW, \
CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/jdk.security.auth, \
@@ -53,7 +51,6 @@
LDFLAGS_windows := netapi32.lib user32.lib mpr.lib advapi32.lib, \
LDFLAGS_SUFFIX_windows := $(LDFLAGS_JDKLIB_SUFFIX), \
LDFLAGS_SUFFIX_solaris := -lc, \
- EXCLUDE_FILES := $(LIBJAAS_EXCLUDE_FILES), \
VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
RC_FLAGS := $(RC_FLAGS) \
-D "JDK_FNAME=$(LIBJAAS_NAME).dll" \
diff --git a/jdk/make/lib/NetworkingLibraries.gmk b/jdk/make/lib/NetworkingLibraries.gmk
index 47d0b67..57d86ea 100644
--- a/jdk/make/lib/NetworkingLibraries.gmk
+++ b/jdk/make/lib/NetworkingLibraries.gmk
@@ -23,39 +23,16 @@
# questions.
#
-LIBNET_SRC_DIRS := $(JDK_TOPDIR)/src/java.base/share/native/libnet \
- $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libnet
-LIBNET_CFLAGS += -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
- $(LIBJAVA_HEADER_FLAGS)
-
-LIBNET_CFLAGS += $(foreach dir, $(LIBNET_SRC_DIRS), -I$(dir))
-
-LIBNET_EXCLUDE_FILES :=
-ifneq ($(OPENJDK_TARGET_OS), solaris)
- LIBNET_EXCLUDE_FILES += solaris_close.c
-endif
-
-ifneq ($(OPENJDK_TARGET_OS), linux)
- LIBNET_EXCLUDE_FILES += linux_close.c
-endif
-
-ifneq ($(OPENJDK_TARGET_OS), macosx)
- LIBNET_EXCLUDE_FILES += bsd_close.c
-endif
-
-ifeq ($(OPENJDK_TARGET_OS), aix)
- LIBNET_SRC_DIRS += $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libnet/java/net/
-endif
+LIBNET_SRC_DIRS := $(call FindSrcDirsForLib, java.base, net)
$(eval $(call SetupNativeCompilation,BUILD_LIBNET, \
LIBRARY := net, \
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
SRC := $(LIBNET_SRC_DIRS), \
- EXCLUDE_FILES := $(LIBNET_EXCLUDE_FILES), \
LANG := C, \
OPTIMIZATION := LOW, \
- CFLAGS := $(CFLAGS_JDKLIB) \
- $(LIBNET_CFLAGS), \
+ CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
+ $(LIBJAVA_HEADER_FLAGS) $(addprefix -I, $(LIBNET_SRC_DIRS)), \
MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libnet/mapfile-vers, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
diff --git a/jdk/make/lib/NioLibraries.gmk b/jdk/make/lib/NioLibraries.gmk
index aaf798c..9a6e3e0 100644
--- a/jdk/make/lib/NioLibraries.gmk
+++ b/jdk/make/lib/NioLibraries.gmk
@@ -65,7 +65,6 @@
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
SRC := $(BUILD_LIBNIO_SRC), \
EXCLUDE_FILES := $(BUILD_LIBNIO_EXFILES), \
- EXCLUDES := sctp, \
LANG := C, \
OPTIMIZATION := HIGH, \
CFLAGS := $(CFLAGS_JDKLIB) \
diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers
index a91eb85..df91f94 100644
--- a/jdk/make/mapfiles/libjava/mapfile-vers
+++ b/jdk/make/mapfiles/libjava/mapfile-vers
@@ -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
@@ -214,10 +214,10 @@
Java_java_lang_Throwable_fillInStackTrace;
Java_java_lang_Throwable_getStackTraceDepth;
Java_java_lang_Throwable_getStackTraceElement;
- Java_java_lang_UNIXProcess_init;
- Java_java_lang_UNIXProcess_waitForProcessExit;
- Java_java_lang_UNIXProcess_forkAndExec;
- Java_java_lang_UNIXProcess_destroyProcess;
+ Java_java_lang_ProcessImpl_init;
+ Java_java_lang_ProcessImpl_waitForProcessExit;
+ Java_java_lang_ProcessImpl_forkAndExec;
+ Java_java_lang_ProcessImpl_destroyProcess;
Java_java_nio_Bits_copyFromShortArray;
Java_java_nio_Bits_copyToShortArray;
Java_java_nio_Bits_copyFromIntArray;
diff --git a/jdk/make/src/classes/build/tools/deps/CheckDeps.java b/jdk/make/src/classes/build/tools/deps/CheckDeps.java
deleted file mode 100644
index 347a2b2..0000000
--- a/jdk/make/src/classes/build/tools/deps/CheckDeps.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. 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 build.tools.deps;
-
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.charset.StandardCharsets;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Enumeration;
-import java.util.Properties;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-
-import com.sun.tools.classfile.ClassFile;
-import com.sun.tools.classfile.Dependencies;
-import com.sun.tools.classfile.Dependency;
-
-/**
- * A simple tool to check the JAR files in a JRE image to ensure that there
- * aren't any references to types that do not exist. The tool is intended to
- * be used in the JDK "profiles" build to help ensure that the profile
- * definitions are kept up to date.
- */
-
-public class CheckDeps {
-
- // classfile API for finding dependencies
- static final Dependency.Finder finder = Dependencies.getClassDependencyFinder();
-
- // "known types", found in rt.jar or other JAR files
- static final Set<String> knownTypes = new HashSet<>();
-
- // References to unknown types. The map key is the unknown type, the
- // map value is the set of classes that reference it.
- static final Map<String,Set<String>> unknownRefs = new HashMap<>();
-
- // The property name is the name of an unknown type that is allowed to be
- // references. The property value is a comma separated list of the types
- // that are allowed to reference it. The list also includes the names of
- // the profiles that the reference is allowed.
- static final Properties allowedBadRefs = new Properties();
-
- /**
- * Returns the class name for the given class file. In the case of inner
- * classes then the enclosing class is returned in order to keep the
- * rules simple.
- */
- static String toClassName(String s) {
- int i = s.indexOf('$');
- if (i > 0)
- s = s.substring(0, i);
- return s.replace("/", ".");
- }
-
- /**
- * Analyze the dependencies of all classes in the given JAR file. The
- * method updates knownTypes and unknownRefs as part of the analysis.
- */
- static void analyzeDependencies(Path jarpath) throws Exception {
- System.out.format("Analyzing %s%n", jarpath);
- try (JarFile jf = new JarFile(jarpath.toFile())) {
- Enumeration<JarEntry> entries = jf.entries();
- while (entries.hasMoreElements()) {
- JarEntry e = entries.nextElement();
- String name = e.getName();
- if (name.endsWith(".class")) {
- ClassFile cf = ClassFile.read(jf.getInputStream(e));
- for (Dependency d : finder.findDependencies(cf)) {
- String origin = toClassName(d.getOrigin().getName());
- String target = toClassName(d.getTarget().getName());
-
- // origin is now known
- unknownRefs.remove(origin);
- knownTypes.add(origin);
-
- // if the target is not known then record the reference
- if (!knownTypes.contains(target)) {
- Set<String> refs = unknownRefs.get(target);
- if (refs == null) {
- // first time seeing this unknown type
- refs = new HashSet<>();
- unknownRefs.put(target, refs);
- }
- refs.add(origin);
- }
- }
- }
- }
- }
- }
-
- /**
- * We have closure (no references to types that do not exist) if
- * unknownRefs is empty. When unknownRefs is not empty then it should
- * only contain references that are allowed to be present (these are
- * loaded from the refs.allowed properties file).
- *
- * @param the profile that is being tested, this determines the exceptions
- * in {@code allowedBadRefs} that apply.
- *
- * @return {@code true} if there are no missing types or the only references
- * to missing types are described by {@code allowedBadRefs}.
- */
- static boolean checkClosure(String profile) {
- // process the references to types that do not exist.
- boolean fail = false;
- for (Map.Entry<String,Set<String>> entry: unknownRefs.entrySet()) {
- String target = entry.getKey();
- for (String origin: entry.getValue()) {
- // check if origin -> target allowed
- String value = allowedBadRefs.getProperty(target);
- if (value == null) {
- System.err.format("%s -> %s (unknown type)%n", origin, target);
- fail = true;
- } else {
- // target is known, check if the origin is one that we
- // expect and that the exception applies to the profile.
- boolean found = false;
- boolean applicable = false;
- for (String s: value.split(",")) {
- s = s.trim();
- if (s.equals(origin))
- found = true;
- if (s.equals(profile))
- applicable = true;
- }
- if (!found || !applicable) {
- if (!found) {
- System.err.format("%s -> %s (not allowed)%n", origin, target);
- } else {
- System.err.format("%s -> %s (reference not applicable to %s)%n",
- origin, target, profile);
- }
- fail = true;
- }
- }
-
- }
- }
-
- return !fail;
- }
-
- static void fail(URL url) throws Exception {
- System.err.println("One or more unexpected references encountered");
- if (url != null)
- System.err.format("Check %s is up to date%n", Paths.get(url.toURI()));
- System.exit(-1);
- }
-
- public static void main(String[] args) throws Exception {
- // load properties file so that we know what missing types that are
- // allowed to be referenced.
- URL url = CheckDeps.class.getResource("refs.allowed");
- if (url != null) {
- try (InputStream in = url.openStream()) {
- allowedBadRefs.load(new InputStreamReader(in, StandardCharsets.UTF_8));
- }
- }
-
- if (args.length != 2) {
- System.err.println("Usage: java CheckDeps <image> <profile>");
- System.exit(-1);
- }
-
- String image = args[0];
- String profile = args[1];
-
- // process JAR files on boot class path
- Path lib = Paths.get(image, "lib");
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(lib, "*.jar")) {
- for (Path jarpath: stream) {
- analyzeDependencies(jarpath);
- }
- }
-
- // classes on boot class path should not reference other types
- boolean okay = checkClosure(profile);
- if (!okay)
- fail(url);
-
- // process JAR files in the extensions directory
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(lib.resolve("ext"), "*.jar")) {
- for (Path jarpath: stream) {
- analyzeDependencies(jarpath);
- }
- }
-
- // re-check to ensure that the extensions doesn't reference types that
- // do not exist.
- okay = checkClosure(profile);
- if (!okay)
- fail(url);
- }
-}
diff --git a/jdk/src/java.base/aix/native/libnet/java/net/aix_close.c b/jdk/src/java.base/aix/native/libnet/aix_close.c
similarity index 100%
rename from jdk/src/java.base/aix/native/libnet/java/net/aix_close.c
rename to jdk/src/java.base/aix/native/libnet/aix_close.c
diff --git a/jdk/src/java.base/unix/native/libnet/linux_close.c b/jdk/src/java.base/linux/native/libnet/linux_close.c
similarity index 100%
rename from jdk/src/java.base/unix/native/libnet/linux_close.c
rename to jdk/src/java.base/linux/native/libnet/linux_close.c
diff --git a/jdk/src/java.base/unix/native/libjava/java_props_macosx.c b/jdk/src/java.base/macosx/native/libjava/java_props_macosx.c
similarity index 100%
rename from jdk/src/java.base/unix/native/libjava/java_props_macosx.c
rename to jdk/src/java.base/macosx/native/libjava/java_props_macosx.c
diff --git a/jdk/src/java.base/unix/native/libjava/java_props_macosx.h b/jdk/src/java.base/macosx/native/libjava/java_props_macosx.h
similarity index 100%
rename from jdk/src/java.base/unix/native/libjava/java_props_macosx.h
rename to jdk/src/java.base/macosx/native/libjava/java_props_macosx.h
diff --git a/jdk/src/java.base/unix/native/libnet/bsd_close.c b/jdk/src/java.base/macosx/native/libnet/bsd_close.c
similarity index 100%
rename from jdk/src/java.base/unix/native/libnet/bsd_close.c
rename to jdk/src/java.base/macosx/native/libnet/bsd_close.c
diff --git a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java
index 97713d3..93b1093 100644
--- a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java
+++ b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, 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
@@ -27,6 +27,9 @@
import sun.misc.FloatingDecimal;
import java.util.Arrays;
+import java.util.Spliterator;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
/**
* A mutable sequence of characters.
@@ -292,7 +295,7 @@
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
- return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex);
+ return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
}
/**
@@ -1432,6 +1435,34 @@
public abstract String toString();
/**
+ * {@inheritDoc}
+ * @since 1.9
+ */
+ @Override
+ public IntStream chars() {
+ // Reuse String-based spliterator. This requires a supplier to
+ // capture the value and count when the terminal operation is executed
+ return StreamSupport.intStream(
+ () -> new String.IntCharArraySpliterator(value, 0, count, 0),
+ Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED,
+ false);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.9
+ */
+ @Override
+ public IntStream codePoints() {
+ // Reuse String-based spliterator. This requires a supplier to
+ // capture the value and count when the terminal operation is executed
+ return StreamSupport.intStream(
+ () -> new String.CodePointsSpliterator(value, 0, count, 0),
+ Spliterator.ORDERED,
+ false);
+ }
+
+ /**
* Needed by {@code String} for the contentEquals method.
*/
final char[] getValue() {
diff --git a/jdk/src/java.base/share/classes/java/lang/Object.java b/jdk/src/java.base/share/classes/java/lang/Object.java
index 04ca331..2eeac24 100644
--- a/jdk/src/java.base/share/classes/java/lang/Object.java
+++ b/jdk/src/java.base/share/classes/java/lang/Object.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -42,6 +42,11 @@
}
/**
+ * Constructs a new object.
+ */
+ public Object() {}
+
+ /**
* Returns the runtime class of this {@code Object}. The returned
* {@code Class} object is the object that is locked by {@code
* static synchronized} methods of the represented class.
@@ -86,12 +91,11 @@
* for unequal objects may improve the performance of hash tables.
* </ul>
* <p>
- * As much as is reasonably practical, the hashCode method defined by
- * class {@code Object} does return distinct integers for distinct
- * objects. (This is typically implemented by converting the internal
- * address of the object into an integer, but this implementation
- * technique is not required by the
- * Java™ programming language.)
+ * As much as is reasonably practical, the hashCode method defined
+ * by class {@code Object} does return distinct integers for
+ * distinct objects. (The hashCode may or may not be implemented
+ * as some function of an object's memory address at some point
+ * in time.)
*
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
@@ -344,10 +348,12 @@
* ... // Perform action appropriate to condition
* }
* </pre>
- * (For more information on this topic, see Section 3.2.3 in Doug Lea's
- * "Concurrent Programming in Java (Second Edition)" (Addison-Wesley,
- * 2000), or Item 50 in Joshua Bloch's "Effective Java Programming
- * Language Guide" (Addison-Wesley, 2001).
+ *
+ * (For more information on this topic, see section 14.2,
+ * Condition Queues, in Brian Goetz and others' "Java Concurrency
+ * in Practice" (Addison-Wesley, 2006) or Item 69 in Joshua
+ * Bloch's "Effective Java (Second Edition)" (Addison-Wesley,
+ * 2008).
*
* <p>If the current thread is {@linkplain java.lang.Thread#interrupt()
* interrupted} by any thread before or while it is waiting, then an
diff --git a/jdk/src/java.base/share/classes/java/lang/String.java b/jdk/src/java.base/share/classes/java/lang/String.java
index 9ff32f4..bd39fa6 100644
--- a/jdk/src/java.base/share/classes/java/lang/String.java
+++ b/jdk/src/java.base/share/classes/java/lang/String.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -34,10 +34,14 @@
import java.util.Formatter;
import java.util.Locale;
import java.util.Objects;
+import java.util.Spliterator;
import java.util.StringJoiner;
+import java.util.function.IntConsumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
/**
* The {@code String} class represents character strings. All
@@ -2894,6 +2898,180 @@
return this;
}
+ static class IntCharArraySpliterator implements Spliterator.OfInt {
+ private final char[] array;
+ private int index; // current index, modified on advance/split
+ private final int fence; // one past last index
+ private final int cs;
+
+ IntCharArraySpliterator(char[] array, int acs) {
+ this(array, 0, array.length, acs);
+ }
+
+ IntCharArraySpliterator(char[] array, int origin, int fence, int acs) {
+ this.array = array;
+ this.index = origin;
+ this.fence = fence;
+ this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
+ | Spliterator.SUBSIZED;
+ }
+
+ @Override
+ public OfInt trySplit() {
+ int lo = index, mid = (lo + fence) >>> 1;
+ return (lo >= mid)
+ ? null
+ : new IntCharArraySpliterator(array, lo, index = mid, cs);
+ }
+
+ @Override
+ public void forEachRemaining(IntConsumer action) {
+ char[] a; int i, hi; // hoist accesses and checks from loop
+ if (action == null)
+ throw new NullPointerException();
+ if ((a = array).length >= (hi = fence) &&
+ (i = index) >= 0 && i < (index = hi)) {
+ do { action.accept(a[i]); } while (++i < hi);
+ }
+ }
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ if (action == null)
+ throw new NullPointerException();
+ if (index >= 0 && index < fence) {
+ action.accept(array[index++]);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public long estimateSize() { return (long)(fence - index); }
+
+ @Override
+ public int characteristics() {
+ return cs;
+ }
+ }
+
+ /**
+ * Returns a stream of {@code int} zero-extending the {@code char} values
+ * from this sequence. Any char which maps to a <a
+ * href="{@docRoot}/java/lang/Character.html#unicode">surrogate code
+ * point</a> is passed through uninterpreted.
+ *
+ * @return an IntStream of char values from this sequence
+ * @since 1.9
+ */
+ @Override
+ public IntStream chars() {
+ return StreamSupport.intStream(
+ new IntCharArraySpliterator(value, Spliterator.IMMUTABLE), false);
+ }
+
+ static class CodePointsSpliterator implements Spliterator.OfInt {
+ private final char[] array;
+ private int index; // current index, modified on advance/split
+ private final int fence; // one past last index
+ private final int cs;
+
+ CodePointsSpliterator(char[] array, int acs) {
+ this(array, 0, array.length, acs);
+ }
+
+ CodePointsSpliterator(char[] array, int origin, int fence, int acs) {
+ this.array = array;
+ this.index = origin;
+ this.fence = fence;
+ this.cs = acs | Spliterator.ORDERED;
+ }
+
+ @Override
+ public OfInt trySplit() {
+ int lo = index, mid = (lo + fence) >>> 1;
+ if (lo >= mid)
+ return null;
+
+ int midOneLess;
+ // If the mid-point intersects a surrogate pair
+ if (Character.isLowSurrogate(array[mid]) &&
+ Character.isHighSurrogate(array[midOneLess = (mid -1)])) {
+ // If there is only one pair it cannot be split
+ if (lo >= midOneLess)
+ return null;
+ // Shift the mid-point to align with the surrogate pair
+ return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
+ }
+ return new CodePointsSpliterator(array, lo, index = mid, cs);
+ }
+
+ @Override
+ public void forEachRemaining(IntConsumer action) {
+ char[] a; int i, hi; // hoist accesses and checks from loop
+ if (action == null)
+ throw new NullPointerException();
+ if ((a = array).length >= (hi = fence) &&
+ (i = index) >= 0 && i < (index = hi)) {
+ do {
+ i = advance(a, i, hi, action);
+ } while (i < hi);
+ }
+ }
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ if (action == null)
+ throw new NullPointerException();
+ if (index >= 0 && index < fence) {
+ index = advance(array, index, fence, action);
+ return true;
+ }
+ return false;
+ }
+
+ // Advance one code point from the index, i, and return the next
+ // index to advance from
+ private static int advance(char[] a, int i, int hi, IntConsumer action) {
+ char c1 = a[i++];
+ int cp = c1;
+ if (Character.isHighSurrogate(c1) && i < hi) {
+ char c2 = a[i];
+ if (Character.isLowSurrogate(c2)) {
+ i++;
+ cp = Character.toCodePoint(c1, c2);
+ }
+ }
+ action.accept(cp);
+ return i;
+ }
+
+ @Override
+ public long estimateSize() { return (long)(fence - index); }
+
+ @Override
+ public int characteristics() {
+ return cs;
+ }
+ }
+
+ /**
+ * Returns a stream of code point values from this sequence. Any surrogate
+ * pairs encountered in the sequence are combined as if by {@linkplain
+ * Character#toCodePoint Character.toCodePoint} and the result is passed
+ * to the stream. Any other code units, including ordinary BMP characters,
+ * unpaired surrogates, and undefined code units, are zero-extended to
+ * {@code int} values which are then passed to the stream.
+ *
+ * @return an IntStream of Unicode code points from this sequence
+ * @since 1.9
+ */
+ @Override
+ public IntStream codePoints() {
+ return StreamSupport.intStream(
+ new CodePointsSpliterator(value, Spliterator.IMMUTABLE), false);
+ }
+
/**
* Converts this string to a new character array.
*
diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java
index 1871774..ee65884 100644
--- a/jdk/src/java.base/share/classes/java/lang/System.java
+++ b/jdk/src/java.base/share/classes/java/lang/System.java
@@ -376,19 +376,16 @@
* the difference between two such values, obtained within the same
* instance of a Java virtual machine, is computed.
*
- * <p> For example, to measure how long some code takes to execute:
- * <pre> {@code
+ * <p>For example, to measure how long some code takes to execute:
+ * <pre> {@code
* long startTime = System.nanoTime();
* // ... the code being measured ...
- * long estimatedTime = System.nanoTime() - startTime;}</pre>
+ * long elapsedNanos = System.nanoTime() - startTime;}</pre>
*
- * <p>To compare two nanoTime values
- * <pre> {@code
- * long t0 = System.nanoTime();
- * ...
- * long t1 = System.nanoTime();}</pre>
- *
- * one should use {@code t1 - t0 < 0}, not {@code t1 < t0},
+ * <p>To compare elapsed time against a timeout, use <pre> {@code
+ * if (System.nanoTime() - startTime >= timeoutNanos) ...}</pre>
+ * instead of <pre> {@code
+ * if (System.nanoTime() >= startTime + timeoutNanos) ...}</pre>
* because of the possibility of numerical overflow.
*
* @return the current value of the running Java Virtual Machine's
diff --git a/jdk/src/java.base/share/classes/java/util/Spliterator.java b/jdk/src/java.base/share/classes/java/util/Spliterator.java
index 324f9e0..96db12f0 100644
--- a/jdk/src/java.base/share/classes/java/util/Spliterator.java
+++ b/jdk/src/java.base/share/classes/java/util/Spliterator.java
@@ -553,6 +553,12 @@
* sub-split size is known and additions or removals to the source are not
* reflected when traversing.
*
+ * <p>A top-level Spliterator should not report both {@code CONCURRENT} and
+ * {@code IMMUTABLE}, since they are mutually exclusive. Such a Spliterator
+ * is inconsistent and no guarantees can be made about any computation using
+ * that Spliterator. Sub-spliterators may report {@code IMMUTABLE} if
+ * additions or removals to the source are not reflected when traversing.
+ *
* @apiNote Most concurrent collections maintain a consistency policy
* guaranteeing accuracy with respect to elements present at the point of
* Spliterator construction, but possibly not reflecting subsequent
diff --git a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java
index 08d04fd..46080c3 100644
--- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java
+++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, 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
@@ -845,22 +845,6 @@
public native Object allocateInstance(Class<?> cls)
throws InstantiationException;
- /** Lock the object. It must get unlocked via {@link #monitorExit}. */
- public native void monitorEnter(Object o);
-
- /**
- * Unlock the object. It must have been locked via {@link
- * #monitorEnter}.
- */
- public native void monitorExit(Object o);
-
- /**
- * Tries to lock the object. Returns true or false to indicate
- * whether the lock succeeded. If it did, the object must be
- * unlocked via {@link #monitorExit}.
- */
- public native boolean tryMonitorEnter(Object o);
-
/** Throw the exception without telling the verifier. */
public native void throwException(Throwable ee);
diff --git a/jdk/src/java.base/unix/native/libnet/solaris_close.c b/jdk/src/java.base/solaris/native/libnet/solaris_close.c
similarity index 100%
rename from jdk/src/java.base/unix/native/libnet/solaris_close.c
rename to jdk/src/java.base/solaris/native/libnet/solaris_close.c
diff --git a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java
index 777018b..a35405f 100644
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java
+++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, 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,24 +25,156 @@
package java.lang;
-import java.io.IOException;
+import java.lang.ProcessBuilder.Redirect;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.lang.ProcessBuilder.Redirect;
-import java.lang.ProcessBuilder.Redirect;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Locale;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.security.AccessController;
+import static java.security.AccessController.doPrivileged;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
/**
- * This class is for the exclusive use of ProcessBuilder.start() to
- * create new processes.
+ * This java.lang.Process subclass in the UNIX environment is for the exclusive use of
+ * ProcessBuilder.start() to create new processes.
*
+ * @author Mario Wolczko and Ross Knippel.
+ * @author Konstantin Kladko (ported to Linux and Bsd)
* @author Martin Buchholz
+ * @author Volker Simonis (ported to AIX)
* @since 1.5
*/
-final class ProcessImpl {
+final class ProcessImpl extends Process {
private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
= sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
- private ProcessImpl() {} // Not instantiable
+ private final int pid;
+ private int exitcode;
+ private boolean hasExited;
+
+ private /* final */ OutputStream stdin;
+ private /* final */ InputStream stdout;
+ private /* final */ InputStream stderr;
+
+ // only used on Solaris
+ private /* final */ DeferredCloseInputStream stdout_inner_stream;
+
+ private static enum LaunchMechanism {
+ // order IS important!
+ FORK,
+ POSIX_SPAWN,
+ VFORK
+ }
+
+ private static enum Platform {
+
+ LINUX(LaunchMechanism.VFORK, LaunchMechanism.FORK),
+
+ BSD(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
+
+ SOLARIS(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
+
+ AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK);
+
+ final LaunchMechanism defaultLaunchMechanism;
+ final Set<LaunchMechanism> validLaunchMechanisms;
+
+ Platform(LaunchMechanism ... launchMechanisms) {
+ this.defaultLaunchMechanism = launchMechanisms[0];
+ this.validLaunchMechanisms =
+ EnumSet.copyOf(Arrays.asList(launchMechanisms));
+ }
+
+ @SuppressWarnings("fallthrough")
+ private String helperPath(String javahome, String osArch) {
+ switch (this) {
+ case SOLARIS:
+ if (osArch.equals("x86")) { osArch = "i386"; }
+ else if (osArch.equals("x86_64")) { osArch = "amd64"; }
+ // fall through...
+ case LINUX:
+ case AIX:
+ return javahome + "/lib/" + osArch + "/jspawnhelper";
+
+ case BSD:
+ return javahome + "/lib/jspawnhelper";
+
+ default:
+ throw new AssertionError("Unsupported platform: " + this);
+ }
+ }
+
+ String helperPath() {
+ return AccessController.doPrivileged(
+ (PrivilegedAction<String>) () ->
+ helperPath(System.getProperty("java.home"),
+ System.getProperty("os.arch"))
+ );
+ }
+
+ LaunchMechanism launchMechanism() {
+ return AccessController.doPrivileged(
+ (PrivilegedAction<LaunchMechanism>) () -> {
+ String s = System.getProperty(
+ "jdk.lang.Process.launchMechanism");
+ LaunchMechanism lm;
+ if (s == null) {
+ lm = defaultLaunchMechanism;
+ s = lm.name().toLowerCase(Locale.ENGLISH);
+ } else {
+ try {
+ lm = LaunchMechanism.valueOf(
+ s.toUpperCase(Locale.ENGLISH));
+ } catch (IllegalArgumentException e) {
+ lm = null;
+ }
+ }
+ if (lm == null || !validLaunchMechanisms.contains(lm)) {
+ throw new Error(
+ s + " is not a supported " +
+ "process launch mechanism on this platform."
+ );
+ }
+ return lm;
+ }
+ );
+ }
+
+ static Platform get() {
+ String osName = AccessController.doPrivileged(
+ (PrivilegedAction<String>) () -> System.getProperty("os.name")
+ );
+
+ if (osName.equals("Linux")) { return LINUX; }
+ if (osName.contains("OS X")) { return BSD; }
+ if (osName.equals("SunOS")) { return SOLARIS; }
+ if (osName.equals("AIX")) { return AIX; }
+
+ throw new Error(osName + " is not a supported OS platform.");
+ }
+ }
+
+ private static final Platform platform = Platform.get();
+ private static final LaunchMechanism launchMechanism = platform.launchMechanism();
+ private static final byte[] helperpath = toCString(platform.helperPath());
+
+ /* this is for the reaping thread */
+ private native int waitForProcessExit(int pid);
private static byte[] toCString(String s) {
if (s == null)
@@ -50,8 +182,8 @@
byte[] bytes = s.getBytes();
byte[] result = new byte[bytes.length + 1];
System.arraycopy(bytes, 0,
- result, 0,
- bytes.length);
+ result, 0,
+ bytes.length);
result[result.length-1] = (byte)0;
return result;
}
@@ -62,7 +194,7 @@
String dir,
ProcessBuilder.Redirect[] redirects,
boolean redirectErrorStream)
- throws IOException
+ throws IOException
{
assert cmdarray != null && cmdarray.length > 0;
@@ -112,7 +244,7 @@
std_fds[1] = 1;
else {
f1 = new FileOutputStream(redirects[1].file(),
- redirects[1].append());
+ redirects[1].append());
std_fds[1] = fdAccess.get(f1.getFD());
}
@@ -122,18 +254,18 @@
std_fds[2] = 2;
else {
f2 = new FileOutputStream(redirects[2].file(),
- redirects[2].append());
+ redirects[2].append());
std_fds[2] = fdAccess.get(f2.getFD());
}
}
- return new UNIXProcess
- (toCString(cmdarray[0]),
- argBlock, args.length,
- envBlock, envc[0],
- toCString(dir),
- std_fds,
- redirectErrorStream);
+ return new ProcessImpl
+ (toCString(cmdarray[0]),
+ argBlock, args.length,
+ envBlock, envc[0],
+ toCString(dir),
+ std_fds,
+ redirectErrorStream);
} finally {
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
@@ -144,4 +276,654 @@
}
}
}
+
+
+ /**
+ * Creates a process. Depending on the {@code mode} flag, this is done by
+ * one of the following mechanisms:
+ * <pre>
+ * 1 - fork(2) and exec(2)
+ * 2 - posix_spawn(3P)
+ * 3 - vfork(2) and exec(2)
+ *
+ * (4 - clone(2) and exec(2) - obsolete and currently disabled in native code)
+ * </pre>
+ * @param fds an array of three file descriptors.
+ * Indexes 0, 1, and 2 correspond to standard input,
+ * standard output and standard error, respectively. On
+ * input, a value of -1 means to create a pipe to connect
+ * child and parent processes. On output, a value which
+ * is not -1 is the parent pipe fd corresponding to the
+ * pipe which has been created. An element of this array
+ * is -1 on input if and only if it is <em>not</em> -1 on
+ * output.
+ * @return the pid of the subprocess
+ */
+ private native int forkAndExec(int mode, byte[] helperpath,
+ byte[] prog,
+ byte[] argBlock, int argc,
+ byte[] envBlock, int envc,
+ byte[] dir,
+ int[] fds,
+ boolean redirectErrorStream)
+ throws IOException;
+
+ /**
+ * The thread pool of "process reaper" daemon threads.
+ */
+ private static final Executor processReaperExecutor =
+ doPrivileged((PrivilegedAction<Executor>) () -> {
+
+ ThreadGroup tg = Thread.currentThread().getThreadGroup();
+ while (tg.getParent() != null) tg = tg.getParent();
+ ThreadGroup systemThreadGroup = tg;
+
+ ThreadFactory threadFactory = grimReaper -> {
+ // Our thread stack requirement is quite modest.
+ Thread t = new Thread(systemThreadGroup, grimReaper,
+ "process reaper", 32768);
+ t.setDaemon(true);
+ // A small attempt (probably futile) to avoid priority inversion
+ t.setPriority(Thread.MAX_PRIORITY);
+ return t;
+ };
+
+ return Executors.newCachedThreadPool(threadFactory);
+ });
+
+ private ProcessImpl(final byte[] prog,
+ final byte[] argBlock, final int argc,
+ final byte[] envBlock, final int envc,
+ final byte[] dir,
+ final int[] fds,
+ final boolean redirectErrorStream)
+ throws IOException {
+
+ pid = forkAndExec(launchMechanism.ordinal() + 1,
+ helperpath,
+ prog,
+ argBlock, argc,
+ envBlock, envc,
+ dir,
+ fds,
+ redirectErrorStream);
+
+ try {
+ doPrivileged((PrivilegedExceptionAction<Void>) () -> {
+ initStreams(fds);
+ return null;
+ });
+ } catch (PrivilegedActionException ex) {
+ throw (IOException) ex.getException();
+ }
+ }
+
+ static FileDescriptor newFileDescriptor(int fd) {
+ FileDescriptor fileDescriptor = new FileDescriptor();
+ fdAccess.set(fileDescriptor, fd);
+ return fileDescriptor;
+ }
+
+ void initStreams(int[] fds) throws IOException {
+ switch (platform) {
+ case LINUX:
+ case BSD:
+ stdin = (fds[0] == -1) ?
+ ProcessBuilder.NullOutputStream.INSTANCE :
+ new ProcessPipeOutputStream(fds[0]);
+
+ stdout = (fds[1] == -1) ?
+ ProcessBuilder.NullInputStream.INSTANCE :
+ new ProcessPipeInputStream(fds[1]);
+
+ stderr = (fds[2] == -1) ?
+ ProcessBuilder.NullInputStream.INSTANCE :
+ new ProcessPipeInputStream(fds[2]);
+
+ processReaperExecutor.execute(() -> {
+ int exitcode = waitForProcessExit(pid);
+
+ synchronized (this) {
+ this.exitcode = exitcode;
+ this.hasExited = true;
+ this.notifyAll();
+ }
+
+ if (stdout instanceof ProcessPipeInputStream)
+ ((ProcessPipeInputStream) stdout).processExited();
+
+ if (stderr instanceof ProcessPipeInputStream)
+ ((ProcessPipeInputStream) stderr).processExited();
+
+ if (stdin instanceof ProcessPipeOutputStream)
+ ((ProcessPipeOutputStream) stdin).processExited();
+ });
+ break;
+
+ case SOLARIS:
+ stdin = (fds[0] == -1) ?
+ ProcessBuilder.NullOutputStream.INSTANCE :
+ new BufferedOutputStream(
+ new FileOutputStream(newFileDescriptor(fds[0])));
+
+ stdout = (fds[1] == -1) ?
+ ProcessBuilder.NullInputStream.INSTANCE :
+ new BufferedInputStream(
+ stdout_inner_stream =
+ new DeferredCloseInputStream(
+ newFileDescriptor(fds[1])));
+
+ stderr = (fds[2] == -1) ?
+ ProcessBuilder.NullInputStream.INSTANCE :
+ new DeferredCloseInputStream(newFileDescriptor(fds[2]));
+
+ /*
+ * For each subprocess forked a corresponding reaper task
+ * is submitted. That task is the only thread which waits
+ * for the subprocess to terminate and it doesn't hold any
+ * locks while doing so. This design allows waitFor() and
+ * exitStatus() to be safely executed in parallel (and they
+ * need no native code).
+ */
+ processReaperExecutor.execute(() -> {
+ int exitcode = waitForProcessExit(pid);
+
+ synchronized (this) {
+ this.exitcode = exitcode;
+ this.hasExited = true;
+ this.notifyAll();
+ }
+ });
+ break;
+
+ case AIX:
+ stdin = (fds[0] == -1) ?
+ ProcessBuilder.NullOutputStream.INSTANCE :
+ new ProcessPipeOutputStream(fds[0]);
+
+ stdout = (fds[1] == -1) ?
+ ProcessBuilder.NullInputStream.INSTANCE :
+ new DeferredCloseProcessPipeInputStream(fds[1]);
+
+ stderr = (fds[2] == -1) ?
+ ProcessBuilder.NullInputStream.INSTANCE :
+ new DeferredCloseProcessPipeInputStream(fds[2]);
+
+ processReaperExecutor.execute(() -> {
+ int exitcode = waitForProcessExit(pid);
+
+ synchronized (this) {
+ this.exitcode = exitcode;
+ this.hasExited = true;
+ this.notifyAll();
+ }
+
+ if (stdout instanceof DeferredCloseProcessPipeInputStream)
+ ((DeferredCloseProcessPipeInputStream) stdout).processExited();
+
+ if (stderr instanceof DeferredCloseProcessPipeInputStream)
+ ((DeferredCloseProcessPipeInputStream) stderr).processExited();
+
+ if (stdin instanceof ProcessPipeOutputStream)
+ ((ProcessPipeOutputStream) stdin).processExited();
+ });
+ break;
+
+ default: throw new AssertionError("Unsupported platform: " + platform);
+ }
+ }
+
+ public OutputStream getOutputStream() {
+ return stdin;
+ }
+
+ public InputStream getInputStream() {
+ return stdout;
+ }
+
+ public InputStream getErrorStream() {
+ return stderr;
+ }
+
+ public synchronized int waitFor() throws InterruptedException {
+ while (!hasExited) {
+ wait();
+ }
+ return exitcode;
+ }
+
+ @Override
+ public synchronized boolean waitFor(long timeout, TimeUnit unit)
+ throws InterruptedException
+ {
+ if (hasExited) return true;
+ if (timeout <= 0) return false;
+
+ long remainingNanos = unit.toNanos(timeout);
+ long deadline = System.nanoTime() + remainingNanos;
+
+ do {
+ // Round up to next millisecond
+ wait(TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L));
+ if (hasExited) {
+ return true;
+ }
+ remainingNanos = deadline - System.nanoTime();
+ } while (remainingNanos > 0);
+ return hasExited;
+ }
+
+ public synchronized int exitValue() {
+ if (!hasExited) {
+ throw new IllegalThreadStateException("process hasn't exited");
+ }
+ return exitcode;
+ }
+
+ private static native void destroyProcess(int pid, boolean force);
+
+ private void destroy(boolean force) {
+ switch (platform) {
+ case LINUX:
+ case BSD:
+ case AIX:
+ // There is a risk that pid will be recycled, causing us to
+ // kill the wrong process! So we only terminate processes
+ // that appear to still be running. Even with this check,
+ // there is an unavoidable race condition here, but the window
+ // is very small, and OSes try hard to not recycle pids too
+ // soon, so this is quite safe.
+ synchronized (this) {
+ if (!hasExited)
+ destroyProcess(pid, force);
+ }
+ try { stdin.close(); } catch (IOException ignored) {}
+ try { stdout.close(); } catch (IOException ignored) {}
+ try { stderr.close(); } catch (IOException ignored) {}
+ break;
+
+ case SOLARIS:
+ // There is a risk that pid will be recycled, causing us to
+ // kill the wrong process! So we only terminate processes
+ // that appear to still be running. Even with this check,
+ // there is an unavoidable race condition here, but the window
+ // is very small, and OSes try hard to not recycle pids too
+ // soon, so this is quite safe.
+ synchronized (this) {
+ if (!hasExited)
+ destroyProcess(pid, force);
+ try {
+ stdin.close();
+ if (stdout_inner_stream != null)
+ stdout_inner_stream.closeDeferred(stdout);
+ if (stderr instanceof DeferredCloseInputStream)
+ ((DeferredCloseInputStream) stderr)
+ .closeDeferred(stderr);
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ break;
+
+ default: throw new AssertionError("Unsupported platform: " + platform);
+ }
+ }
+
+ public void destroy() {
+ destroy(false);
+ }
+
+ @Override
+ public Process destroyForcibly() {
+ destroy(true);
+ return this;
+ }
+
+ @Override
+ public long getPid() {
+ return pid;
+ }
+
+ @Override
+ public synchronized boolean isAlive() {
+ return !hasExited;
+ }
+
+ private static native void init();
+
+ static {
+ init();
+ }
+
+ /**
+ * A buffered input stream for a subprocess pipe file descriptor
+ * that allows the underlying file descriptor to be reclaimed when
+ * the process exits, via the processExited hook.
+ *
+ * This is tricky because we do not want the user-level InputStream to be
+ * closed until the user invokes close(), and we need to continue to be
+ * able to read any buffered data lingering in the OS pipe buffer.
+ */
+ private static class ProcessPipeInputStream extends BufferedInputStream {
+ private final Object closeLock = new Object();
+
+ ProcessPipeInputStream(int fd) {
+ super(new FileInputStream(newFileDescriptor(fd)));
+ }
+ private static byte[] drainInputStream(InputStream in)
+ throws IOException {
+ int n = 0;
+ int j;
+ byte[] a = null;
+ while ((j = in.available()) > 0) {
+ a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
+ n += in.read(a, n, j);
+ }
+ return (a == null || n == a.length) ? a : Arrays.copyOf(a, n);
+ }
+
+ /** Called by the process reaper thread when the process exits. */
+ synchronized void processExited() {
+ synchronized (closeLock) {
+ try {
+ InputStream in = this.in;
+ // this stream is closed if and only if: in == null
+ if (in != null) {
+ byte[] stragglers = drainInputStream(in);
+ in.close();
+ this.in = (stragglers == null) ?
+ ProcessBuilder.NullInputStream.INSTANCE :
+ new ByteArrayInputStream(stragglers);
+ }
+ } catch (IOException ignored) {}
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ // BufferedInputStream#close() is not synchronized unlike most other
+ // methods. Synchronizing helps avoid race with processExited().
+ synchronized (closeLock) {
+ super.close();
+ }
+ }
+ }
+
+ /**
+ * A buffered output stream for a subprocess pipe file descriptor
+ * that allows the underlying file descriptor to be reclaimed when
+ * the process exits, via the processExited hook.
+ */
+ private static class ProcessPipeOutputStream extends BufferedOutputStream {
+ ProcessPipeOutputStream(int fd) {
+ super(new FileOutputStream(newFileDescriptor(fd)));
+ }
+
+ /** Called by the process reaper thread when the process exits. */
+ synchronized void processExited() {
+ OutputStream out = this.out;
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException ignored) {
+ // We know of no reason to get an IOException, but if
+ // we do, there's nothing else to do but carry on.
+ }
+ this.out = ProcessBuilder.NullOutputStream.INSTANCE;
+ }
+ }
+ }
+
+ // A FileInputStream that supports the deferment of the actual close
+ // operation until the last pending I/O operation on the stream has
+ // finished. This is required on Solaris because we must close the stdin
+ // and stdout streams in the destroy method in order to reclaim the
+ // underlying file descriptors. Doing so, however, causes any thread
+ // currently blocked in a read on one of those streams to receive an
+ // IOException("Bad file number"), which is incompatible with historical
+ // behavior. By deferring the close we allow any pending reads to see -1
+ // (EOF) as they did before.
+ //
+ private static class DeferredCloseInputStream extends FileInputStream
+ {
+ DeferredCloseInputStream(FileDescriptor fd) {
+ super(fd);
+ }
+
+ private Object lock = new Object(); // For the following fields
+ private boolean closePending = false;
+ private int useCount = 0;
+ private InputStream streamToClose;
+
+ private void raise() {
+ synchronized (lock) {
+ useCount++;
+ }
+ }
+
+ private void lower() throws IOException {
+ synchronized (lock) {
+ useCount--;
+ if (useCount == 0 && closePending) {
+ streamToClose.close();
+ }
+ }
+ }
+
+ // stc is the actual stream to be closed; it might be this object, or
+ // it might be an upstream object for which this object is downstream.
+ //
+ private void closeDeferred(InputStream stc) throws IOException {
+ synchronized (lock) {
+ if (useCount == 0) {
+ stc.close();
+ } else {
+ closePending = true;
+ streamToClose = stc;
+ }
+ }
+ }
+
+ public void close() throws IOException {
+ synchronized (lock) {
+ useCount = 0;
+ closePending = false;
+ }
+ super.close();
+ }
+
+ public int read() throws IOException {
+ raise();
+ try {
+ return super.read();
+ } finally {
+ lower();
+ }
+ }
+
+ public int read(byte[] b) throws IOException {
+ raise();
+ try {
+ return super.read(b);
+ } finally {
+ lower();
+ }
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ raise();
+ try {
+ return super.read(b, off, len);
+ } finally {
+ lower();
+ }
+ }
+
+ public long skip(long n) throws IOException {
+ raise();
+ try {
+ return super.skip(n);
+ } finally {
+ lower();
+ }
+ }
+
+ public int available() throws IOException {
+ raise();
+ try {
+ return super.available();
+ } finally {
+ lower();
+ }
+ }
+ }
+
+ /**
+ * A buffered input stream for a subprocess pipe file descriptor
+ * that allows the underlying file descriptor to be reclaimed when
+ * the process exits, via the processExited hook.
+ *
+ * This is tricky because we do not want the user-level InputStream to be
+ * closed until the user invokes close(), and we need to continue to be
+ * able to read any buffered data lingering in the OS pipe buffer.
+ *
+ * On AIX this is especially tricky, because the 'close()' system call
+ * will block if another thread is at the same time blocked in a file
+ * operation (e.g. 'read()') on the same file descriptor. We therefore
+ * combine 'ProcessPipeInputStream' approach used on Linux and Bsd
+ * with the DeferredCloseInputStream approach used on Solaris. This means
+ * that every potentially blocking operation on the file descriptor
+ * increments a counter before it is executed and decrements it once it
+ * finishes. The 'close()' operation will only be executed if there are
+ * no pending operations. Otherwise it is deferred after the last pending
+ * operation has finished.
+ *
+ */
+ private static class DeferredCloseProcessPipeInputStream
+ extends BufferedInputStream {
+
+ private final Object closeLock = new Object();
+ private int useCount = 0;
+ private boolean closePending = false;
+
+ DeferredCloseProcessPipeInputStream(int fd) {
+ super(new FileInputStream(newFileDescriptor(fd)));
+ }
+
+ private InputStream drainInputStream(InputStream in)
+ throws IOException {
+ int n = 0;
+ int j;
+ byte[] a = null;
+ synchronized (closeLock) {
+ if (buf == null) // asynchronous close()?
+ return null; // discard
+ j = in.available();
+ }
+ while (j > 0) {
+ a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
+ synchronized (closeLock) {
+ if (buf == null) // asynchronous close()?
+ return null; // discard
+ n += in.read(a, n, j);
+ j = in.available();
+ }
+ }
+ return (a == null) ?
+ ProcessBuilder.NullInputStream.INSTANCE :
+ new ByteArrayInputStream(n == a.length ? a : Arrays.copyOf(a, n));
+ }
+
+ /** Called by the process reaper thread when the process exits. */
+ synchronized void processExited() {
+ try {
+ InputStream in = this.in;
+ if (in != null) {
+ InputStream stragglers = drainInputStream(in);
+ in.close();
+ this.in = stragglers;
+ }
+ } catch (IOException ignored) { }
+ }
+
+ private void raise() {
+ synchronized (closeLock) {
+ useCount++;
+ }
+ }
+
+ private void lower() throws IOException {
+ synchronized (closeLock) {
+ useCount--;
+ if (useCount == 0 && closePending) {
+ closePending = false;
+ super.close();
+ }
+ }
+ }
+
+ @Override
+ public int read() throws IOException {
+ raise();
+ try {
+ return super.read();
+ } finally {
+ lower();
+ }
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ raise();
+ try {
+ return super.read(b);
+ } finally {
+ lower();
+ }
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ raise();
+ try {
+ return super.read(b, off, len);
+ } finally {
+ lower();
+ }
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ raise();
+ try {
+ return super.skip(n);
+ } finally {
+ lower();
+ }
+ }
+
+ @Override
+ public int available() throws IOException {
+ raise();
+ try {
+ return super.available();
+ } finally {
+ lower();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ // BufferedInputStream#close() is not synchronized unlike most other
+ // methods. Synchronizing helps avoid racing with drainInputStream().
+ synchronized (closeLock) {
+ if (useCount == 0) {
+ super.close();
+ }
+ else {
+ closePending = true;
+ }
+ }
+ }
+ }
}
diff --git a/jdk/src/java.base/unix/classes/java/lang/UNIXProcess.java b/jdk/src/java.base/unix/classes/java/lang/UNIXProcess.java
deleted file mode 100644
index d3adac9..0000000
--- a/jdk/src/java.base/unix/classes/java/lang/UNIXProcess.java
+++ /dev/null
@@ -1,836 +0,0 @@
-/*
- * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. 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 java.lang;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.Locale;
-import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-import java.security.AccessController;
-import static java.security.AccessController.doPrivileged;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-
-/**
- * java.lang.Process subclass in the UNIX environment.
- *
- * @author Mario Wolczko and Ross Knippel.
- * @author Konstantin Kladko (ported to Linux and Bsd)
- * @author Martin Buchholz
- * @author Volker Simonis (ported to AIX)
- */
-final class UNIXProcess extends Process {
- private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
- = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
-
- private final int pid;
- private int exitcode;
- private boolean hasExited;
-
- private /* final */ OutputStream stdin;
- private /* final */ InputStream stdout;
- private /* final */ InputStream stderr;
-
- // only used on Solaris
- private /* final */ DeferredCloseInputStream stdout_inner_stream;
-
- private static enum LaunchMechanism {
- // order IS important!
- FORK,
- POSIX_SPAWN,
- VFORK
- }
-
- private static enum Platform {
-
- LINUX(LaunchMechanism.VFORK, LaunchMechanism.FORK),
-
- BSD(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
-
- SOLARIS(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
-
- AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK);
-
- final LaunchMechanism defaultLaunchMechanism;
- final Set<LaunchMechanism> validLaunchMechanisms;
-
- Platform(LaunchMechanism ... launchMechanisms) {
- this.defaultLaunchMechanism = launchMechanisms[0];
- this.validLaunchMechanisms =
- EnumSet.copyOf(Arrays.asList(launchMechanisms));
- }
-
- @SuppressWarnings("fallthrough")
- private String helperPath(String javahome, String osArch) {
- switch (this) {
- case SOLARIS:
- if (osArch.equals("x86")) { osArch = "i386"; }
- else if (osArch.equals("x86_64")) { osArch = "amd64"; }
- // fall through...
- case LINUX:
- case AIX:
- return javahome + "/lib/" + osArch + "/jspawnhelper";
-
- case BSD:
- return javahome + "/lib/jspawnhelper";
-
- default:
- throw new AssertionError("Unsupported platform: " + this);
- }
- }
-
- String helperPath() {
- return AccessController.doPrivileged(
- (PrivilegedAction<String>) () ->
- helperPath(System.getProperty("java.home"),
- System.getProperty("os.arch"))
- );
- }
-
- LaunchMechanism launchMechanism() {
- return AccessController.doPrivileged(
- (PrivilegedAction<LaunchMechanism>) () -> {
- String s = System.getProperty(
- "jdk.lang.Process.launchMechanism");
- LaunchMechanism lm;
- if (s == null) {
- lm = defaultLaunchMechanism;
- s = lm.name().toLowerCase(Locale.ENGLISH);
- } else {
- try {
- lm = LaunchMechanism.valueOf(
- s.toUpperCase(Locale.ENGLISH));
- } catch (IllegalArgumentException e) {
- lm = null;
- }
- }
- if (lm == null || !validLaunchMechanisms.contains(lm)) {
- throw new Error(
- s + " is not a supported " +
- "process launch mechanism on this platform."
- );
- }
- return lm;
- }
- );
- }
-
- static Platform get() {
- String osName = AccessController.doPrivileged(
- (PrivilegedAction<String>) () -> System.getProperty("os.name")
- );
-
- if (osName.equals("Linux")) { return LINUX; }
- if (osName.contains("OS X")) { return BSD; }
- if (osName.equals("SunOS")) { return SOLARIS; }
- if (osName.equals("AIX")) { return AIX; }
-
- throw new Error(osName + " is not a supported OS platform.");
- }
- }
-
- private static final Platform platform = Platform.get();
- private static final LaunchMechanism launchMechanism = platform.launchMechanism();
- private static final byte[] helperpath = toCString(platform.helperPath());
-
- private static byte[] toCString(String s) {
- if (s == null)
- return null;
- byte[] bytes = s.getBytes();
- byte[] result = new byte[bytes.length + 1];
- System.arraycopy(bytes, 0,
- result, 0,
- bytes.length);
- result[result.length-1] = (byte)0;
- return result;
- }
-
- /* this is for the reaping thread */
- private native int waitForProcessExit(int pid);
-
- /**
- * Creates a process. Depending on the {@code mode} flag, this is done by
- * one of the following mechanisms:
- * <pre>
- * 1 - fork(2) and exec(2)
- * 2 - posix_spawn(3P)
- * 3 - vfork(2) and exec(2)
- *
- * (4 - clone(2) and exec(2) - obsolete and currently disabled in native code)
- * </pre>
- * @param fds an array of three file descriptors.
- * Indexes 0, 1, and 2 correspond to standard input,
- * standard output and standard error, respectively. On
- * input, a value of -1 means to create a pipe to connect
- * child and parent processes. On output, a value which
- * is not -1 is the parent pipe fd corresponding to the
- * pipe which has been created. An element of this array
- * is -1 on input if and only if it is <em>not</em> -1 on
- * output.
- * @return the pid of the subprocess
- */
- private native int forkAndExec(int mode, byte[] helperpath,
- byte[] prog,
- byte[] argBlock, int argc,
- byte[] envBlock, int envc,
- byte[] dir,
- int[] fds,
- boolean redirectErrorStream)
- throws IOException;
-
- /**
- * The thread pool of "process reaper" daemon threads.
- */
- private static final Executor processReaperExecutor =
- doPrivileged((PrivilegedAction<Executor>) () -> {
-
- ThreadGroup tg = Thread.currentThread().getThreadGroup();
- while (tg.getParent() != null) tg = tg.getParent();
- ThreadGroup systemThreadGroup = tg;
-
- ThreadFactory threadFactory = grimReaper -> {
- // Our thread stack requirement is quite modest.
- Thread t = new Thread(systemThreadGroup, grimReaper,
- "process reaper", 32768);
- t.setDaemon(true);
- // A small attempt (probably futile) to avoid priority inversion
- t.setPriority(Thread.MAX_PRIORITY);
- return t;
- };
-
- return Executors.newCachedThreadPool(threadFactory);
- });
-
- UNIXProcess(final byte[] prog,
- final byte[] argBlock, final int argc,
- final byte[] envBlock, final int envc,
- final byte[] dir,
- final int[] fds,
- final boolean redirectErrorStream)
- throws IOException {
-
- pid = forkAndExec(launchMechanism.ordinal() + 1,
- helperpath,
- prog,
- argBlock, argc,
- envBlock, envc,
- dir,
- fds,
- redirectErrorStream);
-
- try {
- doPrivileged((PrivilegedExceptionAction<Void>) () -> {
- initStreams(fds);
- return null;
- });
- } catch (PrivilegedActionException ex) {
- throw (IOException) ex.getException();
- }
- }
-
- static FileDescriptor newFileDescriptor(int fd) {
- FileDescriptor fileDescriptor = new FileDescriptor();
- fdAccess.set(fileDescriptor, fd);
- return fileDescriptor;
- }
-
- void initStreams(int[] fds) throws IOException {
- switch (platform) {
- case LINUX:
- case BSD:
- stdin = (fds[0] == -1) ?
- ProcessBuilder.NullOutputStream.INSTANCE :
- new ProcessPipeOutputStream(fds[0]);
-
- stdout = (fds[1] == -1) ?
- ProcessBuilder.NullInputStream.INSTANCE :
- new ProcessPipeInputStream(fds[1]);
-
- stderr = (fds[2] == -1) ?
- ProcessBuilder.NullInputStream.INSTANCE :
- new ProcessPipeInputStream(fds[2]);
-
- processReaperExecutor.execute(() -> {
- int exitcode = waitForProcessExit(pid);
-
- synchronized (this) {
- this.exitcode = exitcode;
- this.hasExited = true;
- this.notifyAll();
- }
-
- if (stdout instanceof ProcessPipeInputStream)
- ((ProcessPipeInputStream) stdout).processExited();
-
- if (stderr instanceof ProcessPipeInputStream)
- ((ProcessPipeInputStream) stderr).processExited();
-
- if (stdin instanceof ProcessPipeOutputStream)
- ((ProcessPipeOutputStream) stdin).processExited();
- });
- break;
-
- case SOLARIS:
- stdin = (fds[0] == -1) ?
- ProcessBuilder.NullOutputStream.INSTANCE :
- new BufferedOutputStream(
- new FileOutputStream(newFileDescriptor(fds[0])));
-
- stdout = (fds[1] == -1) ?
- ProcessBuilder.NullInputStream.INSTANCE :
- new BufferedInputStream(
- stdout_inner_stream =
- new DeferredCloseInputStream(
- newFileDescriptor(fds[1])));
-
- stderr = (fds[2] == -1) ?
- ProcessBuilder.NullInputStream.INSTANCE :
- new DeferredCloseInputStream(newFileDescriptor(fds[2]));
-
- /*
- * For each subprocess forked a corresponding reaper task
- * is submitted. That task is the only thread which waits
- * for the subprocess to terminate and it doesn't hold any
- * locks while doing so. This design allows waitFor() and
- * exitStatus() to be safely executed in parallel (and they
- * need no native code).
- */
- processReaperExecutor.execute(() -> {
- int exitcode = waitForProcessExit(pid);
-
- synchronized (this) {
- this.exitcode = exitcode;
- this.hasExited = true;
- this.notifyAll();
- }
- });
- break;
-
- case AIX:
- stdin = (fds[0] == -1) ?
- ProcessBuilder.NullOutputStream.INSTANCE :
- new ProcessPipeOutputStream(fds[0]);
-
- stdout = (fds[1] == -1) ?
- ProcessBuilder.NullInputStream.INSTANCE :
- new DeferredCloseProcessPipeInputStream(fds[1]);
-
- stderr = (fds[2] == -1) ?
- ProcessBuilder.NullInputStream.INSTANCE :
- new DeferredCloseProcessPipeInputStream(fds[2]);
-
- processReaperExecutor.execute(() -> {
- int exitcode = waitForProcessExit(pid);
-
- synchronized (this) {
- this.exitcode = exitcode;
- this.hasExited = true;
- this.notifyAll();
- }
-
- if (stdout instanceof DeferredCloseProcessPipeInputStream)
- ((DeferredCloseProcessPipeInputStream) stdout).processExited();
-
- if (stderr instanceof DeferredCloseProcessPipeInputStream)
- ((DeferredCloseProcessPipeInputStream) stderr).processExited();
-
- if (stdin instanceof ProcessPipeOutputStream)
- ((ProcessPipeOutputStream) stdin).processExited();
- });
- break;
-
- default: throw new AssertionError("Unsupported platform: " + platform);
- }
- }
-
- public OutputStream getOutputStream() {
- return stdin;
- }
-
- public InputStream getInputStream() {
- return stdout;
- }
-
- public InputStream getErrorStream() {
- return stderr;
- }
-
- public synchronized int waitFor() throws InterruptedException {
- while (!hasExited) {
- wait();
- }
- return exitcode;
- }
-
- @Override
- public synchronized boolean waitFor(long timeout, TimeUnit unit)
- throws InterruptedException
- {
- if (hasExited) return true;
- if (timeout <= 0) return false;
-
- long remainingNanos = unit.toNanos(timeout);
- long deadline = System.nanoTime() + remainingNanos;
-
- do {
- // Round up to next millisecond
- wait(TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L));
- if (hasExited) {
- return true;
- }
- remainingNanos = deadline - System.nanoTime();
- } while (remainingNanos > 0);
- return hasExited;
- }
-
- public synchronized int exitValue() {
- if (!hasExited) {
- throw new IllegalThreadStateException("process hasn't exited");
- }
- return exitcode;
- }
-
- private static native void destroyProcess(int pid, boolean force);
-
- private void destroy(boolean force) {
- switch (platform) {
- case LINUX:
- case BSD:
- case AIX:
- // There is a risk that pid will be recycled, causing us to
- // kill the wrong process! So we only terminate processes
- // that appear to still be running. Even with this check,
- // there is an unavoidable race condition here, but the window
- // is very small, and OSes try hard to not recycle pids too
- // soon, so this is quite safe.
- synchronized (this) {
- if (!hasExited)
- destroyProcess(pid, force);
- }
- try { stdin.close(); } catch (IOException ignored) {}
- try { stdout.close(); } catch (IOException ignored) {}
- try { stderr.close(); } catch (IOException ignored) {}
- break;
-
- case SOLARIS:
- // There is a risk that pid will be recycled, causing us to
- // kill the wrong process! So we only terminate processes
- // that appear to still be running. Even with this check,
- // there is an unavoidable race condition here, but the window
- // is very small, and OSes try hard to not recycle pids too
- // soon, so this is quite safe.
- synchronized (this) {
- if (!hasExited)
- destroyProcess(pid, force);
- try {
- stdin.close();
- if (stdout_inner_stream != null)
- stdout_inner_stream.closeDeferred(stdout);
- if (stderr instanceof DeferredCloseInputStream)
- ((DeferredCloseInputStream) stderr)
- .closeDeferred(stderr);
- } catch (IOException e) {
- // ignore
- }
- }
- break;
-
- default: throw new AssertionError("Unsupported platform: " + platform);
- }
- }
-
- public void destroy() {
- destroy(false);
- }
-
- @Override
- public Process destroyForcibly() {
- destroy(true);
- return this;
- }
-
- @Override
- public long getPid() {
- return pid;
- }
-
- @Override
- public synchronized boolean isAlive() {
- return !hasExited;
- }
-
- private static native void init();
-
- static {
- init();
- }
-
- /**
- * A buffered input stream for a subprocess pipe file descriptor
- * that allows the underlying file descriptor to be reclaimed when
- * the process exits, via the processExited hook.
- *
- * This is tricky because we do not want the user-level InputStream to be
- * closed until the user invokes close(), and we need to continue to be
- * able to read any buffered data lingering in the OS pipe buffer.
- */
- private static class ProcessPipeInputStream extends BufferedInputStream {
- private final Object closeLock = new Object();
-
- ProcessPipeInputStream(int fd) {
- super(new FileInputStream(newFileDescriptor(fd)));
- }
- private static byte[] drainInputStream(InputStream in)
- throws IOException {
- int n = 0;
- int j;
- byte[] a = null;
- while ((j = in.available()) > 0) {
- a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
- n += in.read(a, n, j);
- }
- return (a == null || n == a.length) ? a : Arrays.copyOf(a, n);
- }
-
- /** Called by the process reaper thread when the process exits. */
- synchronized void processExited() {
- synchronized (closeLock) {
- try {
- InputStream in = this.in;
- // this stream is closed if and only if: in == null
- if (in != null) {
- byte[] stragglers = drainInputStream(in);
- in.close();
- this.in = (stragglers == null) ?
- ProcessBuilder.NullInputStream.INSTANCE :
- new ByteArrayInputStream(stragglers);
- }
- } catch (IOException ignored) {}
- }
- }
-
- @Override
- public void close() throws IOException {
- // BufferedInputStream#close() is not synchronized unlike most other
- // methods. Synchronizing helps avoid race with processExited().
- synchronized (closeLock) {
- super.close();
- }
- }
- }
-
- /**
- * A buffered output stream for a subprocess pipe file descriptor
- * that allows the underlying file descriptor to be reclaimed when
- * the process exits, via the processExited hook.
- */
- private static class ProcessPipeOutputStream extends BufferedOutputStream {
- ProcessPipeOutputStream(int fd) {
- super(new FileOutputStream(newFileDescriptor(fd)));
- }
-
- /** Called by the process reaper thread when the process exits. */
- synchronized void processExited() {
- OutputStream out = this.out;
- if (out != null) {
- try {
- out.close();
- } catch (IOException ignored) {
- // We know of no reason to get an IOException, but if
- // we do, there's nothing else to do but carry on.
- }
- this.out = ProcessBuilder.NullOutputStream.INSTANCE;
- }
- }
- }
-
- // A FileInputStream that supports the deferment of the actual close
- // operation until the last pending I/O operation on the stream has
- // finished. This is required on Solaris because we must close the stdin
- // and stdout streams in the destroy method in order to reclaim the
- // underlying file descriptors. Doing so, however, causes any thread
- // currently blocked in a read on one of those streams to receive an
- // IOException("Bad file number"), which is incompatible with historical
- // behavior. By deferring the close we allow any pending reads to see -1
- // (EOF) as they did before.
- //
- private static class DeferredCloseInputStream extends FileInputStream
- {
- DeferredCloseInputStream(FileDescriptor fd) {
- super(fd);
- }
-
- private Object lock = new Object(); // For the following fields
- private boolean closePending = false;
- private int useCount = 0;
- private InputStream streamToClose;
-
- private void raise() {
- synchronized (lock) {
- useCount++;
- }
- }
-
- private void lower() throws IOException {
- synchronized (lock) {
- useCount--;
- if (useCount == 0 && closePending) {
- streamToClose.close();
- }
- }
- }
-
- // stc is the actual stream to be closed; it might be this object, or
- // it might be an upstream object for which this object is downstream.
- //
- private void closeDeferred(InputStream stc) throws IOException {
- synchronized (lock) {
- if (useCount == 0) {
- stc.close();
- } else {
- closePending = true;
- streamToClose = stc;
- }
- }
- }
-
- public void close() throws IOException {
- synchronized (lock) {
- useCount = 0;
- closePending = false;
- }
- super.close();
- }
-
- public int read() throws IOException {
- raise();
- try {
- return super.read();
- } finally {
- lower();
- }
- }
-
- public int read(byte[] b) throws IOException {
- raise();
- try {
- return super.read(b);
- } finally {
- lower();
- }
- }
-
- public int read(byte[] b, int off, int len) throws IOException {
- raise();
- try {
- return super.read(b, off, len);
- } finally {
- lower();
- }
- }
-
- public long skip(long n) throws IOException {
- raise();
- try {
- return super.skip(n);
- } finally {
- lower();
- }
- }
-
- public int available() throws IOException {
- raise();
- try {
- return super.available();
- } finally {
- lower();
- }
- }
- }
-
- /**
- * A buffered input stream for a subprocess pipe file descriptor
- * that allows the underlying file descriptor to be reclaimed when
- * the process exits, via the processExited hook.
- *
- * This is tricky because we do not want the user-level InputStream to be
- * closed until the user invokes close(), and we need to continue to be
- * able to read any buffered data lingering in the OS pipe buffer.
- *
- * On AIX this is especially tricky, because the 'close()' system call
- * will block if another thread is at the same time blocked in a file
- * operation (e.g. 'read()') on the same file descriptor. We therefore
- * combine 'ProcessPipeInputStream' approach used on Linux and Bsd
- * with the DeferredCloseInputStream approach used on Solaris. This means
- * that every potentially blocking operation on the file descriptor
- * increments a counter before it is executed and decrements it once it
- * finishes. The 'close()' operation will only be executed if there are
- * no pending operations. Otherwise it is deferred after the last pending
- * operation has finished.
- *
- */
- private static class DeferredCloseProcessPipeInputStream
- extends BufferedInputStream {
-
- private final Object closeLock = new Object();
- private int useCount = 0;
- private boolean closePending = false;
-
- DeferredCloseProcessPipeInputStream(int fd) {
- super(new FileInputStream(newFileDescriptor(fd)));
- }
-
- private InputStream drainInputStream(InputStream in)
- throws IOException {
- int n = 0;
- int j;
- byte[] a = null;
- synchronized (closeLock) {
- if (buf == null) // asynchronous close()?
- return null; // discard
- j = in.available();
- }
- while (j > 0) {
- a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
- synchronized (closeLock) {
- if (buf == null) // asynchronous close()?
- return null; // discard
- n += in.read(a, n, j);
- j = in.available();
- }
- }
- return (a == null) ?
- ProcessBuilder.NullInputStream.INSTANCE :
- new ByteArrayInputStream(n == a.length ? a : Arrays.copyOf(a, n));
- }
-
- /** Called by the process reaper thread when the process exits. */
- synchronized void processExited() {
- try {
- InputStream in = this.in;
- if (in != null) {
- InputStream stragglers = drainInputStream(in);
- in.close();
- this.in = stragglers;
- }
- } catch (IOException ignored) { }
- }
-
- private void raise() {
- synchronized (closeLock) {
- useCount++;
- }
- }
-
- private void lower() throws IOException {
- synchronized (closeLock) {
- useCount--;
- if (useCount == 0 && closePending) {
- closePending = false;
- super.close();
- }
- }
- }
-
- @Override
- public int read() throws IOException {
- raise();
- try {
- return super.read();
- } finally {
- lower();
- }
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- raise();
- try {
- return super.read(b);
- } finally {
- lower();
- }
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- raise();
- try {
- return super.read(b, off, len);
- } finally {
- lower();
- }
- }
-
- @Override
- public long skip(long n) throws IOException {
- raise();
- try {
- return super.skip(n);
- } finally {
- lower();
- }
- }
-
- @Override
- public int available() throws IOException {
- raise();
- try {
- return super.available();
- } finally {
- lower();
- }
- }
-
- @Override
- public void close() throws IOException {
- // BufferedInputStream#close() is not synchronized unlike most other
- // methods. Synchronizing helps avoid racing with drainInputStream().
- synchronized (closeLock) {
- if (useCount == 0) {
- super.close();
- }
- else {
- closePending = true;
- }
- }
- }
- }
-}
diff --git a/jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c b/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c
similarity index 98%
rename from jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c
rename to jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c
index 18dee4d..3a962ab 100644
--- a/jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c
+++ b/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -203,7 +203,7 @@
}
JNIEXPORT void JNICALL
-Java_java_lang_UNIXProcess_init(JNIEnv *env, jclass clazz)
+Java_java_lang_ProcessImpl_init(JNIEnv *env, jclass clazz)
{
parentPathv = effectivePathv(env);
CHECK_NULL(parentPathv);
@@ -230,7 +230,7 @@
/* Block until a child process exits and return its exit code.
Note, can only be called once for any given pid. */
JNIEXPORT jint JNICALL
-Java_java_lang_UNIXProcess_waitForProcessExit(JNIEnv* env,
+Java_java_lang_ProcessImpl_waitForProcessExit(JNIEnv* env,
jobject junk,
jint pid)
{
@@ -562,7 +562,7 @@
}
JNIEXPORT jint JNICALL
-Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
+Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
jobject process,
jint mode,
jbyteArray helperpath,
@@ -714,7 +714,7 @@
}
JNIEXPORT void JNICALL
-Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env,
+Java_java_lang_ProcessImpl_destroyProcess(JNIEnv *env,
jobject junk,
jint pid,
jboolean force)
diff --git a/jdk/src/java.base/unix/native/libjava/childproc.h b/jdk/src/java.base/unix/native/libjava/childproc.h
index 75352a7..4dd129c 100644
--- a/jdk/src/java.base/unix/native/libjava/childproc.h
+++ b/jdk/src/java.base/unix/native/libjava/childproc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -79,7 +79,7 @@
} while((_result == -1) && (errno == EINTR)); \
} while(0)
-/* These numbers must be the same as the Enum in UNIXProcess.java
+/* These numbers must be the same as the Enum in ProcessImpl.java
* Must be a better way of doing this.
*/
#define MODE_FORK 1
diff --git a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c
index 921a725..40c0f71 100644
--- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c
+++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c
@@ -48,6 +48,8 @@
isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
"(Ljava/net/InetAddress;I)V");
+ initInetAddressIDs(env);
+
// implement read timeout with select.
isRcvTimeoutSupported = 0;
}
@@ -294,6 +296,8 @@
return -1;
}
+ SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
+
ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
diff --git a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c
index c4686e0..b4f9f14 100644
--- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c
+++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c
@@ -699,6 +699,7 @@
}
return;
}
+ SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0);
(*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd);
if (him.him.sa_family == AF_INET) {
diff --git a/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c b/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c
index 30d6d64..8cd94ea 100644
--- a/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c
+++ b/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c
@@ -105,6 +105,7 @@
return IOS_THROWN;
}
+ SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
(*env)->SetIntField(env, newfdo, fd_fdID, newfd);
remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port);
CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java
index 30f5f67..72d8423 100644
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java
@@ -913,9 +913,9 @@
private static String unquote(String s) {
s = s.trim();
- if (s.isEmpty()) return s;
- if (s.charAt(0) == '"' && s.charAt(s.length()-1) == '"' ||
- s.charAt(0) == '\'' && s.charAt(s.length()-1) == '\'') {
+ if (s.length() >= 2 &&
+ ((s.charAt(0) == '"' && s.charAt(s.length()-1) == '"') ||
+ (s.charAt(0) == '\'' && s.charAt(s.length()-1) == '\''))) {
s = s.substring(1, s.length()-1).trim();
}
return s;
diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java
index 4c63fe1..7bf3ac6 100644
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbKdcRep.java
@@ -62,7 +62,8 @@
throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
}
- for (int i = 1; i < 6; i++) {
+ // We allow KDC to return a non-forwardable ticket if request has -f
+ for (int i = 2; i < 6; i++) {
if (req.reqBody.kdcOptions.get(i) !=
rep.encKDCRepPart.flags.get(i)) {
if (Krb5.DEBUG) {
diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java
index 45f25e8..a8b3404 100644
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java
@@ -149,19 +149,11 @@
ctime = KerberosTime.now();
// check if they are valid arguments. The optional fields
- // should be consistent with settings in KDCOptions.
-
- // TODO: Is this necessary? If the TGT is not FORWARDABLE,
- // you can still request for a FORWARDABLE ticket, just the
- // KDC will give you a non-FORWARDABLE one. Even if you
- // cannot use the ticket expected, it still contains info.
- // This means there will be problem later. We already have
- // flags check in KrbTgsRep. Of course, sometimes the KDC
- // will not issue the ticket at all.
+ // should be consistent with settings in KDCOptions.
if (options.get(KDCOptions.FORWARDABLE) &&
(!(asCreds.flags.get(Krb5.TKT_OPTS_FORWARDABLE)))) {
- throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
+ options.set(KDCOptions.FORWARDABLE, false);
}
if (options.get(KDCOptions.FORWARDED)) {
if (!(asCreds.flags.get(KDCOptions.FORWARDABLE)))
diff --git a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java
index b6a3677..14620e9 100644
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/CredentialsUtil.java
@@ -58,6 +58,9 @@
// TODO: we do not support kerberos referral now
throw new KrbException("Cross realm impersonation not supported");
}
+ if (!ccreds.isForwardable()) {
+ throw new KrbException("S4U2self needs a FORWARDABLE ticket");
+ }
KrbTgsReq req = new KrbTgsReq(
ccreds,
ccreds.getClient(),
@@ -68,6 +71,9 @@
if (!creds.getClient().equals(client)) {
throw new KrbException("S4U2self request not honored by KDC");
}
+ if (!creds.isForwardable()) {
+ throw new KrbException("S4U2self ticket must be FORWARDABLE");
+ }
return creds;
}
diff --git a/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c
index db97c94..6a5e2cb 100644
--- a/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c
+++ b/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c
@@ -316,11 +316,12 @@
if (isaCls == 0) {
jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress");
CHECK_NULL(c);
+ isaCtrID = (*env)->GetMethodID(env, c, "<init>",
+ "(Ljava/net/InetAddress;I)V");
+ CHECK_NULL(isaCtrID);
isaCls = (*env)->NewGlobalRef(env, c);
CHECK_NULL(isaCls);
(*env)->DeleteLocalRef(env, c);
- isaCtrID = (*env)->GetMethodID(env, isaCls, "<init>",
- "(Ljava/net/InetAddress;I)V");
}
}
diff --git a/jdk/src/jdk.security.auth/unix/native/libjaas/Solaris.c b/jdk/src/jdk.security.auth/solaris/native/libjaas/Solaris.c
similarity index 100%
rename from jdk/src/jdk.security.auth/unix/native/libjaas/Solaris.c
rename to jdk/src/jdk.security.auth/solaris/native/libjaas/Solaris.c
diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt
index c6c35f2..fde49fa 100644
--- a/jdk/test/ProblemList.txt
+++ b/jdk/test/ProblemList.txt
@@ -128,9 +128,6 @@
# jdk_instrument
-# 8058536
-java/lang/instrument/NativeMethodPrefixAgent.java generic-all
-
# 8061177
java/lang/instrument/RedefineBigClass.sh generic-all
java/lang/instrument/RetransformBigClass.sh generic-all
@@ -246,6 +243,9 @@
# 8062758
java/security/Security/ClassLoaderDeadlock/Deadlock2.sh generic-all
+# 8026393
+sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java generic-all
+
############################################################################
# jdk_sound
diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups
index 4d4705c..7acb6ab 100644
--- a/jdk/test/TEST.groups
+++ b/jdk/test/TEST.groups
@@ -628,7 +628,6 @@
sun/net/www/protocol/http \
java/io/BufferedReader/Lines.java \
java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java \
- java/lang/CharSequence/DefaultTest.java \
java/lang/IntegralPrimitiveToString.java \
java/lang/PrimitiveSumMinMaxTest.java \
java/lang/String/StringJoinTest.java \
diff --git a/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java b/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java
index 323a05e..ae16712 100644
--- a/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java
+++ b/jdk/test/java/io/Serializable/subclassGC/SubclassGC.java
@@ -50,8 +50,9 @@
}
ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
- ClassLoader loader = new URLClassLoader(((URLClassLoader) systemLoader).getURLs(),
- systemLoader.getParent());
+ URL testClassesURL = new File(System.getProperty("test.classes")).toURI().toURL();
+ ClassLoader loader = new URLClassLoader(new URL[] { testClassesURL } ,
+ systemLoader.getParent());
Class<? extends ObjectOutputStream> cl =
Class.forName(SubclassOfOOS.class.getName(), false,
loader).asSubclass(ObjectOutputStream.class);
diff --git a/jdk/test/java/io/Serializable/subclassGC/security.policy b/jdk/test/java/io/Serializable/subclassGC/security.policy
index 894df4c..a3ef804 100644
--- a/jdk/test/java/io/Serializable/subclassGC/security.policy
+++ b/jdk/test/java/io/Serializable/subclassGC/security.policy
@@ -2,5 +2,7 @@
grant {
permission java.lang.RuntimePermission "createClassLoader";
permission java.lang.RuntimePermission "getClassLoader";
+ permission java.util.PropertyPermission "test.classes", "read";
+ permission java.io.FilePermission "<<ALL FILES>>", "read";
};
diff --git a/jdk/test/java/lang/CharSequence/DefaultTest.java b/jdk/test/java/lang/CharSequence/DefaultTest.java
deleted file mode 100644
index 0595f74..0000000
--- a/jdk/test/java/lang/CharSequence/DefaultTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.PrimitiveIterator;
-import java.util.Spliterator;
-import java.util.stream.Collectors;
-
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.*;
-
-/*
- * @test
- * @summary Unit test for CharSequence default methods
- * @bug 8012665 8025002
- * @run testng DefaultTest
- */
-
-@Test(groups = "lib")
-public class DefaultTest {
-
- @Test(expectedExceptions = NoSuchElementException.class)
- public void testEmptyChars() {
- PrimitiveIterator.OfInt s = "".chars().iterator();
- assertFalse(s.hasNext());
- int ch = s.nextInt();
- }
-
- public void testSimpleChars() {
- List<Integer> list = "abc".chars().boxed().collect(Collectors.toList());
- assertEquals(list, Arrays.asList((int) 'a', (int) 'b', (int) 'c'));
- }
-
- public void testCodePointsCharacteristics() {
- Spliterator.OfInt s = "".codePoints().spliterator();
- assertFalse(s.hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED));
- assertTrue(s.hasCharacteristics(Spliterator.ORDERED));
- }
-
- @Test(expectedExceptions = NoSuchElementException.class)
- public void testEmptyCodePoints() {
- PrimitiveIterator.OfInt s = "".codePoints().iterator();
- assertFalse(s.hasNext());
- int cp = s.nextInt();
- }
-
- public void testSimpleCodePoints() {
- List<Integer> list = "abc".codePoints().boxed().collect(Collectors.toList());
- assertEquals(list, Arrays.asList((int)'a', (int)'b', (int)'c'));
- }
-
- public void testUndefCodePoints() {
- List<Integer> list = "X\ufffeY".codePoints().boxed().collect(Collectors.toList());
- assertEquals(list, Arrays.asList((int)'X', 0xFFFE, (int)'Y'));
- }
-
- public void testSurrogatePairing() {
- // U+1D11E = MUSICAL SYMBOL G CLEF
- // equivalent to surrogate pair U+D834 U+DD1E
- List<Integer> list;
- final int GCLEF = 0x1d11e;
-
- list = "\ud834\udd1e".codePoints().boxed().collect(Collectors.toList());
- assertEquals(list, Arrays.asList(GCLEF));
- list = "A\ud834\udd1e".codePoints().boxed().collect(Collectors.toList());
- assertEquals(list, Arrays.asList((int)'A', GCLEF));
- list = "\ud834\udd1eB".codePoints().boxed().collect(Collectors.toList());
- assertEquals(list, Arrays.asList(GCLEF, (int)'B'));
- list = "X\ud834\udd1eY".codePoints().boxed().collect(Collectors.toList());
- assertEquals(list, Arrays.asList((int)'X', GCLEF, (int)'Y'));
- }
-
- public void testUndefUnpaired() {
- List<Integer> list = "W\udd1eX\ud834Y\ufffeZ".codePoints().boxed().collect(Collectors.toList());
- assertEquals(list, Arrays.asList(
- (int)'W', 0xdd1e, (int)'X', 0xd834, (int)'Y', 0xfffe, (int)'Z'));
- }
-}
diff --git a/jdk/test/java/lang/ProcessBuilder/Basic.java b/jdk/test/java/lang/ProcessBuilder/Basic.java
index b81853b..03d165f 100644
--- a/jdk/test/java/lang/ProcessBuilder/Basic.java
+++ b/jdk/test/java/lang/ProcessBuilder/Basic.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, 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
@@ -26,7 +26,7 @@
* @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689
* 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313
* 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958
- * 4947220 7018606 7034570 4244896 5049299 8003488
+ * 4947220 7018606 7034570 4244896 5049299 8003488 8054494
* @summary Basic tests for Process and Environment Variable code
* @run main/othervm/timeout=300 Basic
* @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=fork Basic
@@ -2042,7 +2042,7 @@
final Object deferred;
Class<?> c = s.getClass();
if (c.getName().equals(
- "java.lang.UNIXProcess$DeferredCloseInputStream"))
+ "java.lang.ProcessImpl$DeferredCloseInputStream"))
{
deferred = s;
} else {
@@ -2059,13 +2059,11 @@
Thread.yield();
}
} else if (s instanceof BufferedInputStream) {
- Field f = Unsafe.class.getDeclaredField("theUnsafe");
- f.setAccessible(true);
- Unsafe unsafe = (Unsafe)f.get(null);
-
- while (unsafe.tryMonitorEnter(s)) {
- unsafe.monitorExit(s);
- Thread.sleep(1);
+ // Wait until after the s.read occurs in "thread" by
+ // checking when the input stream monitor is acquired
+ // (BufferedInputStream.read is synchronized)
+ while (!isLocked(s, 10)) {
+ Thread.sleep(100);
}
}
p.destroy();
@@ -2565,4 +2563,21 @@
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
+
+ static boolean isLocked(final Object monitor, final long millis) throws InterruptedException {
+ return new Thread() {
+ volatile boolean unlocked;
+
+ @Override
+ public void run() {
+ synchronized (monitor) { unlocked = true; }
+ }
+
+ boolean isLocked() throws InterruptedException {
+ start();
+ join(millis);
+ return !unlocked;
+ }
+ }.isLocked();
+ }
}
diff --git a/jdk/test/java/lang/ref/OOMEInReferenceHandler.java b/jdk/test/java/lang/ref/OOMEInReferenceHandler.java
index 39848fa..cd09b07 100644
--- a/jdk/test/java/lang/ref/OOMEInReferenceHandler.java
+++ b/jdk/test/java/lang/ref/OOMEInReferenceHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,7 @@
* @test
* @bug 7038914 8016341
* @summary Verify that the reference handler does not die after an OOME allocating the InterruptedException object
- * @run main/othervm -Xmx24M -XX:-UseTLAB OOMEInReferenceHandler
+ * @run main/othervm -XX:-UseGCOverheadLimit -Xmx24M -XX:-UseTLAB OOMEInReferenceHandler
* @author peter.levart@gmail.com
*/
diff --git a/jdk/test/java/net/ServerSocket/AcceptInheritHandle.java b/jdk/test/java/net/ServerSocket/AcceptInheritHandle.java
new file mode 100644
index 0000000..ce175f2
--- /dev/null
+++ b/jdk/test/java/net/ServerSocket/AcceptInheritHandle.java
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ * 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 8067105
+ * @summary Socket returned by ServerSocket.accept() is inherited by child process on Windows
+ * @author Chris Hegarty
+ */
+
+import java.io.*;
+import java.net.*;
+import java.nio.channels.ServerSocketChannel;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+public class AcceptInheritHandle {
+
+ enum ServerSocketProducer {
+ JAVA_NET(() -> {
+ try {
+ return new ServerSocket(); }
+ catch(IOException x) {
+ throw new UncheckedIOException(x);
+ }
+ }),
+ NIO_CHANNELS(() -> {
+ try {
+ return ServerSocketChannel.open().socket();
+ } catch (IOException x) {
+ throw new UncheckedIOException(x);
+ }
+ });
+
+ final Supplier<ServerSocket> supplier;
+ ServerSocketProducer(Supplier<ServerSocket> supplier) {
+ this.supplier = supplier;
+ }
+ Supplier<ServerSocket> supplier () { return supplier; }
+ }
+
+ static final String JAVA = System.getProperty("java.home")
+ + File.separator + "bin" + File.separator + "java";
+
+ static final String CLASSPATH = System.getProperty("java.class.path");
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 1)
+ server(ServerSocketProducer.valueOf(args[0]));
+ else
+ mainEntry();
+ }
+
+ static void mainEntry() throws Exception {
+ testJavaNetServerSocket();
+ testNioServerSocketChannel();
+ }
+
+ static void testJavaNetServerSocket() throws Exception {
+ test(ServerSocketProducer.JAVA_NET);
+ test(ServerSocketProducer.JAVA_NET, "-Djava.net.preferIPv4Stack=true");
+ }
+ static void testNioServerSocketChannel() throws Exception {
+ test(ServerSocketProducer.NIO_CHANNELS);
+ }
+
+ static void test(ServerSocketProducer ssp, String... sysProps) throws Exception {
+ System.out.println("\nStarting test for " + ssp.name());
+
+ List<String> commands = new ArrayList<>();
+ commands.add(JAVA);
+ for (String prop : sysProps)
+ commands.add(prop);
+ commands.add("-cp");
+ commands.add(CLASSPATH);
+ commands.add("AcceptInheritHandle");
+ commands.add(ssp.name());
+
+ System.out.println("Executing: "+ commands);
+ ProcessBuilder pb = new ProcessBuilder(commands);
+ pb.redirectError(ProcessBuilder.Redirect.INHERIT);
+ Process serverProcess = pb.start();
+ DataInputStream dis = new DataInputStream(serverProcess.getInputStream());
+
+ int port = dis.readInt();
+ System.out.println("Server process listening on " + port + ", connecting...");
+
+ Socket socket = new Socket("localhost", port);
+ String s = dis.readUTF();
+ System.out.println("Server process said " + s);
+
+ serverProcess.destroy();
+ serverProcess.waitFor(30, TimeUnit.SECONDS);
+ System.out.println("serverProcess exitCode:" + serverProcess.exitValue());
+
+ try {
+ socket.setSoTimeout(10 * 1000);
+ socket.getInputStream().read();
+ } catch (SocketTimeoutException x) {
+ // failed
+ throw new RuntimeException("Failed: should get reset, not " + x);
+ } catch (SocketException x) {
+ System.out.println("Expected:" + x);
+ }
+ }
+
+ static void server(ServerSocketProducer producer) throws Exception {
+ try (ServerSocket ss = producer.supplier().get()) {
+ ss.bind(new InetSocketAddress(0));
+ int port = ss.getLocalPort();
+ DataOutputStream dos = new DataOutputStream(System.out);
+ dos.writeInt(port);
+ dos.flush();
+
+ ss.accept(); // do not close
+
+ Runtime.getRuntime().exec("sleep 20");
+ Thread.sleep(3 * 1000);
+
+ dos.writeUTF("kill me!");
+ dos.flush();
+ Thread.sleep(30 * 1000);
+ }
+ }
+}
diff --git a/jdk/test/java/net/Socket/GetLocalAddress.java b/jdk/test/java/net/Socket/GetLocalAddress.java
index e9573d2..3e98bc9 100644
--- a/jdk/test/java/net/Socket/GetLocalAddress.java
+++ b/jdk/test/java/net/Socket/GetLocalAddress.java
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4106601 8026245
+ * @bug 4106601 8026245 8071424
* @run main/othervm GetLocalAddress
* @run main/othervm -Djava.net.preferIPv4Stack=true GetLocalAddress
* @run main/othervm -Djava.net.preferIPv6Addresses=true GetLocalAddress
@@ -39,6 +39,8 @@
static int port;
public static void main(String args[]) throws Exception {
+ testBindNull();
+
boolean error = true;
int linger = 65546;
int value = 0;
@@ -66,4 +68,18 @@
}
}
+ static void testBindNull() throws Exception {
+ try (Socket soc = new Socket()) {
+ soc.bind(null);
+ if (!soc.isBound())
+ throw new RuntimeException(
+ "should be bound after bind(null)");
+ if (soc.getLocalPort() <= 0)
+ throw new RuntimeException(
+ "bind(null) failed, local port: " + soc.getLocalPort());
+ if (soc.getLocalAddress() == null)
+ throw new RuntimeException(
+ "bind(null) failed, local address is null");
+ }
+ }
}
diff --git a/jdk/test/java/util/ResourceBundle/Bug6287579.java b/jdk/test/java/util/ResourceBundle/Bug6287579.java
deleted file mode 100644
index 43e7e8c..0000000
--- a/jdk/test/java/util/ResourceBundle/Bug6287579.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * 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 6287579
- * @summary Make sure that getContents() of ListResourceBundle subclasses is 'protected'
- * and returns a different Object[]][] instance in each invocation.
- */
-
-import java.lang.reflect.*;
-import java.util.*;
-
-public class Bug6287579 {
- static final Locale ROOT = new Locale("");
-
- static final String[] baseNames = {
- "sun.text.resources.BreakIteratorInfo",
- "sun.text.resources.FormatData",
- "sun.text.resources.CollationData",
- "sun.util.resources.LocaleNames",
- "sun.util.resources.TimeZoneNames",
-
- // Make sure the properties-to-class conversion tool generates
- // the proper getContents().
- "sun.awt.resources.awt",
- };
-
- public static void main(String[] args) throws Exception {
- int errors = 0;
-
- List<Locale> locales = new ArrayList<Locale>();
- locales.addAll(Arrays.asList(Locale.getAvailableLocales()));
- locales.add(ROOT);
-
- for (Locale locale : locales) {
- for (String base : baseNames) {
- String className = getResourceName(base, locale);
- errors += checkGetContents(className);
- }
- }
- if (errors > 0) {
- throw new RuntimeException(errors + " errors found");
- }
- }
-
- static int checkGetContents(String className) throws Exception {
- int err = 0;
- try {
- Class clazz = Class.forName(className);
- Method getContentsMethod = clazz.getDeclaredMethod("getContents",
- (Class[]) null);
- if (!Modifier.isProtected(getContentsMethod.getModifiers())) {
- System.err.println(className + ": not protected");
- err++;
- }
- getContentsMethod.setAccessible(true);
- Object bundle = clazz.newInstance();
- Object o1 = getContentsMethod.invoke(bundle, (Object[]) null);
- Object o2 = getContentsMethod.invoke(bundle, (Object[]) null);
- if (o1 == o2) {
- System.err.println(className + ": same instance returned");
- err++;
- }
- } catch (ClassNotFoundException ce) {
- // Skip nonexistent classes
- } catch (NoSuchMethodException me) {
- System.out.println(className + ": no declared getContents()");
- }
- return err;
- }
-
- static String getResourceName(String base, Locale locale) {
- if (locale.equals(ROOT)) {
- return base;
- }
- StringBuilder sb = new StringBuilder(base);
- sb.append('_').append(locale.getLanguage());
- if (locale.getCountry().length() > 0
- || locale.getVariant().length() > 0) {
- sb.append('_').append(locale.getCountry());
- }
- if (locale.getVariant().length() > 0) {
- sb.append('_').append(locale.getVariant());
- }
- return sb.toString();
- }
-}
diff --git a/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java b/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java
index f226a82..9815340 100644
--- a/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java
+++ b/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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,7 +23,7 @@
/**
* @test
- * @bug 8020156 8020009 8022326 8012913 8024405 8024408
+ * @bug 8020156 8020009 8022326 8012913 8024405 8024408 8071477
* @run testng SpliteratorCharacteristics
*/
@@ -59,6 +59,57 @@
@Test
public class SpliteratorCharacteristics {
+ public void testSpliteratorFromCharSequence() {
+ class CharSequenceImpl implements CharSequence {
+ final String s;
+
+ public CharSequenceImpl(String s) {
+ this.s = s;
+ }
+
+ @Override
+ public int length() {
+ return s.length();
+ }
+
+ @Override
+ public char charAt(int index) {
+ return s.charAt(index);
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ return s.subSequence(start, end);
+ }
+
+ @Override
+ public String toString() {
+ return s;
+ }
+ }
+
+ CharSequence cs = "A";
+ Spliterator.OfInt s = cs.chars().spliterator();
+ assertCharacteristics(s, Spliterator.IMMUTABLE | Spliterator.ORDERED |
+ Spliterator.SIZED | Spliterator.SUBSIZED);
+ assertHasNotCharacteristics(s, Spliterator.CONCURRENT);
+ s = cs.codePoints().spliterator();
+ assertCharacteristics(s, Spliterator.IMMUTABLE | Spliterator.ORDERED);
+ assertHasNotCharacteristics(s, Spliterator.CONCURRENT);
+
+ for (CharSequence c : Arrays.asList(new CharSequenceImpl("A"),
+ new StringBuilder("A"),
+ new StringBuffer("A"))) {
+ s = cs.chars().spliterator();
+ assertCharacteristics(s, Spliterator.ORDERED |
+ Spliterator.SIZED | Spliterator.SUBSIZED);
+ assertHasNotCharacteristics(s, Spliterator.CONCURRENT);
+ s = cs.codePoints().spliterator();
+ assertCharacteristics(s, Spliterator.ORDERED);
+ assertHasNotCharacteristics(s, Spliterator.CONCURRENT);
+ }
+ }
+
public void testSpliteratorFromCollection() {
List<Integer> l = Arrays.asList(1, 2, 3, 4);
diff --git a/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java b/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java
index 69c7cf5..d959300 100644
--- a/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java
+++ b/jdk/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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,7 +25,7 @@
* @test
* @summary Spliterator traversing and splitting tests
* @run testng SpliteratorTraversingAndSplittingTest
- * @bug 8020016
+ * @bug 8020016 8071477
*/
import org.testng.annotations.DataProvider;
@@ -85,7 +85,38 @@
@Test
public class SpliteratorTraversingAndSplittingTest {
- private static List<Integer> SIZES = Arrays.asList(0, 1, 10, 100, 1000);
+ private static final List<Integer> SIZES = Arrays.asList(0, 1, 10, 100, 1000);
+
+ private static final String LOW = new String(new char[] {Character.MIN_LOW_SURROGATE});
+ private static final String HIGH = new String(new char[] {Character.MIN_HIGH_SURROGATE});
+ private static final String HIGH_LOW = HIGH + LOW;
+ private static final String CHAR_HIGH_LOW = "A" + HIGH_LOW;
+ private static final String HIGH_LOW_CHAR = HIGH_LOW + "A";
+ private static final String CHAR_HIGH_LOW_CHAR = "A" + HIGH_LOW + "A";
+
+ private static final List<String> STRINGS = generateTestStrings();
+
+ private static List<String> generateTestStrings() {
+ List<String> strings = new ArrayList<>();
+ for (int n : Arrays.asList(1, 2, 3, 16, 17)) {
+ strings.add(generate("A", n));
+ strings.add(generate(LOW, n));
+ strings.add(generate(HIGH, n));
+ strings.add(generate(HIGH_LOW, n));
+ strings.add(generate(CHAR_HIGH_LOW, n));
+ strings.add(generate(HIGH_LOW_CHAR, n));
+ strings.add(generate(CHAR_HIGH_LOW_CHAR, n));
+ }
+ return strings;
+ }
+
+ private static String generate(String s, int n) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < n; i++) {
+ sb.append(s);
+ }
+ return sb.toString();
+ }
private static class SpliteratorDataBuilder<T> {
List<Object[]> data;
@@ -564,6 +595,60 @@
}
}
+ private static class SpliteratorOfIntCharDataBuilder {
+ List<Object[]> data;
+
+ String s;
+
+ List<Integer> expChars;
+
+ List<Integer> expCodePoints;
+
+ SpliteratorOfIntCharDataBuilder(List<Object[]> data, String s) {
+ this.data = data;
+ this.s = s;
+ this.expChars = transform(s, false);
+ this.expCodePoints = transform(s, true);
+ }
+
+ static List<Integer> transform(String s, boolean toCodePoints) {
+ List<Integer> l = new ArrayList<>();
+
+ if (!toCodePoints) {
+ for (int i = 0; i < s.length(); i++) {
+ l.add((int) s.charAt(i));
+ }
+ }
+ else {
+ for (int i = 0; i < s.length();) {
+ char c1 = s.charAt(i++);
+ int cp = c1;
+ if (Character.isHighSurrogate(c1) && i < s.length()) {
+ char c2 = s.charAt(i);
+ if (Character.isLowSurrogate(c2)) {
+ i++;
+ cp = Character.toCodePoint(c1, c2);
+ }
+ }
+ l.add(cp);
+ }
+ }
+ return l;
+ }
+
+ void add(String description, Function<String, CharSequence> f) {
+ description = description.replace("%s", s);
+ {
+ Supplier<Spliterator.OfInt> supplier = () -> f.apply(s).chars().spliterator();
+ data.add(new Object[]{description + ".chars().spliterator()", expChars, supplier});
+ }
+ {
+ Supplier<Spliterator.OfInt> supplier = () -> f.apply(s).codePoints().spliterator();
+ data.add(new Object[]{description + ".codePoints().spliterator()", expCodePoints, supplier});
+ }
+ }
+ }
+
static Object[][] spliteratorOfIntDataProvider;
@DataProvider(name = "Spliterator.OfInt")
@@ -615,6 +700,43 @@
() -> new IntSpliteratorFromArray(exp));
}
+ // Class for testing default methods
+ class CharSequenceImpl implements CharSequence {
+ final String s;
+
+ public CharSequenceImpl(String s) {
+ this.s = s;
+ }
+
+ @Override
+ public int length() {
+ return s.length();
+ }
+
+ @Override
+ public char charAt(int index) {
+ return s.charAt(index);
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ return s.subSequence(start, end);
+ }
+
+ @Override
+ public String toString() {
+ return s;
+ }
+ }
+
+ for (String string : STRINGS) {
+ SpliteratorOfIntCharDataBuilder cdb = new SpliteratorOfIntCharDataBuilder(data, string);
+ cdb.add("\"%s\"", s -> s);
+ cdb.add("new CharSequenceImpl(\"%s\")", CharSequenceImpl::new);
+ cdb.add("new StringBuilder(\"%s\")", StringBuilder::new);
+ cdb.add("new StringBuffer(\"%s\")", StringBuffer::new);
+ }
+
return spliteratorOfIntDataProvider = data.toArray(new Object[0][]);
}
diff --git a/jdk/test/javax/xml/jaxp/transform/8062923/XslSubstringTest.java b/jdk/test/javax/xml/jaxp/transform/8062923/XslSubstringTest.java
new file mode 100644
index 0000000..fcc36ae
--- /dev/null
+++ b/jdk/test/javax/xml/jaxp/transform/8062923/XslSubstringTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ *
+ * 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 8062923 8062924
+ * @run testng XslSubstringTest
+ * @summary Test xsl substring function with negative, Inf and
+ * NaN length and few other use cases
+ */
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+
+public class XslSubstringTest {
+
+ final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test></test>";
+ final String xslPre = "<xsl:stylesheet version='1.0'"
+ + " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>"
+ + "<xsl:output method='xml' indent='yes' omit-xml-declaration='yes'/>"
+ + "<xsl:template match='/'><t>";
+ final String xslPost = "</t></xsl:template></xsl:stylesheet>";
+
+ private String testTransform(String xsl) throws Exception {
+ //Prepare sources for transormation
+ Source src = new StreamSource(new StringReader(xml));
+ Source xslsrc = new StreamSource(new StringReader(xslPre + xsl + xslPost));
+ //Create factory, template and transformer
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Templates tmpl = tf.newTemplates(xslsrc);
+ Transformer t = tmpl.newTransformer();
+ //Prepare output stream
+ StringWriter xmlResultString = new StringWriter();
+ StreamResult xmlResultStream = new StreamResult(xmlResultString);
+ //Transform
+ t.transform(src, xmlResultStream);
+ return xmlResultString.toString().trim();
+ }
+
+ @Test
+ public void test8062923() throws Exception {
+ assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2,-1)\"/>|"),
+ "<t>||</t>");
+ }
+
+ @Test
+ public void test8062924() throws Exception {
+ assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2,-1 div 0)\"/>|"),
+ "<t>||</t>");
+ }
+
+ @Test
+ public void testGeneral1() throws Exception {
+ assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2, 1)\"/>|"),
+ "<t>|s|</t>");
+ }
+
+ @Test
+ public void testGeneral2() throws Exception {
+ assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2, 1 div 0)\"/>|"),
+ "<t>|sdf|</t>");
+ }
+
+ @Test
+ public void testGeneral3() throws Exception {
+ assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2, -0 div 0)\"/>|"),
+ "<t>||</t>");
+ }
+
+ @Test
+ public void testGeneral4() throws Exception {
+ assertEquals(testTransform("|<xsl:value-of select=\"substring('asdf',2, 0 div 0)\"/>|"),
+ "<t>||</t>");
+ }
+}
diff --git a/jdk/test/javax/xml/ws/8046817/GenerateEnumSchema.java b/jdk/test/javax/xml/ws/8046817/GenerateEnumSchema.java
new file mode 100644
index 0000000..cb70d22
--- /dev/null
+++ b/jdk/test/javax/xml/ws/8046817/GenerateEnumSchema.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8046817
+ * @summary schemagen fails to generate xsd for enum types
+ * @run main/othervm GenerateEnumSchema
+ */
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.file.Paths;
+import java.util.Scanner;
+
+public class GenerateEnumSchema {
+
+ private static final String SCHEMA_OUTPUT_FILENAME = "schema1.xsd";
+ private static final File schemaOutputFile = new File(SCHEMA_OUTPUT_FILENAME);
+
+ public static void main(String[] args) throws Exception, IOException {
+ //Check schema generation for class type
+ runSchemaGen("TestClassType.java");
+ checkIfSchemaGenerated();
+ checkSchemaContent("<xs:complexType name=\"testClassType\">");
+ checkSchemaContent("<xs:element name=\"a\" type=\"xs:int\"/>");
+ schemaOutputFile.delete();
+ //Check schema generation for enum type
+ runSchemaGen("TestEnumType.java");
+ checkIfSchemaGenerated();
+ checkSchemaContent("<xs:simpleType name=\"testEnumType\">");
+ checkSchemaContent("<xs:enumeration value=\"ONE\"/>");
+ checkSchemaContent("<xs:enumeration value=\"TWO\"/>");
+ checkSchemaContent("<xs:enumeration value=\"THREE\"/>");
+ schemaOutputFile.delete();
+ }
+
+ private static void checkIfSchemaGenerated() {
+ if (!schemaOutputFile.exists()) {
+ throw new RuntimeException("FAIL:" + SCHEMA_OUTPUT_FILENAME + " was not generated by schemagen tool");
+ }
+ }
+
+ private static void checkSchemaContent(String exp_token) throws FileNotFoundException {
+ System.out.print("Check if generated schema contains '" + exp_token + "' string: ");
+ try (Scanner scanner = new Scanner(schemaOutputFile)) {
+ if (scanner.findWithinHorizon(exp_token, 0) != null) {
+ System.out.println("OK");
+ return;
+ }
+ }
+ System.out.println("FAIL");
+ throw new RuntimeException("The '" + exp_token + "' is not found in generated schema");
+
+ }
+
+ private static String getClassFilePath(String filename) {
+ String testSrc = System.getProperty("test.src");
+ if (testSrc == null) {
+ testSrc = ".";
+ }
+ return Paths.get(testSrc).resolve(filename).toString();
+ }
+
+ private static String getSchemagen() {
+ String javaHome = System.getProperty("java.home");
+ if (javaHome.endsWith("jre")) {
+ javaHome = new File(javaHome).getParent();
+ }
+ String schemagen = javaHome + File.separator + "bin" + File.separator + "schemagen";
+ if (System.getProperty("os.name").startsWith("Windows")) {
+ schemagen = schemagen.concat(".exe");
+ }
+ return schemagen;
+ }
+
+ private static void logOutput(Process p) throws IOException {
+ BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ String s = r.readLine();
+ while (s != null) {
+ System.out.println(s.trim());
+ s = r.readLine();
+ }
+ }
+
+ private static void runSchemaGen(String classFile) {
+ String schemagen = getSchemagen();
+
+ try {
+ System.out.println("Call to schemagen: " + schemagen + " " + classFile);
+ String[] schemagen_args = {
+ schemagen,
+ getClassFilePath(classFile)
+ };
+
+ ProcessBuilder pb = new ProcessBuilder(schemagen_args);
+ pb.redirectErrorStream(true);
+ Process p = pb.start();
+ logOutput(p);
+ int result = p.waitFor();
+ p.destroy();
+
+ if (result != 0) {
+ throw new RuntimeException("schemagen failed");
+ }
+ } catch (IOException | InterruptedException e) {
+ System.err.println("Can't run schemagen tool. Exception:");
+ e.printStackTrace(System.err);
+ throw new RuntimeException("Error launching schemagen tool");
+ }
+ }
+}
diff --git a/jdk/test/javax/xml/ws/8046817/TestClassType.java b/jdk/test/javax/xml/ws/8046817/TestClassType.java
new file mode 100644
index 0000000..e5d72f3
--- /dev/null
+++ b/jdk/test/javax/xml/ws/8046817/TestClassType.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType
+public class TestClassType {
+ public int a;
+}
diff --git a/jdk/test/javax/xml/ws/8046817/TestEnumType.java b/jdk/test/javax/xml/ws/8046817/TestEnumType.java
new file mode 100644
index 0000000..785fb19
--- /dev/null
+++ b/jdk/test/javax/xml/ws/8046817/TestEnumType.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.xml.bind.annotation.XmlEnum;
+
+@XmlEnum(String.class)
+public enum TestEnumType {
+ ONE, TWO, THREE
+}
diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/JarUtils.java b/jdk/test/lib/testlibrary/jdk/testlibrary/JarUtils.java
new file mode 100644
index 0000000..69c2101
--- /dev/null
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JarUtils.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.testlibrary;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+/**
+ * Common library for various test jar file utility functions.
+ */
+public final class JarUtils {
+
+ /**
+ * Create jar file with specified files.
+ */
+ public static void createJar(String dest, String... files)
+ throws IOException {
+ try (JarOutputStream jos = new JarOutputStream(
+ new FileOutputStream(dest), new Manifest())) {
+ for (String file : files) {
+ System.out.println(String.format("Adding %s to %s",
+ file, dest));
+
+ // add an archive entry, and write a file
+ jos.putNextEntry(new JarEntry(file));
+ try (FileInputStream fis = new FileInputStream(file)) {
+ fis.transferTo(jos);
+ }
+ }
+ }
+ System.out.println();
+ }
+
+ /**
+ * Add specified files to existing jar file.
+ */
+ public static void updateJar(String src, String dest, String... files)
+ throws IOException {
+ try (JarOutputStream jos = new JarOutputStream(
+ new FileOutputStream(dest))) {
+
+ // copy each old entry into destination unless the entry name
+ // is in the updated list
+ List<String> updatedFiles = new ArrayList<>();
+ try (JarFile srcJarFile = new JarFile(src)) {
+ Enumeration entries = srcJarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = (JarEntry) entries.nextElement();
+ String name = entry.getName();
+ boolean found = false;
+ for (String file : files) {
+ if (name.equals(file)) {
+ updatedFiles.add(file);
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ System.out.println(String.format("Updating %s with %s",
+ dest, name));
+ jos.putNextEntry(new JarEntry(name));
+ try (FileInputStream fis = new FileInputStream(name)) {
+ fis.transferTo(jos);
+ }
+ } else {
+ System.out.println(String.format("Copying %s to %s",
+ name, dest));
+ jos.putNextEntry(entry);
+ srcJarFile.getInputStream(entry).transferTo(jos);
+ }
+ }
+ }
+
+ // append new files
+ for (String file : files) {
+ if (!updatedFiles.contains(file)) {
+ System.out.println(String.format("Adding %s with %s",
+ dest, file));
+ jos.putNextEntry(new JarEntry(file));
+ try (FileInputStream fis = new FileInputStream(file)) {
+ fis.transferTo(jos);
+ }
+ }
+ }
+ }
+ System.out.println();
+ }
+
+}
diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java
index 290a879..2ed5fca 100644
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -30,6 +30,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.Map;
@@ -378,4 +379,40 @@
}
return cmd.toString().trim();
}
+
+ /**
+ * Executes a process, waits for it to finish, prints the process output
+ * to stdout, and returns the process output.
+ *
+ * The process will have exited before this method returns.
+ *
+ * @param cmds The command line to execute.
+ * @return The {@linkplain OutputAnalyzer} instance wrapping the process.
+ */
+ public static OutputAnalyzer executeCommand(String... cmds)
+ throws Throwable {
+ String cmdLine = Arrays.stream(cmds).collect(Collectors.joining(" "));
+ System.out.println("Command line: [" + cmdLine + "]");
+ OutputAnalyzer analyzer = ProcessTools.executeProcess(cmds);
+ System.out.println(analyzer.getOutput());
+ return analyzer;
+ }
+
+ /**
+ * Executes a process, waits for it to finish, prints the process output
+ * to stdout and returns the process output.
+ *
+ * The process will have exited before this method returns.
+ *
+ * @param pb The ProcessBuilder to execute.
+ * @return The {@linkplain OutputAnalyzer} instance wrapping the process.
+ */
+ public static OutputAnalyzer executeCommand(ProcessBuilder pb)
+ throws Throwable {
+ String cmdLine = pb.command().stream().collect(Collectors.joining(" "));
+ System.out.println("Command line: [" + cmdLine + "]");
+ OutputAnalyzer analyzer = ProcessTools.executeProcess(pb);
+ System.out.println(analyzer.getOutput());
+ return analyzer;
+ }
}
diff --git a/jdk/test/sun/security/krb5/auto/Context.java b/jdk/test/sun/security/krb5/auto/Context.java
index 02beb2e..e7c601d 100644
--- a/jdk/test/sun/security/krb5/auto/Context.java
+++ b/jdk/test/sun/security/krb5/auto/Context.java
@@ -23,6 +23,7 @@
import com.sun.security.auth.module.Krb5LoginModule;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
@@ -584,7 +585,12 @@
out.name = name + " as " + out.cred.getName().toString();
return out;
} catch (PrivilegedActionException pae) {
- throw pae.getException();
+ Exception e = pae.getException();
+ if (e instanceof InvocationTargetException) {
+ throw (Exception)((InvocationTargetException) e).getTargetException();
+ } else {
+ throw e;
+ }
}
}
diff --git a/jdk/test/sun/security/krb5/auto/ForwardableCheck.java b/jdk/test/sun/security/krb5/auto/ForwardableCheck.java
new file mode 100644
index 0000000..df6e49e
--- /dev/null
+++ b/jdk/test/sun/security/krb5/auto/ForwardableCheck.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8022582
+ * @summary Relax response flags checking in sun.security.krb5.KrbKdcRep.check.
+ * @compile -XDignore.symbol.file ForwardableCheck.java
+ * @run main/othervm ForwardableCheck
+ */
+
+import org.ietf.jgss.GSSException;
+import sun.security.jgss.GSSUtil;
+
+import java.util.Arrays;
+
+public class ForwardableCheck {
+
+ public static void main(String[] args) throws Exception {
+ OneKDC kdc = new OneKDC(null);
+ kdc.writeJAASConf();
+
+ // USER can impersonate someone else
+ kdc.setOption(KDC.Option.ALLOW_S4U2SELF,
+ Arrays.asList(OneKDC.USER + "@" + OneKDC.REALM));
+ // USER2 is sensitive
+ kdc.setOption(KDC.Option.SENSITIVE_ACCOUNTS,
+ Arrays.asList(OneKDC.USER2 + "@" + OneKDC.REALM));
+
+ Context c;
+
+ // USER2 is sensitive but it's still able to get a normal ticket
+ c = Context.fromUserPass(OneKDC.USER2, OneKDC.PASS2, false);
+
+ // ... and connect to another account
+ c.startAsClient(OneKDC.USER, GSSUtil.GSS_KRB5_MECH_OID);
+ c.x().requestCredDeleg(true);
+ c.x().requestMutualAuth(false);
+
+ c.take(new byte[0]);
+
+ if (!c.x().isEstablished()) {
+ throw new Exception("Context should have been established");
+ }
+
+ // ... but will not be able to delegate itself
+ if (c.x().getCredDelegState()) {
+ throw new Exception("Impossible");
+ }
+
+ // Although USER is allowed to impersonate other people,
+ // it cannot impersonate USER2 coz it's sensitive.
+ c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
+ try {
+ c.impersonate(OneKDC.USER2);
+ throw new Exception("Should fail");
+ } catch (GSSException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/jdk/test/sun/security/krb5/auto/KDC.java b/jdk/test/sun/security/krb5/auto/KDC.java
index 1b2814d..117e676 100644
--- a/jdk/test/sun/security/krb5/auto/KDC.java
+++ b/jdk/test/sun/security/krb5/auto/KDC.java
@@ -198,6 +198,10 @@
* Krb5.KDC_ERR_POLICY will be send for S4U2proxy request.
*/
ALLOW_S4U2PROXY,
+ /**
+ * Sensitive accounts can never be delegated.
+ */
+ SENSITIVE_ACCOUNTS,
};
static {
@@ -643,7 +647,7 @@
try {
System.out.println(realm + "> " + tgsReq.reqBody.cname +
" sends TGS-REQ for " +
- service);
+ service + ", " + tgsReq.reqBody.kdcOptions);
KDCReqBody body = tgsReq.reqBody;
int[] eTypes = KDCReqBodyDotEType(body);
int e2 = eTypes[0]; // etype for outgoing session key
@@ -719,7 +723,13 @@
boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1];
if (body.kdcOptions.get(KDCOptions.FORWARDABLE)
&& allowForwardable) {
- bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true;
+ List<String> sensitives = (List<String>)
+ options.get(Option.SENSITIVE_ACCOUNTS);
+ if (sensitives != null && sensitives.contains(cname.toString())) {
+ // Cannot make FORWARDABLE
+ } else {
+ bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true;
+ }
}
if (body.kdcOptions.get(KDCOptions.FORWARDED) ||
etp.flags.get(Krb5.TKT_OPTS_FORWARDED)) {
@@ -824,7 +834,8 @@
t,
edata);
System.out.println(" Return " + tgsRep.cname
- + " ticket for " + tgsRep.ticket.sname);
+ + " ticket for " + tgsRep.ticket.sname + ", flags "
+ + tFlags);
DerOutputStream out = new DerOutputStream();
out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
@@ -869,7 +880,7 @@
try {
System.out.println(realm + "> " + asReq.reqBody.cname +
" sends AS-REQ for " +
- service);
+ service + ", " + asReq.reqBody.kdcOptions);
KDCReqBody body = asReq.reqBody;
@@ -926,7 +937,13 @@
//body.from
boolean[] bFlags = new boolean[Krb5.TKT_OPTS_MAX+1];
if (body.kdcOptions.get(KDCOptions.FORWARDABLE)) {
- bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true;
+ List<String> sensitives = (List<String>)
+ options.get(Option.SENSITIVE_ACCOUNTS);
+ if (sensitives != null && sensitives.contains(body.cname.toString())) {
+ // Cannot make FORWARDABLE
+ } else {
+ bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true;
+ }
}
if (body.kdcOptions.get(KDCOptions.RENEWABLE)) {
bFlags[Krb5.TKT_OPTS_RENEWABLE] = true;
@@ -1102,7 +1119,8 @@
edata);
System.out.println(" Return " + asRep.cname
- + " ticket for " + asRep.ticket.sname);
+ + " ticket for " + asRep.ticket.sname + ", flags "
+ + tFlags);
DerOutputStream out = new DerOutputStream();
out.write(DerValue.createTag(DerValue.TAG_APPLICATION,
diff --git a/jdk/test/sun/security/krb5/config/ParseConfig.java b/jdk/test/sun/security/krb5/config/ParseConfig.java
index ecbfa8a..3a73956 100644
--- a/jdk/test/sun/security/krb5/config/ParseConfig.java
+++ b/jdk/test/sun/security/krb5/config/ParseConfig.java
@@ -22,7 +22,7 @@
*/
/*
* @test
- * @bug 6319046
+ * @bug 6319046 8055045
* @compile -XDignore.symbol.file ParseConfig.java
* @run main/othervm ParseConfig
* @summary Problem with parsing krb5.conf
@@ -32,7 +32,8 @@
public class ParseConfig {
public static void main(String[] args) throws Exception {
- System.setProperty("java.security.krb5.conf", System.getProperty("test.src", ".") +"/krb5.conf");
+ System.setProperty("java.security.krb5.conf",
+ System.getProperty("test.src", ".") + "/krb5.conf");
Config config = Config.getInstance();
config.listTable();
@@ -44,5 +45,11 @@
expected + "\"");
}
}
+
+ // JDK-8055045: IOOBE when reading an empty value
+ config.get("empty1", "NOVAL.COM");
+ config.get("empty2", "NOVAL.COM");
+ config.get("quote1", "NOVAL.COM");
+ config.get("quote2", "NOVAL.COM");
}
}
diff --git a/jdk/test/sun/security/krb5/config/krb5.conf b/jdk/test/sun/security/krb5/config/krb5.conf
index 2a3a2db..7962443 100644
--- a/jdk/test/sun/security/krb5/config/krb5.conf
+++ b/jdk/test/sun/security/krb5/config/krb5.conf
@@ -27,3 +27,9 @@
}
}
+ NOVAL.COM = {
+ empty1 =
+ empty2 =.
+ quote1 = "
+ quote2 = '
+ }
diff --git a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java
index 8ac9d41..a23d1e7 100644
--- a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java
+++ b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, 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
@@ -58,7 +58,12 @@
static final String defaultPolicyId = "2.3.4.5";
- static class Handler implements HttpHandler {
+ static class Handler implements HttpHandler, AutoCloseable {
+
+ private final HttpServer httpServer;
+ private final String keystore;
+
+ @Override
public void handle(HttpExchange t) throws IOException {
int len = 0;
for (String h: t.getRequestHeaders().keySet()) {
@@ -136,7 +141,9 @@
// Write TSResponse
System.err.println("\nResponse\n===================");
KeyStore ks = KeyStore.getInstance("JKS");
- ks.load(new FileInputStream(TSKS), "changeit".toCharArray());
+ try (FileInputStream fis = new FileInputStream(keystore)) {
+ ks.load(fis, "changeit".toCharArray());
+ }
String alias = "ts";
if (path == 6) alias = "tsbad1";
@@ -240,33 +247,74 @@
return out.toByteArray();
}
+
+ private Handler(HttpServer httpServer, String keystore) {
+ this.httpServer = httpServer;
+ this.keystore = keystore;
+ }
+
+ /**
+ * Initialize TSA instance.
+ *
+ * Extended Key Info extension of certificate that is used for
+ * signing TSA responses should contain timeStamping value.
+ */
+ static Handler init(int port, String keystore) throws IOException {
+ HttpServer httpServer = HttpServer.create(
+ new InetSocketAddress(port), 0);
+ Handler tsa = new Handler(httpServer, keystore);
+ httpServer.createContext("/", tsa);
+ return tsa;
+ }
+
+ /**
+ * Start TSA service.
+ */
+ void start() {
+ httpServer.start();
+ }
+
+ /**
+ * Stop TSA service.
+ */
+ void stop() {
+ httpServer.stop(0);
+ }
+
+ /**
+ * Return server port number.
+ */
+ int getPort() {
+ return httpServer.getAddress().getPort();
+ }
+
+ @Override
+ public void close() throws Exception {
+ stop();
+ }
}
public static void main(String[] args) throws Exception {
+ try (Handler tsa = Handler.init(0, TSKS);) {
+ tsa.start();
+ int port = tsa.getPort();
- Handler h = new Handler();
- HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
- int port = server.getAddress().getPort();
- HttpContext ctx = server.createContext("/", h);
- server.start();
+ String cmd;
+ // Use -J-Djava.security.egd=file:/dev/./urandom to speed up
+ // nonce generation in timestamping request. Not avaibale on
+ // Windows and defaults to thread seed generator, not too bad.
+ if (System.getProperty("java.home").endsWith("jre")) {
+ cmd = System.getProperty("java.home") + "/../bin/jarsigner";
+ } else {
+ cmd = System.getProperty("java.home") + "/bin/jarsigner";
+ }
- String cmd = null;
- // Use -J-Djava.security.egd=file:/dev/./urandom to speed up
- // nonce generation in timestamping request. Not avaibale on
- // Windows and defaults to thread seed generator, not too bad.
- if (System.getProperty("java.home").endsWith("jre")) {
- cmd = System.getProperty("java.home") + "/../bin/jarsigner";
- } else {
- cmd = System.getProperty("java.home") + "/bin/jarsigner";
- }
+ cmd += " " + System.getProperty("test.tool.vm.opts")
+ + " -J-Djava.security.egd=file:/dev/./urandom"
+ + " -debug -keystore " + TSKS + " -storepass changeit"
+ + " -tsa http://localhost:" + port + "/%d"
+ + " -signedjar new_%d.jar " + JAR + " old";
- cmd += " " + System.getProperty("test.tool.vm.opts") +
- " -J-Djava.security.egd=file:/dev/./urandom" +
- " -debug -keystore " + TSKS + " -storepass changeit" +
- " -tsa http://localhost:" + port + "/%d" +
- " -signedjar new_%d.jar " + JAR + " old";
-
- try {
if (args.length == 0) { // Run this test
jarsigner(cmd, 0, true); // Success, normal call
jarsigner(cmd, 1, false); // These 4 should fail
@@ -287,8 +335,6 @@
System.err.println("Press Enter to quit server");
System.in.read();
}
- } finally {
- server.stop(0);
}
}
diff --git a/jdk/test/sun/security/tools/jarsigner/TsacertOptionTest.java b/jdk/test/sun/security/tools/jarsigner/TsacertOptionTest.java
new file mode 100644
index 0000000..3664ca9
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/TsacertOptionTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary The test signs and verifies a jar file with -tsacert option
+ * @library /lib/testlibrary
+ * @run main TsacertOptionTest
+ */
+public class TsacertOptionTest {
+
+ private static final String FS = System.getProperty("file.separator");
+ private static final String JAVA_HOME = System.getProperty("java.home");
+ private static final String KEYTOOL = JAVA_HOME + FS + "bin" + FS
+ + "keytool";
+ private static final String JARSIGNER = JAVA_HOME + FS + "bin" + FS
+ + "jarsigner";
+ private static final String UNSIGNED_JARFILE = "unsigned.jar";
+ private static final String SIGNED_JARFILE = "signed.jar";
+ private static final String FILENAME = TsacertOptionTest.class.getName()
+ + ".txt";
+ private static final String PASSWORD = "changeit";
+ private static final String KEYSTORE = "ks.jks";
+ private static final String SIGNING_KEY_ALIAS = "sign_alias";
+ private static final String TSA_KEY_ALIAS = "ts";
+ private static final String KEY_ALG = "RSA";
+ private static final int KEY_SIZE = 2048;
+ private static final int VALIDITY = 365;
+ private static final String WARNING = "Warning:";
+ private static final String JAR_SIGNED = "jar signed.";
+ private static final String JAR_VERIFIED = "jar verified.";
+
+ /**
+ * The test signs and verifies a jar file with -tsacert option,
+ * and checks that no warning was shown.
+ * A certificate that is addressed in -tsacert option contains URL to TSA
+ * in Subject Information Access extension.
+ */
+ public static void main(String[] args) throws Throwable {
+ TsacertOptionTest test = new TsacertOptionTest();
+ test.start();
+ }
+
+ void start() throws Throwable {
+ // create a jar file that contains one file
+ Utils.createFiles(FILENAME);
+ JarUtils.createJar(UNSIGNED_JARFILE, FILENAME);
+
+ // look for free network port for TSA service
+ int port = jdk.testlibrary.Utils.getFreePort();
+ String host = jdk.testlibrary.Utils.getHostname();
+ String tsaUrl = "http://" + host + ":" + port;
+
+ // create key pair for jar signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", SIGNING_KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Test",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // create key pair for TSA service
+ // SubjectInfoAccess extension contains URL to TSA service
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-v",
+ "-alias", TSA_KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=TSA",
+ "-ext", "ExtendedkeyUsage:critical=timeStamping",
+ "-ext", "SubjectInfoAccess=timeStamping:URI:" + tsaUrl,
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ try (TimestampCheck.Handler tsa = TimestampCheck.Handler.init(port,
+ KEYSTORE);) {
+
+ // start TSA
+ tsa.start();
+
+ // sign jar file
+ // specify -tsadigestalg option because
+ // TSA server uses SHA-1 digest algorithm
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ "-tsacert", TSA_KEY_ALIAS,
+ "-tsadigestalg", "SHA-1",
+ UNSIGNED_JARFILE,
+ SIGNING_KEY_ALIAS);
+
+ analyzer.shouldHaveExitValue(0);
+ analyzer.stdoutShouldNotContain(WARNING);
+ analyzer.shouldContain(JAR_SIGNED);
+
+ // verify signed jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verbose",
+ "-verify",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ SIGNED_JARFILE);
+
+ analyzer.shouldHaveExitValue(0);
+ analyzer.stdoutShouldNotContain(WARNING);
+ analyzer.shouldContain(JAR_VERIFIED);
+ }
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/Utils.java b/jdk/test/sun/security/tools/jarsigner/Utils.java
new file mode 100644
index 0000000..3fc9009
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/Utils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Helper class.
+ */
+public class Utils {
+
+ static void createFiles(String... filenames) throws IOException {
+ for (String filename : filenames) {
+ new File(filename).createNewFile();
+ }
+ }
+
+}
+
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/AliasNotInStoreTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/AliasNotInStoreTest.java
new file mode 100644
index 0000000..81475fb
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/AliasNotInStoreTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for aliasNotInStore warning
+ * @library /lib/testlibrary ../
+ * @run main AliasNotInStoreTest
+ */
+public class AliasNotInStoreTest extends Test {
+
+ /**
+ * The test signs and verifies a jar that contains signed entries
+ * that are not signed by any alias in keystore (aliasNotInStore).
+ * Warning message is expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ AliasNotInStoreTest test = new AliasNotInStoreTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ Utils.createFiles(FIRST_FILE, SECOND_FILE);
+ System.out.println(String.format("Create a %s that contains %s",
+ new Object[]{UNSIGNED_JARFILE, FIRST_FILE}));
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create first key pair for signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", FIRST_KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", BOTH_KEYS_KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=First",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // create second key pair for signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", SECOND_KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", BOTH_KEYS_KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Second",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // sign jar with first key
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-keystore", BOTH_KEYS_KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ FIRST_KEY_ALIAS);
+
+ checkSigning(analyzer);
+
+ System.out.println(String.format("Copy %s to %s, and add %s",
+ new Object[] {SIGNED_JARFILE, UPDATED_SIGNED_JARFILE,
+ SECOND_FILE}));
+
+ JarUtils.updateJar(SIGNED_JARFILE, UPDATED_SIGNED_JARFILE, SECOND_FILE);
+
+ // sign jar with second key
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-keystore", BOTH_KEYS_KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ UPDATED_SIGNED_JARFILE,
+ SECOND_KEY_ALIAS);
+
+ checkSigning(analyzer);
+
+ // create keystore that contains only first key
+ ProcessTools.executeCommand(KEYTOOL,
+ "-importkeystore",
+ "-srckeystore", BOTH_KEYS_KEYSTORE,
+ "-srcalias", FIRST_KEY_ALIAS,
+ "-srcstorepass", PASSWORD,
+ "-srckeypass", PASSWORD,
+ "-destkeystore", FIRST_KEY_KEYSTORE,
+ "-destalias", FIRST_KEY_ALIAS,
+ "-deststorepass", PASSWORD,
+ "-destkeypass", PASSWORD).shouldHaveExitValue(0);
+
+ // verify jar with keystore that contains only first key in strict mode,
+ // so there is signed entry (FirstClass.class) that is not signed
+ // by any alias in the keystore
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-keystore", FIRST_KEY_KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ UPDATED_SIGNED_JARFILE);
+
+ checkVerifying(analyzer, 0, CHAIN_NOT_VALIDATED_VERIFYING_WARNING,
+ ALIAS_NOT_IN_STORE_VERIFYING_WARNING);
+
+ // verify jar with keystore that contains only first key in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-strict",
+ "-keystore", FIRST_KEY_KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ UPDATED_SIGNED_JARFILE);
+
+ int expectedExitCode = ALIAS_NOT_IN_STORE_EXIT_CODE
+ + CHAIN_NOT_VALIDATED_EXIT_CODE;
+ checkVerifying(analyzer, expectedExitCode,
+ CHAIN_NOT_VALIDATED_VERIFYING_WARNING,
+ ALIAS_NOT_IN_STORE_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java
new file mode 100644
index 0000000..a8c3c8a
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for badExtendedKeyUsage warning
+ * @library /lib/testlibrary ../
+ * @run main BadExtendedKeyUsageTest
+ */
+public class BadExtendedKeyUsageTest extends Test {
+
+ /**
+ * The test signs and verifies a jar that contains entries
+ * whose signer certificate's ExtendedKeyUsage extension
+ * doesn't allow code signing (badExtendedKeyUsage).
+ * Warning message is expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ BadExtendedKeyUsageTest test = new BadExtendedKeyUsageTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ // create a jar file that contains one class file
+ Utils.createFiles(FIRST_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create a certificate whose signer certificate's
+ // ExtendedKeyUsage extension doesn't allow code signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Test",
+ "-ext", "ExtendedkeyUsage=serverAuth",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // sign jar
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkSigning(analyzer, BAD_EXTENDED_KEY_USAGE_SIGNING_WARNING);
+
+ // verify signed jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, 0, BAD_EXTENDED_KEY_USAGE_VERIFYING_WARNING);
+
+ // verity signed jar in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, BAD_EXTENDED_KEY_USAGE_EXIT_CODE,
+ BAD_EXTENDED_KEY_USAGE_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java
new file mode 100644
index 0000000..fd37eb9
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for badKeyUsage warning
+ * @library /lib/testlibrary ../
+ * @ignore until 8026393 is fixed
+ * @run main BadKeyUsageTest
+ */
+public class BadKeyUsageTest extends Test {
+
+ /**
+ * The test signs and verifies a jar that contains entries
+ * whose signer certificate's KeyUsage extension
+ * doesn't allow code signing (badKeyUsage).
+ * Warning message is expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ BadKeyUsageTest test = new BadKeyUsageTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ // create a jar file that contains one class file
+ Utils.createFiles(FIRST_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create a certificate whose signer certificate's KeyUsage extension
+ // doesn't allow code signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Test",
+ "-ext", "KeyUsage=keyAgreement",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // sign jar
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkSigning(analyzer, BAD_KEY_USAGE_SIGNING_WARNING);
+
+ // verify signed jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, 0, BAD_KEY_USAGE_VERIFYING_WARNING);
+
+ // verify signed jar in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, BAD_KEY_USAGE_EXIT_CODE,
+ BAD_KEY_USAGE_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java
new file mode 100644
index 0000000..e2e8086
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Base64;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for badNetscapeCertType warning
+ * @library /lib/testlibrary ../
+ * @run main BadNetscapeCertTypeTest
+ */
+public class BadNetscapeCertTypeTest extends Test {
+
+ private static final String NETSCAPE_KEYSTORE_BASE64 = TEST_SOURCES + FS
+ + "bad_netscape_cert_type.jks.base64";
+
+ private static final String NETSCAPE_KEYSTORE
+ = "bad_netscape_cert_type.jks";
+
+ /**
+ * The test signs and verifies a jar that contains entries
+ * whose signer certificate's NetscapeCertType extension
+ * doesn't allow code signing (badNetscapeCertType).
+ * Warning message is expected.
+ * Run bad_netscape_cert_type.sh script to create bad_netscape_cert_type.jks
+ */
+ public static void main(String[] args) throws Throwable {
+
+ Files.write(Paths.get(NETSCAPE_KEYSTORE),
+ Base64.getMimeDecoder().decode(
+ Files.readAllBytes(Paths.get(NETSCAPE_KEYSTORE_BASE64))));
+
+ BadNetscapeCertTypeTest test = new BadNetscapeCertTypeTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ // create a jar file that contains one class file
+ Utils.createFiles(FIRST_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // sign jar
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verbose",
+ "-keystore", NETSCAPE_KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkSigning(analyzer, BAD_NETSCAPE_CERT_TYPE_SIGNING_WARNING);
+
+ // verify signed jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-keystore", NETSCAPE_KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, 0, BAD_NETSCAPE_CERT_TYPE_VERIFYING_WARNING);
+
+ // verify signed jar in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-strict",
+ "-keystore", NETSCAPE_KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, BAD_NETSCAPE_CERT_TYPE_EXIT_CODE,
+ BAD_NETSCAPE_CERT_TYPE_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java
new file mode 100644
index 0000000..21f0979
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import java.io.File;
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for chainNotValidated warning
+ * @library /lib/testlibrary ../
+ * @run main ChainNotValidatedTest
+ */
+public class ChainNotValidatedTest extends Test {
+
+ private static final String CHAIN = "chain";
+
+ /**
+ * The test signs and verifies a jar that contains entries
+ * whose cert chain can't be correctly validated (chainNotValidated).
+ * Warning message is expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ ChainNotValidatedTest test = new ChainNotValidatedTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ // create a jar file that contains one class file
+ Utils.createFiles(FIRST_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create self-signed certificate whose BasicConstraints extension
+ // is set to false, so the certificate may not be used
+ // as a parent certificate (certpath validation should fail)
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkeypair",
+ "-alias", CA_KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=CA",
+ "-ext", "BasicConstraints:critical=ca:false",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // create a certificate that is signed by self-signed certificate
+ // despite of it may not be used as a parent certificate
+ // (certpath validation should fail)
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkeypair",
+ "-alias", KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Test",
+ "-ext", "BasicConstraints:critical=ca:false",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ ProcessTools.executeCommand(KEYTOOL,
+ "-certreq",
+ "-alias", KEY_ALIAS,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-file", CERT_REQUEST_FILENAME).shouldHaveExitValue(0);
+
+ ProcessTools.executeCommand(KEYTOOL,
+ "-gencert",
+ "-alias", CA_KEY_ALIAS,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-infile", CERT_REQUEST_FILENAME,
+ "-validity", Integer.toString(VALIDITY),
+ "-outfile", CERT_FILENAME).shouldHaveExitValue(0);
+
+ ProcessTools.executeCommand(KEYTOOL,
+ "-importcert",
+ "-alias", KEY_ALIAS,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-file", CERT_FILENAME).shouldHaveExitValue(0);
+
+ ProcessBuilder pb = new ProcessBuilder(KEYTOOL,
+ "-export",
+ "-rfc",
+ "-alias", KEY_ALIAS,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD);
+ pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(CHAIN)));
+ ProcessTools.executeCommand(pb).shouldHaveExitValue(0);
+
+ pb = new ProcessBuilder(KEYTOOL,
+ "-export",
+ "-rfc",
+ "-alias", CA_KEY_ALIAS,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD);
+ pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(CHAIN)));
+ ProcessTools.executeCommand(pb).shouldHaveExitValue(0);
+
+ // remove CA certificate
+ ProcessTools.executeCommand(KEYTOOL,
+ "-delete",
+ "-alias", CA_KEY_ALIAS,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD).shouldHaveExitValue(0);
+
+ // sign jar
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-certchain", CHAIN,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkSigning(analyzer, CHAIN_NOT_VALIDATED_SIGNING_WARNING);
+
+ // verify signed jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-certchain", CHAIN,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, 0, CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
+
+ // verify signed jar in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-certchain", CHAIN,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, CHAIN_NOT_VALIDATED_EXIT_CODE,
+ CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java
new file mode 100644
index 0000000..ccb8e91
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for hasExpiredCert warning
+ * @library /lib/testlibrary ../
+ * @run main HasExpiredCertTest
+ */
+public class HasExpiredCertTest extends Test {
+
+ static final int SHORT_VALIDITY = 365;
+
+ /**
+ * The test signs and verifies a jar that contains entries
+ * whose signer certificate has expired (hasExpiredCert).
+ * Warning message is expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ HasExpiredCertTest test = new HasExpiredCertTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ // create a jar file that contains one class file
+ Utils.createFiles(FIRST_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create key pair for jar signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Test",
+ "-startdate", "-" + SHORT_VALIDITY * 2 + "d",
+ "-validity", Integer.toString(SHORT_VALIDITY))
+ .shouldHaveExitValue(0);
+
+ // sign jar
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkSigning(analyzer, HAS_EXPIRED_CERT_SIGNING_WARNING);
+
+ // verify signed jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, 0, HAS_EXPIRED_CERT_VERIFYING_WARNING);
+
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE);
+
+ checkVerifying(analyzer, HAS_EXPIRED_CERT_EXIT_CODE,
+ HAS_EXPIRED_CERT_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java
new file mode 100644
index 0000000..f34148e
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for hasExpiringCert warning
+ * @library /lib/testlibrary ../
+ * @run main HasExpiringCertTest
+ */
+public class HasExpiringCertTest extends Test {
+
+ static final int SHORT_VALIDITY = 90; // less than 6 month
+
+ /**
+ * The test signs and verifies a jar that contains entries
+ * whose signer certificate will expire within six months (hasExpiringCert).
+ * Warning message is expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ HasExpiringCertTest test = new HasExpiringCertTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ // create a jar file that contains one class file
+ Utils.createFiles(FIRST_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create key pair for jar signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Test",
+ "-validity", Integer.toString(SHORT_VALIDITY))
+ .shouldHaveExitValue(0);
+
+ // sign jar
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-keystore", KEYSTORE,
+ "-verbose",
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkSigning(analyzer, HAS_EXPIRING_CERT_SIGNING_WARNING);
+
+ // verify signed jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkVerifying(analyzer, 0, HAS_EXPIRING_CERT_VERIFYING_WARNING);
+
+ // verify signed jar in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkVerifying(analyzer, 0, HAS_EXPIRING_CERT_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java
new file mode 100644
index 0000000..e71feb3
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for hasUnsignedEntry warning
+ * @library /lib/testlibrary ../
+ * @run main HasUnsignedEntryTest
+ */
+public class HasUnsignedEntryTest extends Test {
+
+ /**
+ * The test signs and verifies a jar that contains unsigned entries
+ * which have not been integrity-checked (hasUnsignedEntry).
+ * Warning message is expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ HasUnsignedEntryTest test = new HasUnsignedEntryTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ System.out.println(String.format("Create a %s that contains %s",
+ UNSIGNED_JARFILE, FIRST_FILE));
+ Utils.createFiles(FIRST_FILE, SECOND_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create key pair for signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Test",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // sign jar
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkSigning(analyzer);
+
+ System.out.println(String.format("Copy %s to %s, and add %s.class, "
+ + "so it contains unsigned entry",
+ new Object[]{SIGNED_JARFILE, UPDATED_SIGNED_JARFILE,
+ SECOND_FILE}));
+
+ JarUtils.updateJar(SIGNED_JARFILE, UPDATED_SIGNED_JARFILE, SECOND_FILE);
+
+ // verify jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ UPDATED_SIGNED_JARFILE);
+
+ checkVerifying(analyzer, 0, HAS_UNSIGNED_ENTRY_VERIFYING_WARNING);
+
+ // verify jar in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ UPDATED_SIGNED_JARFILE);
+
+ checkVerifying(analyzer, HAS_UNSIGNED_ENTRY_EXIT_CODE,
+ HAS_UNSIGNED_ENTRY_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java
new file mode 100644
index 0000000..677914c
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Checks if jarsigner prints appropriate warnings
+ * @library /lib/testlibrary ../
+ * @run main MultipleWarningsTest
+ */
+public class MultipleWarningsTest extends Test {
+
+ /**
+ * The test signs and verifies a jar that:
+ * - contains entries whose signer certificate has expired
+ * - contains entries whose signer certificate's ExtendedKeyUsage
+ * extension doesn't allow code signing
+ * - contains unsigned entries which have not been integrity-checked
+ * - contains signed entries which are not signed by the specified alias
+ * Warning messages are expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ MultipleWarningsTest test = new MultipleWarningsTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ Utils.createFiles(FIRST_FILE, SECOND_FILE);
+
+ // create a jar file that contains one class file
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create first expired certificate
+ // whose ExtendedKeyUsage extension does not allow code signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", FIRST_KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=First",
+ "-ext", "ExtendedkeyUsage=serverAuth",
+ "-startdate", "-" + VALIDITY * 2 + "d",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // create second expired certificate
+ // whose KeyUsage extension does not allow code signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", SECOND_KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Second",
+ "-ext", "ExtendedkeyUsage=serverAuth",
+ "-startdate", "-" + VALIDITY * 2 + "d",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // sign jar with first key
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ FIRST_KEY_ALIAS);
+
+ checkSigning(analyzer, HAS_EXPIRED_CERT_SIGNING_WARNING,
+ BAD_EXTENDED_KEY_USAGE_SIGNING_WARNING);
+
+ // add a second class to created jar, so it contains unsigned entry
+ JarUtils.updateJar(SIGNED_JARFILE, UPDATED_SIGNED_JARFILE, SECOND_FILE);
+
+ // verify jar with second key
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ UPDATED_SIGNED_JARFILE,
+ SECOND_KEY_ALIAS);
+
+ checkVerifying(analyzer, 0, BAD_EXTENDED_KEY_USAGE_VERIFYING_WARNING,
+ HAS_EXPIRED_CERT_VERIFYING_WARNING,
+ HAS_UNSIGNED_ENTRY_VERIFYING_WARNING,
+ NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING);
+
+ // verify jar with second key in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ UPDATED_SIGNED_JARFILE,
+ SECOND_KEY_ALIAS);
+
+ int expectedExitCode = HAS_EXPIRED_CERT_EXIT_CODE
+ + BAD_EXTENDED_KEY_USAGE_EXIT_CODE
+ + HAS_UNSIGNED_ENTRY_EXIT_CODE
+ + NOT_SIGNED_BY_ALIAS_EXIT_CODE;
+ checkVerifying(analyzer, expectedExitCode,
+ BAD_EXTENDED_KEY_USAGE_VERIFYING_WARNING,
+ HAS_EXPIRED_CERT_VERIFYING_WARNING,
+ HAS_UNSIGNED_ENTRY_VERIFYING_WARNING,
+ NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING);
+
+ // verify jar with non-exisiting alias
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ UPDATED_SIGNED_JARFILE,
+ "bogus");
+
+ checkVerifying(analyzer, 0, BAD_EXTENDED_KEY_USAGE_VERIFYING_WARNING,
+ HAS_EXPIRED_CERT_VERIFYING_WARNING,
+ HAS_UNSIGNED_ENTRY_VERIFYING_WARNING,
+ NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING);
+
+ // verify jar with non-exisiting alias in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ UPDATED_SIGNED_JARFILE,
+ "bogus");
+
+ checkVerifying(analyzer, expectedExitCode,
+ BAD_EXTENDED_KEY_USAGE_VERIFYING_WARNING,
+ HAS_EXPIRED_CERT_VERIFYING_WARNING,
+ HAS_UNSIGNED_ENTRY_VERIFYING_WARNING,
+ NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/NoTimestampTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/NoTimestampTest.java
new file mode 100644
index 0000000..10b142a
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/NoTimestampTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import java.util.Date;
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Checks warnings if -tsa and -tsacert options are not specified
+ * @library /lib/testlibrary ../
+ * @run main NoTimestampTest
+ */
+public class NoTimestampTest extends Test {
+
+ /**
+ * The test signs and verifies a jar file without -tsa and -tsacert options,
+ * and checks that proper warnings are shown.
+ */
+ public static void main(String[] args) throws Throwable {
+ NoTimestampTest test = new NoTimestampTest();
+ test.start();
+ }
+
+ private void start() throws Throwable {
+ String timezone = System.getProperty("user.timezone");
+ System.out.println(String.format("Timezone = %s", timezone));
+
+ // create a jar file that contains one class file
+ Utils.createFiles(FIRST_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // calculate certificate expiration date
+ Date expirationDate = new Date(System.currentTimeMillis() + VALIDITY
+ * 24 * 60 * 60 * 1000L);
+
+ // create key pair
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Test",
+ "-validity", Integer.toString(VALIDITY));
+
+ // sign jar file
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-J-Duser.timezone=" + timezone,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ KEY_ALIAS);
+
+ String warning = String.format(NO_TIMESTAMP_SIGNING_WARN_TEMPLATE,
+ expirationDate);
+ checkSigning(analyzer, warning);
+
+ // verify signed jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-J-Duser.timezone=" + timezone,
+ "-verify",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ KEY_ALIAS);
+
+ warning = String.format(NO_TIMESTAMP_VERIFYING_WARN_TEMPLATE, expirationDate);
+ checkVerifying(analyzer, 0, warning);
+
+ // verify signed jar in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-J-Duser.timezone=" + timezone,
+ "-verify",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkVerifying(analyzer, 0, warning);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java
new file mode 100644
index 0000000..40ef68e
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for notSignedByAlias warning
+ * @library /lib/testlibrary ../
+ * @run main NotSignedByAliasTest
+ */
+public class NotSignedByAliasTest extends Test {
+
+ /**
+ * The test signs and verifies a jar that contains signed entries
+ * which are not signed by the specified alias(es) (notSignedByAlias).
+ * Warning message is expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ NotSignedByAliasTest test = new NotSignedByAliasTest();
+ test.start();
+ }
+
+ protected void start() throws Throwable {
+ // create a jar file that contains one class file
+ Utils.createFiles(FIRST_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create first key pair for signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", FIRST_KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=First",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // create first key pair for signing
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", SECOND_KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Second",
+ "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+
+ // sign jar with first key
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ FIRST_KEY_ALIAS);
+
+ checkSigning(analyzer);
+
+ // verify jar with second key
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ SECOND_KEY_ALIAS);
+
+ checkVerifying(analyzer, 0, NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING);
+
+ // verify jar with second key in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ SECOND_KEY_ALIAS);
+
+ checkVerifying(analyzer, NOT_SIGNED_BY_ALIAS_EXIT_CODE,
+ NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING);
+
+ // verify jar with non-existing alias
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ "bogus");
+
+ checkVerifying(analyzer, 0, NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING);
+
+ // verify jar with non-existing alias in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ "bogus");
+
+ checkVerifying(analyzer, NOT_SIGNED_BY_ALIAS_EXIT_CODE,
+ NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java b/jdk/test/sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java
new file mode 100644
index 0000000..a75c278
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.JarUtils;
+
+/**
+ * @test
+ * @bug 8024302 8026037
+ * @summary Test for notYetValidCert warning
+ * @library /lib/testlibrary ../
+ * @run main NotYetValidCertTest
+ */
+public class NotYetValidCertTest extends Test {
+
+ /**
+ * The test signs and verifies a jar that contains entries
+ * whose signer certificate is not yet valid (notYetValidCert).
+ * Warning message is expected.
+ */
+ public static void main(String[] args) throws Throwable {
+ NotYetValidCertTest test = new NotYetValidCertTest();
+ test.start();
+ }
+
+ protected void start() throws Throwable {
+ // create a jar file that contains one class file
+ Utils.createFiles(FIRST_FILE);
+ JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
+
+ // create certificate that will be valid only tomorrow
+ ProcessTools.executeCommand(KEYTOOL,
+ "-genkey",
+ "-alias", KEY_ALIAS,
+ "-keyalg", KEY_ALG,
+ "-keysize", Integer.toString(KEY_SIZE),
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-dname", "CN=Test",
+ "-startdate", "+1d",
+ "-validity", Integer.toString(VALIDITY));
+
+ // sign jar
+ OutputAnalyzer analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ "-signedjar", SIGNED_JARFILE,
+ UNSIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkSigning(analyzer, NOT_YET_VALID_CERT_SIGNING_WARNING);
+
+ // verify signed jar
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkVerifying(analyzer, 0, NOT_YET_VALID_CERT_VERIFYING_WARNING);
+
+ // verify jar in strict mode
+ analyzer = ProcessTools.executeCommand(JARSIGNER,
+ "-verify",
+ "-verbose",
+ "-strict",
+ "-keystore", KEYSTORE,
+ "-storepass", PASSWORD,
+ "-keypass", PASSWORD,
+ SIGNED_JARFILE,
+ KEY_ALIAS);
+
+ checkVerifying(analyzer, HAS_EXPIRED_CERT_EXIT_CODE,
+ NOT_YET_VALID_CERT_VERIFYING_WARNING);
+
+ System.out.println("Test passed");
+ }
+
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/Test.java b/jdk/test/sun/security/tools/jarsigner/warnings/Test.java
new file mode 100644
index 0000000..ce16d4d
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/Test.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import jdk.testlibrary.OutputAnalyzer;
+
+/**
+ * Base class.
+ */
+public abstract class Test {
+
+ static final String TEST_SOURCES = System.getProperty("test.src", ".");
+ static final String TEST_CLASSES = System.getProperty("test.classes");
+ static final String FS = System.getProperty("file.separator");
+ static final String JAVA_HOME = System.getProperty("java.home");
+ static final String KEYTOOL = JAVA_HOME + FS + "bin" + FS + "keytool";
+ static final String JARSIGNER = JAVA_HOME + FS + "bin" + FS + "jarsigner";
+ static final String UNSIGNED_JARFILE = "unsigned.jar";
+ static final String SIGNED_JARFILE = "signed.jar";
+ static final String UPDATED_SIGNED_JARFILE = "updated_signed.jar";
+ static final String FIRST_FILE = "first.txt";
+ static final String SECOND_FILE = "second.txt";
+ static final String PASSWORD = "password";
+ static final String BOTH_KEYS_KEYSTORE = "both_keys.jks";
+ static final String FIRST_KEY_KEYSTORE = "first_key.jks";
+ static final String KEYSTORE = "keystore.jks";
+ static final String FIRST_KEY_ALIAS = "first";
+ static final String SECOND_KEY_ALIAS = "second";
+ static final String KEY_ALG = "RSA";
+ static final String KEY_ALIAS = "alias";
+ static final String CERT_REQUEST_FILENAME = "test.req";
+ static final String CERT_FILENAME = "test.crt";
+ static final String CA_KEY_ALIAS = "ca";
+ static final int KEY_SIZE = 2048;
+ static final int TIMEOUT = 6 * 60 * 1000; // in millis
+ static final int VALIDITY = 365;
+
+ static final String WARNING = "Warning:";
+
+ static final String CHAIN_NOT_VALIDATED_VERIFYING_WARNING
+ = "This jar contains entries "
+ + "whose certificate chain is not validated.";
+
+ static final String ALIAS_NOT_IN_STORE_VERIFYING_WARNING
+ = "This jar contains signed entries "
+ + "that are not signed by alias in this keystore.";
+
+ static final String BAD_EXTENDED_KEY_USAGE_SIGNING_WARNING
+ = "The signer certificate's ExtendedKeyUsage extension "
+ + "doesn't allow code signing.";
+
+ static final String BAD_EXTENDED_KEY_USAGE_VERIFYING_WARNING
+ = "This jar contains entries whose signer certificate's "
+ + "ExtendedKeyUsage extension doesn't allow code signing.";
+
+ static final String BAD_KEY_USAGE_SIGNING_WARNING
+ = "The signer certificate's KeyUsage extension "
+ + "doesn't allow code signing.";
+
+ static final String BAD_KEY_USAGE_VERIFYING_WARNING
+ = "This jar contains entries whose signer certificate's KeyUsage "
+ + "extension doesn't allow code signing.";
+
+ static final String BAD_NETSCAPE_CERT_TYPE_SIGNING_WARNING
+ = "The signer certificate's NetscapeCertType extension "
+ + "doesn't allow code signing.";
+
+ static final String BAD_NETSCAPE_CERT_TYPE_VERIFYING_WARNING
+ = "This jar contains entries "
+ + "whose signer certificate's NetscapeCertType extension "
+ + "doesn't allow code signing.";
+
+ static final String CHAIN_NOT_VALIDATED_SIGNING_WARNING
+ = "The signer's certificate chain is not validated.";
+
+ static final String HAS_EXPIRING_CERT_SIGNING_WARNING
+ = "The signer certificate will expire within six months.";
+
+ static final String HAS_EXPIRING_CERT_VERIFYING_WARNING
+ = "This jar contains entries "
+ + "whose signer certificate will expire within six months.";
+
+ static final String HAS_EXPIRED_CERT_SIGNING_WARNING
+ = "The signer certificate has expired.";
+
+ static final String HAS_EXPIRED_CERT_VERIFYING_WARNING
+ = "This jar contains entries whose signer certificate has expired.";
+
+ static final String HAS_UNSIGNED_ENTRY_VERIFYING_WARNING
+ = "This jar contains unsigned entries "
+ + "which have not been integrity-checked.";
+
+ static final String NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING
+ = "This jar contains signed entries "
+ + "which are not signed by the specified alias(es).";
+
+ static final String NO_TIMESTAMP_SIGNING_WARN_TEMPLATE
+ = "No -tsa or -tsacert is provided "
+ + "and this jar is not timestamped. "
+ + "Without a timestamp, users may not be able to validate this jar "
+ + "after the signer certificate's expiration date "
+ + "(%1$tY-%1$tm-%1$td) or after any future revocation date.";
+
+ static final String NO_TIMESTAMP_VERIFYING_WARN_TEMPLATE
+ = "This jar contains signatures that does not include a timestamp. "
+ + "Without a timestamp, users may not be able to validate this jar "
+ + "after the signer certificate's expiration date "
+ + "(%1$tY-%1$tm-%1$td) or after any future revocation date.";
+
+ static final String NOT_YET_VALID_CERT_SIGNING_WARNING
+ = "The signer certificate is not yet valid.";
+
+ static final String NOT_YET_VALID_CERT_VERIFYING_WARNING
+ = "This jar contains entries "
+ + "whose signer certificate is not yet valid.";
+
+ static final String JAR_SIGNED = "jar signed.";
+
+ static final String JAR_VERIFIED = "jar verified.";
+
+ static final String JAR_VERIFIED_WITH_SIGNER_ERRORS
+ = "jar verified, with signer errors.";
+
+ static final int CHAIN_NOT_VALIDATED_EXIT_CODE = 4;
+ static final int HAS_EXPIRED_CERT_EXIT_CODE = 4;
+ static final int BAD_KEY_USAGE_EXIT_CODE = 8;
+ static final int BAD_EXTENDED_KEY_USAGE_EXIT_CODE = 8;
+ static final int BAD_NETSCAPE_CERT_TYPE_EXIT_CODE = 8;
+ static final int HAS_UNSIGNED_ENTRY_EXIT_CODE = 16;
+ static final int ALIAS_NOT_IN_STORE_EXIT_CODE = 32;
+ static final int NOT_SIGNED_BY_ALIAS_EXIT_CODE = 32;
+
+ protected void checkVerifying(OutputAnalyzer analyzer, int expectedExitCode,
+ String... warnings) {
+ analyzer.shouldHaveExitValue(expectedExitCode);
+ for (String warning : warnings) {
+ analyzer.shouldContain(warning);
+ }
+ if (warnings.length > 0) {
+ analyzer.shouldContain(WARNING);
+ }
+ if (expectedExitCode == 0) {
+ analyzer.shouldContain(JAR_VERIFIED);
+ } else {
+ analyzer.shouldContain(JAR_VERIFIED_WITH_SIGNER_ERRORS);
+ }
+ }
+
+ protected void checkSigning(OutputAnalyzer analyzer, String... warnings) {
+ analyzer.shouldHaveExitValue(0);
+ for (String warning : warnings) {
+ analyzer.shouldContain(warning);
+ }
+ if (warnings.length > 0) {
+ analyzer.shouldContain(WARNING);
+ }
+ analyzer.shouldContain(JAR_SIGNED);
+ }
+}
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.jks.base64 b/jdk/test/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.jks.base64
new file mode 100644
index 0000000..756d5ff
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.jks.base64
@@ -0,0 +1,26 @@
+/u3+7QAAAAIAAAABAAAAAQAFYWxpYXMAAAFBpkwW0gAAAr0wggK5MA4GCisGAQQB
+KgIRAQEFAASCAqWkGJ3PPjYmWNKrV23Y1u413RMAkrRZ+1OLWYRcQt4jtxtIyEH5
+Ho5b9dy9XN9FBKlTOD4c2Pc1T43BLKXeuLu3uLLeIxgXFt0z9CLyGwdYZZ751kXr
+DQ99qY6aNQUO6SeE4Wdty0KPAqid6ZJ8bF7T6wsTZSvNhaBRzyFydEfG7bbUYjOl
+mWC44nlsu6VEU3o9RQpcm1gIMwradOaIVT/HoB2bKmAv8gHqI6kreiEZwTdZkSAI
+IRi2vt1RPllXt5hgjDxUfZe8XOYYweR4Vt2/jVuKLJ80DNTu/9SeUD88zQAz53k4
+r3nRhv6TRcPm6tV/Fh92XLHiskL+TAzTfm+bUAudPCCVxN+yRtxvAgA+UhdV/SuM
+Zn5F6nrmP+YJG1hmprgCJIJJaCEXa9RXYC+vIVpO0WVNRuGlGm+/1afnOuQC8Wss
+ShXwjkaqTwAhqBFq7eYmmP8BK3gflYrt2zDLXvhl4ndVvMhMthFJ3ZvLh2LWpqLI
+/n8EMCf8US3lIEFk9DTHBZjffiHkqK2e7+FXEpG3xrgE6ZYLMdbd5Pb3YjZfhQx+
+ZTtiEFzYSaEGhacek/m7dRq1qmwgFsytng2OdWZe2ln8LJY0odr1dGUfJHfgafvi
+tlfbkg/rgjONtwliChDggbkUwnerrj/D/zrdEufUvfyltSshhHXRNDD3fH6spmEk
+hHKgxEc4yvxqJxzdMGtuib355aSfNegyl+GsnsKzXQCVEK2h3BLTQObzaD+8NZ12
+LQHvbrCiaS34vxJ3rEC+a+SW7itZp0aCdXMWdMJNkRKqyLBD3vG3zN05sN3XrhEM
+8BRT020TWY00tbVFbbBFheYLQRgTjrQtr0Yt6UHWBZc4N20crDLcSH5gqcCOVpla
+1Y2uqFEn8yqrGRwn/kgfNgAAAAEABVguNTA5AAABtTCCAbEwggEaoAMCAQICCQDH
+cEuVvzCuqzANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQDDARUZXN0MB4XDTEzMTAx
+MTA2NTUwNloXDTIzMTAwOTA2NTUwNlowDzENMAsGA1UEAwwEVGVzdDCBnzANBgkq
+hkiG9w0BAQEFAAOBjQAwgYkCgYEA8hOfp2Dcnvt//ZZQAja9TRiwKqXVS+TiYE3S
+gngCBjIi+YYdo0DsUeO5MBfE6uvCWOr5lwAR/u1iaJOhIoGJDiGoPasZlt+yIgtR
+LzA7j2q+1q6kcwiVxfikI3aUgHV/QsybTriT4Bf7TQNKtJG23MQa4sD7+PjtCWD7
+p3cHTfkCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgeAMA0GCSqGSIb3DQEBBQUA
+A4GBAKoDlTJ8wLRA7G8XdGm4gv733n1cSQzlkcsjfOO6/mA5Jvu8tyFNq9HTf9AT
+VXbrbGcUYJjhzSSY3w5apXK1kXyqTB1LUNEJ45WnmciqSSecVTpJz9TuegyoX0Zf
+HScSgqfDmjqoiiFiNCgn3ZEJ85ykGvoFYGH+php+BVi3S0bj5E/jRpyV3vNnii/S
+wJDSAXF6bYU=
diff --git a/jdk/test/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.sh b/jdk/test/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.sh
new file mode 100644
index 0000000..49fe91e
--- /dev/null
+++ b/jdk/test/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.sh
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2013, 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.
+#
+
+#!/bin/sh
+
+# This script creates JKS keystore with a certificate
+# that contains Netscape Certificate Type extension
+# that does not allow code signing
+# The keystore is used by BadNetscapeCertTypeTest.java test
+
+rm -rf keystore.jks
+echo "nsCertType = client" > ext.cfg
+
+openssl req -new -out cert.req -keyout key.pem -days 3650 \
+ -passin pass:password -passout pass:password -subj "/CN=Test"
+openssl x509 -in cert.req -out cert.pem -req -signkey key.pem -days 3650 \
+ -passin pass:password -extfile ext.cfg
+openssl pkcs12 -export -in cert.pem -inkey key.pem -out keystore.p12 \
+ -passin pass:password -passout pass:password -name alias
+
+${JAVA_HOME}/bin/keytool -importkeystore \
+ -srckeystore keystore.p12 -srcstoretype pkcs12 \
+ -srcstorepass password -alias alias \
+ -destkeystore bad_netscape_cert_type.jks -deststoretype jks \
+ -deststorepass password -destalias alias \
+
+openssl base64 < bad_netscape_cert_type.jks > bad_netscape_cert_type.jks.base64
+rm -rf cert.req key.pem cert.pem keystore.p12 ext.cfg bad_netscape_cert_type.jks
diff --git a/jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java b/jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java
new file mode 100644
index 0000000..fe856d7
--- /dev/null
+++ b/jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ *
+ * 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 8042397
+ * @summary Unit test for jmap utility test heap configuration reader
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.*
+ * @build JMapHeapConfigTest LingeredApp TmtoolTestScenario
+ * @run main JMapHeapConfigTest
+ */
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import jdk.testlibrary.Utils;
+
+public class JMapHeapConfigTest {
+
+ static final String expectedJMapValues[] = {
+ "MinHeapFreeRatio",
+ "MaxHeapFreeRatio",
+ "MaxHeapSize",
+ "NewSize",
+ "MaxNewSize",
+ "OldSize",
+ "NewRatio",
+ "SurvivorRatio",
+ "MetaspaceSize",
+ "CompressedClassSpaceSize",
+ "G1HeapRegionSize"};
+
+ // ignoring MaxMetaspaceSize
+
+ private static Map<String, String> parseJMapOutput(List<String> jmapOutput) {
+ Map<String, String> heapConfigMap = new HashMap<String, String>();
+ boolean shouldParse = false;
+
+ for (String line : jmapOutput) {
+ line = line.trim();
+
+ if (line.startsWith("Heap Configuration:")) {
+ shouldParse = true;
+ continue;
+ }
+
+ if (line.startsWith("Heap Usage:")) {
+ shouldParse = false;
+ continue;
+ }
+
+ if (shouldParse && !line.equals("")) {
+ String[] lv = line.split("\\s+");
+ try {
+ heapConfigMap.put(lv[0], lv[2]);
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // Ignore mailformed lines
+ }
+ }
+ }
+ return heapConfigMap;
+ }
+
+ // Compare stored values
+ private static void compareValues(Map<String, String> parsedJMapOutput, Map<String, String> parsedVmOutput) {
+ for (String key : expectedJMapValues) {
+ try {
+ String jmapVal = parsedJMapOutput.get(key);
+ if (jmapVal == null) {
+ throw new RuntimeException("Key '" + key + "' doesn't exists in jmap output");
+ }
+
+ String vmVal = parsedVmOutput.get(key);
+ if (vmVal == null) {
+ throw new RuntimeException("Key '" + key + "' doesn't exists in vm output");
+ }
+
+ if (new BigDecimal(jmapVal).compareTo(new BigDecimal(vmVal)) != 0) {
+ throw new RuntimeException(String.format("Key %s doesn't match %s vs %s", key, vmVal, jmapVal));
+ }
+ } catch (NumberFormatException ex) {
+ throw new RuntimeException("Unexpected key '" + key + "' value", ex);
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ System.out.println("Starting JMapHeapConfigTest");
+
+ // Forward vm options to LingeredApp
+ ArrayList<String> cmd = new ArrayList();
+ cmd.addAll(Utils.getVmOptions());
+ cmd.add("-XX:+PrintFlagsFinal");
+
+ TmtoolTestScenario tmt = TmtoolTestScenario.create("jmap", "-heap");
+ int exitcode = tmt.launch(cmd);
+ if (exitcode != 0) {
+ throw new RuntimeException("Test FAILED jmap exits with non zero exit code " + exitcode);
+ }
+
+ Map<String,String> parsedJmapOutput = parseJMapOutput(tmt.getToolOutput());
+ Map<String,String> parsedVMOutput = tmt.parseFlagsFinal();
+
+ compareValues(parsedJmapOutput, parsedVMOutput);
+
+ // If test fails it throws RuntimeException
+ System.out.println("Test PASSED");
+ }
+}
diff --git a/jdk/test/sun/tools/jmap/heapconfig/LingeredApp.java b/jdk/test/sun/tools/jmap/heapconfig/LingeredApp.java
new file mode 100644
index 0000000..176f82f
--- /dev/null
+++ b/jdk/test/sun/tools/jmap/heapconfig/LingeredApp.java
@@ -0,0 +1,402 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * This is a framework to launch an app that could be synchronized with caller
+ * to make further attach actions reliable across supported platforms
+
+ * Caller example:
+ * SmartTestApp a = SmartTestApp.startApp(cmd);
+ * // do something
+ * a.stopApp();
+ *
+ * or fine grained control
+ *
+ * a = new SmartTestApp("MyLock.lck");
+ * a.createLock();
+ * a.runApp();
+ * a.waitAppReady();
+ * // do something
+ * a.deleteLock();
+ * a.waitAppTerminate();
+ *
+ * Then you can work with app output and process object
+ *
+ * output = a.getAppOutput();
+ * process = a.getProcess();
+ *
+ */
+public class LingeredApp {
+
+ private static final long spinDelay = 1000;
+
+ private final String lockFileName;
+ private long lockCreationTime;
+ private Process appProcess;
+ private final ArrayList<String> storedAppOutput;
+
+ /*
+ * Drain child process output, store it into string array
+ */
+ class InputGobbler extends Thread {
+
+ InputStream is;
+ List<String> astr;
+
+ InputGobbler(InputStream is, List<String> astr) {
+ this.is = is;
+ this.astr = astr;
+ }
+
+ public void run() {
+ try {
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader br = new BufferedReader(isr);
+ String line = null;
+ while ((line = br.readLine()) != null) {
+ astr.add(line);
+ }
+ } catch (IOException ex) {
+ // pass
+ }
+ }
+ }
+
+ /**
+ * Create LingeredApp object on caller side. Lock file have be a valid filename
+ * at writable location
+ *
+ * @param lockFileName - the name of lock file
+ */
+ public LingeredApp(String lockFileName) {
+ this.lockFileName = lockFileName;
+ this.storedAppOutput = new ArrayList();
+ }
+
+ /**
+ *
+ * @return name of lock file
+ */
+ public String getLockFileName() {
+ return this.lockFileName;
+ }
+
+ /**
+ *
+ * @return name of testapp
+ */
+ public String getAppName() {
+ return this.getClass().getName();
+ }
+
+ /**
+ *
+ * @return pid of java process running testapp
+ */
+ public long getPid() {
+ if (appProcess == null) {
+ throw new RuntimeException("Process is not alive");
+ }
+ return appProcess.getPid();
+ }
+
+ /**
+ *
+ * @return process object
+ */
+ public Process getProcess() {
+ return appProcess;
+ }
+
+ /**
+ *
+ * @return application output as string array. Empty array if application produced no output
+ */
+ List<String> getAppOutput() {
+ if (appProcess.isAlive()) {
+ throw new RuntimeException("Process is still alive. Can't get its output.");
+ }
+ return storedAppOutput;
+ }
+
+ /* Make sure all part of the app use the same method to get dates,
+ as different methods could produce different results
+ */
+ private static long epoch() {
+ return new Date().getTime();
+ }
+
+ private static long lastModified(String fileName) throws IOException {
+ Path path = Paths.get(fileName);
+ BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class);
+ return attr.lastModifiedTime().toMillis();
+ }
+
+ private static void setLastModified(String fileName, long newTime) throws IOException {
+ Path path = Paths.get(fileName);
+ FileTime fileTime = FileTime.fromMillis(newTime);
+ Files.setLastModifiedTime(path, fileTime);
+ }
+
+ /**
+ * create lock
+ *
+ * @throws IOException
+ */
+ public void createLock() throws IOException {
+ Path path = Paths.get(lockFileName);
+ // Files.deleteIfExists(path);
+ Files.createFile(path);
+ lockCreationTime = lastModified(lockFileName);
+ }
+
+ /**
+ * Delete lock
+ *
+ * @throws IOException
+ */
+ public void deleteLock() throws IOException {
+ try {
+ Path path = Paths.get(lockFileName);
+ Files.delete(path);
+ } catch (NoSuchFileException ex) {
+ // Lock already deleted. Ignore error
+ }
+ }
+
+ public void waitAppTerminate() {
+ while (true) {
+ try {
+ appProcess.waitFor();
+ break;
+ } catch (InterruptedException ex) {
+ // pass
+ }
+ }
+ }
+
+ /**
+ * The app touches the lock file when it's started
+ * wait while it happens. Caller have to delete lock on wait error.
+ *
+ * @param timeout
+ * @throws java.io.IOException
+ */
+ public void waitAppReady(long timeout) throws IOException {
+ long here = epoch();
+ while (true) {
+ long epoch = epoch();
+ if (epoch - here > (timeout * 1000)) {
+ throw new IOException("App waiting timeout");
+ }
+
+ // Live process should touch lock file every second
+ long lm = lastModified(lockFileName);
+ if (lm > lockCreationTime) {
+ break;
+ }
+
+ // Make sure process didn't already exit
+ if (!appProcess.isAlive()) {
+ throw new IOException("App exited unexpectedly with " + appProcess.exitValue());
+ }
+
+ try {
+ Thread.sleep(spinDelay);
+ } catch (InterruptedException ex) {
+ // pass
+ }
+ }
+ }
+
+ /**
+ * Run the app
+ *
+ * @param vmArguments
+ * @throws IOException
+ */
+ public void runApp(List<String> vmArguments)
+ throws IOException {
+
+ // We should always use testjava or throw an exception,
+ // so we can't use JDKToolFinder.getJDKTool("java");
+ // that falls back to compile java on error
+ String jdkPath = System.getProperty("test.jdk");
+ if (jdkPath == null) {
+ // we are not under jtreg, try env
+ Map<String, String> env = System.getenv();
+ jdkPath = env.get("TESTJAVA");
+ }
+
+ if (jdkPath == null) {
+ throw new RuntimeException("Can't determine jdk path neither test.jdk property no TESTJAVA env are set");
+ }
+
+ String osname = System.getProperty("os.name");
+ String javapath = jdkPath + ((osname.startsWith("window")) ? "/bin/java.exe" : "/bin/java");
+
+ List<String> cmd = new ArrayList();
+ cmd.add(javapath);
+
+
+ if (vmArguments == null) {
+ // Propagate test.vm.options to LingeredApp, filter out possible empty options
+ String testVmOpts[] = System.getProperty("test.vm.opts","").split("\\s+");
+ for (String s : testVmOpts) {
+ if (!s.equals("")) {
+ cmd.add(s);
+ }
+ }
+ }
+ else{
+ // Lets user manage LingerApp options
+ cmd.addAll(vmArguments);
+ }
+
+ // Make sure we set correct classpath to run the app
+ cmd.add("-cp");
+ String classpath = System.getProperty("test.class.path");
+ cmd.add((classpath == null) ? "." : classpath);
+
+ cmd.add(this.getAppName());
+ cmd.add(lockFileName);
+
+ // Reporting
+ StringBuilder cmdLine = new StringBuilder();
+ for (String strCmd : cmd) {
+ cmdLine.append("'").append(strCmd).append("' ");
+ }
+
+ // A bit of verbosity
+ System.out.println("Command line: [" + cmdLine.toString() + "]");
+
+ ProcessBuilder pb = new ProcessBuilder(cmd);
+ // we don't expect any error output but make sure we are not stuck on pipe
+ // pb.redirectErrorStream(false);
+ pb.redirectError(ProcessBuilder.Redirect.INHERIT);
+
+ appProcess = pb.start();
+
+ // Create pipe reader for process, and read stdin and stderr to array of strings
+ InputGobbler gb = new InputGobbler(appProcess.getInputStream(), storedAppOutput);
+ gb.start();
+ }
+
+ /**
+ * High level interface for test writers
+ */
+ /**
+ * Factory method that creates SmartAppTest object with ready to use application
+ * lock name is autogenerated, wait timeout is hardcoded
+ * @param cmd - vm options, could be null to auto add testvm.options
+ * @return LingeredApp object
+ * @throws IOException
+ */
+ public static LingeredApp startApp(List<String> cmd) throws IOException {
+ final String lockName = UUID.randomUUID().toString() + ".lck";
+ final int waitTime = 10;
+
+ LingeredApp a = new LingeredApp(lockName);
+ a.createLock();
+ try {
+ a.runApp(cmd);
+ a.waitAppReady(waitTime);
+ } catch (Exception ex) {
+ a.deleteLock();
+ throw ex;
+ }
+
+ return a;
+ }
+
+ public static LingeredApp startApp() throws IOException {
+ return startApp(null);
+ }
+
+ /**
+ * Delete lock file that signal app to terminate, then
+ * waits until app is actually terminated.
+ * @throws IOException
+ */
+ public void stopApp() throws IOException {
+ deleteLock();
+ waitAppTerminate();
+ int exitcode = appProcess.exitValue();
+ if (exitcode != 0) {
+ throw new IOException("LingeredApp terminated with non-zero exit code " + exitcode);
+ }
+ }
+
+ /**
+ * This part is the application it self
+ */
+ public static void main(String args[]) {
+
+ if (args.length != 1) {
+ System.err.println("Lock file name is not specified");
+ System.exit(7);
+ }
+
+ String theLockFileName = args[0];
+
+ try {
+ Path path = Paths.get(theLockFileName);
+
+ while (Files.exists(path)) {
+ long lm = lastModified(theLockFileName);
+ long now = epoch();
+
+ // A bit of paranoja, don't allow test app to run more than an hour
+ if (now - lm > 3600) {
+ throw new IOException("Lock is too old. Aborting");
+ }
+
+ // Touch lock to indicate our rediness
+ setLastModified(theLockFileName, now);
+ Thread.sleep(spinDelay);
+ }
+
+ } catch (Exception ex) {
+ System.err.println("LingeredApp ERROR: " + ex);
+ // Leave exit_code = 1 to Java launcher
+ System.exit(3);
+ }
+
+ System.exit(0);
+ }
+}
diff --git a/jdk/test/sun/tools/jmap/heapconfig/LingeredAppTest.java b/jdk/test/sun/tools/jmap/heapconfig/LingeredAppTest.java
new file mode 100644
index 0000000..e492add
--- /dev/null
+++ b/jdk/test/sun/tools/jmap/heapconfig/LingeredAppTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Unit test for LingeredApp
+ * @compile LingeredAppTest.java
+ * @compile LingeredApp.java
+ * @run main LingeredAppTest
+ */
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class LingeredAppTest {
+
+ public static void main(String[] args) {
+ try {
+ System.out.println("Starting LingeredApp with default parameters");
+
+ ArrayList<String> cmd = new ArrayList();
+
+ // Propagate test.vm.options to LingeredApp, filter out possible empty options
+ String testVmOpts[] = System.getProperty("test.vm.opts","").split("\\s+");
+ for (String s : testVmOpts) {
+ if (!s.equals("")) {
+ cmd.add(s);
+ }
+ }
+
+ cmd.add("-XX:+PrintFlagsFinal");
+
+ LingeredApp a = LingeredApp.startApp(cmd);
+ System.out.printf("App pid: %d\n", a.getPid());
+ a.stopApp();
+
+ System.out.println("App output:");
+ int count = 0;
+ for (String line : a.getAppOutput()) {
+ count += 1;
+ }
+ System.out.println("Found " + count + " lines in VM output");
+ System.out.println("Test PASSED");
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ System.out.println("Test ERROR");
+ System.exit(3);
+ }
+ }
+}
diff --git a/jdk/test/sun/tools/jmap/heapconfig/TmtoolTestScenario.java b/jdk/test/sun/tools/jmap/heapconfig/TmtoolTestScenario.java
new file mode 100644
index 0000000..667085f
--- /dev/null
+++ b/jdk/test/sun/tools/jmap/heapconfig/TmtoolTestScenario.java
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import jdk.testlibrary.JDKToolLauncher;
+import jdk.testlibrary.Utils;
+
+public class TmtoolTestScenario {
+
+ private final ArrayList<String> toolOutput = new ArrayList();
+ private LingeredApp theApp = null;
+ private final String toolName;
+ private final String[] toolArgs;
+
+ /**
+ * @param toolName - name of tool to test
+ * @param toolArgs - tool arguments
+ * @return the object
+ */
+ public static TmtoolTestScenario create(String toolName, String... toolArgs) {
+ return new TmtoolTestScenario(toolName, toolArgs);
+ }
+
+ /**
+ * @return STDOUT of tool
+ */
+ public List<String> getToolOutput() {
+ return toolOutput;
+ }
+
+ /**
+ *
+ * @return STDOUT of test app
+ */
+ public List<String> getAppOutput() {
+ return theApp.getAppOutput();
+ }
+
+ /**
+ * @return Value of the app output with -XX:+PrintFlagsFinal as a map.
+ */
+ public Map<String, String> parseFlagsFinal() {
+ List<String> astr = theApp.getAppOutput();
+ Map<String, String> vmMap = new HashMap();
+
+ for (String line : astr) {
+ String[] lv = line.trim().split("\\s+");
+ try {
+ vmMap.put(lv[1], lv[3]);
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // ignore mailformed lines
+ }
+ }
+ return vmMap;
+ }
+
+ /**
+ *
+ * @param vmArgs - vm and java arguments to launch test app
+ * @return exit code of tool
+ */
+ public int launch(List<String> vmArgs) {
+ System.out.println("Starting LingeredApp");
+ try {
+ try {
+ theApp = LingeredApp.startApp(vmArgs);
+
+ System.out.println("Starting " + toolName + " against " + theApp.getPid());
+ JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK(toolName);
+
+ for (String cmd : toolArgs) {
+ launcher.addToolArg(cmd);
+ }
+ launcher.addToolArg(Long.toString(theApp.getPid()));
+
+ ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand());
+ processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
+ Process toolProcess = processBuilder.start();
+
+ // By default child process output stream redirected to pipe, so we are reading it in foreground.
+ BufferedReader reader = new BufferedReader(new InputStreamReader(toolProcess.getInputStream()));
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ toolOutput.add(line.trim());
+ }
+
+ toolProcess.waitFor();
+
+ return toolProcess.exitValue();
+ } finally {
+ theApp.stopApp();
+ }
+ } catch (IOException | InterruptedException ex) {
+ throw new RuntimeException("Test ERROR " + ex, ex);
+ }
+ }
+
+ public void launch(String... appArgs) throws IOException {
+ launch(Arrays.asList(appArgs));
+ }
+
+ private TmtoolTestScenario(String toolName, String[] toolArgs) {
+ this.toolName = toolName;
+ this.toolArgs = toolArgs;
+ }
+
+}
diff --git a/make/Images.gmk b/make/Images.gmk
index 20c5e10..5913c07 100644
--- a/make/Images.gmk
+++ b/make/Images.gmk
@@ -111,14 +111,16 @@
# Use this file inside the image as target for make rule
JIMAGE_TARGET_FILE := bin/java$(EXE_SUFFIX)
-$(JDK_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES)
+$(JDK_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \
+ $(call DependOnVariable, JDK_MODULES_LIST)
$(ECHO) Creating jdk jimage
$(RM) -r $(JDK_IMAGE_DIR) $(JDK_SORTED_MODULES)
$(JIMAGE_TOOL) --mods $(JDK_MODULES_LIST) --output $(JDK_IMAGE_DIR) \
$(MODULES_XML) > $(JDK_SORTED_MODULES)
$(TOUCH) $@
-$(JRE_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES)
+$(JRE_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \
+ $(call DependOnVariable, JRE_MODULES_LIST)
$(ECHO) Creating jre jimage
$(RM) -r $(JRE_IMAGE_DIR) $(JRE_SORTED_MODULES)
$(JIMAGE_TOOL) --mods $(JRE_MODULES_LIST) --output $(JRE_IMAGE_DIR) \
@@ -131,7 +133,8 @@
COMPACT_EXTRA_MODULES := jdk.localedata jdk.crypto.pkcs11 jdk.crypto.ec
-$(JRE_COMPACT1_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES)
+$(JRE_COMPACT1_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \
+ $(call DependOnVariable, JRE_COMPACT1_MODULES_LIST)
$(ECHO) Creating jre compact1 jimage
$(RM) -r $(JRE_COMPACT1_IMAGE_DIR) $(JRE_COMPACT1_SORTED_MODULES)
$(JIMAGE_TOOL) \
@@ -140,7 +143,8 @@
$(MODULES_XML) > $(JRE_COMPACT1_SORTED_MODULES)
$(TOUCH) $@
-$(JRE_COMPACT2_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES)
+$(JRE_COMPACT2_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \
+ $(call DependOnVariable, JRE_COMPACT2_MODULES_LIST)
$(ECHO) Creating jre compact2 jimage
$(RM) -r $(JRE_COMPACT2_IMAGE_DIR) $(JRE_COMPACT2_SORTED_MODULES)
$(JIMAGE_TOOL) \
@@ -149,7 +153,8 @@
$(MODULES_XML) > $(JRE_COMPACT2_SORTED_MODULES)
$(TOUCH) $@
-$(JRE_COMPACT3_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES)
+$(JRE_COMPACT3_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(DEPENDENCIES) \
+ $(call DependOnVariable, JRE_COMPACT3_MODULES_LIST)
$(ECHO) Creating jre compact3 jimage
$(RM) -r $(JRE_COMPACT3_IMAGE_DIR) $(JRE_COMPACT3_SORTED_MODULES)
$(JIMAGE_TOOL) \
@@ -368,45 +373,59 @@
# Common way to emit a line into the release or info file
define info-file-item # name value
- $(PRINTF) '%s="%s"\n' $1 $2 >> $@
+ $(PRINTF) '%s="%s"\n' $1 $2 >> $@
endef
# Param 1 - The file containing the MODULES list
define create-info-file
- $(ECHO) $(LOG_INFO) Generating $(patsubst $(OUTPUT_ROOT)/%,%,$@)
- $(MKDIR) -p $(@D)
- $(RM) $@
- $(call info-file-item, "JAVA_VERSION", "$(JDK_VERSION)")
- $(call info-file-item, "OS_NAME", "$(REQUIRED_OS_NAME)")
- $(call info-file-item, "OS_VERSION", "$(REQUIRED_OS_VERSION)")
- $(call info-file-item, "OS_ARCH", "$(OPENJDK_TARGET_CPU_LEGACY)")
- $(if $(JDK_ARCH_ABI_PROP_NAME), \
- $(call info-file-item, "SUN_ARCH_ABI", "$(JDK_ARCH_ABI_PROP_NAME)"))
- $(call info-file-item, "SOURCE", "$(ALL_SOURCE_TIPS)")
- $(call info-file-item, "MODULES", "`$(CAT) $1`")
+ $(call info-file-item, "JAVA_VERSION", "$(JDK_VERSION)")
+ $(call info-file-item, "OS_NAME", "$(REQUIRED_OS_NAME)")
+ $(call info-file-item, "OS_VERSION", "$(REQUIRED_OS_VERSION)")
+ $(call info-file-item, "OS_ARCH", "$(OPENJDK_TARGET_CPU_LEGACY)")
+ $(if $(JDK_ARCH_ABI_PROP_NAME), \
+ $(call info-file-item, "SUN_ARCH_ABI", "$(JDK_ARCH_ABI_PROP_NAME)"))
+ $(call info-file-item, "SOURCE", "$(ALL_SOURCE_TIPS)")
+ $(call info-file-item, "MODULES", "`$(CAT) $1`")
endef
+# Param 1 - The file containing the MODULES list
+define prepare-info-file
+ $(ECHO) $(LOG_INFO) Generating $(patsubst $(OUTPUT_ROOT)/%,%,$@)
+ $(MKDIR) -p $(@D)
+ $(RM) $@
+endef
+
+define info-file
+ $(call prepare-info-file, $1)
+ $(call create-info-file, $1)
+endef
+
+# Create a variable dependency file common for all release info files. The
+# sorted module list will only change if the image is regenerated, which will
+# trigger a rebuild of these files anyway.
+INFO_FILE_VARDEPS := $(call DependOnVariable, create-info-file)
+
ALL_SOURCE_TIPS = $(shell \
if [ -f $(SUPPORT_OUTPUTDIR)/source_tips ] ; then \
$(CAT) $(SUPPORT_OUTPUTDIR)/source_tips ; \
fi)
-$(JRE_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips
- $(call create-info-file, $(JRE_SORTED_MODULES))
+$(JRE_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips
+ $(call info-file, $(JRE_SORTED_MODULES))
-$(JDK_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips
- $(call create-info-file, $(JDK_SORTED_MODULES))
+$(JDK_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips
+ $(call info-file, $(JDK_SORTED_MODULES))
-$(JRE_COMPACT1_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips
- $(call create-info-file, $(JRE_COMPACT1_SORTED_MODULES))
+$(JRE_COMPACT1_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips
+ $(call info-file, $(JRE_COMPACT1_SORTED_MODULES))
$(call info-file-item, "JAVA_PROFILE", "compact1")
-$(JRE_COMPACT2_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips
- $(call create-info-file, $(JRE_COMPACT2_SORTED_MODULES))
+$(JRE_COMPACT2_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips
+ $(call info-file, $(JRE_COMPACT2_SORTED_MODULES))
$(call info-file-item, "JAVA_PROFILE", "compact2")
-$(JRE_COMPACT3_INFO_FILE): $(OUTPUT_ROOT)/spec.gmk $(SUPPORT_OUTPUTDIR)/source_tips
- $(call create-info-file, $(JRE_COMPACT3_SORTED_MODULES))
+$(JRE_COMPACT3_INFO_FILE): $(INFO_FILE_VARDEPS) $(SUPPORT_OUTPUTDIR)/source_tips
+ $(call info-file, $(JRE_COMPACT3_SORTED_MODULES))
$(call info-file-item, "JAVA_PROFILE", "compact3")
JRE_TARGETS += $(JRE_INFO_FILE)
diff --git a/make/Main.gmk b/make/Main.gmk
index a46f1de..3bb6dd1 100644
--- a/make/Main.gmk
+++ b/make/Main.gmk
@@ -402,6 +402,8 @@
verify-modules: exploded-image
+ test-make: clean-test-make
+
endif
################################################################################
@@ -446,7 +448,7 @@
# alias for ease of use.
jdk: exploded-image
-images: test-image jimages demos samples zip-security
+images: test-image jimages demos samples zip-security verify-modules
ifeq ($(OPENJDK_TARGET_OS), macosx)
images: mac-bundles
@@ -477,7 +479,7 @@
# file.
CLEAN_DIRS += hotspot jdk bootcycle-build test buildtools support \
- images make-support
+ images make-support test-make
CLEAN_DIR_TARGETS := $(addprefix clean-, $(CLEAN_DIRS))
CLEAN_PHASES := gensrc java native include
CLEAN_PHASE_TARGETS := $(addprefix clean-, $(CLEAN_PHASES))
diff --git a/make/ZipSource.gmk b/make/ZipSource.gmk
index 52bf6aa..a83d1d7 100644
--- a/make/ZipSource.gmk
+++ b/make/ZipSource.gmk
@@ -71,7 +71,7 @@
$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_API_DIR)/native/libjli/java_md*)))
# This dir needs to exist before macro is evaluated to avoid warning from find.
-$(eval $(call MakeDir, $(SUPPORT_OUTPUTDIR)/src))
+$(call MakeDir, $(SUPPORT_OUTPUTDIR)/src)
$(eval $(call SetupZipArchive,BUILD_SRC_ZIP, \
SRC := $(SRC_ZIP_SRCS) $(SUPPORT_OUTPUTDIR)/src, \
INCLUDES := $(SRC_ZIP_INCLUDES) launcher, \
diff --git a/make/common/IdlCompilation.gmk b/make/common/IdlCompilation.gmk
index 3fdf979..f1a2fd9 100644
--- a/make/common/IdlCompilation.gmk
+++ b/make/common/IdlCompilation.gmk
@@ -99,7 +99,7 @@
$(if $(16),$(error Internal makefile error: Too many arguments to SetupIdlCompilation, please update IdlCompilation.gmk))
# Find all existing java files and existing class files.
- $$(eval $$(call MakeDir,$$($1_BIN)))
+ $$(call MakeDir,$$($1_BIN))
$1_SRCS := $$(shell find $$($1_SRC) -name "*.idl")
$1_BINS := $$(shell find $$($1_BIN) -name "*.java")
# Prepend the source/bin path to the filter expressions.
diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk
index a183b30..77f95d6 100644
--- a/make/common/JavaCompilation.gmk
+++ b/make/common/JavaCompilation.gmk
@@ -126,17 +126,20 @@
$1_FIND_PATTERNS:=$(FALSE_FIND_PATTERN) $$(patsubst %,$(SPACE)-o$(SPACE)-name$(SPACE)$(DQUOTE)*%$(DQUOTE),$$($1_SUFFIXES))
# On windows, a lot of includes/excludes risk making the command line too long, so
# writing the grep patterns to files.
+ # Grep returns 1 if nothing is matched. Do not fail the build for this.
ifneq (,$$($1_INCLUDES))
$1_GREP_INCLUDE_PATTERNS:=$$(call EscapeDollar, \
$$(foreach src,$$($1_SRCS), $$(addprefix $$(src)/,$$($1_INCLUDES))))
# If there are a lot of include patterns, output to file to shorten command lines
ifeq ($$(word 20,$$($1_GREP_INCLUDE_PATTERNS)),)
- $1_GREP_INCLUDES:=| $(GREP) $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_INCLUDE_PATTERNS))
+ $1_GREP_INCLUDES:=| ( $(GREP) $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_INCLUDE_PATTERNS)) \
+ || test "$$$$?" = "1" )
else
$1_GREP_INCLUDE_OUTPUT:=$(RM) $$($1_BIN)/_the.$$($1_JARNAME)_include $$(NEWLINE) \
$$(call ListPathsSafely,$1_GREP_INCLUDE_PATTERNS,\n, \
>> $$($1_BIN)/_the.$$($1_JARNAME)_include)
- $1_GREP_INCLUDES:=| $(GREP) -f $$($1_BIN)/_the.$$($1_JARNAME)_include
+ $1_GREP_INCLUDES:=| ( $(GREP) -f $$($1_BIN)/_the.$$($1_JARNAME)_include \
+ || test "$$$$?" = "1" )
endif
endif
ifneq (,$$($1_EXCLUDES)$$($1_EXCLUDE_FILES))
@@ -145,12 +148,14 @@
$$($1_EXCLUDES) $$($1_EXCLUDE_FILES))))
# If there are a lot of include patterns, output to file to shorten command lines
ifeq ($$(word 20,$$($1_GREP_EXCLUDE_PATTERNS)),)
- $1_GREP_EXCLUDES:=| $(GREP) -v $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_EXCLUDE_PATTERNS))
+ $1_GREP_EXCLUDES:=| ( $(GREP) -v $$(patsubst %,$(SPACE)-e$(SPACE)$(DQUOTE)%$(DQUOTE),$$($1_GREP_EXCLUDE_PATTERNS)) \
+ || test "$$$$?" = "1" )
else
$1_GREP_EXCLUDE_OUTPUT=$(RM) $$($1_BIN)/_the.$$($1_JARNAME)_exclude $$(NEWLINE) \
$$(call ListPathsSafely,$1_GREP_EXCLUDE_PATTERNS,\n, \
>> $$($1_BIN)/_the.$$($1_JARNAME)_exclude)
- $1_GREP_EXCLUDES:=| $(GREP) -v -f $$($1_BIN)/_the.$$($1_JARNAME)_exclude
+ $1_GREP_EXCLUDES:=| ( $(GREP) -v -f $$($1_BIN)/_the.$$($1_JARNAME)_exclude \
+ || test "$$$$?" = "1" )
endif
endif
@@ -222,9 +227,11 @@
$$($1_CAPTURE_EXTRA_FILES)
# The capture metainf macro finds all files below the META-INF directory that are newer than the jar-file.
+ # Find returns non zero if the META-INF dir does not exist, ignore this.
ifeq (,$$($1_SKIP_METAINF))
$1_CAPTURE_METAINF =$$(foreach src,$$($1_SRCS), \
- ( $(FIND) $$(src)/META-INF -type f -a -newer $$@ 2> /dev/null | $(SED) 's|$$(src)/|-C $$(src) |g' >> \
+ ( ( $(FIND) $$(src)/META-INF -type f -a -newer $$@ 2> /dev/null || true ) \
+ | $(SED) 's|$$(src)/|-C $$(src) |g' >> \
$$($1_BIN)/_the.$$($1_JARNAME)_contents ) $$(NEWLINE) )
endif
# The capture deletes macro finds all deleted files and concatenates them. The resulting file
@@ -248,9 +255,11 @@
>> $$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE)) \
$$($1_CAPTURE_EXTRA_FILES)
+ # Find returns non zero if the META-INF dir does not exist, ignore this.
ifeq (,$$($1_SKIP_METAINF))
$1_SCAPTURE_METAINF=$$(foreach src,$$($1_SRCS), \
- ( $(FIND) $$(src)/META-INF -type f 2> /dev/null | $(SED) 's|$$(src)/|-C $$(src) |g' >> \
+ ( ( $(FIND) $$(src)/META-INF -type f 2> /dev/null || true ) \
+ | $(SED) 's|$$(src)/|-C $$(src) |g' >> \
$$($1_BIN)/_the.$$($1_JARNAME)_contents) $$(NEWLINE) )
endif
$1_SUPDATE_CONTENTS=$(JAR) $$($1_JAR_UPDATE_OPTIONS) $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE)
@@ -270,19 +279,37 @@
$1_JAR_UPDATE_OPTIONS := uf
endif
+ # Include all variables of significance in the vardeps file
+ $1_VARDEPS := $(JAR) $$($1_JAR_CREATE_OPTIONS) $$($1_MANIFEST) $(RELEASE) $(COMPANY_NAME) \
+ $$($1_JARMAIN) $$($1_EXTRA_MANIFEST_ATTR)
+ $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$(dir $$($1_JAR))_the.$$($1_JARNAME).vardeps)
+
# Here is the rule that creates/updates the jar file.
- $$($1_JAR) : $$($1_DEPS)
+ $$($1_JAR) : $$($1_DEPS) $$($1_MANIFEST) $$($1_VARDEPS_FILE)
$(MKDIR) -p $$($1_BIN)
$$($1_GREP_INCLUDE_OUTPUT)
$$($1_GREP_EXCLUDE_OUTPUT)
- $$(if $$($1_MANIFEST), \
- $(SED) -e "s#@@RELEASE@@#$(RELEASE)#" \
- -e "s#@@COMPANY_NAME@@#$(COMPANY_NAME)#" $$($1_MANIFEST) > $$($1_MANIFEST_FILE) \
+ # If the vardeps file is part of the newer prereq list, it means that
+ # either the jar file does not exist, or we need to recreate it from
+ # from scratch anyway since a simple update will not catch all the
+ # potential changes.
+ $$(if $$(filter $$($1_VARDEPS_FILE) $$($1_MANIFEST), $$?), \
+ $$(if $$($1_MANIFEST), \
+ $(SED) -e "s#@@RELEASE@@#$(RELEASE)#" \
+ -e "s#@@COMPANY_NAME@@#$(COMPANY_NAME)#" $$($1_MANIFEST) > $$($1_MANIFEST_FILE) $$(NEWLINE) \
+ , \
+ $(RM) $$($1_MANIFEST_FILE) && $(TOUCH) $$($1_MANIFEST_FILE) $$(NEWLINE)) \
+ $$(if $$($1_JARMAIN), \
+ $(ECHO) "Main-Class: $$(strip $$($1_JARMAIN))" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \
+ $$(if $$($1_EXTRA_MANIFEST_ATTR), \
+ $(PRINTF) "$$($1_EXTRA_MANIFEST_ATTR)\n" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \
+ $(ECHO) Creating $$($1_NAME) $$(NEWLINE) \
+ $(JAR) $$($1_JAR_CREATE_OPTIONS) $$@ $$($1_MANIFEST_FILE) $$(NEWLINE) \
+ $$($1_SCAPTURE_CONTENTS) \
+ $$($1_SCAPTURE_METAINF) \
+ $$($1_SUPDATE_CONTENTS) \
+ $$($1_JARINDEX) && true \
, \
- $(RM) $$($1_MANIFEST_FILE) && $(TOUCH) $$($1_MANIFEST_FILE))
- $$(if $$($1_JARMAIN),$(ECHO) "Main-Class: $$(strip $$($1_JARMAIN))" >> $$($1_MANIFEST_FILE))
- $$(if $$($1_EXTRA_MANIFEST_ATTR),$(PRINTF) "$$($1_EXTRA_MANIFEST_ATTR)\n" >> $$($1_MANIFEST_FILE))
- $$(if $$(wildcard $$@), \
$(ECHO) Modifying $$($1_NAME) $$(NEWLINE) \
$$($1_CAPTURE_CONTENTS) \
$$($1_CAPTURE_METAINF) \
@@ -294,12 +321,6 @@
$(ZIP) -q -d $$@ `$(CAT) $$($1_DELETESS_FILE)` ; \
fi $$(NEWLINE) \
$$($1_UPDATE_CONTENTS) true $$(NEWLINE) \
- $$($1_JARINDEX) && true \
- , \
- $(ECHO) Creating $$($1_NAME) && $(JAR) $$($1_JAR_CREATE_OPTIONS) $$@ $$($1_MANIFEST_FILE) $$(NEWLINE) \
- $$($1_SCAPTURE_CONTENTS) \
- $$($1_SCAPTURE_METAINF) \
- $$($1_SUPDATE_CONTENTS) \
$$($1_JARINDEX) && true )
# Add jar to target list
@@ -431,7 +452,7 @@
$1_SRC:=$$(call ADD_SRCS,$$($1_SRC))
# Make sure the dirs exist.
$$(foreach d,$$($1_SRC), $$(if $$(wildcard $$d),,$$(error SRC specified to SetupJavaCompilation $1 contains missing directory $$d)))
- $$(eval $$(call MakeDir,$$($1_BIN)))
+ $$(call MakeDir,$$($1_BIN))
# Add all source roots to the find cache since we are likely going to run find
# on these more than once. The cache will only be updated if necessary.
$$(eval $$(call FillCacheFind,$$($1_SRC)))
@@ -475,23 +496,23 @@
$1_ALL_COPIES += $$(filter $$(addprefix %,$$($1_COPY)),$$($1_ALL_SRCS))
# Copy these explicitly
$1_ALL_COPIES += $$($1_COPY_FILES)
- # Copy must also respect filters.
- ifneq (,$$($1_INCLUDES))
- $1_ALL_COPIES := $$(filter $$($1_SRC_INCLUDES),$$($1_ALL_COPIES))
- endif
- ifneq (,$$($1_EXCLUDES))
- $1_ALL_COPIES := $$(filter-out $$($1_SRC_EXCLUDES),$$($1_ALL_COPIES))
- endif
- ifneq (,$$($1_EXCLUDE_FILES))
- $1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_FILES_PATTERN),$$($1_ALL_COPIES))
- endif
endif
- ifneq (,$$($1_ALL_COPIES))
- # Yep, there are files to be copied!
- $1_ALL_COPY_TARGETS:=
- $$(foreach i,$$($1_ALL_COPIES),$$(eval $$(call add_file_to_copy,$1,$$i)))
- # Now we can depend on $$($1_ALL_COPY_TARGETS) to copy all files!
- endif
+ # Copy must also respect filters.
+ ifneq (,$$($1_INCLUDES))
+ $1_ALL_COPIES := $$(filter $$($1_SRC_INCLUDES),$$($1_ALL_COPIES))
+ endif
+ ifneq (,$$($1_EXCLUDES))
+ $1_ALL_COPIES := $$(filter-out $$($1_SRC_EXCLUDES),$$($1_ALL_COPIES))
+ endif
+ ifneq (,$$($1_EXCLUDE_FILES))
+ $1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_FILES_PATTERN),$$($1_ALL_COPIES))
+ endif
+ ifneq (,$$($1_ALL_COPIES))
+ # Yep, there are files to be copied!
+ $1_ALL_COPY_TARGETS:=
+ $$(foreach i,$$($1_ALL_COPIES),$$(eval $$(call add_file_to_copy,$1,$$i)))
+ # Now we can depend on $$($1_ALL_COPY_TARGETS) to copy all files!
+ endif
# Find all property files to be copied and cleaned from source to bin.
ifneq (,$$($1_CLEAN)$$($1_CLEAN_FILES))
@@ -535,9 +556,14 @@
$1_SJAVAC:=$$(subst com.sun.tools.javac.Main,com.sun.tools.sjavac.Main,$$($1_JAVAC))
# Set the $1_REMOTE to spawn a background javac server.
- $1_REMOTE:=--server:portfile=$$($1_SJAVAC_PORTFILE),id=$1,sjavac=$$(subst $$(SPACE),%20,$$(subst $$(COMMA),%2C,$$(strip $$($1_SERVER_JVM) $$($1_SJAVAC))))
+ $1_REMOTE:=--server:portfile=$$($1_SJAVAC_PORTFILE),id=$1,sjavac=$$(subst \
+ $$(SPACE),%20,$$(subst $$(COMMA),%2C,$$(strip $$($1_SERVER_JVM) $$($1_SJAVAC))))
- $$($1_BIN)/_the.$1_batch: $$($1_SRCS) $$($1_DEPENDS)
+ $1_VARDEPS := $$($1_JVM) $$($1_SJAVAC) $$($1_SJAVAC_ARGS) $$($1_FLAGS) \
+ $$($1_HEADERS_ARG) $$($1_BIN)
+ $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BIN)/_the.$1.vardeps)
+
+ $$($1_BIN)/_the.$1_batch: $$($1_SRCS) $$($1_DEPENDS) $$($1_VARDEPS_FILE)
$(MKDIR) -p $$(@D) $$(dir $$($1_SJAVAC_PORTFILE))
# As a workaround for sjavac not tracking api changed from the classpath, force full
# recompile if an external dependency, which is something other than a source
@@ -592,8 +618,11 @@
$1_HEADER_TARGETS := $$($1_HEADERS)/_the.$1_headers
endif
+ $1_VARDEPS := $$($1_JVM) $$($1_JAVAC) $$($1_FLAGS) $$($1_BIN) $$($1_HEADERS_ARG)
+ $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BIN)/_the.$1.vardeps)
+
# When not using sjavac, pass along all sources to javac using an @file.
- $$($1_BIN)/_the.$1_batch: $$($1_SRCS) $$($1_DEPENDS)
+ $$($1_BIN)/_the.$1_batch: $$($1_SRCS) $$($1_DEPENDS) $$($1_VARDEPS_FILE)
$(MKDIR) -p $$(@D)
$(RM) $$($1_BIN)/_the.$1_batch $$($1_BIN)/_the.$1_batch.tmp
$$(call ListPathsSafely,$1_SRCS,\n, >> $$($1_BIN)/_the.$1_batch.tmp)
@@ -659,4 +688,5 @@
$(if $(findstring yes, $(ENABLE_SJAVAC)), $(strip $2)/_the.$(strip $1)_pubapi, \
$(strip $2)/_the.$(strip $1)_batch)
endef
-endif
+
+endif # _JAVA_COMPILATION_GMK
diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk
index b45fd52..58ddb2c 100644
--- a/make/common/MakeBase.gmk
+++ b/make/common/MakeBase.gmk
@@ -349,7 +349,7 @@
# (and causing a crash on Cygwin).
# Default shell seems to always be /bin/sh. Must override with bash to get this to work on Solaris.
# Only use time if it's GNU time which supports format and output file.
- WRAPPER_SHELL:=$$(BASH) $$(SRC_ROOT)/common/bin/shell-tracer.sh $$(if $$(findstring yes,$$(IS_GNU_TIME)),$$(TIME),-) $$(OUTPUT_ROOT)/build-trace-time.log $$(BASH)
+ WRAPPER_SHELL:=$$(BASH) $$(SRC_ROOT)/common/bin/shell-tracer.sh $$(if $$(findstring yes,$$(IS_GNU_TIME)),$$(TIME),-) $$(OUTPUT_ROOT)/build-trace-time.log $$(SHELL)
SHELL=$$(warning $$(if $$@,Building $$@,Running shell command) $$(if $$<, (from $$<))$$(if $$?, ($$(wordlist 1, 20, $$?) $$(if $$(wordlist 21, 22, $$?), ... [in total $$(words $$?) files]) newer)))$$(WRAPPER_SHELL)
endif
# Never remove warning messages; this is just for completeness
@@ -392,11 +392,9 @@
endef
# Make directory without forking mkdir if not needed
-define MakeDir
- ifneq ($$(wildcard $1 $2 $3 $4 $5 $6 $7 $8 $9),$$(strip $1 $2 $3 $4 $5 $6 $7 $8 $9))
- $$(shell $(MKDIR) -p $1 $2 $3 $4 $5 $6 $7 $8 $9)
- endif
-endef
+MakeDir = \
+ $(strip $(if $(subst $(wildcard $1 $2 $3 $4 $5 $6 $7 $8 $9),,$(strip $1 $2 $3 $4 $5 $6 $7 $8 $9)),\
+ $(shell $(MKDIR) -p $1 $2 $3 $4 $5 $6 $7 $8 $9)))
ifeq ($(OPENJDK_TARGET_OS),solaris)
# On Solaris, if the target is a symlink and exists, cp won't overwrite.
@@ -446,6 +444,11 @@
# Filter out duplicate sub strings while preserving order. Keeps the first occurance.
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
+# String equals
+equals = \
+ $(and $(findstring $(strip $1),$(strip $2)),\
+ $(findstring $(strip $2),$(strip $1)))
+
ifneq ($(DISABLE_CACHE_FIND), true)
################################################################################
# In Cygwin, finds are very costly, both because of expensive forks and because
@@ -543,6 +546,80 @@
endef
################################################################################
+# ShellQuote
+#
+# Quotes a string with single quotes and replaces single quotes with '\'' so
+# that the contents survives being given to the shell.
+
+ShellQuote = \
+ $(SQUOTE)$(subst $(SQUOTE),$(SQUOTE)\$(SQUOTE)$(SQUOTE),$(strip $1))$(SQUOTE)
+
+################################################################################
+# Write to and read from file
+
+# Param 1 - File to read
+ReadFile = \
+ $(shell $(CAT) $1)
+
+# Param 1 - Text to write
+# Param 2 - File to write to
+# Use printf to get consistent behavior on all platforms.
+WriteFile = \
+ $(shell $(PRINTF) "%s" $(call ShellQuote, $1) > $2)
+
+################################################################################
+# DependOnVariable
+#
+# This macro takes a variable name and puts the value in a file only if the
+# value has changed since last. The name of the file is returned. This can be
+# used to create rule dependencies on make variable values. The following
+# example would get rebuilt if the value of SOME_VAR was changed:
+#
+# path/to/some-file: $(call DependOnVariable, SOME_VAR)
+# echo $(SOME_VAR) > $@
+#
+# Note that leading and trailing white space in the value is ignored.
+#
+
+# Defines the sub directory structure to store variable value file in
+DependOnVariableDirName = \
+ $(strip $(subst $(SRC_ROOT)/,,\
+ $(if $(filter /%, $(firstword $(MAKEFILE_LIST))), \
+ $(firstword $(MAKEFILE_LIST)), \
+ $(CURDIR)/$(firstword $(MAKEFILE_LIST)))))
+
+# Defines the name of the file to store variable value in. Generates a name
+# unless parameter 2 is given.
+# Param 1 - Name of variable
+# Param 2 - (optional) name of file to store value in
+DependOnVariableFileName = \
+ $(strip $(if $(strip $2), $2, \
+ $(MAKESUPPORT_OUTPUTDIR)/vardeps/$(DependOnVariableDirName)/$(strip $1).vardeps))
+
+# Does the actual work with parameters stripped.
+# If the file exists AND the contents is the same as the variable, do nothing
+# else print a new file.
+# Always returns the name of the file where the value was printed.
+# Param 1 - Name of variable
+# Param 2 - (optional) name of file to store value in
+DependOnVariableHelper = \
+ $(strip $(if $(and $(wildcard $(call DependOnVariableFileName, $1, $2)),\
+ $(call equals, $(strip $($1)), \
+ $(call ReadFile, $(call DependOnVariableFileName, $1, $2)))),,\
+ $(call MakeDir, $(dir $(call DependOnVariableFileName, $1, $2))) \
+ $(if $(findstring $(LOG_LEVEL), trace), \
+ $(info Variable $1: >$(strip $($1))<) \
+ $(info File: >$(call ReadFile, $(call DependOnVariableFileName, $1, $2))<)) \
+ $(call WriteFile, $($1), $(call DependOnVariableFileName, $1, $2))) \
+ $(call DependOnVariableFileName, $1, $2))
+
+# Main macro
+# Param 1 - Name of variable
+# Param 2 - (optional) name of file to store value in
+DependOnVariable = \
+ $(call DependOnVariableHelper,$(strip $1),$(strip $2))
+
+################################################################################
# Hook to include the corresponding custom file, if present.
$(eval $(call IncludeCustomExtension, , common/MakeBase.gmk))
diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk
index 9088a61..8ed6ae2 100644
--- a/make/common/NativeCompilation.gmk
+++ b/make/common/NativeCompilation.gmk
@@ -114,7 +114,7 @@
endif
endif
- $$($1_$2_OBJ) : $2 | $$($1_BUILD_INFO)
+ $$($1_$2_OBJ) : $2 $$($1_COMPILE_VARDEPS_FILE) | $$($1_BUILD_INFO)
$(ECHO) $(LOG_INFO) "Compiling $$(notdir $2) (for $$(notdir $$($1_TARGET)))"
ifneq ($(TOOLCHAIN_TYPE), microsoft)
# The Solaris studio compiler doesn't output the full path to the object file in the
@@ -133,7 +133,8 @@
($$($1_$2_COMP) $$($1_$2_FLAGS) -showIncludes $$($1_$2_DEBUG_OUT_FLAGS) \
$(CC_OUT_OPTION)$$($1_$2_OBJ) $2 ; echo $$$$? > $$($1_$2_DEP).exitvalue) \
| $(TEE) $$($1_$2_DEP).raw | $(GREP) -v -e "^Note: including file:" \
- -e "^$(notdir $2)$$$$" ; exit `cat $$($1_$2_DEP).exitvalue`
+ -e "^$(notdir $2)$$$$" || test "$$$$?" = "1" ; \
+ exit `cat $$($1_$2_DEP).exitvalue`
$(RM) $$($1_$2_DEP).exitvalue
($(ECHO) $$@: \\ \
&& $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_$2_DEP).raw) > $$($1_$2_DEP)
@@ -306,7 +307,7 @@
endif
# Make sure the dirs exist.
- $$(eval $$(call MakeDir,$$($1_OBJECT_DIR) $$($1_OUTPUT_DIR)))
+ $$(call MakeDir,$$($1_OBJECT_DIR) $$($1_OUTPUT_DIR))
$$(foreach d,$$($1_SRC), $$(if $$(wildcard $$d),,$$(error SRC specified to SetupNativeCompilation $1 contains missing directory $$d)))
# Find all files in the source trees. Sort to remove duplicates.
@@ -426,15 +427,16 @@
$1_BUILD_INFO := $$($1_OBJECT_DIR)/_build-info.marker
- # Setup rule for printing progress info when compiling source files.
- # This is a rough heuristic and may not always print accurate information.
- $$($1_BUILD_INFO): $$($1_SRCS)
- ifeq ($$(wildcard $$($1_TARGET)),)
- $(ECHO) 'Creating $$($1_BASENAME) from $$(words $$?) file(s)'
- else
- $(ECHO) 'Updating $$($1_BASENAME) from $$(words $$?) file(s)'
- endif
- $(TOUCH) $$@
+ # Track variable changes for all variables that affect the compilation command
+ # lines for all object files in this setup. This includes at least all the
+ # variables used in the call to add_native_source below.
+ $1_COMPILE_VARDEPS := $$($1_CFLAGS) $$($1_EXTRA_CFLAGS) $(SYSROOT_CFLAGS) \
+ $$($1_CXXFLAGS) $$($1_EXTRA_CXXFLAGS) \
+ $$($1_CC) $$($1_CXX) $$($1_OBJC) $$($1_ASFLAGS) \
+ $$(foreach s, $$($1_SRCS), \
+ $$($1_$$(notdir $$s)_CFLAGS) $$($1_$$(notdir $$s)_CXXFLAGS))
+ $1_COMPILE_VARDEPS_FILE := $$(call DependOnVariable, $1_COMPILE_VARDEPS, \
+ $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).comp.vardeps)
# Now call add_native_source for each source file we are going to compile.
$$(foreach p,$$($1_SRCS), \
@@ -444,13 +446,28 @@
$$($1_CXXFLAGS) $$($1_EXTRA_CXXFLAGS) $(SYSROOT_CFLAGS), \
$$($1_CXX),$$($1_OBJC),$$($1_ASFLAGS))))
+ # Setup rule for printing progress info when compiling source files.
+ # This is a rough heuristic and may not always print accurate information.
+ $$($1_BUILD_INFO): $$($1_SRCS) $$($1_COMPILE_VARDEPS_FILE)
+ ifeq ($$(wildcard $$($1_TARGET)),)
+ $(ECHO) 'Creating $$($1_BASENAME) from $$(words $$(filter-out %.vardeps, $$?)) file(s)'
+ else
+ $(ECHO) 'Updating $$($1_BASENAME) from $$(words $$(filter-out %.vardeps, $$?)) file(s)'
+ endif
+ $(TOUCH) $$@
+
# On windows we need to create a resource file
ifeq ($(OPENJDK_TARGET_OS), windows)
ifneq (,$$($1_VERSIONINFO_RESOURCE))
$1_RES:=$$($1_OBJECT_DIR)/$$($1_BASENAME).res
$1_RES_DEP:=$$($1_RES).d
-include $$($1_RES_DEP)
- $$($1_RES): $$($1_VERSIONINFO_RESOURCE)
+
+ $1_RES_VARDEPS := $(RC) $$($1_RC_FLAGS)
+ $1_RES_VARDEPS_FILE := $$(call DependOnVariable, $1_RES_VARDEPS, \
+ $$($1_RES).vardeps)
+
+ $$($1_RES): $$($1_VERSIONINFO_RESOURCE) $$($1_RES_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Compiling resource $$(notdir $$($1_VERSIONINFO_RESOURCE)) (for $$(notdir $$($1_TARGET)))"
$(RC) $$($1_RC_FLAGS) $(CC_OUT_OPTION)$$@ $$($1_VERSIONINFO_RESOURCE)
# Windows RC compiler does not support -showIncludes, so we mis-use CL for this.
@@ -462,7 +479,9 @@
ifneq (,$$($1_MANIFEST))
$1_GEN_MANIFEST:=$$($1_OBJECT_DIR)/$$($1_PROGRAM).manifest
IMVERSIONVALUE:=$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION).$(JDK_UPDATE_VERSION).$(COOKED_BUILD_NUMBER)
- $$($1_GEN_MANIFEST): $$($1_MANIFEST)
+ $1_MANIFEST_VARDEPS_FILE := $$(call DependOnVariable, IMVERSIONVALUE, \
+ $$($1_GEN_MANIFEST).vardeps)
+ $$($1_GEN_MANIFEST): $$($1_MANIFEST) $$($1_MANIFEST_VARDEPS_FILE)
$(SED) 's%IMVERSION%$$(IMVERSIONVALUE)%g;s%PROGRAM%$$($1_PROGRAM)%g' $$< > $$@
endif
endif
@@ -575,8 +594,13 @@
$1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX)
+ $1_VARDEPS := $$($1_LD) $(SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \
+ $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX)
+ $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \
+ $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).vardeps)
+
$$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_REAL_MAPFILE) \
- $$($1_DEBUGINFO_EXTRA_DEPS)
+ $$($1_DEBUGINFO_EXTRA_DEPS) $$($1_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Linking $$($1_BASENAME)"
$$($1_LD) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $(SYSROOT_LDFLAGS) \
$(LD_OUT_OPTION)$$@ \
@@ -592,8 +616,12 @@
endif
ifneq (,$$($1_STATIC_LIBRARY))
+ $1_VARDEPS := $(AR) $$($1_ARFLAGS) $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX)
+ $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \
+ $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).vardeps)
+
# Generating a static library, ie object file archive.
- $$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES)
+ $$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Archiving $$($1_STATIC_LIBRARY)"
$(AR) $$($1_ARFLAGS) $(AR_OUT_OPTION)$$($1_TARGET) $$($1_EXPECTED_OBJS) \
$$($1_RES) $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX)
@@ -603,8 +631,13 @@
# A executable binary has been specified, setup the target for it.
$1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX)
+ $1_VARDEPS := $$($1_LDEXE) $(SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \
+ $$($1_LDFLAGS_SUFFIX) $$($1_EXTRA_LDFLAGS_SUFFIX)
+ $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \
+ $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).vardeps)
+
$$($1_TARGET): $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_GEN_MANIFEST) \
- $$($1_DEBUGINFO_EXTRA_DEPS)
+ $$($1_DEBUGINFO_EXTRA_DEPS) $$($1_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Linking executable $$($1_BASENAME)"
$$($1_LDEXE) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $(SYSROOT_LDFLAGS) \
$(EXE_OUT_OPTION)$$($1_TARGET) \
diff --git a/make/common/TextFileProcessing.gmk b/make/common/TextFileProcessing.gmk
index 466d49a..cc89c37 100644
--- a/make/common/TextFileProcessing.gmk
+++ b/make/common/TextFileProcessing.gmk
@@ -34,7 +34,7 @@
# param 3 = the target base directory
# param 4 = the target file name (possibly with a partial path)
define SetupSingleTextFileForProcessing
- $(strip $3)/$(strip $4): $2
+ $(strip $3)/$(strip $4): $2 $$($1_VARDEPS_FILE)
$(ECHO) $(LOG_INFO) "Processing $(strip $4)"
$(MKDIR) -p '$$(@D)'
$(RM) '$$@' '$$@.includes.tmp' '$$@.replacements.tmp'
@@ -193,6 +193,9 @@
$1_INCLUDES_COMMAND_LINE := $(CAT)
endif
+ $1_VARDEPS := $$($1_INCLUDES_COMMAND_LINE) $$($1_REPLACEMENTS_COMMAND_LINE)
+ $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS)
+
# Reset target list before populating it
$1 :=
diff --git a/nashorn/.hgtags b/nashorn/.hgtags
index f754a23..76c29cd 100644
--- a/nashorn/.hgtags
+++ b/nashorn/.hgtags
@@ -281,3 +281,4 @@
3c2bbeda038aef7061455fec604db7d8a342fac5 jdk9-b45
2ecf0a617f0f9af1ffd278a0c70e76f1946ce773 jdk9-b46
29046d42a95e5b9f105ab086a628bbd7f81c915d jdk9-b47
+f08660f30051ba0b38ad00e692979b37d107c9c4 jdk9-b48
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
index f860886..1b85e94 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
@@ -926,9 +926,7 @@
@Override
public Node leaveTryNode(final TryNode tryNode) {
tryNode.setException(exceptionSymbol());
- if (tryNode.getFinallyBody() != null) {
- tryNode.setFinallyCatchAll(exceptionSymbol());
- }
+ assert tryNode.getFinallyBody() == null;
end(tryNode);
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
index b4ccca1..d285541 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -85,7 +85,6 @@
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
-import jdk.nashorn.internal.ir.BreakableNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
@@ -102,6 +101,7 @@
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.JoinPredecessorExpression;
import jdk.nashorn.internal.ir.JumpStatement;
+import jdk.nashorn.internal.ir.JumpToInlinedFinally;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
@@ -1110,7 +1110,14 @@
@Override
public boolean enterBlock(final Block block) {
- method.label(block.getEntryLabel());
+ final Label entryLabel = block.getEntryLabel();
+ if (entryLabel.isBreakTarget()) {
+ // Entry label is a break target only for an inlined finally block.
+ assert !method.isReachable();
+ method.breakLabel(entryLabel, lc.getUsedSlotCount());
+ } else {
+ method.label(entryLabel);
+ }
if(!method.isReachable()) {
return false;
}
@@ -1240,6 +1247,11 @@
return enterJumpStatement(breakNode);
}
+ @Override
+ public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
+ return enterJumpStatement(jumpToInlinedFinally);
+ }
+
private boolean enterJumpStatement(final JumpStatement jump) {
if(!method.isReachable()) {
return false;
@@ -1247,9 +1259,8 @@
enterStatement(jump);
method.beforeJoinPoint(jump);
- final BreakableNode target = jump.getTarget(lc);
- popScopesUntil(target);
- final Label targetLabel = jump.getTargetLabel(target);
+ popScopesUntil(jump.getPopScopeLimit(lc));
+ final Label targetLabel = jump.getTargetLabel(lc);
targetLabel.markAsBreakTarget();
method._goto(targetLabel);
@@ -3053,6 +3064,14 @@
if (method.isReachable()) {
method._goto(skip);
}
+
+ for (final Block inlinedFinally : tryNode.getInlinedFinallies()) {
+ TryNode.getLabelledInlinedFinallyBlock(inlinedFinally).accept(this);
+ // All inlined finallies end with a jump or a return
+ assert !method.isReachable();
+ }
+
+
method._catch(recovery);
method.store(vmException, EXCEPTION_TYPE);
@@ -3112,15 +3131,14 @@
catchBody.accept(this);
leaveBlock(catchBlock);
lc.pop(catchBlock);
- if(method.isReachable()) {
- method._goto(afterCatch);
- }
if(nextCatch != null) {
+ if(method.isReachable()) {
+ method._goto(afterCatch);
+ }
method.breakLabel(nextCatch, lc.getUsedSlotCount());
}
}
- assert !method.isReachable();
// afterCatch could be the same as skip, except that we need to establish that the vmException is dead.
method.label(afterCatch);
if(method.isReachable()) {
@@ -3129,6 +3147,8 @@
method.label(skip);
// Finally body is always inlined elsewhere so it doesn't need to be emitted
+ assert tryNode.getFinallyBody() == null;
+
return false;
}
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java
index 87a0802..ccd9065 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java
@@ -74,7 +74,7 @@
/** size of next free slot vector */
private int nextFreeSlotsSize;
- private boolean isWithBoundary(final LexicalContextNode node) {
+ private boolean isWithBoundary(final Object node) {
return node instanceof Block && !isEmpty() && peek() instanceof WithNode;
}
@@ -102,7 +102,7 @@
}
@Override
- public <T extends LexicalContextNode> T pop(final T node) {
+ public <T extends Node> T pop(final T node) {
final T popped = super.pop(node);
if (isWithBoundary(node)) {
dynamicScopeCount--;
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
index 28cc551..79e151b 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
@@ -62,6 +62,7 @@
import jdk.nashorn.internal.ir.JoinPredecessor;
import jdk.nashorn.internal.ir.JoinPredecessorExpression;
import jdk.nashorn.internal.ir.JumpStatement;
+import jdk.nashorn.internal.ir.JumpToInlinedFinally;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
@@ -529,8 +530,7 @@
return false;
}
assertTypeStackIsEmpty();
- final BreakableNode target = jump.getTarget(lc);
- jumpToLabel(jump, jump.getTargetLabel(target), getBreakTargetTypes(target));
+ jumpToLabel(jump, jump.getTargetLabel(lc), getBreakTargetTypes(jump.getPopScopeLimit(lc)));
doesNotContinueSequentially();
return false;
}
@@ -784,6 +784,11 @@
}
@Override
+ public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
+ return enterJumpStatement(jumpToInlinedFinally);
+ }
+
+ @Override
public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
if (literalNode instanceof ArrayLiteralNode) {
final List<Expression> expressions = ((ArrayLiteralNode)literalNode).getElementExpressions();
@@ -1042,6 +1047,17 @@
}
doesNotContinueSequentially();
+ for (final Block inlinedFinally : tryNode.getInlinedFinallies()) {
+ final Block finallyBody = TryNode.getLabelledInlinedFinallyBlock(inlinedFinally);
+ joinOnLabel(finallyBody.getEntryLabel());
+ // NOTE: the jump to inlined finally can end up in dead code, so it is not necessarily reachable.
+ if (reachable) {
+ finallyBody.accept(this);
+ // All inlined finallies end with a jump or a return
+ assert !reachable;
+ }
+ }
+
joinOnLabel(catchLabel);
for(final CatchNode catchNode: tryNode.getCatches()) {
final IdentNode exception = catchNode.getException();
@@ -1125,7 +1141,7 @@
return false;
};
- private Map<Symbol, LvarType> getBreakTargetTypes(final BreakableNode target) {
+ private Map<Symbol, LvarType> getBreakTargetTypes(final LexicalContextNode target) {
// Remove symbols defined in the the blocks that are being broken out of.
Map<Symbol, LvarType> types = localVariableTypes;
for(final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
@@ -1380,7 +1396,11 @@
if(node instanceof JoinPredecessor) {
final JoinPredecessor original = joinPredecessors.pop();
assert original.getClass() == node.getClass() : original.getClass().getName() + "!=" + node.getClass().getName();
- return (Node)setLocalVariableConversion(original, (JoinPredecessor)node);
+ final JoinPredecessor newNode = setLocalVariableConversion(original, (JoinPredecessor)node);
+ if (newNode instanceof LexicalContextNode) {
+ lc.replace((LexicalContextNode)node, (LexicalContextNode)newNode);
+ }
+ return (Node)newNode;
}
return node;
}
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
index a30e79a..8bb947c 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
@@ -56,9 +56,11 @@
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.JumpStatement;
+import jdk.nashorn.internal.ir.JumpToInlinedFinally;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ReturnNode;
@@ -115,7 +117,7 @@
for (final Statement statement : statements) {
if (!terminated) {
newStatements.add(statement);
- if (statement.isTerminal() || statement instanceof BreakNode || statement instanceof ContinueNode) { //TODO hasGoto? But some Loops are hasGoto too - why?
+ if (statement.isTerminal() || statement instanceof JumpStatement) { //TODO hasGoto? But some Loops are hasGoto too - why?
terminated = true;
}
} else {
@@ -183,6 +185,12 @@
}
@Override
+ public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
+ addStatement(jumpToInlinedFinally);
+ return false;
+ }
+
+ @Override
public boolean enterEmptyNode(final EmptyNode emptyNode) {
return false;
}
@@ -318,8 +326,8 @@
return addStatement(throwNode); //ThrowNodes are always terminal, marked as such in constructor
}
- private static Node ensureUniqueNamesIn(final Node node) {
- return node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ private static <T extends Node> T ensureUniqueNamesIn(final T node) {
+ return (T)node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
final String name = functionNode.getName();
@@ -333,15 +341,15 @@
});
}
- private static List<Statement> copyFinally(final Block finallyBody) {
+ private static Block createFinallyBlock(final Block finallyBody) {
final List<Statement> newStatements = new ArrayList<>();
for (final Statement statement : finallyBody.getStatements()) {
- newStatements.add((Statement)ensureUniqueNamesIn(statement));
+ newStatements.add(statement);
if (statement.hasTerminalFlags()) {
- return newStatements;
+ break;
}
}
- return newStatements;
+ return finallyBody.setStatements(null, newStatements);
}
private Block catchAllBlock(final TryNode tryNode) {
@@ -367,28 +375,24 @@
return new IdentNode(functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
}
- private static boolean isTerminal(final List<Statement> statements) {
- return !statements.isEmpty() && statements.get(statements.size() - 1).hasTerminalFlags();
+ private static boolean isTerminalFinally(final Block finallyBlock) {
+ return finallyBlock.getLastStatement().hasTerminalFlags();
}
/**
* Splice finally code into all endpoints of a trynode
* @param tryNode the try node
- * @param rethrows list of rethrowing throw nodes from synthetic catch blocks
+ * @param rethrow the rethrowing throw nodes from the synthetic catch block
* @param finallyBody the code in the original finally block
* @return new try node after splicing finally code (same if nop)
*/
- private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) {
+ private TryNode spliceFinally(final TryNode tryNode, final ThrowNode rethrow, final Block finallyBody) {
assert tryNode.getFinallyBody() == null;
+ final Block finallyBlock = createFinallyBlock(finallyBody);
+ final ArrayList<Block> inlinedFinallies = new ArrayList<>();
+ final FunctionNode fn = lc.getCurrentFunction();
final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- final List<Node> insideTry = new ArrayList<>();
-
- @Override
- public boolean enterDefault(final Node node) {
- insideTry.add(node);
- return true;
- }
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
@@ -398,12 +402,8 @@
@Override
public Node leaveThrowNode(final ThrowNode throwNode) {
- if (rethrows.contains(throwNode)) {
- final List<Statement> newStatements = copyFinally(finallyBody);
- if (!isTerminal(newStatements)) {
- newStatements.add(throwNode);
- }
- return BlockStatement.createReplacement(throwNode, newStatements);
+ if (rethrow == throwNode) {
+ return new BlockStatement(prependFinally(finallyBlock, throwNode));
}
return throwNode;
}
@@ -419,58 +419,94 @@
}
private Node leaveJumpStatement(final JumpStatement jump) {
- return copy(jump, (Node)jump.getTarget(Lower.this.lc));
+ // NOTE: leaveJumpToInlinedFinally deliberately does not delegate to this method, only break and
+ // continue are edited. JTIF nodes should not be changed, rather the surroundings of
+ // break/continue/return that were moved into the inlined finally block itself will be changed.
+
+ // If this visitor's lc doesn't find the target of the jump, it means it's external to the try block.
+ if (jump.getTarget(lc) == null) {
+ return createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, jump));
+ }
+ return jump;
}
@Override
public Node leaveReturnNode(final ReturnNode returnNode) {
- final Expression expr = returnNode.getExpression();
- final List<Statement> newStatements = new ArrayList<>();
-
- final Expression resultNode;
- if (expr != null) {
- //we need to evaluate the result of the return in case it is complex while
- //still in the try block, store it in a result value and return it afterwards
- resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
- newStatements.add(new ExpressionStatement(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
- } else {
- resultNode = null;
- }
-
- newStatements.addAll(copyFinally(finallyBody));
- if (!isTerminal(newStatements)) {
- newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
- }
-
- return BlockStatement.createReplacement(returnNode, lc.getCurrentBlock().getFinish(), newStatements);
- }
-
- private Node copy(final Statement endpoint, final Node targetNode) {
- if (!insideTry.contains(targetNode)) {
- final List<Statement> newStatements = copyFinally(finallyBody);
- if (!isTerminal(newStatements)) {
- newStatements.add(endpoint);
+ final Expression expr = returnNode.getExpression();
+ if (isTerminalFinally(finallyBlock)) {
+ if (expr == null) {
+ // Terminal finally; no return expression.
+ return createJumpToInlinedFinally(fn, inlinedFinallies, ensureUniqueNamesIn(finallyBlock));
}
- return BlockStatement.createReplacement(endpoint, tryNode.getFinish(), newStatements);
+ // Terminal finally; has a return expression.
+ final List<Statement> newStatements = new ArrayList<>(2);
+ final int retLineNumber = returnNode.getLineNumber();
+ final long retToken = returnNode.getToken();
+ // Expression is evaluated for side effects.
+ newStatements.add(new ExpressionStatement(retLineNumber, retToken, returnNode.getFinish(), expr));
+ newStatements.add(createJumpToInlinedFinally(fn, inlinedFinallies, ensureUniqueNamesIn(finallyBlock)));
+ return new BlockStatement(retLineNumber, new Block(retToken, finallyBlock.getFinish(), newStatements));
+ } else if (expr == null || expr instanceof PrimitiveLiteralNode<?> || (expr instanceof IdentNode && RETURN.symbolName().equals(((IdentNode)expr).getName()))) {
+ // Nonterminal finally; no return expression, or returns a primitive literal, or returns :return.
+ // Just move the return expression into the finally block.
+ return createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, returnNode));
+ } else {
+ // We need to evaluate the result of the return in case it is complex while still in the try block,
+ // store it in :return, and return it afterwards.
+ final List<Statement> newStatements = new ArrayList<>();
+ final int retLineNumber = returnNode.getLineNumber();
+ final long retToken = returnNode.getToken();
+ final int retFinish = returnNode.getFinish();
+ final Expression resultNode = new IdentNode(expr.getToken(), expr.getFinish(), RETURN.symbolName());
+ // ":return = <expr>;"
+ newStatements.add(new ExpressionStatement(retLineNumber, retToken, retFinish, new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
+ // inline finally and end it with "return :return;"
+ newStatements.add(createJumpToInlinedFinally(fn, inlinedFinallies, prependFinally(finallyBlock, returnNode.setExpression(resultNode))));
+ return new BlockStatement(retLineNumber, new Block(retToken, retFinish, newStatements));
}
- return endpoint;
}
});
-
- addStatement(newTryNode);
- for (final Node statement : finallyBody.getStatements()) {
- addStatement((Statement)statement);
- }
+ addStatement(inlinedFinallies.isEmpty() ? newTryNode : newTryNode.setInlinedFinallies(lc, inlinedFinallies));
+ // TODO: if finallyStatement is terminal, we could just have sites of inlined finallies jump here.
+ addStatement(new BlockStatement(finallyBlock));
return newTryNode;
}
+ private static JumpToInlinedFinally createJumpToInlinedFinally(final FunctionNode fn, final List<Block> inlinedFinallies, final Block finallyBlock) {
+ final String labelName = fn.uniqueName(":finally");
+ final long token = finallyBlock.getToken();
+ final int finish = finallyBlock.getFinish();
+ inlinedFinallies.add(new Block(token, finish, new LabelNode(finallyBlock.getFirstStatementLineNumber(),
+ token, finish, labelName, finallyBlock)));
+ return new JumpToInlinedFinally(labelName);
+ }
+
+ private static Block prependFinally(final Block finallyBlock, final Statement statement) {
+ final Block inlinedFinally = ensureUniqueNamesIn(finallyBlock);
+ if (isTerminalFinally(finallyBlock)) {
+ return inlinedFinally;
+ }
+ final List<Statement> stmts = inlinedFinally.getStatements();
+ final List<Statement> newStmts = new ArrayList<>(stmts.size() + 1);
+ newStmts.addAll(stmts);
+ newStmts.add(statement);
+ return new Block(inlinedFinally.getToken(), statement.getFinish(), newStmts);
+ }
+
@Override
public Node leaveTryNode(final TryNode tryNode) {
final Block finallyBody = tryNode.getFinallyBody();
+ TryNode newTryNode = tryNode.setFinallyBody(lc, null);
- if (finallyBody == null) {
- return addStatement(ensureUnconditionalCatch(tryNode));
+ // No finally or empty finally
+ if (finallyBody == null || finallyBody.getStatementCount() == 0) {
+ final List<CatchNode> catches = newTryNode.getCatches();
+ if (catches == null || catches.isEmpty()) {
+ // A completely degenerate try block: empty finally, no catches. Replace it with try body.
+ return addStatement(new BlockStatement(tryNode.getBody()));
+ }
+ return addStatement(ensureUnconditionalCatch(newTryNode));
}
/*
@@ -496,11 +532,9 @@
* now splice in finally code wherever needed
*
*/
- TryNode newTryNode;
-
final Block catchAll = catchAllBlock(tryNode);
- final List<ThrowNode> rethrows = new ArrayList<>();
+ final List<ThrowNode> rethrows = new ArrayList<>(1);
catchAll.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterThrowNode(final ThrowNode throwNode) {
@@ -510,20 +544,18 @@
});
assert rethrows.size() == 1;
- if (tryNode.getCatchBlocks().isEmpty()) {
- newTryNode = tryNode.setFinallyBody(null);
- } else {
- final Block outerBody = new Block(tryNode.getToken(), tryNode.getFinish(), ensureUnconditionalCatch(tryNode.setFinallyBody(null)));
- newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
+ if (!tryNode.getCatchBlocks().isEmpty()) {
+ final Block outerBody = new Block(newTryNode.getToken(), newTryNode.getFinish(), ensureUnconditionalCatch(newTryNode));
+ newTryNode = newTryNode.setBody(lc, outerBody).setCatchBlocks(lc, null);
}
- newTryNode = newTryNode.setCatchBlocks(Arrays.asList(catchAll)).setFinallyBody(null);
+ newTryNode = newTryNode.setCatchBlocks(lc, Arrays.asList(catchAll));
/*
* Now that the transform is done, we have to go into the try and splice
* the finally block in front of any statement that is outside the try
*/
- return spliceFinally(newTryNode, rethrows, finallyBody);
+ return (TryNode)lc.replace(tryNode, spliceFinally(newTryNode, rethrows.get(0), finallyBody));
}
private TryNode ensureUnconditionalCatch(final TryNode tryNode) {
@@ -535,7 +567,7 @@
final List<Block> newCatchBlocks = new ArrayList<>(tryNode.getCatchBlocks());
newCatchBlocks.add(catchAllBlock(tryNode));
- return tryNode.setCatchBlocks(newCatchBlocks);
+ return tryNode.setCatchBlocks(lc, newCatchBlocks);
}
@Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java
index 9b980b5..6fc6e3a 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java
@@ -52,6 +52,7 @@
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.JumpStatement;
+import jdk.nashorn.internal.ir.JumpToInlinedFinally;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ReturnNode;
@@ -359,6 +360,11 @@
return leaveJumpNode(continueNode);
}
+ @Override
+ public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
+ return leaveJumpNode(jumpToInlinedFinally);
+ }
+
private JumpStatement leaveJumpNode(final JumpStatement jump) {
if (inSplitNode()) {
final SplitState splitState = getCurrentSplitState();
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java
index 26660a3..b1181c8 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java
@@ -40,6 +40,7 @@
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
+import jdk.nashorn.internal.ir.JumpToInlinedFinally;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
@@ -197,6 +198,12 @@
return indexNode;
}
+ @Override
+ public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
+ weight += BREAK_WEIGHT;
+ return jumpToInlinedFinally;
+ }
+
@SuppressWarnings("rawtypes")
@Override
public boolean enterLiteralNode(final LiteralNode literalNode) {
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java
index 7666041..c68dba2 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java
@@ -322,6 +322,14 @@
}
/**
+ * Returns the last statement in the block.
+ * @return the last statement in the block, or null if the block has no statements.
+ */
+ public Statement getLastStatement() {
+ return statements.isEmpty() ? null : statements.get(statements.size() - 1);
+ }
+
+ /**
* Reset the statement list for this block
*
* @param lc lexical context
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java
index 7e16b5e..0deb25f 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockLexicalContext.java
@@ -74,7 +74,7 @@
@SuppressWarnings("unchecked")
@Override
- public <T extends LexicalContextNode> T pop(final T node) {
+ public <T extends Node> T pop(final T node) {
T expected = node;
if (node instanceof Block) {
final List<Statement> newStatements = popStatements();
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java
index 6f6a1d2..3a7c810 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BlockStatement.java
@@ -40,6 +40,15 @@
/**
* Constructor
*
+ * @param block the block to execute
+ */
+ public BlockStatement(final Block block) {
+ this(block.getFirstStatementLineNumber(), block);
+ }
+
+ /**
+ * Constructor
+ *
* @param lineNumber line number
* @param block the block to execute
*/
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java
index 4cbf4c0..3e80bcc 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BreakNode.java
@@ -77,7 +77,7 @@
}
@Override
- public Label getTargetLabel(final BreakableNode target) {
+ Label getTargetLabel(final BreakableNode target) {
return target.getBreakLabel();
}
}
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java
index c58531b..eb67f41 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ContinueNode.java
@@ -78,7 +78,7 @@
}
@Override
- public Label getTargetLabel(final BreakableNode target) {
+ Label getTargetLabel(final BreakableNode target) {
return ((LoopNode)target).getContinueLabel();
}
}
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java
index 0770717..628bc77 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpStatement.java
@@ -101,7 +101,26 @@
* @throws ClassCastException if invoked on the kind of breakable node that this jump statement is not prepared to
* handle.
*/
- public abstract Label getTargetLabel(final BreakableNode target);
+ abstract Label getTargetLabel(final BreakableNode target);
+
+ /**
+ * Returns the label this jump statement targets.
+ * @param lc the lexical context
+ * @return the label this jump statement targets.
+ */
+ public Label getTargetLabel(final LexicalContext lc) {
+ return getTargetLabel(getTarget(lc));
+ }
+
+ /**
+ * Returns the limit node for popping scopes when this jump statement is effected.
+ * @param lc the current lexical context
+ * @return the limit node for popping scopes when this jump statement is effected.
+ */
+ public LexicalContextNode getPopScopeLimit(final LexicalContext lc) {
+ // In most cases (break and continue) this is equal to the target.
+ return getTarget(lc);
+ }
@Override
public JumpStatement setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) {
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpToInlinedFinally.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpToInlinedFinally.java
new file mode 100644
index 0000000..bba0d99
--- /dev/null
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JumpToInlinedFinally.java
@@ -0,0 +1,90 @@
+/*
+ * 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 jdk.nashorn.internal.ir;
+
+import java.util.Objects;
+import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.ir.annotations.Immutable;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * IR representation for synthetic jump into an inlined finally statement.
+ */
+@Immutable
+public final class JumpToInlinedFinally extends JumpStatement {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor
+ *
+ * @param labelName label name for inlined finally block
+ */
+ public JumpToInlinedFinally(final String labelName) {
+ super(NO_LINE_NUMBER, NO_TOKEN, NO_FINISH, Objects.requireNonNull(labelName));
+ }
+
+ private JumpToInlinedFinally(final JumpToInlinedFinally breakNode, final LocalVariableConversion conversion) {
+ super(breakNode, conversion);
+ }
+
+ @Override
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+ if (visitor.enterJumpToInlinedFinally(this)) {
+ return visitor.leaveJumpToInlinedFinally(this);
+ }
+
+ return this;
+ }
+
+ @Override
+ JumpStatement createNewJumpStatement(final LocalVariableConversion conversion) {
+ return new JumpToInlinedFinally(this, conversion);
+ }
+
+ @Override
+ String getStatementName() {
+ return ":jumpToInlinedFinally";
+ }
+
+ @Override
+ public Block getTarget(final LexicalContext lc) {
+ return lc.getInlinedFinally(getLabelName());
+ }
+
+ @Override
+ public TryNode getPopScopeLimit(final LexicalContext lc) {
+ // Returns the try node to which this jump's target belongs. This will make scope popping also pop the scope
+ // for the body of the try block, if it needs scope.
+ return lc.getTryNodeForInlinedFinally(getLabelName());
+ }
+
+ @Override
+ Label getTargetLabel(final BreakableNode target) {
+ assert target != null;
+ // We're jumping to the entry of the inlined finally block
+ return ((Block)target).getEntryLabel();
+ }
+}
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java
index 487d6ae..8fbb2bc 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java
@@ -190,7 +190,7 @@
* @return the node that was popped
*/
@SuppressWarnings("unchecked")
- public <T extends LexicalContextNode> T pop(final T node) {
+ public <T extends Node> T pop(final T node) {
--sp;
final LexicalContextNode popped = stack[sp];
stack[sp] = null;
@@ -469,7 +469,7 @@
* scopes that need to be explicitly popped in order to perform a break or continue jump within the current bytecode
* method. For this reason, the method returns 0 if it encounters a {@code SplitNode} between the current location
* and the break/continue target.
- * @param until node to stop counting at. Must be within the current function
+ * @param until node to stop counting at. Must be within the current function
* @return number of with scopes encountered in the context
*/
public int getScopeNestingLevelTo(final LexicalContextNode until) {
@@ -565,11 +565,41 @@
}
/**
+ * Find the inlined finally block node corresponding to this label.
+ * @param labelName label name to search for. Must not be null.
+ * @return closest inlined finally block with the given label
+ */
+ public Block getInlinedFinally(final String labelName) {
+ for (final NodeIterator<TryNode> iter = new NodeIterator<>(TryNode.class); iter.hasNext(); ) {
+ final Block inlinedFinally = iter.next().getInlinedFinally(labelName);
+ if (inlinedFinally != null) {
+ return inlinedFinally;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Find the try node for an inlined finally block corresponding to this label.
+ * @param labelName label name to search for. Must not be null.
+ * @return the try node to which the labelled inlined finally block belongs.
+ */
+ public TryNode getTryNodeForInlinedFinally(final String labelName) {
+ for (final NodeIterator<TryNode> iter = new NodeIterator<>(TryNode.class); iter.hasNext(); ) {
+ final TryNode tryNode = iter.next();
+ if (tryNode.getInlinedFinally(labelName) != null) {
+ return tryNode;
+ }
+ }
+ return null;
+ }
+
+ /**
* Check the lexical context for a given label node by name
* @param name name of the label
* @return LabelNode if found, null otherwise
*/
- public LabelNode findLabel(final String name) {
+ private LabelNode findLabel(final String name) {
for (final Iterator<LabelNode> iter = new NodeIterator<>(LabelNode.class, getCurrentFunction()); iter.hasNext(); ) {
final LabelNode next = iter.next();
if (next.getLabelName().equals(name)) {
@@ -592,6 +622,12 @@
return true;
} else if (next == target) {
return false;
+ } else if (next instanceof TryNode) {
+ for(final Block inlinedFinally: ((TryNode)next).getInlinedFinallies()) {
+ if (TryNode.getLabelledInlinedFinallyBlock(inlinedFinally) == target) {
+ return false;
+ }
+ }
}
}
throw new AssertionError(target + " was expected in lexical context " + LexicalContext.this + " but wasn't");
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextNode.java
index b53d9f6..5054b01 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextNode.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContextNode.java
@@ -54,8 +54,8 @@
static Node accept(final LexicalContextNode node, final NodeVisitor<? extends LexicalContext> visitor) {
final LexicalContext lc = visitor.getLexicalContext();
lc.push(node);
- final LexicalContextNode newNode = (LexicalContextNode)node.accept(lc, visitor);
- return (Node)lc.pop(newNode);
+ final Node newNode = node.accept(lc, visitor);
+ return lc.pop(newNode);
}
}
}
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/OptimisticLexicalContext.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/OptimisticLexicalContext.java
index 9d97a43..18f68fe 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/OptimisticLexicalContext.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/OptimisticLexicalContext.java
@@ -115,7 +115,7 @@
}
@Override
- public <T extends LexicalContextNode> T pop(final T node) {
+ public <T extends Node> T pop(final T node) {
final T popped = super.pop(node);
if (isEnabled) {
if(node instanceof FunctionNode) {
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java
index 605e0a9..9e68ee8 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java
@@ -27,7 +27,9 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -35,7 +37,7 @@
* IR representation of a TRY statement.
*/
@Immutable
-public final class TryNode extends Statement implements JoinPredecessor {
+public final class TryNode extends LexicalContextStatement implements JoinPredecessor {
private static final long serialVersionUID = 1L;
/** Try statements. */
@@ -47,12 +49,24 @@
/** Finally clause. */
private final Block finallyBody;
+ /**
+ * List of inlined finally blocks. The structure of every inlined finally is:
+ * Block(LabelNode(label, Block(finally-statements, (JumpStatement|ReturnNode)?))).
+ * That is, the block has a single LabelNode statement with the label and a block containing the
+ * statements of the inlined finally block with the jump or return statement appended (if the finally
+ * block was not terminal; the original jump/return is simply ignored if the finally block itself
+ * terminates). The reason for this somewhat strange arrangement is that we didn't want to create a
+ * separate class for the (label, BlockStatement pair) but rather reused the already available LabelNode.
+ * However, if we simply used List<LabelNode> without wrapping the label nodes in an additional Block,
+ * that would've thrown off visitors relying on BlockLexicalContext -- same reason why we never use
+ * Statement as the type of bodies of e.g. IfNode, WhileNode etc. but rather blockify them even when they're
+ * single statements.
+ */
+ private final List<Block> inlinedFinallies;
+
/** Exception symbol. */
private Symbol exception;
- /** Catchall exception for finally expansion, where applicable */
- private Symbol finallyCatchAll;
-
private final LocalVariableConversion conversion;
/**
@@ -71,21 +85,23 @@
this.catchBlocks = catchBlocks;
this.finallyBody = finallyBody;
this.conversion = null;
+ this.inlinedFinallies = Collections.emptyList();
}
- private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion) {
+ private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List<Block> inlinedFinallies) {
super(tryNode);
this.body = body;
this.catchBlocks = catchBlocks;
this.finallyBody = finallyBody;
this.conversion = conversion;
+ this.inlinedFinallies = inlinedFinallies;
this.exception = tryNode.exception;
}
@Override
public Node ensureUniqueLabels(final LexicalContext lc) {
//try nodes are never in lex context
- return new TryNode(this, body, catchBlocks, finallyBody, conversion);
+ return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
}
@Override
@@ -106,16 +122,16 @@
* @param visitor IR navigating visitor.
*/
@Override
- public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+ public Node accept(final LexicalContext lc, NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterTryNode(this)) {
// Need to do finallybody first for termination analysis. TODO still necessary?
final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor);
final Block newBody = (Block)body.accept(visitor);
return visitor.leaveTryNode(
- setBody(newBody).
- setFinallyBody(newFinallyBody).
- setCatchBlocks(Node.accept(visitor, catchBlocks)).
- setFinallyCatchAll(finallyCatchAll));
+ setBody(lc, newBody).
+ setFinallyBody(lc, newFinallyBody).
+ setCatchBlocks(lc, Node.accept(visitor, catchBlocks)).
+ setInlinedFinallies(lc, Node.accept(visitor, inlinedFinallies)));
}
return this;
@@ -136,14 +152,15 @@
/**
* Reset the body of this try block
+ * @param lc current lexical context
* @param body new body
* @return new TryNode or same if unchanged
*/
- public TryNode setBody(final Block body) {
+ public TryNode setBody(final LexicalContext lc, final Block body) {
if (this.body == body) {
return this;
}
- return new TryNode(this, body, catchBlocks, finallyBody, conversion);
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
}
/**
@@ -172,14 +189,15 @@
/**
* Set the catch blocks of this try
+ * @param lc current lexical context
* @param catchBlocks list of catch blocks
* @return new TryNode or same if unchanged
*/
- public TryNode setCatchBlocks(final List<Block> catchBlocks) {
+ public TryNode setCatchBlocks(final LexicalContext lc, final List<Block> catchBlocks) {
if (this.catchBlocks == catchBlocks) {
return this;
}
- return new TryNode(this, body, catchBlocks, finallyBody, conversion);
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
}
/**
@@ -200,27 +218,6 @@
}
/**
- * Get the catch all symbol for this try block
- * @return catch all symbol
- */
- public Symbol getFinallyCatchAll() {
- return this.finallyCatchAll;
- }
-
- /**
- * If a finally block exists, the synthetic catchall needs another symbol to
- * store its throwable
- * @param finallyCatchAll a symbol for the finally catch all exception
- * @return new TryNode or same if unchanged
- *
- * TODO can this still be stateful?
- */
- public TryNode setFinallyCatchAll(final Symbol finallyCatchAll) {
- this.finallyCatchAll = finallyCatchAll;
- return this;
- }
-
- /**
* Get the body of the finally clause for this try
* @return finally body, or null if no finally
*/
@@ -229,15 +226,87 @@
}
/**
+ * Get the inlined finally block with the given label name. This returns the actual finally block in the
+ * {@link LabelNode}, not the outer wrapper block for the {@link LabelNode}.
+ * @param labelName the name of the inlined finally's label
+ * @return the requested finally block, or null if no finally block's label matches the name.
+ */
+ public Block getInlinedFinally(final String labelName) {
+ for(final Block inlinedFinally: inlinedFinallies) {
+ final LabelNode labelNode = getInlinedFinallyLabelNode(inlinedFinally);
+ if (labelNode.getLabelName().equals(labelName)) {
+ return labelNode.getBody();
+ }
+ }
+ return null;
+ }
+
+ private static LabelNode getInlinedFinallyLabelNode(final Block inlinedFinally) {
+ return (LabelNode)inlinedFinally.getStatements().get(0);
+ }
+
+ /**
+ * Given an outer wrapper block for the {@link LabelNode} as returned by {@link #getInlinedFinallies()},
+ * returns its actual inlined finally block.
+ * @param inlinedFinally the outer block for inlined finally, as returned as an element of
+ * {@link #getInlinedFinallies()}.
+ * @return the block contained in the {@link LabelNode} contained in the passed block.
+ */
+ public static Block getLabelledInlinedFinallyBlock(final Block inlinedFinally) {
+ return getInlinedFinallyLabelNode(inlinedFinally).getBody();
+ }
+
+ /**
+ * Returns a list of inlined finally blocks. Note that this returns a list of {@link Block}s such that each one of
+ * them has a single {@link LabelNode}, which in turn contains the label name for the finally block and the
+ * actual finally block. To safely extract the actual finally block, use
+ * {@link #getLabelledInlinedFinallyBlock(Block)}.
+ * @return a list of inlined finally blocks.
+ */
+ public List<Block> getInlinedFinallies() {
+ return Collections.unmodifiableList(inlinedFinallies);
+ }
+
+ /**
* Set the finally body of this try
+ * @param lc current lexical context
* @param finallyBody new finally body
* @return new TryNode or same if unchanged
*/
- public TryNode setFinallyBody(final Block finallyBody) {
+ public TryNode setFinallyBody(final LexicalContext lc, final Block finallyBody) {
if (this.finallyBody == finallyBody) {
return this;
}
- return new TryNode(this, body, catchBlocks, finallyBody, conversion);
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ }
+
+ /**
+ * Set the inlined finally blocks of this try. Each element should be a block with a single statement that is a
+ * {@link LabelNode} with a unique label, and the block within the label node should contain the actual inlined
+ * finally block.
+ * @param lc current lexical context
+ * @param inlinedFinallies list of inlined finally blocks
+ * @return new TryNode or same if unchanged
+ */
+ public TryNode setInlinedFinallies(final LexicalContext lc, final List<Block> inlinedFinallies) {
+ if (this.inlinedFinallies == inlinedFinallies) {
+ return this;
+ }
+ assert checkInlinedFinallies(inlinedFinallies);
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ }
+
+ private static boolean checkInlinedFinallies(final List<Block> inlinedFinallies) {
+ if (!inlinedFinallies.isEmpty()) {
+ final Set<String> labels = new HashSet<>();
+ for (final Block inlinedFinally : inlinedFinallies) {
+ final List<Statement> stmts = inlinedFinally.getStatements();
+ assert stmts.size() == 1;
+ final LabelNode ln = getInlinedFinallyLabelNode(inlinedFinally);
+ assert labels.add(ln.getLabelName()); // unique label
+ }
+ }
+ return true;
}
@Override
@@ -245,7 +314,7 @@
if(this.conversion == conversion) {
return this;
}
- return new TryNode(this, body, catchBlocks, finallyBody, conversion);
+ return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
}
@Override
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index 52e9b66..47fc044 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -391,6 +391,9 @@
finallyBody.accept(this);
}
+ for (final Block inlinedFinally : tryNode.getInlinedFinallies()) {
+ inlinedFinally.accept(this);
+ }
return false;
}
diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
index f9fd386..28022b1 100644
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
@@ -43,6 +43,7 @@
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.JoinPredecessorExpression;
+import jdk.nashorn.internal.ir.JumpToInlinedFinally;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
@@ -473,6 +474,26 @@
}
/**
+ * Callback for entering a JumpToInlinedFinally
+ *
+ * @param jumpToInlinedFinally the node
+ * @return true if traversal should continue and node children be traversed, false otherwise
+ */
+ public boolean enterJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
+ return enterDefault(jumpToInlinedFinally);
+ }
+
+ /**
+ * Callback for leaving a JumpToInlinedFinally
+ *
+ * @param jumpToInlinedFinally the node
+ * @return processed node, which will replace the original one, or the original node
+ */
+ public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
+ return leaveDefault(jumpToInlinedFinally);
+ }
+
+ /**
* Callback for entering a LabelNode
*
* @param labelNode the node
diff --git a/nashorn/test/script/basic/JDK-8067139.js b/nashorn/test/script/basic/JDK-8067139.js
new file mode 100644
index 0000000..004efe1
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8067139.js
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8067139: Finally blocks inlined incorrectly
+ *
+ * @test
+ * @run
+ */
+
+// Test case for JDK-8067139
+// as well as for JDK-8030198 which is a duplicate.
+(function(){
+ var catchCount = 0;
+ try {
+ (function (){
+ try {
+ return;
+ } catch(x) {
+ ++catchCount;
+ } finally {
+ throw 0;
+ }
+ })();
+ Assert.fail(); // must throw
+ } catch(e) {
+ Assert.assertEquals(e, 0); // threw 0
+ Assert.assertEquals(catchCount, 0); // inner catch never executed
+ }
+})();
+
+// Test case for JDK-8048862 which is a duplicate of this bug
+var ret = (function(o) {
+ try{
+ with(o) {
+ return x;
+ }
+ } finally {
+ try {
+ return x;
+ } catch(e) {
+ Assert.assertTrue(e instanceof ReferenceError);
+ return 2;
+ }
+ }
+})({x: 1});
+Assert.assertEquals(ret, 2); // executed the catch block
+
+// Test cases for JDK-8066231 that is a duplicate of this bug
+// Case 1
+(function (){ try { Object; } catch(x if x >>>=0) { throw x2; } finally { } })();
+// Case 2
+try {
+ (function (){ try { return; } catch(x) { return x ^= 0; } finally { throw 0; } })();
+ Assert.fail();
+} catch(e) {
+ Assert.assertEquals(e, 0); // threw 0
+}
+// Case 3
+try {
+ (function (){ try { return; } catch(x) { return x ^= Object; } finally { throw Object; } })();
+ Assert.fail();
+} catch(e) {
+ Assert.assertEquals(e, Object); // threw Object
+}
+// Case from comment
+try {
+ (function () { try { Object } catch(x) { (x=y); return; } finally { throw Object; } })();
+ Assert.fail();
+} catch(e) {
+ Assert.assertEquals(e, Object); // threw Object
+}
diff --git a/test/make/TestJavaCompilation.gmk b/test/make/TestJavaCompilation.gmk
index c82d205..59f73da 100644
--- a/test/make/TestJavaCompilation.gmk
+++ b/test/make/TestJavaCompilation.gmk
@@ -50,6 +50,9 @@
clean-jar1:
$(RM) -r $(OUTPUT_DIR)/_jar1* $(OUTPUT_DIR)/jar1*
+$(JAR1_MANIFEST): | $(OUTPUT_DIR)/_jar1_created
+ $(ECHO) "Test-Attribute: value" > $(JAR1_MANIFEST)
+
$(OUTPUT_DIR)/_jar1_created: $(DEPS)
$(RM) -r $(JAR1_SRC_ROOT)
$(RM) $(JAR1_FILE)
@@ -61,7 +64,6 @@
$(TOUCH) $(JAR1_SRC_ROOT)/dir1/file1.class
$(TOUCH) $(JAR1_SRC_ROOT)/dir2/file2.class
$(TOUCH) $(JAR1_SRC_ROOT)/META-INF/metafile
- $(ECHO) "Test-Attribute: value" > $(JAR1_MANIFEST)
$(TOUCH) $@
$(eval $(call SetupArchive,BUILD_JAR1, \
@@ -77,7 +79,7 @@
$(DIFF) -r $(JAR1_SRC_ROOT)/dir1 $(JAR1_UNZIP)/dir1
$(DIFF) -r $(JAR1_SRC_ROOT)/dir2 $(JAR1_UNZIP)/dir2
$(DIFF) -r $(JAR1_SRC_ROOT)/META-INF/metafile $(JAR1_UNZIP)/META-INF/metafile
- if [ "`$(GREP) 'Test-Attribute: value' $(JAR1_MANIFEST)`" = "" ]; then \
+ if [ "`$(GREP) 'Test-Attribute: value' $(JAR1_UNZIP)/META-INF/MANIFEST.MF`" = "" ]; then \
$(ECHO) "Could not find Test-Attribute in manifest of $(JAR1_FILE)"; \
exit 1; \
fi
@@ -88,7 +90,7 @@
# Change a source file and call this makefile again to force the jar to be
# updated.
-$(OUTPUT_DIR)_jar1_updated: $(OUTPUT_DIR)/_jar1_verified
+$(OUTPUT_DIR)/_jar1_updated: $(OUTPUT_DIR)/_jar1_verified
$(ECHO) updated > $(JAR1_SRC_ROOT)/dir1/file1.class
$(ECHO) updated > $(JAR1_SRC_ROOT)/META-INF/metafile
$(TOUCH) $(OUTPUT_DIR)/_jar1_created
@@ -96,9 +98,26 @@
$(TOUCH) $@
update-jar1: $(OUTPUT_DIR)_jar1_updated
-TEST_TARGETS += $(OUTPUT_DIR)_jar1_updated
-.PHONY: clean-jar1 create-jar1 update-jar1
+# Change the manifest file and call this makefile again to force the jar
+# to be updated
+$(OUTPUT_DIR)/_jar1_updated_manifest: $(OUTPUT_DIR)/_jar1_updated
+ $(ECHO) "Test-Attribute: foobar" > $(JAR1_MANIFEST)
+ +$(MAKE) -f $(THIS_FILE) $(BUILD_JAR1)
+ $(RM) -r $(JAR1_UNZIP)
+ $(MKDIR) -p $(JAR1_UNZIP)
+ $(CD) $(JAR1_UNZIP) && $(UNZIP) $(JAR1_FILE) $(LOG_DEBUG)
+ if [ "`$(GREP) 'Test-Attribute: foobar' $(JAR1_UNZIP)/META-INF/MANIFEST.MF`" = "" ]; then \
+ $(ECHO) "Could not find Test-Attribute in manifest of $(JAR1_FILE)"; \
+ exit 1; \
+ fi
+ $(TOUCH) $@
+
+update-jar1-manifest: $(OUTPUT_DIR)/_jar1_updated_manifest
+
+TEST_TARGETS += $(OUTPUT_DIR)/_jar1_updated $(OUTPUT_DIR)/_jar1_updated_manifest
+
+.PHONY: clean-jar1 create-jar1 update-jar1 update-jar1-manifest
################################################################################
# Test: jar2
@@ -139,14 +158,14 @@
create-jar2: $(OUTPUT_DIR)/_jar2_verified
TEST_TARGETS += $(OUTPUT_DIR)/_jar2_verified
-$(OUTPUT_DIR)_jar2_updated: $(OUTPUT_DIR)/_jar2_verified
+$(OUTPUT_DIR)/_jar2_updated: $(OUTPUT_DIR)/_jar2_verified
$(ECHO) updated > $(JAR2_SRC_ROOT1)/dir1/file1.class
$(TOUCH) $(OUTPUT_DIR)/_jar2_created
+$(MAKE) -f $(THIS_FILE) $(OUTPUT_DIR)/_jar2_verified
$(TOUCH) $@
-update-jar2: $(OUTPUT_DIR)_jar2_updated
-TEST_TARGETS += $(OUTPUT_DIR)_jar2_updated
+update-jar2: $(OUTPUT_DIR)/_jar2_updated
+TEST_TARGETS += $(OUTPUT_DIR)/_jar2_updated
.PHONY: clean-jar2 create-jar2 update-jar2
@@ -200,14 +219,14 @@
create-jar3: $(OUTPUT_DIR)/_jar3_verified
TEST_TARGETS += $(OUTPUT_DIR)/_jar3_verified
-$(OUTPUT_DIR)_jar3_updated: $(OUTPUT_DIR)/_jar3_verified
+$(OUTPUT_DIR)/_jar3_updated: $(OUTPUT_DIR)/_jar3_verified
$(ECHO) updated > $(JAR3_SRC_ROOT2)/extra-file
$(TOUCH) $(OUTPUT_DIR)/_jar3_created
+$(MAKE) -f $(THIS_FILE) $(OUTPUT_DIR)/_jar3_verified
$(TOUCH) $@
-update-jar3: $(OUTPUT_DIR)_jar3_updated
-TEST_TARGETS += $(OUTPUT_DIR)_jar3_updated
+update-jar3: $(OUTPUT_DIR)/_jar3_updated
+TEST_TARGETS += $(OUTPUT_DIR)/_jar3_updated
.PHONY: clean-jar3 create-jar3 update-jar3
diff --git a/test/make/TestMakeBase.gmk b/test/make/TestMakeBase.gmk
index 809115c..407ec93 100644
--- a/test/make/TestMakeBase.gmk
+++ b/test/make/TestMakeBase.gmk
@@ -33,7 +33,14 @@
$(SRC_ROOT)/make/common/MakeBase.gmk \
#
+# On macosx, file system timestamps only have 1 second resultion so must add
+# sleeps to properly test dependencies.
+ifeq ($(OPENJDK_BUILD_OS), macosx)
+ SLEEP_ON_MAC := sleep 1
+endif
+
OUTPUT_DIR := $(TESTMAKE_OUTPUTDIR)/make-base
+$(call MakeDir, $(OUTPUT_DIR))
################################################################################
# Escape $
@@ -56,5 +63,124 @@
TEST_TARGETS += $(ESCAPE_DOLLAR_DIR)/_escape_dollar
################################################################################
+# Test Equals
+
+EQUALS_VALUE1 := value1$(SPACE)
+EQUALS_VALUE2 := value2
+
+ifneq ($(call equals, $(EQUALS_VALUE1), $(EQUALS_VALUE2)), )
+ $(error The strings >$(EQUALS_VALUE1)< and >$(EQUALS_VALUE2)< are equal)
+endif
+
+ifeq ($(call equals, $(EQUALS_VALUE1), $(EQUALS_VALUE1)), )
+ $(error The strings >$(EQUALS_VALUE1)< and >$(EQUALS_VALUE1)< are not equal)
+endif
+
+################################################################################
+# Test ShellQuote
+
+SHELL_QUOTE_VALUE := foo '""' "''" bar
+SHELL_QUOTE_RESULT := $(shell $(ECHO) $(call ShellQuote, \
+ $(SHELL_QUOTE_VALUE)))
+
+ifneq ($(SHELL_QUOTE_VALUE), $(SHELL_QUOTE_RESULT))
+ $(error Expected: >$(SHELL_QUOTE_VALUE)< - Result: >$(SHELL_QUOTE_RESULT)<)
+endif
+
+################################################################################
+# Test read and write to file
+
+READ_WRITE_FILE := $(OUTPUT_DIR)/read-write
+READ_WRITE_VALUE := foo '""' "''" \t\n\\ bar
+$(call WriteFile, $(READ_WRITE_VALUE), $(READ_WRITE_FILE))
+READ_WRITE_RESULT := $(call ReadFile, $(READ_WRITE_FILE))
+
+ifneq ($(READ_WRITE_VALUE), $(READ_WRITE_RESULT))
+ $(error Expected: >$(READ_WRITE_VALUE)< - Result: >$(READ_WRITE_RESULT)<)
+endif
+
+################################################################################
+# Test creating dependencies on make variables
+
+VARDEP_DIR := $(OUTPUT_DIR)/vardep
+VARDEP_SRC_FILE := $(VARDEP_DIR)/src-file
+VARDEP_TARGET_FILE := $(VARDEP_DIR)/target-file
+VARDEP_FLAG_FILE := $(VARDEP_DIR)/flag-file
+
+$(VARDEP_DIR)/src-file:
+ $(MKDIR) -p $(@D)
+ $(ECHO) "some string XXX" > $@
+
+$(VARDEP_TARGET_FILE): $(VARDEP_DIR)/src-file \
+ $(call DependOnVariable, VARDEP_TEST_VAR)
+ $(MKDIR) -p $(@D)
+ $(SED) -e 's/XXX/$(VARDEP_TEST_VAR)/g' $< > $@
+ $(TOUCH) $(VARDEP_FLAG_FILE)
+
+test-vardep:
+ $(RM) $(VARDEP_SRC_FILE) $(VARDEP_TARGET_FILE) $(VARDEP_FLAG_FILE)
+ #
+ # Simply create the target file and verify that it has the correct value
+ #
+ $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR=value1 $(VARDEP_TARGET_FILE)
+ $(PRINTF) "Expecting value1: %s\n" "`$(CAT) $(VARDEP_DIR)/target-file`"
+ test "some string value1" = "`$(CAT) $(VARDEP_DIR)/target-file`"
+ test -e $(VARDEP_FLAG_FILE)
+ #
+ # Make the target file again and verify that the value is updated with
+ # the new value
+ #
+ $(SLEEP_ON_MAC)
+ $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR=value2 $(VARDEP_TARGET_FILE)
+ $(PRINTF) "Expecting value2: %s\n" "`$(CAT) $(VARDEP_DIR)/target-file`"
+ test "some string value2" = "`$(CAT) $(VARDEP_DIR)/target-file`"
+ test -e $(VARDEP_FLAG_FILE)
+ #
+ # Make the target again with the same value and verify that the recipe
+ # was never run by checking that the flag file was not recreated
+ #
+ $(SLEEP_ON_MAC)
+ $(RM) $(VARDEP_FLAG_FILE)
+ $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR=value2 $(VARDEP_TARGET_FILE)
+ $(PRINTF) "Expecting value2: %s\n" "`$(CAT) $(VARDEP_DIR)/target-file`"
+ test "some string value2" = "`$(CAT) $(VARDEP_DIR)/target-file`"
+ test ! -e $(VARDEP_FLAG_FILE)
+ #
+ # Test running with spaces at the end and the middle of the value
+ # and verify that the file isn't rewritten the second time
+ #
+ $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR="value3 foo " $(VARDEP_TARGET_FILE)
+ $(RM) $(VARDEP_FLAG_FILE)
+ $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR="value3 foo" $(VARDEP_TARGET_FILE)
+ test ! -e $(VARDEP_FLAG_FILE)
+ $(MAKE) -f $(THIS_FILE) VARDEP_TEST_VAR=" value3 foo" $(VARDEP_TARGET_FILE)
+ test ! -e $(VARDEP_FLAG_FILE)
+
+# Test specifying a specific value file to store variable in
+VARDEP_VALUE_FILE := $(VARDEP_DIR)/value-file
+VARDEP_TEST_VAR2 := value3
+
+VARDEP_RETURN_VALUE := $(call DependOnVariable, VARDEP_TEST_VAR2, $(VARDEP_VALUE_FILE))
+ifneq ($(VARDEP_VALUE_FILE), $(VARDEP_RETURN_VALUE))
+ $(error Expected: $(VARDEP_VALUE_FILE) - DependOnVariable: $(VARDEP_RETURN_VALUE))
+endif
+VARDEP_FILE_CONTENTS := $(shell $(CAT) $(VARDEP_VALUE_FILE))
+ifneq ($(VARDEP_TEST_VAR2), $(VARDEP_FILE_CONTENTS))
+ $(error Expected: $(VARDEP_TEST_VAR2) - DependOnVariable file contained: \
+ $(VARDEP_FILE_CONTENTS))
+endif
+
+# Test with a variable value containing some problematic characters
+VARDEP_TEST_VAR3 := foo '""' "''" bar
+VARDEP_VALUE_FILE := $(call DependOnVariable, VARDEP_TEST_VAR3)
+VARDEP_FILE_CONTENTS := $(shell $(CAT) $(VARDEP_VALUE_FILE))
+ifneq ($(VARDEP_TEST_VAR3), $(VARDEP_FILE_CONTENTS))
+ $(error Expected: >$(VARDEP_TEST_VAR3)< - DependOnVariable file contained: \
+ >$(VARDEP_FILE_CONTENTS)<)
+endif
+
+TEST_TARGETS += test-vardep
+
+################################################################################
all: $(TEST_TARGETS)