OpenJDK / amber / amber
changeset 28699:06e2c7a14944
Merge
author | duke |
---|---|
date | Wed, 05 Jul 2017 20:17:15 +0200 |
parents | f9e5640d832e cf8fe951ca93 |
children | 4adaea63f465 |
files | jdk/make/data/checkdeps/refs.allowed jdk/make/src/classes/build/tools/deps/CheckDeps.java jdk/src/java.base/aix/native/libnet/java/net/aix_close.c jdk/src/java.base/unix/classes/java/lang/UNIXProcess.java jdk/src/java.base/unix/native/libjava/UNIXProcess_md.c jdk/src/java.base/unix/native/libjava/java_props_macosx.c jdk/src/java.base/unix/native/libjava/java_props_macosx.h jdk/src/java.base/unix/native/libnet/bsd_close.c jdk/src/java.base/unix/native/libnet/linux_close.c jdk/src/java.base/unix/native/libnet/solaris_close.c jdk/src/jdk.security.auth/unix/native/libjaas/Solaris.c jdk/test/java/lang/CharSequence/DefaultTest.java jdk/test/java/util/ResourceBundle/Bug6287579.java |
diffstat | 228 files changed, 9993 insertions(+), 5080 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags-top-repo Thu Jan 29 15:36:12 2015 -0800 +++ b/.hgtags-top-repo Wed Jul 05 20:17:15 2017 +0200 @@ -290,3 +290,4 @@ 3dd628fde2086218d548841022ee8436b6b88185 jdk9-b45 12f1e276447bcc81516e85367d53e4f08897049d jdk9-b46 b6cca3e6175a69f39e5799b7349ddb0176630291 jdk9-b47 +0064e246d83f6f9fc245c19b6d05041ecaf4b6d4 jdk9-b48
--- a/common/autoconf/basics.m4 Thu Jan 29 15:36:12 2015 -0800 +++ b/common/autoconf/basics.m4 Wed Jul 05 20:17:15 2017 +0200 @@ -987,3 +987,26 @@ IS_RECONFIGURE=no fi ]) + +# Check for support for specific options in bash +AC_DEFUN_ONCE([BASIC_CHECK_BASH_OPTIONS], +[ + # Test if bash supports pipefail. + AC_MSG_CHECKING([if bash supports pipefail]) + if ${BASH} -c 'set -o pipefail'; then + BASH_ARGS="$BASH_ARGS -o pipefail" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + AC_MSG_CHECKING([if bash supports errexit (-e)]) + if ${BASH} -e -c 'true'; then + BASH_ARGS="$BASH_ARGS -e" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + + AC_SUBST(BASH_ARGS) +])
--- a/common/autoconf/bootcycle-spec.gmk.in Thu Jan 29 15:36:12 2015 -0800 +++ b/common/autoconf/bootcycle-spec.gmk.in Wed Jul 05 20:17:15 2017 +0200 @@ -46,8 +46,12 @@ BOOT_JDK := $(JDK_IMAGE_DIR) # The bootcycle build has a different output directory -BUILD_OUTPUT:=@BUILD_OUTPUT@/bootcycle-build -SJAVAC_SERVER_DIR:=$(subst @BUILD_OUTPUT@,$(BUILD_OUTPUT),$(SJAVAC_SERVER_DIR)) +OLD_BUILD_OUTPUT:=@BUILD_OUTPUT@ +BUILD_OUTPUT:=$(OLD_BUILD_OUTPUT)/bootcycle-build +# The HOTSPOT_DIST dir is not defined relative to BUILD_OUTPUT in spec.gmk. Must not +# use space in this patsubst to avoid leading space in HOTSPOT_DIST. +HOTSPOT_DIST:=$(patsubst $(OLD_BUILD_OUTPUT)%,$(BUILD_OUTPUT)%,$(HOTSPOT_DIST)) +SJAVAC_SERVER_DIR:=$(patsubst $(OLD_BUILD_OUTPUT)%, $(BUILD_OUTPUT)%, $(SJAVAC_SERVER_DIR)) JAVA_CMD:=$(BOOT_JDK)/bin/java JAVAC_CMD:=$(BOOT_JDK)/bin/javac
--- a/common/autoconf/configure.ac Thu Jan 29 15:36:12 2015 -0800 +++ b/common/autoconf/configure.ac Wed Jul 05 20:17:15 2017 +0200 @@ -113,6 +113,7 @@ # Setup tools that requires more complex handling, or that is not needed by the configure script. BASIC_SETUP_COMPLEX_TOOLS +BASIC_CHECK_BASH_OPTIONS # Check if pkg-config is available. PKG_PROG_PKG_CONFIG
--- a/common/autoconf/generated-configure.sh Thu Jan 29 15:36:12 2015 -0800 +++ b/common/autoconf/generated-configure.sh Wed Jul 05 20:17:15 2017 +0200 @@ -853,6 +853,7 @@ OS_VERSION_MINOR OS_VERSION_MAJOR PKG_CONFIG +BASH_ARGS CODESIGN XATTR DSYMUTIL @@ -3522,6 +3523,9 @@ +# Check for support for specific options in bash + + # # Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -4329,7 +4333,7 @@ #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1420811523 +DATE_WHEN_GENERATED=1421247827 ############################################################################### # @@ -19609,6 +19613,32 @@ fi + # Test if bash supports pipefail. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if bash supports pipefail" >&5 +$as_echo_n "checking if bash supports pipefail... " >&6; } + if ${BASH} -c 'set -o pipefail'; then + BASH_ARGS="$BASH_ARGS -o pipefail" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if bash supports errexit (-e)" >&5 +$as_echo_n "checking if bash supports errexit (-e)... " >&6; } + if ${BASH} -e -c 'true'; then + BASH_ARGS="$BASH_ARGS -e" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + + + + # Check if pkg-config is available. @@ -27408,8 +27438,8 @@ # The trailing space for everyone except PATH is no typo, but is needed due # to trailing \ in the Windows paths. These will be stripped later. $ECHO "$WINPATH_BASH -c 'echo VS_PATH="'\"$PATH\" > set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE - $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE\;$include \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE - $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB\;$lib \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_INCLUDE="'\"$INCLUDE \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE + $ECHO "$WINPATH_BASH -c 'echo VS_LIB="'\"$LIB \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE $ECHO "$WINPATH_BASH -c 'echo VCINSTALLDIR="'\"$VCINSTALLDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE $ECHO "$WINPATH_BASH -c 'echo WindowsSdkDir="'\"$WindowsSdkDir \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE $ECHO "$WINPATH_BASH -c 'echo WINDOWSSDKDIR="'\"$WINDOWSSDKDIR \" >> set-vs-env.sh' >> $EXTRACT_VC_ENV_BAT_FILE
--- a/common/autoconf/spec.gmk.in Thu Jan 29 15:36:12 2015 -0800 +++ b/common/autoconf/spec.gmk.in Wed Jul 05 20:17:15 2017 +0200 @@ -78,6 +78,11 @@ OUTPUT_SYNC_SUPPORTED:=@OUTPUT_SYNC_SUPPORTED@ OUTPUT_SYNC:=@OUTPUT_SYNC@ +# Override the shell with bash +BASH:=@BASH@ +BASH_ARGS:=@BASH_ARGS@ +SHELL:=$(BASH) $(BASH_ARGS) + # The "human readable" name of this configuration CONF_NAME:=@CONF_NAME@ @@ -243,7 +248,7 @@ HOTSPOT_OUTPUTDIR=$(BUILD_OUTPUT)/hotspot JDK_OUTPUTDIR=$(BUILD_OUTPUT)/jdk IMAGES_OUTPUTDIR=$(BUILD_OUTPUT)/images -TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/testmake +TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/test-make MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/make-support HOTSPOT_DIST=@HOTSPOT_DIST@ @@ -495,7 +500,6 @@ # Tools adhering to a minimal and common standard of posix compliance. AWK:=@AWK@ BASENAME:=@BASENAME@ -BASH:=@BASH@ CAT:=@CAT@ CCACHE:=@CCACHE@ # CD is going away, but remains to cater for legacy makefiles.
--- a/corba/.hgtags Thu Jan 29 15:36:12 2015 -0800 +++ b/corba/.hgtags Wed Jul 05 20:17:15 2017 +0200 @@ -290,3 +290,4 @@ 9e3f2bed80c0e5a84a256ce41f1d10c5ade48466 jdk9-b45 326f2068b4a4c05e2fa27d6acf93eba7b54b090d jdk9-b46 ee8447ca632e1d39180b4767c749db101bff7314 jdk9-b47 +a13c49c5f2899b702652a460ed7aa73123e671e6 jdk9-b48
--- a/hotspot/.hgtags Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/.hgtags Wed Jul 05 20:17:15 2017 +0200 @@ -450,3 +450,4 @@ 5dc8184af1e2bb30b0103113d1f1a58a21a80c37 jdk9-b45 a184ee1d717297bd35b7c3e35393e137921a3ed2 jdk9-b46 3b241fb72b8925b75941d612db762a6d5da66d02 jdk9-b47 +cc775a4a24c7f5d9e624b4205e9fbd48a17331f6 jdk9-b48
--- a/hotspot/make/aix/Makefile Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/aix/Makefile Wed Jul 05 20:17:15 2017 +0200 @@ -246,8 +246,7 @@ XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \
--- a/hotspot/make/aix/makefiles/xlc.make Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/aix/makefiles/xlc.make Wed Jul 05 20:17:15 2017 +0200 @@ -74,6 +74,12 @@ # no xlc counterpart for -fcheck-new # CFLAGS += -fcheck-new +# We need to define this on the command line if we want to use the the +# predefined format specifiers from "inttypes.h". Otherwise system headrs +# can indirectly include inttypes.h before we define __STDC_FORMAT_MACROS +# in globalDefinitions.hpp +CFLAGS += -D__STDC_FORMAT_MACROS + ARCHFLAG = -q64 CFLAGS += $(ARCHFLAG)
--- a/hotspot/make/bsd/Makefile Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/bsd/Makefile Wed Jul 05 20:17:15 2017 +0200 @@ -240,8 +240,7 @@ XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \
--- a/hotspot/make/bsd/makefiles/dtrace.make Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/bsd/makefiles/dtrace.make Wed Jul 05 20:17:15 2017 +0200 @@ -179,23 +179,23 @@ # $@.tmp is created first to avoid an empty $(JVMOFFS).h if an error occurs. $(JVMOFFS).h: $(GENOFFS) $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -header > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1 ; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS)Index.h: $(GENOFFS) $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -index > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1 ; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS).cpp: $(GENOFFS) $(JVMOFFS).h $(JVMOFFS)Index.h $(QUIETLY) DYLD_LIBRARY_PATH=.:$(DYLD_LIBRARY_PATH) ./$(GENOFFS) -table > $@.tmp; touch $@; \ - if [ `diff $@.tmp $@ > /dev/null 2>&1; echo $$?` -ne 0 ] ; \ - then rm -f $@; mv $@.tmp $@; \ - else rm -f $@.tmp; \ + if diff $@.tmp $@ > /dev/null 2>&1; \ + then rm -f $@.tmp; \ + else rm -f $@; mv $@.tmp $@; \ fi $(JVMOFFS.o): $(JVMOFFS).h $(JVMOFFS).cpp
--- a/hotspot/make/bsd/makefiles/universal.gmk Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/bsd/makefiles/universal.gmk Wed Jul 05 20:17:15 2017 +0200 @@ -59,7 +59,7 @@ # Package built libraries in a universal binary $(UNIVERSAL_LIPO_LIST): - BUILT_LIPO_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`"; \ + BUILT_LIPO_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_LIPO_FILES}" ]; then \ $(MKDIR) -p $(shell dirname $@); \ lipo -create -output $@ $${BUILT_LIPO_FILES}; \ @@ -70,7 +70,7 @@ # - copies directories; including empty dirs # - copies files, symlinks, other non-directory files $(UNIVERSAL_COPY_LIST): - BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) -prune 2>/dev/null`"; \ + BUILT_COPY_FILES="`find $(EXPORT_JRE_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_JRE_LIB_DIR)/,,$@) -prune 2>/dev/null`" || test $$? = "1"; \ if [ -n "$${BUILT_COPY_FILES}" ]; then \ for i in $${BUILT_COPY_FILES}; do \ $(MKDIR) -p $(shell dirname $@); \
--- a/hotspot/make/linux/Makefile Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/linux/Makefile Wed Jul 05 20:17:15 2017 +0200 @@ -246,8 +246,7 @@ XSLT_CHECK = $(REMOTE) $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(REMOTE) $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \
--- a/hotspot/make/linux/makefiles/vm.make Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/linux/makefiles/vm.make Wed Jul 05 20:17:15 2017 +0200 @@ -334,10 +334,8 @@ rm -f $@.1; ln -s $@ $@.1; \ if [ \"$(CROSS_COMPILE_ARCH)\" = \"\" ] ; then \ if [ -x /usr/sbin/selinuxenabled ] ; then \ - /usr/sbin/selinuxenabled; \ - if [ $$? = 0 ] ; then \ - /usr/bin/chcon -t textrel_shlib_t $@; \ - if [ $$? != 0 ]; then \ + if /usr/sbin/selinuxenabled; then \ + if ! /usr/bin/chcon -t textrel_shlib_t $@; then \ echo "ERROR: Cannot chcon $@"; \ fi \ fi \
--- a/hotspot/make/sa.files Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/sa.files Wed Jul 05 20:17:15 2017 +0200 @@ -39,6 +39,7 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/asm/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/c1/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/ci/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/classfile/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/code/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/compiler/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/*.java \ @@ -49,8 +50,10 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/cdbg/basic/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/dummy/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/sparc/*.java \ @@ -71,6 +74,7 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/win32/coff/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/ia64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windows/amd64/*.java \ @@ -101,6 +105,8 @@ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/sparc/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/x86/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_amd64/*.java \ +$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/win32_x86/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/ppc64/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/*.java \ $(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/jcore/*.java \
--- a/hotspot/make/solaris/Makefile Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/solaris/Makefile Wed Jul 05 20:17:15 2017 +0200 @@ -190,8 +190,7 @@ XSLT_CHECK = $(RUN.JAVAP) javax.xml.transform.TransformerFactory # If not found then fail fast. check_j2se_version: - $(QUIETLY) $(XSLT_CHECK) > /dev/null 2>&1; \ - if [ $$? -ne 0 ]; then \ + $(QUIETLY) if ! $(XSLT_CHECK) > /dev/null 2>&1; then \ $(RUN.JAVA) -version; \ echo "*** An XSLT processor (J2SE 1.4.x or newer) is required" \ "to bootstrap this build" 1>&2; \
--- a/hotspot/make/solaris/makefiles/dtrace.make Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/make/solaris/makefiles/dtrace.make Wed Jul 05 20:17:15 2017 +0200 @@ -171,11 +171,11 @@ ./lib$(GENOFFS).so CONDITIONALLY_UPDATE_JVMOFFS_TARGET = \ - cmp -s $@ $@.tmp; \ - case $$? in \ - 0) rm -f $@.tmp;; \ - *) rm -f $@ && mv $@.tmp $@ && echo Updated $@;; \ - esac + if cmp -s $@ $@.tmp; then \ + rm -f $@.tmp; \ + else \ + rm -f $@ && mv $@.tmp $@ && echo Updated $@; \ + fi # $@.tmp is created first to avoid an empty $(JVMOFFS).h if an error occurs. $(JVMOFFS).h: $(GENOFFS)
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -567,16 +567,21 @@ inline void load_with_trap_null_check(Register d, int si16, Register s1); // Load heap oop and decompress. Loaded oop may not be null. - inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg); + // Specify tmp to save one cycle. + inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg, + Register tmp = noreg); + // Store heap oop and decompress. Decompressed oop may not be null. + // Specify tmp register if d should not be changed. inline void store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, - /*specify if d must stay uncompressed*/ Register tmp = noreg); + Register tmp = noreg); // Null allowed. inline void load_heap_oop(Register d, RegisterOrConstant offs, Register s1 = noreg); // Encode/decode heap oop. Oop may not be null, else en/decoding goes wrong. + // src == d allowed. inline Register encode_heap_oop_not_null(Register d, Register src = noreg); - inline void decode_heap_oop_not_null(Register d); + inline Register decode_heap_oop_not_null(Register d, Register src = noreg); // Null allowed. inline void decode_heap_oop(Register d);
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -311,11 +311,14 @@ ld(d, si16, s1); } -inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1) { +inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) { if (UseCompressedOops) { - lwz(d, offs, s1); + // In disjoint mode decoding can save a cycle if src != dst. + Register narrowOop = (tmp != noreg && Universe::narrow_oop_base_disjoint()) ? tmp : d; + lwz(narrowOop, offs, s1); // Attention: no null check here! - decode_heap_oop_not_null(d); + Register res = decode_heap_oop_not_null(d, narrowOop); + assert(res == d, "caller will not consume loaded value"); } else { ld(d, offs, s1); } @@ -340,26 +343,36 @@ } inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register src) { - Register current = (src!=noreg) ? src : d; // Compressed oop is in d if no src provided. - if (Universe::narrow_oop_base() != NULL) { + Register current = (src != noreg) ? src : d; // Oop to be compressed is in d if no src provided. + if (Universe::narrow_oop_base_overlaps()) { sub(d, current, R30); current = d; } if (Universe::narrow_oop_shift() != 0) { - srdi(d, current, LogMinObjAlignmentInBytes); + rldicl(d, current, 64-Universe::narrow_oop_shift(), 32); // Clears the upper bits. current = d; } return current; // Encoded oop is in this register. } -inline void MacroAssembler::decode_heap_oop_not_null(Register d) { +inline Register MacroAssembler::decode_heap_oop_not_null(Register d, Register src) { + if (Universe::narrow_oop_base_disjoint() && src != noreg && src != d && + Universe::narrow_oop_shift() != 0) { + mr(d, R30); + rldimi(d, src, Universe::narrow_oop_shift(), 32-Universe::narrow_oop_shift()); + return d; + } + + Register current = (src != noreg) ? src : d; // Compressed oop is in d if no src provided. if (Universe::narrow_oop_shift() != 0) { - assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - sldi(d, d, LogMinObjAlignmentInBytes); + sldi(d, current, Universe::narrow_oop_shift()); + current = d; } if (Universe::narrow_oop_base() != NULL) { - add(d, d, R30); + add(d, current, R30); + current = d; } + return current; // Decoded oop is in this register. } inline void MacroAssembler::decode_heap_oop(Register d) { @@ -368,13 +381,7 @@ cmpwi(CCR0, d, 0); beq(CCR0, isNull); } - if (Universe::narrow_oop_shift() != 0) { - assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); - sldi(d, d, LogMinObjAlignmentInBytes); - } - if (Universe::narrow_oop_base() != NULL) { - add(d, d, R30); - } + decode_heap_oop_not_null(d); bind(isNull); }
--- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -172,15 +172,15 @@ // Load the invoker, as MH -> MH.form -> LF.vmentry __ verify_oop(recv); - __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), recv); + __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), recv, temp2); __ verify_oop(method_temp); - __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp); + __ load_heap_oop_not_null(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp, temp2); __ verify_oop(method_temp); - // the following assumes that a Method* is normally compressed in the vmtarget field: + // The following assumes that a Method* is normally compressed in the vmtarget field: __ ld(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes()), method_temp); if (VerifyMethodHandles && !for_compiler_entry) { - // make sure recv is already on stack + // Make sure recv is already on stack. __ ld(temp2, in_bytes(Method::const_offset()), method_temp); __ load_sized_value(temp2, in_bytes(ConstMethod::size_of_parameters_offset()), temp2, sizeof(u2), /*is_signed*/ false); @@ -259,8 +259,9 @@ } if (TraceMethodHandles) { - if (tmp_mh != noreg) + if (tmp_mh != noreg) { __ mr(R23_method_handle, tmp_mh); // make stub happy + } trace_method_handle_interpreter_entry(_masm, iid); } @@ -332,7 +333,7 @@ if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) { Label L_ok; Register temp2_defc = temp2; - __ load_heap_oop_not_null(temp2_defc, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg); + __ load_heap_oop_not_null(temp2_defc, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg, temp3); load_klass_from_Class(_masm, temp2_defc, temp3, temp4); __ verify_klass_ptr(temp2_defc); __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, temp4, L_ok); @@ -407,7 +408,7 @@ } Register temp2_intf = temp2; - __ load_heap_oop_not_null(temp2_intf, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg); + __ load_heap_oop_not_null(temp2_intf, NONZERO(java_lang_invoke_MemberName::clazz_offset_in_bytes()), member_reg, temp3); load_klass_from_Class(_masm, temp2_intf, temp3, temp4); __ verify_klass_ptr(temp2_intf); @@ -464,7 +465,7 @@ strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH const char* mh_reg_name = has_mh ? "R23_method_handle" : "G23"; tty->print_cr("MH %s %s="INTPTR_FORMAT " sp=" INTPTR_FORMAT, - adaptername, mh_reg_name, (intptr_t) mh, (intptr_t) entry_sp); + adaptername, mh_reg_name, (intptr_t) mh, entry_sp); if (Verbose) { tty->print_cr("Registers:"); @@ -535,23 +536,22 @@ BLOCK_COMMENT("trace_method_handle {"); - int nbytes_save = 10 * 8; // 10 volatile gprs - __ save_LR_CR(R0); - __ mr(R0, R1_SP); // saved_sp - assert(Assembler::is_simm(-nbytes_save, 16), "Overwriting R0"); - // Push_frame_reg_args only uses R0 if nbytes_save is wider than 16 bit. - __ push_frame_reg_args(nbytes_save, R0); - __ save_volatile_gprs(R1_SP, frame::abi_reg_args_size); // Except R0. + const Register tmp = R11; // Will be preserved. + const int nbytes_save = 11*8; // volatile gprs except R0 + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ save_LR_CR(tmp); // save in old frame - __ load_const(R3_ARG1, (address)adaptername); + __ mr(R5_ARG3, R1_SP); // saved_sp + __ push_frame_reg_args(nbytes_save, tmp); + + __ load_const_optimized(R3_ARG1, (address)adaptername, tmp); __ mr(R4_ARG2, R23_method_handle); - __ mr(R5_ARG3, R0); // saved_sp __ mr(R6_ARG4, R1_SP); __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub)); - __ restore_volatile_gprs(R1_SP, 112); // Except R0. __ pop_frame(); - __ restore_LR_CR(R0); + __ restore_LR_CR(tmp); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 BLOCK_COMMENT("} trace_method_handle"); }
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/ppc/vm/ppc.ad Wed Jul 05 20:17:15 2017 +0200 @@ -1,6 +1,6 @@ // -// Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. -// Copyright 2012, 2014 SAP AG. All rights reserved. +// Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +// Copyright 2012, 2015 SAP AG. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -2698,7 +2698,7 @@ const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else if (constant_reloc == relocInfo::metadata_type) { - AddressLiteral a = __ allocate_metadata_address((Metadata *)val); + AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else { @@ -2727,7 +2727,7 @@ const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else if (constant_reloc == relocInfo::metadata_type) { - AddressLiteral a = __ allocate_metadata_address((Metadata *)val); + AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); __ relocate(a.rspec()); } else { // non-oop pointers, e.g. card mark base, heap top @@ -6029,6 +6029,20 @@ ins_pipe(pipe_class_default); %} +// Optimize DecodeN for disjoint base. +// Load base of compressed oops into a register +instruct loadBase(iRegLdst dst) %{ + effect(DEF dst); + + format %{ "MR $dst, r30_heapbase" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_or); + __ mr($dst$$Register, R30); + %} + ins_pipe(pipe_class_default); +%} + // Loading ConN must be postalloc expanded so that edges between // the nodes are safe. They may not interfere with a safepoint. // GL TODO: This needs three instructions: better put this into the constant pool. @@ -6724,13 +6738,12 @@ ins_pipe(pipe_class_default); %} -// base != 0 -// 32G aligned narrow oop base. -instruct encodeP_32GAligned(iRegNdst dst, iRegPsrc src) %{ +// Disjoint narrow oop base. +instruct encodeP_Disjoint(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodeP src)); - predicate(false /* TODO: PPC port Universe::narrow_oop_base_disjoint()*/); - - format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with 32G aligned base" %} + predicate(Universe::narrow_oop_base_disjoint()); + + format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with disjoint base" %} size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_rldicl); @@ -6745,7 +6758,7 @@ effect(TEMP crx); predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull && Universe::narrow_oop_shift() != 0 && - true /* TODO: PPC port Universe::narrow_oop_base_overlaps()*/); + Universe::narrow_oop_base_overlaps()); format %{ "EncodeP $dst, $crx, $src \t// postalloc expanded" %} postalloc_expand( postalloc_expand_encode_oop(dst, src, crx)); @@ -6756,7 +6769,7 @@ match(Set dst (EncodeP src)); predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull && Universe::narrow_oop_shift() != 0 && - true /* TODO: PPC port Universe::narrow_oop_base_overlaps()*/); + Universe::narrow_oop_base_overlaps()); format %{ "EncodeP $dst, $src\t// $src != Null, postalloc expanded" %} postalloc_expand( postalloc_expand_encode_oop_not_null(dst, src) ); @@ -6876,6 +6889,7 @@ n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && Universe::narrow_oop_shift() != 0 && Universe::narrow_oop_base() != 0); + ins_cost(4 * DEFAULT_COST); // Should be more expensive than decodeN_Disjoint_isel_Ex. effect(TEMP crx); format %{ "DecodeN $dst, $src \t// Kills $crx, postalloc expanded" %} @@ -6897,6 +6911,106 @@ ins_pipe(pipe_class_default); %} +// Optimize DecodeN for disjoint base. +// Shift narrow oop and or it into register that already contains the heap base. +// Base == dst must hold, and is assured by construction in postaloc_expand. +instruct decodeN_mergeDisjoint(iRegPdst dst, iRegNsrc src, iRegLsrc base) %{ + match(Set dst (DecodeN src)); + effect(TEMP base); + predicate(false); + + format %{ "RLDIMI $dst, $src, shift, 32-shift \t// DecodeN (disjoint base)" %} + size(4); + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_rldimi); + __ rldimi($dst$$Register, $src$$Register, Universe::narrow_oop_shift(), 32-Universe::narrow_oop_shift()); + %} + ins_pipe(pipe_class_default); +%} + +// Optimize DecodeN for disjoint base. +// This node requires only one cycle on the critical path. +// We must postalloc_expand as we can not express use_def effects where +// the used register is L and the def'ed register P. +instruct decodeN_Disjoint_notNull_Ex(iRegPdst dst, iRegNsrc src) %{ + match(Set dst (DecodeN src)); + effect(TEMP_DEF dst); + predicate((n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull || + n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && + Universe::narrow_oop_base_disjoint()); + ins_cost(DEFAULT_COST); + + format %{ "MOV $dst, R30 \t\n" + "RLDIMI $dst, $src, shift, 32-shift \t// decode with disjoint base" %} + postalloc_expand %{ + loadBaseNode *n1 = new loadBaseNode(); + n1->add_req(NULL); + n1->_opnds[0] = op_dst; + + decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); + n2->add_req(n_region, n_src, n1); + n2->_opnds[0] = op_dst; + n2->_opnds[1] = op_src; + n2->_opnds[2] = op_dst; + n2->_bottom_type = _bottom_type; + + ra_->set_pair(n1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + + nodes->push(n1); + nodes->push(n2); + %} +%} + +instruct decodeN_Disjoint_isel_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ + match(Set dst (DecodeN src)); + effect(TEMP_DEF dst, TEMP crx); + predicate((n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && + n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && + Universe::narrow_oop_base_disjoint() && VM_Version::has_isel()); + ins_cost(3 * DEFAULT_COST); + + format %{ "DecodeN $dst, $src \t// decode with disjoint base using isel" %} + postalloc_expand %{ + loadBaseNode *n1 = new loadBaseNode(); + n1->add_req(NULL); + n1->_opnds[0] = op_dst; + + cmpN_reg_imm0Node *n_compare = new cmpN_reg_imm0Node(); + n_compare->add_req(n_region, n_src); + n_compare->_opnds[0] = op_crx; + n_compare->_opnds[1] = op_src; + n_compare->_opnds[2] = new immN_0Oper(TypeNarrowOop::NULL_PTR); + + decodeN_mergeDisjointNode *n2 = new decodeN_mergeDisjointNode(); + n2->add_req(n_region, n_src, n1); + n2->_opnds[0] = op_dst; + n2->_opnds[1] = op_src; + n2->_opnds[2] = op_dst; + n2->_bottom_type = _bottom_type; + + cond_set_0_ptrNode *n_cond_set = new cond_set_0_ptrNode(); + n_cond_set->add_req(n_region, n_compare, n2); + n_cond_set->_opnds[0] = op_dst; + n_cond_set->_opnds[1] = op_crx; + n_cond_set->_opnds[2] = op_dst; + n_cond_set->_bottom_type = _bottom_type; + + assert(ra_->is_oop(this) == true, "A decodeN node must produce an oop!"); + ra_->set_oop(n_cond_set, true); + + ra_->set_pair(n1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); + ra_->set_pair(n2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_cond_set->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + + nodes->push(n1); + nodes->push(n_compare); + nodes->push(n2); + nodes->push(n_cond_set); + %} +%} + // src != 0, shift != 0, base != 0 instruct decodeN_notNull_addBase_Ex(iRegPdst dst, iRegNsrc src) %{ match(Set dst (DecodeN src)); @@ -6904,6 +7018,7 @@ n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && Universe::narrow_oop_shift() != 0 && Universe::narrow_oop_base() != 0); + ins_cost(2 * DEFAULT_COST); format %{ "DecodeN $dst, $src \t// $src != NULL, postalloc expanded" %} postalloc_expand( postalloc_expand_decode_oop_not_null(dst, src)); @@ -6973,13 +7088,12 @@ ins_pipe(pipe_class_default); %} -// base != 0 -// 32G aligned narrow oop base. -instruct encodePKlass_32GAligned(iRegNdst dst, iRegPsrc src) %{ +// Disjoint narrow oop base. +instruct encodePKlass_Disjoint(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodePKlass src)); predicate(false /* TODO: PPC port Universe::narrow_klass_base_disjoint()*/); - format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with 32G aligned base" %} + format %{ "EXTRDI $dst, $src, #32, #3 \t// encode with disjoint base" %} size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_rldicl); @@ -7486,7 +7600,7 @@ ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_compound); __ cmpxchgd($crx$$CondRegister, R0, $oldVal$$Register, $newVal$$Register, $mem_ptr$$Register, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + MacroAssembler::MemBarAcq, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, NULL, true); %} ins_pipe(pipe_class_default); @@ -10476,7 +10590,7 @@ match(Set crx (CmpN src1 src2)); size(4); - ins_cost(DEFAULT_COST); + ins_cost(2); format %{ "CMPLW $crx, $src1, $src2 \t// compressed ptr" %} ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_cmpl); @@ -10488,7 +10602,7 @@ instruct cmpN_reg_imm0(flagsReg crx, iRegNsrc src1, immN_0 src2) %{ match(Set crx (CmpN src1 src2)); // Make this more expensive than zeroCheckN_iReg_imm0. - ins_cost(DEFAULT_COST); + ins_cost(2); format %{ "CMPLWI $crx, $src1, $src2 \t// compressed ptr" %} size(4); @@ -10508,6 +10622,7 @@ _kids[0]->_leaf->as_Bool()->_test._test == BoolTest::ne && _leaf->as_If()->_prob >= PROB_LIKELY_MAG(4) && Matcher::branches_to_uncommon_trap(_leaf)); + ins_cost(1); // Should not be cheaper than zeroCheckN. ins_is_TrapBasedCheckNode(true); @@ -10889,7 +11004,7 @@ instruct partialSubtypeCheck(iRegPdst result, iRegP_N2P subklass, iRegP_N2P superklass, iRegPdst tmp_klass, iRegPdst tmp_arrayptr) %{ match(Set result (PartialSubtypeCheck subklass superklass)); - effect(TEMP result, TEMP tmp_klass, TEMP tmp_arrayptr); + effect(TEMP_DEF result, TEMP tmp_klass, TEMP tmp_arrayptr); ins_cost(DEFAULT_COST*10); format %{ "PartialSubtypeCheck $result = ($subklass instanceOf $superklass) tmp: $tmp_klass, $tmp_arrayptr" %} @@ -11000,7 +11115,7 @@ predicate(SpecialStringIndexOf); // type check implicit by parameter type, See Matcher::match_rule_supported match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); - effect(TEMP result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1); ins_cost(150); format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" @@ -11037,7 +11152,7 @@ iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0, flagsRegCR1 cr1) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); - effect(USE_KILL needle, /* TDEF needle, */ TEMP result, + effect(USE_KILL needle, /* TDEF needle, */ TEMP_DEF result, TEMP tmp1, TEMP tmp2); // Required for EA: check if it is still a type_array. predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && @@ -11084,7 +11199,7 @@ iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); - effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP result, + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6); // Required for EA: check if it is still a type_array. predicate(SpecialStringIndexOf && n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && @@ -11118,7 +11233,7 @@ flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6) %{ match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ - TEMP result, + TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6); predicate(SpecialStringIndexOf); // See Matcher::match_rule_supported. ins_cost(300); @@ -11142,7 +11257,7 @@ iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0, flagsRegCR6 cr6, regCTR ctr) %{ match(Set result (StrEquals (Binary str1 str2) cntImm)); - effect(TEMP result, TEMP tmp1, TEMP tmp2, + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr6, KILL ctr); predicate(SpecialStringEquals); // See Matcher::match_rule_supported. ins_cost(250); @@ -11165,7 +11280,7 @@ iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, iRegPdst tmp4, iRegPdst tmp5, flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(TEMP result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); predicate(SpecialStringEquals); // See Matcher::match_rule_supported. ins_cost(300); @@ -11188,7 +11303,7 @@ instruct string_compare(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, iRegPdst tmp, flagsRegCR0 cr0, regCTR ctr) %{ match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(USE_KILL cnt1, USE_KILL cnt2, USE_KILL str1, USE_KILL str2, TEMP result, TEMP tmp, KILL cr0, KILL ctr); + effect(USE_KILL cnt1, USE_KILL cnt2, USE_KILL str1, USE_KILL str2, TEMP_DEF result, TEMP tmp, KILL cr0, KILL ctr); ins_cost(300); ins_alignment(8); // 'compute_padding()' gets called, up to this number-1 nops will get inserted.
--- a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -483,15 +483,6 @@ } -jbyte* G1PostBarrierStub::_byte_map_base = NULL; - -jbyte* G1PostBarrierStub::byte_map_base_slow() { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->is_a(BarrierSet::G1SATBCTLogging), - "Must be if we're using this."); - return ((G1SATBCardTableModRefBS*)bs)->byte_map_base; -} - void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ bind(_entry);
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1374,6 +1374,7 @@ } void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, + Register method_counters, Register Rtmp, Label &profile_continue) { assert(ProfileInterpreter, "must be profiling interpreter"); @@ -1386,9 +1387,8 @@ br_notnull_short(ImethodDataPtr, Assembler::pn, done); // Test to see if we should create a method data oop - AddressLiteral profile_limit((address) &InvocationCounter::InterpreterProfileLimit); - sethi(profile_limit, Rtmp); - ld(Rtmp, profile_limit.low10(), Rtmp); + Address profile_limit(method_counters, MethodCounters::interpreter_profile_limit_offset()); + ld(profile_limit, Rtmp); cmp(invocation_count, Rtmp); // Use long branches because call_VM() code and following code generated by // test_backedge_count_for_osr() is large in debug VM. @@ -2375,6 +2375,7 @@ #ifndef CC_INTERP void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_count, + Register method_counters, Register branch_bcp, Register Rtmp ) { Label did_not_overflow; @@ -2382,8 +2383,8 @@ assert_different_registers(backedge_count, Rtmp, branch_bcp); assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr"); - AddressLiteral limit(&InvocationCounter::InterpreterBackwardBranchLimit); - load_contents(limit, Rtmp); + Address limit(method_counters, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset())); + ld(limit, Rtmp); cmp_and_br_short(backedge_count, Rtmp, Assembler::lessUnsigned, Assembler::pt, did_not_overflow); // When ProfileInterpreter is on, the backedge_count comes from the @@ -2500,17 +2501,13 @@ // Jump if ((*counter_addr += increment) & mask) satisfies the condition. void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask_addr, Register scratch1, Register scratch2, Condition cond, Label *where) { ld(counter_addr, scratch1); add(scratch1, increment, scratch1); - if (is_simm13(mask)) { - andcc(scratch1, mask, G0); - } else { - set(mask, scratch2); - andcc(scratch1, scratch2, G0); - } + ld(mask_addr, scratch2); + andcc(scratch1, scratch2, G0); br(cond, false, Assembler::pn, *where); delayed()->st(scratch1, counter_addr); }
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -267,7 +267,7 @@ void increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); void increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); #ifndef CC_INTERP - void test_backedge_count_for_osr( Register backedge_count, Register branch_bcp, Register Rtmp ); + void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register branch_bcp, Register Rtmp ); #endif /* CC_INTERP */ // Object locking @@ -280,7 +280,7 @@ void set_method_data_pointer_for_bcp(); void test_method_data_pointer(Label& zero_continue); void verify_method_data_pointer(); - void test_invocation_counter_for_mdp(Register invocation_count, Register Rtmp, Label &profile_continue); + void test_invocation_counter_for_mdp(Register invocation_count, Register method_counters, Register Rtmp, Label &profile_continue); void set_mdp_data_at(int constant, Register value); void increment_mdp_data_at(Address counter, Register bumped_count, @@ -291,7 +291,7 @@ Register bumped_count, Register scratch2, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask_addr, Register scratch1, Register scratch2, Condition cond, Label *where); void set_mdp_flag_at(int flag_constant, Register scratch);
--- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -282,12 +282,11 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { // Note: In tiered we increment either counters in MethodCounters* or in // MDO depending if we're profiling or not. - const Register Rcounters = G3_scratch; + const Register G3_method_counters = G3_scratch; Label done; if (TieredCompilation) { const int increment = InvocationCounter::count_increment; - const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // If no method data exists, go to profile_continue. @@ -297,6 +296,7 @@ Address mdo_invocation_counter(G4_scratch, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G4_scratch, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, G3_scratch, Lscratch, Assembler::zero, overflow); @@ -305,20 +305,21 @@ // Increment counter in MethodCounters* __ bind(no_mdo); - Address invocation_counter(Rcounters, + Address invocation_counter(G3_method_counters, in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); - __ get_method_counters(Lmethod, Rcounters, done); + __ get_method_counters(Lmethod, G3_method_counters, done); + Address mask(G3_method_counters, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, G4_scratch, Lscratch, Assembler::zero, overflow); __ bind(done); - } else { + } else { // not TieredCompilation // Update standard invocation counters - __ get_method_counters(Lmethod, Rcounters, done); - __ increment_invocation_counter(Rcounters, O0, G4_scratch); + __ get_method_counters(Lmethod, G3_method_counters, done); + __ increment_invocation_counter(G3_method_counters, O0, G4_scratch); if (ProfileInterpreter) { - Address interpreter_invocation_counter(Rcounters, + Address interpreter_invocation_counter(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_counter_offset())); __ ld(interpreter_invocation_counter, G4_scratch); __ inc(G4_scratch); @@ -327,16 +328,16 @@ if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - AddressLiteral profile_limit((address)&InvocationCounter::InterpreterProfileLimit); - __ load_contents(profile_limit, G3_scratch); - __ cmp_and_br_short(O0, G3_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue); + Address profile_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_profile_limit_offset())); + __ ld(profile_limit, G1_scratch); + __ cmp_and_br_short(O0, G1_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(*profile_method); } - AddressLiteral invocation_limit((address)&InvocationCounter::InterpreterInvocationLimit); - __ load_contents(invocation_limit, G3_scratch); + Address invocation_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_limit_offset())); + __ ld(invocation_limit, G3_scratch); __ cmp(O0, G3_scratch); __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); // Far distance __ delayed()->nop();
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1599,13 +1599,12 @@ // Bump bytecode pointer by displacement (take the branch) __ delayed()->add( O1_disp, Lbcp, Lbcp ); // add to bc addr - const Register Rcounters = G3_scratch; - __ get_method_counters(Lmethod, Rcounters, Lforward); + const Register G3_method_counters = G3_scratch; + __ get_method_counters(Lmethod, G3_method_counters, Lforward); if (TieredCompilation) { Label Lno_mdo, Loverflow; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // If no method data exists, go to profile_continue. __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch); @@ -1614,6 +1613,7 @@ // Increment backedge counter in the MDO Address mdo_backedge_counter(G4_scratch, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G4_scratch, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, O0, Assembler::notZero, &Lforward); __ ba_short(Loverflow); @@ -1621,9 +1621,10 @@ // If there's no MDO, increment counter in MethodCounters* __ bind(Lno_mdo); - Address backedge_counter(Rcounters, + Address backedge_counter(G3_method_counters, in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + Address mask(G3_method_counters, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(backedge_counter, increment, mask, G4_scratch, O0, Assembler::notZero, &Lforward); __ bind(Loverflow); @@ -1663,18 +1664,19 @@ __ jmp(O2, G0); __ delayed()->nop(); - } else { + } else { // not TieredCompilation // Update Backedge branch separately from invocations const Register G4_invoke_ctr = G4; - __ increment_backedge_counter(Rcounters, G4_invoke_ctr, G1_scratch); + __ increment_backedge_counter(G3_method_counters, G4_invoke_ctr, G1_scratch); if (ProfileInterpreter) { - __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_scratch, Lforward); + __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_method_counters, G1_scratch, Lforward); if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(O2_bumped_count, l_cur_bcp, G3_scratch); + + __ test_backedge_count_for_osr(O2_bumped_count, G3_method_counters, l_cur_bcp, G1_scratch); } } else { if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(G4_invoke_ctr, l_cur_bcp, G3_scratch); + __ test_backedge_count_for_osr(G4_invoke_ctr, G3_method_counters, l_cur_bcp, G1_scratch); } } }
--- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -541,15 +541,6 @@ } -jbyte* G1PostBarrierStub::_byte_map_base = NULL; - -jbyte* G1PostBarrierStub::byte_map_base_slow() { - BarrierSet* bs = Universe::heap()->barrier_set(); - assert(bs->is_a(BarrierSet::G1SATBCTLogging), - "Must be if we're using this."); - return ((G1SATBCardTableModRefBS*)bs)->byte_map_base; -} - void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); assert(addr()->is_register(), "Precondition.");
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1360,7 +1360,7 @@ // Jump if ((*counter_addr += increment) & mask) satisfies the condition. void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where) { if (!preloaded) {
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -182,7 +182,7 @@ void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant);
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1426,7 +1426,7 @@ // Jump if ((*counter_addr += increment) & mask) satisfies the condition. void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where) { if (!preloaded) {
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -191,7 +191,7 @@ void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); void increment_mask_and_jump(Address counter_addr, - int increment, int mask, + int increment, Address mask, Register scratch, bool preloaded, Condition cond, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant);
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -346,7 +346,6 @@ // depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -356,6 +355,7 @@ // Increment counter in the MDO const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ jmp(done); } @@ -366,11 +366,12 @@ InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); + const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ bind(done); - } else { - const Address backedge_counter (rax, + } else { // not TieredCompilation + const Address backedge_counter(rax, MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); const Address invocation_counter(rax, @@ -400,16 +401,16 @@ if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(rax, *profile_method); } - __ cmp32(rcx, - ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset()))); __ jcc(Assembler::aboveEqual, *overflow); __ bind(done); }
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -299,7 +299,6 @@ // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. if (TieredCompilation) { int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -309,6 +308,7 @@ // Increment counter in the MDO const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ jmp(done); } @@ -318,10 +318,11 @@ MethodCounters::invocation_counter_offset() + InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); + const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); __ bind(done); - } else { + } else { // not TieredCompilation const Address backedge_counter(rax, MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset()); @@ -350,14 +351,16 @@ if (ProfileInterpreter && profile_method != NULL) { // Test to see if we should create a method data oop - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, *profile_method_continue); // if no method data exists, go to profile_method __ test_method_data_pointer(rax, *profile_method); } - __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterInvocationLimit)); + __ movptr(rax, Address(rbx, Method::method_counters_offset())); + __ cmp32(rcx, Address(rax, in_bytes(MethodCounters::interpreter_invocation_limit_offset()))); __ jcc(Assembler::aboveEqual, *overflow); __ bind(done); }
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1621,7 +1621,6 @@ if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -1630,6 +1629,7 @@ // Increment the MDO backedge counter const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); __ jmp(dispatch); @@ -1637,9 +1637,10 @@ __ bind(no_mdo); // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); + const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); - } else { + } else { // not TieredCompilation // increment counter __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter @@ -1653,8 +1654,7 @@ if (ProfileInterpreter) { // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, dispatch); // if no method data exists, go to profile method @@ -1662,8 +1662,7 @@ if (UseOnStackReplacement) { // check for overflow against rbx, which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rbx, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::below, dispatch); // When ProfileInterpreter is on, the backedge_count comes from the @@ -1678,8 +1677,7 @@ } else { if (UseOnStackReplacement) { // check for overflow against rax, which is the sum of the counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::aboveEqual, backedge_counter_overflow); }
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1642,7 +1642,6 @@ if (TieredCompilation) { Label no_mdo; int increment = InvocationCounter::count_increment; - int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -1651,6 +1650,7 @@ // Increment the MDO backedge counter const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); + const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); __ jmp(dispatch); @@ -1658,9 +1658,10 @@ __ bind(no_mdo); // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); + const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, rax, false, Assembler::zero, &backedge_counter_overflow); - } else { + } else { // not TieredCompilation // increment counter __ movptr(rcx, Address(rcx, Method::method_counters_offset())); __ movl(rax, Address(rcx, be_offset)); // load backedge counter @@ -1674,8 +1675,7 @@ if (ProfileInterpreter) { // Test to see if we should create a method data oop - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_profile_limit_offset()))); __ jcc(Assembler::less, dispatch); // if no method data exists, go to profile method @@ -1683,8 +1683,7 @@ if (UseOnStackReplacement) { // check for overflow against ebx which is the MDO taken count - __ cmp32(rbx, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rbx, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::below, dispatch); // When ProfileInterpreter is on, the backedge_count comes @@ -1702,8 +1701,7 @@ if (UseOnStackReplacement) { // check for overflow against eax, which is the sum of the // counters - __ cmp32(rax, - ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit)); + __ cmp32(rax, Address(rcx, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()))); __ jcc(Assembler::aboveEqual, backedge_counter_overflow); }
--- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -31,6 +31,7 @@ #include "os_aix.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/perfMemory.hpp" +#include "services/memTracker.hpp" #include "utilities/exceptions.hpp" // put OS-includes here @@ -196,12 +197,37 @@ return pid; } +// Check if the given statbuf is considered a secure directory for +// the backing store files. Returns true if the directory is considered +// a secure location. Returns false if the statbuf is a symbolic link or +// if an error occurred. +static bool is_statbuf_secure(struct stat *statp) { + if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { + // The path represents a link or some non-directory file type, + // which is not what we expected. Declare it insecure. + // + return false; + } + // We have an existing directory, check if the permissions are safe. + if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { + // The directory is open for writing and could be subjected + // to a symlink or a hard link attack. Declare it insecure. + return false; + } + // See if the uid of the directory matches the effective uid of the process. + // + if (statp->st_uid != geteuid()) { + // The directory was not created by this user, declare it insecure. + return false; + } + return true; +} -// check if the given path is considered a secure directory for + +// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. -// static bool is_directory_secure(const char* path) { struct stat statbuf; int result = 0; @@ -211,38 +237,276 @@ return false; } - // the path exists, now check it's mode - if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { - // the path represents a link or some non-directory file type, - // which is not what we expected. declare it insecure. - // + // The path exists, see if it is secure. + return is_statbuf_secure(&statbuf); +} + +// (Taken over from Solaris to support the O_NOFOLLOW case on AIX.) +// Check if the given directory file descriptor is considered a secure +// directory for the backing store files. Returns true if the directory +// exists and is considered a secure location. Returns false if the path +// is a symbolic link or if an error occurred. +static bool is_dirfd_secure(int dir_fd) { + struct stat statbuf; + int result = 0; + + RESTARTABLE(::fstat(dir_fd, &statbuf), result); + if (result == OS_ERR) { return false; } - else { - // we have an existing directory, check if the permissions are safe. - // - if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // the directory is open for writing and could be subjected - // to a symlnk attack. declare it insecure. - // - return false; + + // The path exists, now check its mode. + return is_statbuf_secure(&statbuf); +} + + +// Check to make sure fd1 and fd2 are referencing the same file system object. +static bool is_same_fsobject(int fd1, int fd2) { + struct stat statbuf1; + struct stat statbuf2; + int result = 0; + + RESTARTABLE(::fstat(fd1, &statbuf1), result); + if (result == OS_ERR) { + return false; + } + RESTARTABLE(::fstat(fd2, &statbuf2), result); + if (result == OS_ERR) { + return false; + } + + if ((statbuf1.st_ino == statbuf2.st_ino) && + (statbuf1.st_dev == statbuf2.st_dev)) { + return true; + } else { + return false; + } +} + +// Helper functions for open without O_NOFOLLOW which is not present on AIX 5.3/6.1. +// We use the jdk6 implementation here. +#ifndef O_NOFOLLOW +// The O_NOFOLLOW oflag doesn't exist before solaris 5.10, this is to simulate that behaviour +// was done in jdk 5/6 hotspot by Oracle this way +static int open_o_nofollow_impl(const char* path, int oflag, mode_t mode, bool use_mode) { + struct stat orig_st; + struct stat new_st; + bool create; + int error; + int fd; + + create = false; + + if (lstat(path, &orig_st) != 0) { + if (errno == ENOENT && (oflag & O_CREAT) != 0) { + // File doesn't exist, but_we want to create it, add O_EXCL flag + // to make sure no-one creates it (or a symlink) before us + // This works as we expect with symlinks, from posix man page: + // 'If O_EXCL and O_CREAT are set, and path names a symbolic + // link, open() shall fail and set errno to [EEXIST]'. + oflag |= O_EXCL; + create = true; + } else { + // File doesn't exist, and we are not creating it. + return OS_ERR; } + } else { + // Lstat success, check if existing file is a link. + if ((orig_st.st_mode & S_IFMT) == S_IFLNK) { + // File is a symlink. + errno = ELOOP; + return OS_ERR; + } + } + + if (use_mode == true) { + fd = open(path, oflag, mode); + } else { + fd = open(path, oflag); + } + + if (fd == OS_ERR) { + return fd; + } + + // Can't do inode checks on before/after if we created the file. + if (create == false) { + if (fstat(fd, &new_st) != 0) { + // Keep errno from fstat, in case close also fails. + error = errno; + ::close(fd); + errno = error; + return OS_ERR; + } + + if (orig_st.st_dev != new_st.st_dev || orig_st.st_ino != new_st.st_ino) { + // File was tampered with during race window. + ::close(fd); + errno = EEXIST; + if (PrintMiscellaneous && Verbose) { + warning("possible file tampering attempt detected when opening %s", path); + } + return OS_ERR; + } + } + + return fd; +} + +static int open_o_nofollow(const char* path, int oflag, mode_t mode) { + return open_o_nofollow_impl(path, oflag, mode, true); +} + +static int open_o_nofollow(const char* path, int oflag) { + return open_o_nofollow_impl(path, oflag, 0, false); +} +#endif + +// Open the directory of the given path and validate it. +// Return a DIR * of the open directory. +static DIR *open_directory_secure(const char* dirname) { + // Open the directory using open() so that it can be verified + // to be secure by calling is_dirfd_secure(), opendir() and then check + // to see if they are the same file system object. This method does not + // introduce a window of opportunity for the directory to be attacked that + // calling opendir() and is_directory_secure() does. + int result; + DIR *dirp = NULL; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case. +#ifdef O_NOFOLLOW + RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); +#else + // workaround (jdk6 coding) + RESTARTABLE(::open_o_nofollow(dirname, O_RDONLY), result); +#endif + + if (result == OS_ERR) { + // Directory doesn't exist or is a symlink, so there is nothing to cleanup. + if (PrintMiscellaneous && Verbose) { + if (errno == ELOOP) { + warning("directory %s is a symlink and is not secure\n", dirname); + } else { + warning("could not open directory %s: %s\n", dirname, strerror(errno)); + } + } + return dirp; + } + int fd = result; + + // Determine if the open directory is secure. + if (!is_dirfd_secure(fd)) { + // The directory is not a secure directory. + os::close(fd); + return dirp; + } + + // Open the directory. + dirp = ::opendir(dirname); + if (dirp == NULL) { + // The directory doesn't exist, close fd and return. + os::close(fd); + return dirp; + } + + // Check to make sure fd and dirp are referencing the same file system object. + if (!is_same_fsobject(fd, dirp->dd_fd)) { + // The directory is not secure. + os::close(fd); + os::closedir(dirp); + dirp = NULL; + return dirp; + } + + // Close initial open now that we know directory is secure + os::close(fd); + + return dirp; +} + +// NOTE: The code below uses fchdir(), open() and unlink() because +// fdopendir(), openat() and unlinkat() are not supported on all +// versions. Once the support for fdopendir(), openat() and unlinkat() +// is available on all supported versions the code can be changed +// to use these functions. + +// Open the directory of the given path, validate it and set the +// current working directory to it. +// Return a DIR * of the open directory and the saved cwd fd. +// +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { + + // Open the directory. + DIR* dirp = open_directory_secure(dirname); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so there is nothing to cleanup. + return dirp; + } + int fd = dirp->dd_fd; + + // Open a fd to the cwd and save it off. + int result; + RESTARTABLE(::open(".", O_RDONLY), result); + if (result == OS_ERR) { + *saved_cwd_fd = -1; + } else { + *saved_cwd_fd = result; + } + + // Set the current directory to dirname by using the fd of the directory. + result = fchdir(fd); + + return dirp; +} + +// Close the directory and restore the current working directory. +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { + + int result; + // If we have a saved cwd change back to it and close the fd. + if (saved_cwd_fd != -1) { + result = fchdir(saved_cwd_fd); + ::close(saved_cwd_fd); + } + + // Close the directory. + os::closedir(dirp); +} + +// Check if the given file descriptor is considered a secure. +static bool is_file_secure(int fd, const char *filename) { + + int result; + struct stat statbuf; + + // Determine if the file is secure. + RESTARTABLE(::fstat(fd, &statbuf), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("fstat failed on %s: %s\n", filename, strerror(errno)); + } + return false; + } + if (statbuf.st_nlink > 1) { + // A file with multiple links is not expected. + if (PrintMiscellaneous && Verbose) { + warning("file %s has multiple links\n", filename); + } + return false; } return true; } - -// return the user name for the given user id +// Return the user name for the given user id. // -// the caller is expected to free the allocated memory. -// +// The caller is expected to free the allocated memory. static char* get_user_name(uid_t uid) { struct passwd pwent; - // determine the max pwbuf size from sysconf, and hardcode + // Determine the max pwbuf size from sysconf, and hardcode // a default if this not available through sysconf. - // long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (bufsize == -1) bufsize = 1024; @@ -344,7 +608,8 @@ strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); - DIR* subdirp = os::opendir(usrdir_name); + // Open the user directory. + DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name); @@ -464,28 +729,7 @@ } } - -// remove file -// -// this method removes the file with the given file name in the -// named directory. -// -static void remove_file(const char* dirname, const char* filename) { - - size_t nbytes = strlen(dirname) + strlen(filename) + 2; - char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - strcpy(path, dirname); - strcat(path, "/"); - strcat(path, filename); - - remove_file(path); - - FREE_C_HEAP_ARRAY(char, path); -} - - -// cleanup stale shared memory resources +// Cleanup stale shared memory resources // // This method attempts to remove all stale shared memory files in // the named user temporary directory. It scans the named directory @@ -493,33 +737,26 @@ // process id is extracted from the file name and a test is run to // determine if the process is alive. If the process is not alive, // any stale file resources are removed. -// static void cleanup_sharedmem_resources(const char* dirname) { - // open the user temp directory - DIR* dirp = os::opendir(dirname); - + int saved_cwd_fd; + // Open the directory. + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); if (dirp == NULL) { - // directory doesn't exist, so there is nothing to cleanup + // Directory doesn't exist or is insecure, so there is nothing to cleanup. return; } - if (!is_directory_secure(dirname)) { - // the directory is not a secure directory - os::closedir(dirp); - return; - } - - // for each entry in the directory that matches the expected file + // For each entry in the directory that matches the expected file // name pattern, determine if the file resources are stale and if // so, remove the file resources. Note, instrumented HotSpot processes // for this user may start and/or terminate during this search and // remove or create new files in this directory. The behavior of this // loop under these conditions is dependent upon the implementation of // opendir/readdir. - // struct dirent* entry; char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal); + errno = 0; while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) { @@ -529,56 +766,55 @@ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - // attempt to remove all unexpected files, except "." and ".." - remove_file(dirname, entry->d_name); + // Attempt to remove all unexpected files, except "." and "..". + unlink(entry->d_name); } errno = 0; continue; } - // we now have a file name that converts to a valid integer + // We now have a file name that converts to a valid integer // that could represent a process id . if this process id // matches the current process id or the process is not running, // then remove the stale file resources. // - // process liveness is detected by sending signal number 0 to + // Process liveness is detected by sending signal number 0 to // the process id (see kill(2)). if kill determines that the // process does not exist, then the file resources are removed. // if kill determines that that we don't have permission to // signal the process, then the file resources are assumed to // be stale and are removed because the resources for such a // process should be in a different user specific directory. - // if ((pid == os::current_process_id()) || (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - remove_file(dirname, entry->d_name); + unlink(entry->d_name); } errno = 0; } - os::closedir(dirp); - FREE_C_HEAP_ARRAY(char, dbuf); + + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); } -// make the user specific temporary directory. Returns true if +// Make the user specific temporary directory. Returns true if // the directory exists and is secure upon return. Returns false // if the directory exists but is either a symlink, is otherwise // insecure, or if an error occurred. -// static bool make_user_tmp_dir(const char* dirname) { - // create the directory with 0755 permissions. note that the directory + // Create the directory with 0755 permissions. note that the directory // will be owned by euid::egid, which may not be the same as uid::gid. - // if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) { if (errno == EEXIST) { // The directory already exists and was probably created by another // JVM instance. However, this could also be the result of a // deliberate symlink. Verify that the existing directory is safe. - // if (!is_directory_secure(dirname)) { - // directory is not secure + // Directory is not secure. if (PrintMiscellaneous && Verbose) { warning("%s directory is insecure\n", dirname); } @@ -614,19 +850,63 @@ return -1; } + int saved_cwd_fd; + // Open the directory and set the current working directory to it. + DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); + if (dirp == NULL) { + // Directory doesn't exist or is insecure, so cannot create shared + // memory file. + return -1; + } + + // Open the filename in the current directory. + // Cannot use O_TRUNC here; truncation of an existing file has to happen + // after the is_file_secure() check below. int result; - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result); + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case. +#ifdef O_NOFOLLOW + RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); +#else + // workaround function (jdk6 code) + RESTARTABLE(::open_o_nofollow(filename, O_RDWR|O_CREAT, S_IREAD|S_IWRITE), result); +#endif + if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { - warning("could not create file %s: %s\n", filename, strerror(errno)); + if (errno == ELOOP) { + warning("file %s is a symlink and is not secure\n", filename); + } else { + warning("could not create file %s: %s\n", filename, strerror(errno)); + } } + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); + return -1; } + // Close the directory and reset the current working directory. + close_directory_secure_cwd(dirp, saved_cwd_fd); // save the file descriptor int fd = result; + // Check to see if the file is secure. + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + // Truncate the file to get rid of any existing data. + RESTARTABLE(::ftruncate(fd, (off_t)0), result); + if (result == OS_ERR) { + if (PrintMiscellaneous && Verbose) { + warning("could not truncate shared memory file: %s\n", strerror(errno)); + } + ::close(fd); + return -1; + } // set the file size RESTARTABLE(::ftruncate(fd, (off_t)size), result); if (result == OS_ERR) { @@ -648,7 +928,14 @@ // open the file int result; + // No O_NOFOLLOW defined at buildtime, and it is not documented for open; + // so provide a workaround in this case +#ifdef O_NOFOLLOW RESTARTABLE(::open(filename, oflags), result); +#else + RESTARTABLE(::open_o_nofollow(filename, oflags), result); +#endif + if (result == OS_ERR) { if (errno == ENOENT) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), @@ -662,8 +949,15 @@ THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); } } + int fd = result; - return result; + // Check to see if the file is secure. + if (!is_file_secure(fd, filename)) { + ::close(fd); + return -1; + } + + return fd; } // create a named shared memory region. returns the address of the @@ -695,13 +989,21 @@ char* dirname = get_user_tmp_dir(user_name); char* filename = get_sharedmem_filename(dirname, vmid); + // Get the short filename. + char* short_filename = strrchr(filename, '/'); + if (short_filename == NULL) { + short_filename = filename; + } else { + short_filename++; + } + // cleanup any stale shared memory files cleanup_sharedmem_resources(dirname); assert(((size > 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemory region size"); - fd = create_sharedmem_resources(dirname, filename, size); + fd = create_sharedmem_resources(dirname, short_filename, size); FREE_C_HEAP_ARRAY(char, user_name); FREE_C_HEAP_ARRAY(char, dirname); @@ -733,6 +1035,9 @@ // clear the shared memory region (void)::memset((void*) mapAddress, 0, size); + // It does not go through os api, the operation has to record from here. + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal); + return mapAddress; } @@ -807,7 +1112,7 @@ char* mapAddress; int result; int fd; - size_t size; + size_t size = 0; const char* luser = NULL; int mmap_prot; @@ -819,12 +1124,18 @@ // constructs for the file and the shared memory mapping. if (mode == PerfMemory::PERF_MODE_RO) { mmap_prot = PROT_READ; + + // No O_NOFOLLOW defined at buildtime, and it is not documented for open. +#ifdef O_NOFOLLOW + file_flags = O_RDONLY | O_NOFOLLOW; +#else file_flags = O_RDONLY; +#endif } else if (mode == PerfMemory::PERF_MODE_RW) { #ifdef LATER mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR; + file_flags = O_RDWR | O_NOFOLLOW; #else THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Unsupported access mode"); @@ -853,9 +1164,9 @@ // store file, we don't follow them when attaching either. // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); + FREE_C_HEAP_ARRAY(char, dirname, mtInternal); if (luser != user) { - FREE_C_HEAP_ARRAY(char, luser); + FREE_C_HEAP_ARRAY(char, luser, mtInternal); } THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); @@ -901,6 +1212,9 @@ "Could not map PerfMemory"); } + // It does not go through os api, the operation has to record from here. + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal); + *addr = mapAddress; *sizep = size;
--- a/hotspot/src/os/windows/vm/os_windows.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -428,9 +428,9 @@ } // Diagnostic code to investigate JDK-6573254 - int res = 50115; // non-java thread + int res = 30115; // non-java thread if (thread->is_Java_thread()) { - res = 40115; // java thread + res = 20115; // java thread } // Install a win32 structured exception handler around every thread created @@ -3791,6 +3791,7 @@ static INIT_ONCE init_once_crit_sect = INIT_ONCE_STATIC_INIT; static CRITICAL_SECTION crit_sect; + static volatile jint process_exiting = 0; int i, j; DWORD res; HANDLE hproc, hthr; @@ -3798,10 +3799,10 @@ // The first thread that reached this point, initializes the critical section. if (!InitOnceExecuteOnce(&init_once_crit_sect, init_crit_sect_call, &crit_sect, NULL)) { warning("crit_sect initialization failed in %s: %d\n", __FILE__, __LINE__); - } else { + } else if (OrderAccess::load_acquire(&process_exiting) == 0) { EnterCriticalSection(&crit_sect); - if (what == EPT_THREAD) { + if (what == EPT_THREAD && OrderAccess::load_acquire(&process_exiting) == 0) { // Remove from the array those handles of the threads that have completed exiting. for (i = 0, j = 0; i < handle_count; ++i) { res = WaitForSingleObject(handles[i], 0 /* don't wait */); @@ -3856,7 +3857,7 @@ // The current exiting thread has stored its handle in the array, and now // should leave the critical section before calling _endthreadex(). - } else { // what != EPT_THREAD + } else if (what != EPT_THREAD) { if (handle_count > 0) { // Before ending the process, make sure all the threads that had called // _endthreadex() completed. @@ -3882,24 +3883,28 @@ handle_count = 0; } - // End the process, not leaving critical section. - // This makes sure no other thread executes exit-related code at the same - // time, thus a race is avoided. - if (what == EPT_PROCESS) { - ::exit(exit_code); - } else { - _exit(exit_code); - } + OrderAccess::release_store(&process_exiting, 1); } LeaveCriticalSection(&crit_sect); } + + if (what == EPT_THREAD) { + while (OrderAccess::load_acquire(&process_exiting) != 0) { + // Some other thread is about to call exit(), so we + // don't let the current thread proceed to _endthreadex() + SuspendThread(GetCurrentThread()); + // Avoid busy-wait loop, if SuspendThread() failed. + Sleep(EXIT_TIMEOUT); + } + } } // We are here if either // - there's no 'race at exit' bug on this OS release; // - initialization of the critical section failed (unlikely); - // - the current thread has stored its handle and left the critical section. + // - the current thread has stored its handle and left the critical section; + // - the process-exiting thread has raised the flag and left the critical section. if (what == EPT_THREAD) { _endthreadex((unsigned)exit_code); } else if (what == EPT_PROCESS) {
--- a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -601,15 +601,6 @@ LIR_Opr _addr; LIR_Opr _new_val; - static jbyte* _byte_map_base; - static jbyte* byte_map_base_slow(); - static jbyte* byte_map_base() { - if (_byte_map_base == NULL) { - _byte_map_base = byte_map_base_slow(); - } - return _byte_map_base; - } - public: // addr (the address of the object head) and new_val must be registers. G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { }
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -32,6 +32,7 @@ #include "ci/ciArrayKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObjArray.hpp" +#include "runtime/arguments.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/vm_version.hpp" @@ -3351,7 +3352,12 @@ if (!x->inlinee()->is_accessor()) { CodeEmitInfo* info = state_for(x, x->state(), true); // Notify the runtime very infrequently only to take care of counter overflows - increment_event_counter_impl(info, x->inlinee(), (1 << Tier23InlineeNotifyFreqLog) - 1, InvocationEntryBci, false, true); + int freq_log = Tier23InlineeNotifyFreqLog; + double scale; + if (_method->has_option_value("CompileThresholdScaling", scale)) { + freq_log = Arguments::scaled_freq_log(freq_log, scale); + } + increment_event_counter_impl(info, x->inlinee(), right_n_bits(freq_log), InvocationEntryBci, false, true); } } @@ -3366,7 +3372,11 @@ ShouldNotReachHere(); } // Increment the appropriate invocation/backedge counter and notify the runtime. - increment_event_counter_impl(info, info->scope()->method(), (1 << freq_log) - 1, bci, backedge, true); + double scale; + if (_method->has_option_value("CompileThresholdScaling", scale)) { + freq_log = Arguments::scaled_freq_log(freq_log, scale); + } + increment_event_counter_impl(info, info->scope()->method(), right_n_bits(freq_log), bci, backedge, true); } void LIRGenerator::decrement_age(CodeEmitInfo* info) {
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,6 +221,30 @@ return (const char*)end; } +template <class T, class N> void CompactHashtable<T, N>::symbols_do(SymbolClosure *cl) { + assert(!DumpSharedSpaces, "run-time only"); + for (juint i = 0; i < _bucket_count; i ++) { + juint bucket_info = _buckets[i]; + juint bucket_offset = BUCKET_OFFSET(bucket_info); + int bucket_type = BUCKET_TYPE(bucket_info); + juint* bucket = _buckets + bucket_offset; + juint* bucket_end = _buckets; + + Symbol* sym; + if (bucket_type == COMPACT_BUCKET_TYPE) { + sym = (Symbol*)((void*)(_base_address + bucket[0])); + cl->do_symbol(&sym); + } else { + bucket_end += BUCKET_OFFSET(_buckets[i + 1]); + while (bucket < bucket_end) { + sym = (Symbol*)((void*)(_base_address + bucket[1])); + cl->do_symbol(&sym); + bucket += 2; + } + } + } +} + // Explicitly instantiate these types template class CompactHashtable<Symbol*, char>;
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,9 @@ } return NULL; } + + // iterate over symbols + void symbols_do(SymbolClosure *cl); }; ////////////////////////////////////////////////////////////////////////
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,10 @@ // Call function for all symbols in the symbol table. void SymbolTable::symbols_do(SymbolClosure *cl) { + // all symbols from shared table + _shared_table.symbols_do(cl); + + // all symbols from the dynamic table const int n = the_table()->table_size(); for (int i = 0; i < n; i++) { for (HashtableEntry<Symbol*, mtSymbol>* p = the_table()->bucket(i);
--- a/hotspot/src/share/vm/classfile/verifier.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1546,10 +1546,15 @@ no_control_flow = true; break; case Bytecodes::_getstatic : case Bytecodes::_putstatic : + // pass TRUE, operand can be an array type for getstatic/putstatic. + verify_field_instructions( + &bcs, ¤t_frame, cp, true, CHECK_VERIFY(this)); + no_control_flow = false; break; case Bytecodes::_getfield : case Bytecodes::_putfield : + // pass FALSE, operand can't be an array type for getfield/putfield. verify_field_instructions( - &bcs, ¤t_frame, cp, CHECK_VERIFY(this)); + &bcs, ¤t_frame, cp, false, CHECK_VERIFY(this)); no_control_flow = false; break; case Bytecodes::_invokevirtual : case Bytecodes::_invokespecial : @@ -2107,6 +2112,7 @@ void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, StackMapFrame* current_frame, constantPoolHandle cp, + bool allow_arrays, TRAPS) { u2 index = bcs->get_index_u2(); verify_cp_type(bcs->bci(), index, cp, @@ -2126,8 +2132,8 @@ // Get referenced class type VerificationType ref_class_type = cp_ref_index_to_type( index, cp, CHECK_VERIFY(this)); - if (!ref_class_type.is_object()) { - /* Unreachable? Class file parser verifies Fieldref contents */ + if (!ref_class_type.is_object() && + (!allow_arrays || !ref_class_type.is_array())) { verify_error(ErrorContext::bad_type(bcs->bci(), TypeOrigin::cp(index, ref_class_type)), "Expecting reference to class in class %s at constant pool index %d",
--- a/hotspot/src/share/vm/classfile/verifier.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/classfile/verifier.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -297,7 +297,7 @@ void verify_field_instructions( RawBytecodeStream* bcs, StackMapFrame* current_frame, - constantPoolHandle cp, TRAPS); + constantPoolHandle cp, bool allow_arrays, TRAPS); void verify_invoke_init( RawBytecodeStream* bcs, u2 ref_index, VerificationType ref_class_type,
--- a/hotspot/src/share/vm/code/codeCache.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -233,8 +233,8 @@ ReservedCodeSpace CodeCache::reserve_heap_memory(size_t size) { // Determine alignment const size_t page_size = os::can_execute_large_page_memory() ? - MIN2(os::page_size_for_region(InitialCodeCacheSize, 8), - os::page_size_for_region(size, 8)) : + MIN2(os::page_size_for_region_aligned(InitialCodeCacheSize, 8), + os::page_size_for_region_aligned(size, 8)) : os::vm_page_size(); const size_t granularity = os::vm_allocation_granularity(); const size_t r_align = MAX2(page_size, granularity);
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1470,7 +1470,9 @@ // The method may be explicitly excluded by the user. bool quietly; - if (CompilerOracle::should_exclude(method, quietly)) { + double scale; + if (CompilerOracle::should_exclude(method, quietly) + || (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) { if (!quietly) { // This does not happen quietly... ResourceMark rm;
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -162,8 +162,8 @@ "we should have already filtered out humongous regions"); assert(_end == orig_end(), "we should have already filtered out humongous regions"); - - _in_collection_set = false; + assert(!_in_collection_set, + err_msg("Should not clear heap region %u in the collection set", hrm_index())); set_allocation_context(AllocationContext::system()); set_young_index_in_cset(-1);
--- a/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1194,8 +1194,10 @@ return real_forwardee(old); } - new_obj = _next_gen->par_promote(par_scan_state->thread_num(), - old, m, sz); + if (!_promotion_failed) { + new_obj = _next_gen->par_promote(par_scan_state->thread_num(), + old, m, sz); + } if (new_obj == NULL) { // promotion failed, forward to self
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/generationSizer.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -61,9 +61,9 @@ void GenerationSizer::initialize_size_info() { trace_gen_sizes("ps heap raw"); - const size_t max_page_sz = os::page_size_for_region(_max_heap_byte_size, 8); + const size_t max_page_sz = os::page_size_for_region_aligned(_max_heap_byte_size, 8); const size_t min_pages = 4; // 1 for eden + 1 for each survivor + 1 for old - const size_t min_page_sz = os::page_size_for_region(_min_heap_byte_size, min_pages); + const size_t min_page_sz = os::page_size_for_region_aligned(_min_heap_byte_size, min_pages); const size_t page_sz = MIN2(max_page_sz, min_page_sz); // Can a page size be something else than a power of two?
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -41,7 +41,7 @@ const size_t words = bits / BitsPerWord; const size_t raw_bytes = words * sizeof(idx_t); - const size_t page_sz = os::page_size_for_region(raw_bytes, 10); + const size_t page_sz = os::page_size_for_region_aligned(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity));
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -403,7 +403,7 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size) { const size_t raw_bytes = count * element_size; - const size_t page_sz = os::page_size_for_region(raw_bytes, 10); + const size_t page_sz = os::page_size_for_region_aligned(raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity));
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -53,7 +53,7 @@ /* * USELABELS - If using GCC, then use labels for the opcode dispatching * rather -then a switch statement. This improves performance because it - * gives us the oportunity to have the instructions that calculate the + * gives us the opportunity to have the instructions that calculate the * next opcode to jump to be intermixed with the rest of the instructions * that implement the opcode (see UPDATE_PC_AND_TOS_AND_CONTINUE macro). */
--- a/hotspot/src/share/vm/interpreter/invocationCounter.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/interpreter/invocationCounter.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -36,7 +36,7 @@ // Implementation notes: For space reasons, state & counter are both encoded in one word, // The state is encoded using some of the least significant bits, the counter is using the // more significant bits. The counter is incremented before a method is activated and an -// action is triggered when when count() > limit(). +// action is triggered when count() > limit(). class InvocationCounter VALUE_OBJ_CLASS_SPEC { friend class VMStructs; @@ -48,7 +48,6 @@ number_of_state_bits = 2, number_of_carry_bits = 1, number_of_noncount_bits = number_of_state_bits + number_of_carry_bits, - number_of_count_bits = BitsPerInt - number_of_noncount_bits, state_limit = nth_bit(number_of_state_bits), count_grain = nth_bit(number_of_state_bits + number_of_carry_bits), carry_mask = right_n_bits(number_of_carry_bits) << number_of_state_bits, @@ -68,6 +67,7 @@ count_increment = count_grain, // use this value to increment the 32bit _counter word count_mask_value = count_mask, // use this value to mask the backedge counter count_shift = number_of_noncount_bits, + number_of_count_bits = BitsPerInt - number_of_noncount_bits, count_limit = nth_bit(number_of_count_bits - 1) };
--- a/hotspot/src/share/vm/memory/heap.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/memory/heap.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -104,8 +104,8 @@ size_t page_size = os::vm_page_size(); if (os::can_execute_large_page_memory()) { const size_t min_pages = 8; - page_size = MIN2(os::page_size_for_region(committed_size, min_pages), - os::page_size_for_region(rs.size(), min_pages)); + page_size = MIN2(os::page_size_for_region_aligned(committed_size, min_pages), + os::page_size_for_region_aligned(rs.size(), min_pages)); } const size_t granularity = os::vm_allocation_granularity();
--- a/hotspot/src/share/vm/oops/method.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/oops/method.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -412,15 +412,14 @@ } methodHandle mh(m); - ClassLoaderData* loader_data = mh->method_holder()->class_loader_data(); - MethodCounters* counters = MethodCounters::allocate(loader_data, THREAD); + MethodCounters* counters = MethodCounters::allocate(mh, THREAD); if (HAS_PENDING_EXCEPTION) { CompileBroker::log_metaspace_failure(); ClassLoaderDataGraph::set_metaspace_oom(true); return NULL; // return the exception (which is cleared) } if (!mh->init_method_counters(counters)) { - MetadataFactory::free_metadata(loader_data, counters); + MetadataFactory::free_metadata(mh->method_holder()->class_loader_data(), counters); } return mh->method_counters(); }
--- a/hotspot/src/share/vm/oops/methodCounters.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/oops/methodCounters.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -23,10 +23,11 @@ */ #include "precompiled.hpp" #include "oops/methodCounters.hpp" -#include "runtime/thread.inline.hpp" +#include "runtime/handles.inline.hpp" -MethodCounters* MethodCounters::allocate(ClassLoaderData* loader_data, TRAPS) { - return new(loader_data, size(), false, MetaspaceObj::MethodCountersType, THREAD) MethodCounters(); +MethodCounters* MethodCounters::allocate(methodHandle mh, TRAPS) { + ClassLoaderData* loader_data = mh->method_holder()->class_loader_data(); + return new(loader_data, size(), false, MetaspaceObj::MethodCountersType, THREAD) MethodCounters(mh); } void MethodCounters::clear_counters() {
--- a/hotspot/src/share/vm/oops/methodCounters.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/oops/methodCounters.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -26,7 +26,9 @@ #define SHARE_VM_OOPS_METHODCOUNTERS_HPP #include "oops/metadata.hpp" +#include "compiler/compilerOracle.hpp" #include "interpreter/invocationCounter.hpp" +#include "runtime/arguments.hpp" class MethodCounters: public MetaspaceObj { friend class VMStructs; @@ -45,7 +47,11 @@ // 3. (INT_MIN..0] - method is hot and will deopt and get // recompiled without the counters int _nmethod_age; - + int _interpreter_invocation_limit; // per-method InterpreterInvocationLimit + int _interpreter_backward_branch_limit; // per-method InterpreterBackwardBranchLimit + int _interpreter_profile_limit; // per-method InterpreterProfileLimit + int _invoke_mask; // per-method Tier0InvokeNotifyFreqLog + int _backedge_mask; // per-method Tier0BackedgeNotifyFreqLog #ifdef TIERED float _rate; // Events (invocation and backedge counter increments) per millisecond jlong _prev_time; // Previous time the rate was acquired @@ -53,15 +59,15 @@ u1 _highest_osr_comp_level; // Same for OSR level #endif - MethodCounters() : _interpreter_invocation_count(0), - _interpreter_throwout_count(0), - _number_of_breakpoints(0), - _nmethod_age(INT_MAX) + MethodCounters(methodHandle mh) : _interpreter_invocation_count(0), + _interpreter_throwout_count(0), + _number_of_breakpoints(0), + _nmethod_age(INT_MAX) #ifdef TIERED - , _rate(0), - _prev_time(0), - _highest_comp_level(0), - _highest_osr_comp_level(0) + , _rate(0), + _prev_time(0), + _highest_comp_level(0), + _highest_osr_comp_level(0) #endif { invocation_counter()->init(); @@ -70,10 +76,28 @@ if (StressCodeAging) { set_nmethod_age(HotMethodDetectionLimit); } + + // Set per-method thresholds. + double scale = 1.0; + CompilerOracle::has_option_value(mh, "CompileThresholdScaling", scale); + + int compile_threshold = Arguments::scaled_compile_threshold(CompileThreshold, scale); + _interpreter_invocation_limit = compile_threshold << InvocationCounter::count_shift; + if (ProfileInterpreter) { + // If interpreter profiling is enabled, the backward branch limit + // is compared against the method data counter rather than an invocation + // counter, therefore no shifting of bits is required. + _interpreter_backward_branch_limit = (compile_threshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100; + } else { + _interpreter_backward_branch_limit = ((compile_threshold * OnStackReplacePercentage) / 100) << InvocationCounter::count_shift; + } + _interpreter_profile_limit = ((compile_threshold * InterpreterProfilePercentage) / 100) << InvocationCounter::count_shift; + _invoke_mask = right_n_bits(Arguments::scaled_freq_log(Tier0InvokeNotifyFreqLog, scale)) << InvocationCounter::count_shift; + _backedge_mask = right_n_bits(Arguments::scaled_freq_log(Tier0BackedgeNotifyFreqLog, scale)) << InvocationCounter::count_shift; } public: - static MethodCounters* allocate(ClassLoaderData* loader_data, TRAPS); + static MethodCounters* allocate(methodHandle mh, TRAPS); void deallocate_contents(ClassLoaderData* loader_data) {} DEBUG_ONLY(bool on_stack() { return false; }) // for template @@ -161,5 +185,24 @@ return offset_of(MethodCounters, _interpreter_invocation_count); } + static ByteSize interpreter_invocation_limit_offset() { + return byte_offset_of(MethodCounters, _interpreter_invocation_limit); + } + + static ByteSize interpreter_backward_branch_limit_offset() { + return byte_offset_of(MethodCounters, _interpreter_backward_branch_limit); + } + + static ByteSize interpreter_profile_limit_offset() { + return byte_offset_of(MethodCounters, _interpreter_profile_limit); + } + + static ByteSize invoke_mask_offset() { + return byte_offset_of(MethodCounters, _invoke_mask); + } + + static ByteSize backedge_mask_offset() { + return byte_offset_of(MethodCounters, _backedge_mask); + } }; #endif //SHARE_VM_OOPS_METHODCOUNTERS_HPP
--- a/hotspot/src/share/vm/oops/methodData.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/oops/methodData.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -31,6 +31,7 @@ #include "memory/heapInspection.hpp" #include "oops/methodData.hpp" #include "prims/jvmtiRedefineClasses.hpp" +#include "runtime/arguments.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" @@ -1131,6 +1132,13 @@ _backedge_counter.init(); _invocation_counter_start = 0; _backedge_counter_start = 0; + + // Set per-method invoke- and backedge mask. + double scale = 1.0; + CompilerOracle::has_option_value(_method, "CompileThresholdScaling", scale); + _invoke_mask = right_n_bits(Arguments::scaled_freq_log(Tier0InvokeNotifyFreqLog, scale)) << InvocationCounter::count_shift; + _backedge_mask = right_n_bits(Arguments::scaled_freq_log(Tier0BackedgeNotifyFreqLog, scale)) << InvocationCounter::count_shift; + _tenure_traps = 0; _num_loops = 0; _num_blocks = 0;
--- a/hotspot/src/share/vm/oops/methodData.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/oops/methodData.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -2088,6 +2088,8 @@ int _invocation_counter_start; int _backedge_counter_start; uint _tenure_traps; + int _invoke_mask; // per-method Tier0InvokeNotifyFreqLog + int _backedge_mask; // per-method Tier0BackedgeNotifyFreqLog #if INCLUDE_RTM_OPT // State of RTM code generation during compilation of the method @@ -2447,10 +2449,19 @@ static ByteSize invocation_counter_offset() { return byte_offset_of(MethodData, _invocation_counter); } + static ByteSize backedge_counter_offset() { return byte_offset_of(MethodData, _backedge_counter); } + static ByteSize invoke_mask_offset() { + return byte_offset_of(MethodData, _invoke_mask); + } + + static ByteSize backedge_mask_offset() { + return byte_offset_of(MethodData, _backedge_mask); + } + static ByteSize parameters_type_data_di_offset() { return byte_offset_of(MethodData, _parameters_type_data_di); }
--- a/hotspot/src/share/vm/opto/chaitin.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/chaitin.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -582,6 +582,9 @@ // Peephole remove copies post_allocate_copy_removal(); + // Merge multidefs if multiple defs representing the same value are used in a single block. + merge_multidefs(); + #ifdef ASSERT // Veify the graph after RA. verify(&live_arena);
--- a/hotspot/src/share/vm/opto/chaitin.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/chaitin.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -681,6 +681,32 @@ // Extend the node to LRG mapping void add_reference( const Node *node, const Node *old_node); + // Record the first use of a def in the block for a register. + class RegDefUse { + Node* _def; + Node* _first_use; + public: + RegDefUse() : _def(NULL), _first_use(NULL) { } + Node* def() const { return _def; } + Node* first_use() const { return _first_use; } + + void update(Node* def, Node* use) { + if (_def != def) { + _def = def; + _first_use = use; + } + } + void clear() { + _def = NULL; + _first_use = NULL; + } + }; + typedef GrowableArray<RegDefUse> RegToDefUseMap; + int possibly_merge_multidef(Node *n, uint k, Block *block, RegToDefUseMap& reg2defuse); + + // Merge nodes that are a part of a multidef lrg and produce the same value within a block. + void merge_multidefs(); + private: static int _final_loads, _final_stores, _final_copies, _final_memoves;
--- a/hotspot/src/share/vm/opto/doCall.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/doCall.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -94,7 +94,7 @@ if (log != NULL) { int rid = (receiver_count >= 0)? log->identify(profile.receiver(0)): -1; int r2id = (rid != -1 && profile.has_receiver(1))? log->identify(profile.receiver(1)):-1; - log->begin_elem("call method='%d' count='%d' prof_factor='%g'", + log->begin_elem("call method='%d' count='%d' prof_factor='%f'", log->identify(callee), site_count, prof_factor); if (call_does_dispatch) log->print(" virtual='1'"); if (allow_inline) log->print(" inline='1'");
--- a/hotspot/src/share/vm/opto/escape.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/escape.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -2010,14 +2010,9 @@ bt = field->layout_type(); } else { // Check for unsafe oop field access - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - int opcode = n->fast_out(i)->Opcode(); - if (opcode == Op_StoreP || opcode == Op_LoadP || - opcode == Op_StoreN || opcode == Op_LoadN) { - bt = T_OBJECT; - (*unsafe) = true; - break; - } + if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN)) { + bt = T_OBJECT; + (*unsafe) = true; } } } else if (adr_type->isa_aryptr()) { @@ -2031,13 +2026,8 @@ } } else if (adr_type->isa_rawptr() || adr_type->isa_klassptr()) { // Allocation initialization, ThreadLocal field access, unsafe access - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - int opcode = n->fast_out(i)->Opcode(); - if (opcode == Op_StoreP || opcode == Op_LoadP || - opcode == Op_StoreN || opcode == Op_LoadN) { - bt = T_OBJECT; - break; - } + if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN)) { + bt = T_OBJECT; } } } @@ -3092,13 +3082,7 @@ continue; } else if (n->Opcode() == Op_EncodeISOArray) { // get the memory projection - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node *use = n->fast_out(i); - if (use->Opcode() == Op_SCMemProj) { - n = use; - break; - } - } + n = n->find_out_with(Op_SCMemProj); assert(n->Opcode() == Op_SCMemProj, "memory projection required"); } else { assert(n->is_Mem(), "memory node required."); @@ -3122,13 +3106,7 @@ continue; // don't push users } else if (n->is_LoadStore()) { // get the memory projection - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node *use = n->fast_out(i); - if (use->Opcode() == Op_SCMemProj) { - n = use; - break; - } - } + n = n->find_out_with(Op_SCMemProj); assert(n->Opcode() == Op_SCMemProj, "memory projection required"); } }
--- a/hotspot/src/share/vm/opto/ifg.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/ifg.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -535,12 +535,8 @@ // The method add_input_to_liveout() keeps such nodes alive (put them on liveout list) // when it sees SCMemProj node in a block. Unfortunately SCMemProj node could be placed // in block in such order that KILL MachProj nodes are processed first. - uint cnt = def->outcnt(); - for (uint i = 0; i < cnt; i++) { - Node* proj = def->raw_out(i); - if (proj->Opcode() == Op_SCMemProj) { - return false; - } + if (def->has_out_with(Op_SCMemProj)) { + return false; } } b->remove_node(location);
--- a/hotspot/src/share/vm/opto/loopTransform.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -2057,10 +2057,9 @@ } Node *main_cmp = main_bol->in(1); if( main_cmp->outcnt() > 1 ) { // CmpNode shared? - _igvn.hash_delete(main_bol); main_cmp = main_cmp->clone();// Clone a private CmpNode register_new_node( main_cmp, main_cle->in(0) ); - main_bol->set_req(1,main_cmp); + _igvn.replace_input_of(main_bol, 1, main_cmp); } // Hack the now-private loop bounds _igvn.replace_input_of(main_cmp, 2, main_limit);
--- a/hotspot/src/share/vm/opto/machnode.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/machnode.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -616,6 +616,29 @@ #endif }; +// MachMergeNode is similar to a PhiNode in a sense it merges multiple values, +// however it doesn't have a control input and is more like a MergeMem. +// It is inserted after the register allocation is done to ensure that nodes use single +// definition of a multidef lrg in a block. +class MachMergeNode : public MachIdealNode { +public: + MachMergeNode(Node *n1) { + init_class_id(Class_MachMerge); + add_req(NULL); + add_req(n1); + } + virtual const RegMask &out_RegMask() const { return in(1)->out_RegMask(); } + virtual const RegMask &in_RegMask(uint idx) const { return in(1)->in_RegMask(idx); } + virtual const class Type *bottom_type() const { return in(1)->bottom_type(); } + virtual uint ideal_reg() const { return bottom_type()->ideal_reg(); } + virtual uint oper_input_base() const { return 1; } + virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } + virtual uint size(PhaseRegAlloc *ra_) const { return 0; } +#ifndef PRODUCT + virtual const char *Name() const { return "MachMerge"; } +#endif +}; + //------------------------------MachBranchNode-------------------------------- // Abstract machine branch Node class MachBranchNode : public MachIdealNode {
--- a/hotspot/src/share/vm/opto/macro.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/macro.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -258,14 +258,7 @@ // Search for CastP2X->Xor->URShift->Cmp path which // checks if the store done to a different from the value's region. // And replace Cmp with #0 (false) to collapse G1 post barrier. - Node* xorx = NULL; - for (DUIterator_Fast imax, i = p2x->fast_outs(imax); i < imax; i++) { - Node* u = p2x->fast_out(i); - if (u->Opcode() == Op_XorX) { - xorx = u; - break; - } - } + Node* xorx = p2x->find_out_with(Op_XorX); assert(xorx != NULL, "missing G1 post barrier"); Node* shift = xorx->unique_out(); Node* cmpx = shift->unique_out();
--- a/hotspot/src/share/vm/opto/memnode.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/memnode.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -2609,7 +2609,6 @@ return false; // if not a distinct instance, there may be aliases of the address for (DUIterator_Fast imax, i = adr->fast_outs(imax); i < imax; i++) { Node *use = adr->fast_out(i); - int opc = use->Opcode(); if (use->is_Load() || use->is_LoadStore()) { return false; }
--- a/hotspot/src/share/vm/opto/node.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/node.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -881,6 +881,34 @@ return (Node*) this; } +// Find out of current node that matches opcode. +Node* Node::find_out_with(int opcode) { + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + Node* use = fast_out(i); + if (use->Opcode() == opcode) { + return use; + } + } + return NULL; +} + +// Return true if the current node has an out that matches opcode. +bool Node::has_out_with(int opcode) { + return (find_out_with(opcode) != NULL); +} + +// Return true if the current node has an out that matches any of the opcodes. +bool Node::has_out_with(int opcode1, int opcode2, int opcode3, int opcode4) { + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + int opcode = fast_out(i)->Opcode(); + if (opcode == opcode1 || opcode == opcode2 || opcode == opcode3 || opcode == opcode4) { + return true; + } + } + return false; +} + + //---------------------------uncast_helper------------------------------------- Node* Node::uncast_helper(const Node* p) { #ifdef ASSERT
--- a/hotspot/src/share/vm/opto/node.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/node.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -98,6 +98,7 @@ class MachSafePointNode; class MachSpillCopyNode; class MachTempNode; +class MachMergeNode; class Matcher; class MemBarNode; class MemBarStoreStoreNode; @@ -436,6 +437,13 @@ return (this->uncast() == n->uncast()); } + // Find out of current node that matches opcode. + Node* find_out_with(int opcode); + // Return true if the current node has an out that matches opcode. + bool has_out_with(int opcode); + // Return true if the current node has an out that matches any of the opcodes. + bool has_out_with(int opcode1, int opcode2, int opcode3, int opcode4); + private: static Node* uncast_helper(const Node* n); @@ -507,18 +515,25 @@ //----------------- Other Node Properties - // Generate class id for some ideal nodes to avoid virtual query - // methods is_<Node>(). - // Class id is the set of bits corresponded to the node class and all its - // super classes so that queries for super classes are also valid. - // Subclasses of the same super class have different assigned bit - // (the third parameter in the macro DEFINE_CLASS_ID). - // Classes with deeper hierarchy are declared first. - // Classes with the same hierarchy depth are sorted by usage frequency. + // Generate class IDs for (some) ideal nodes so that it is possible to determine + // the type of a node using a non-virtual method call (the method is_<Node>() below). // - // The query method masks the bits to cut off bits of subclasses - // and then compare the result with the class id - // (see the macro DEFINE_CLASS_QUERY below). + // A class ID of an ideal node is a set of bits. In a class ID, a single bit determines + // the type of the node the ID represents; another subset of an ID's bits are reserved + // for the superclasses of the node represented by the ID. + // + // By design, if A is a supertype of B, A.is_B() returns true and B.is_A() + // returns false. A.is_A() returns true. + // + // If two classes, A and B, have the same superclass, a different bit of A's class id + // is reserved for A's type than for B's type. That bit is specified by the third + // parameter in the macro DEFINE_CLASS_ID. + // + // By convention, classes with deeper hierarchy are declared first. Moreover, + // classes with the same hierarchy depth are sorted by usage frequency. + // + // The query method masks the bits to cut off bits of subclasses and then compares + // the result with the class id (see the macro DEFINE_CLASS_QUERY below). // // Class_MachCall=30, ClassMask_MachCall=31 // 12 8 4 0 @@ -592,6 +607,7 @@ DEFINE_CLASS_ID(MachTemp, Mach, 3) DEFINE_CLASS_ID(MachConstantBase, Mach, 4) DEFINE_CLASS_ID(MachConstant, Mach, 5) + DEFINE_CLASS_ID(MachMerge, Mach, 6) DEFINE_CLASS_ID(Type, Node, 2) DEFINE_CLASS_ID(Phi, Type, 0) @@ -763,6 +779,7 @@ DEFINE_CLASS_QUERY(MachSafePoint) DEFINE_CLASS_QUERY(MachSpillCopy) DEFINE_CLASS_QUERY(MachTemp) + DEFINE_CLASS_QUERY(MachMerge) DEFINE_CLASS_QUERY(Mem) DEFINE_CLASS_QUERY(MemBar) DEFINE_CLASS_QUERY(MemBarStoreStore)
--- a/hotspot/src/share/vm/opto/parse1.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/parse1.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -441,7 +441,7 @@ CompileLog* log = C->log(); if (log != NULL) { - log->begin_head("parse method='%d' uses='%g'", + log->begin_head("parse method='%d' uses='%f'", log->identify(parse_method), expected_uses); if (depth() == 1 && C->is_osr_compilation()) { log->print(" osr_bci='%d'", C->entry_bci());
--- a/hotspot/src/share/vm/opto/parse2.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/parse2.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -832,7 +832,7 @@ sprintf(prob_str_buf, "%g", prob); prob_str = prob_str_buf; } - C->log()->elem("branch target_bci='%d' taken='%d' not_taken='%d' cnt='%g' prob='%s'", + C->log()->elem("branch target_bci='%d' taken='%d' not_taken='%d' cnt='%f' prob='%s'", iter().get_dest(), taken, not_taken, cnt, prob_str); } return prob;
--- a/hotspot/src/share/vm/opto/phase.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/phase.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -110,6 +110,7 @@ tty->print_cr (" Compute Liveness: %7.3f s", timers[_t_computeLive].seconds()); tty->print_cr (" Regalloc Split: %7.3f s", timers[_t_regAllocSplit].seconds()); tty->print_cr (" Postalloc Copy Rem: %7.3f s", timers[_t_postAllocCopyRemoval].seconds()); + tty->print_cr (" Merge multidefs: %7.3f s", timers[_t_mergeMultidefs].seconds()); tty->print_cr (" Fixup Spills: %7.3f s", timers[_t_fixupSpills].seconds()); tty->print_cr (" Compact: %7.3f s", timers[_t_chaitinCompact].seconds()); tty->print_cr (" Coalesce 1: %7.3f s", timers[_t_chaitinCoalesce1].seconds()); @@ -126,6 +127,7 @@ timers[_t_computeLive].seconds() + timers[_t_regAllocSplit].seconds() + timers[_t_postAllocCopyRemoval].seconds() + + timers[_t_mergeMultidefs].seconds() + timers[_t_fixupSpills].seconds() + timers[_t_chaitinCompact].seconds() + timers[_t_chaitinCoalesce1].seconds() +
--- a/hotspot/src/share/vm/opto/phase.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/phase.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -88,6 +88,7 @@ _t_computeLive, _t_regAllocSplit, _t_postAllocCopyRemoval, + _t_mergeMultidefs, _t_fixupSpills, _t_chaitinCompact, _t_chaitinCoalesce1,
--- a/hotspot/src/share/vm/opto/postaloc.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/postaloc.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -263,20 +263,6 @@ // intermediate copies might be illegal, i.e., value is stored down to stack // then reloaded BUT survives in a register the whole way. Node *val = skip_copies(n->in(k)); - - if (val == x && nk_idx != 0 && - regnd[nk_reg] != NULL && regnd[nk_reg] != x && - _lrg_map.live_range_id(x) == _lrg_map.live_range_id(regnd[nk_reg])) { - // When rematerialzing nodes and stretching lifetimes, the - // allocator will reuse the original def for multidef LRG instead - // of the current reaching def because it can't know it's safe to - // do so. After allocation completes if they are in the same LRG - // then it should use the current reaching def instead. - n->set_req(k, regnd[nk_reg]); - blk_adjust += yank_if_dead(val, current_block, &value, ®nd); - val = skip_copies(n->in(k)); - } - if (val == x) return blk_adjust; // No progress? int n_regs = RegMask::num_registers(val->ideal_reg()); @@ -382,6 +368,94 @@ return false; } +// The algorithms works as follows: +// We traverse the block top to bottom. possibly_merge_multidef() is invoked for every input edge k +// of the instruction n. We check to see if the input is a multidef lrg. If it is, we record the fact that we've +// seen a definition (coming as an input) and add that fact to the reg2defuse array. The array maps registers to their +// current reaching definitions (we track only multidefs though). With each definition we also associate the first +// instruction we saw use it. If we encounter the situation when we observe an def (an input) that is a part of the +// same lrg but is different from the previous seen def we merge the two with a MachMerge node and substitute +// all the uses that we've seen so far to use the merge. After that we keep replacing the new defs in the same lrg +// as they get encountered with the merge node and keep adding these defs to the merge inputs. +void PhaseChaitin::merge_multidefs() { + Compile::TracePhase tp("mergeMultidefs", &timers[_t_mergeMultidefs]); + ResourceMark rm; + // Keep track of the defs seen in registers and collect their uses in the block. + RegToDefUseMap reg2defuse(_max_reg, _max_reg, RegDefUse()); + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); + for (uint j = 1; j < block->number_of_nodes(); j++) { + Node* n = block->get_node(j); + if (n->is_Phi()) continue; + for (uint k = 1; k < n->req(); k++) { + j += possibly_merge_multidef(n, k, block, reg2defuse); + } + // Null out the value produced by the instruction itself, since we're only interested in defs + // implicitly defined by the uses. We are actually interested in tracking only redefinitions + // of the multidef lrgs in the same register. For that matter it's enough to track changes in + // the base register only and ignore other effects of multi-register lrgs and fat projections. + // It is also ok to ignore defs coming from singledefs. After an implicit overwrite by one of + // those our register is guaranteed to be used by another lrg and we won't attempt to merge it. + uint lrg = _lrg_map.live_range_id(n); + if (lrg > 0 && lrgs(lrg).is_multidef()) { + OptoReg::Name reg = lrgs(lrg).reg(); + reg2defuse.at(reg).clear(); + } + } + // Clear reg->def->use tracking for the next block + for (int j = 0; j < reg2defuse.length(); j++) { + reg2defuse.at(j).clear(); + } + } +} + +int PhaseChaitin::possibly_merge_multidef(Node *n, uint k, Block *block, RegToDefUseMap& reg2defuse) { + int blk_adjust = 0; + + uint lrg = _lrg_map.live_range_id(n->in(k)); + if (lrg > 0 && lrgs(lrg).is_multidef()) { + OptoReg::Name reg = lrgs(lrg).reg(); + + Node* def = reg2defuse.at(reg).def(); + if (def != NULL && lrg == _lrg_map.live_range_id(def) && def != n->in(k)) { + // Same lrg but different node, we have to merge. + MachMergeNode* merge; + if (def->is_MachMerge()) { // is it already a merge? + merge = def->as_MachMerge(); + } else { + merge = new MachMergeNode(def); + + // Insert the merge node into the block before the first use. + uint use_index = block->find_node(reg2defuse.at(reg).first_use()); + block->insert_node(merge, use_index++); + + // Let the allocator know about the new node, use the same lrg + _lrg_map.extend(merge->_idx, lrg); + blk_adjust++; + + // Fixup all the uses (there is at least one) that happened between the first + // use and before the current one. + for (; use_index < block->number_of_nodes(); use_index++) { + Node* use = block->get_node(use_index); + if (use == n) { + break; + } + use->replace_edge(def, merge); + } + } + if (merge->find_edge(n->in(k)) == -1) { + merge->add_req(n->in(k)); + } + n->set_req(k, merge); + } + + // update the uses + reg2defuse.at(reg).update(n->in(k), n); + } + + return blk_adjust; +} + //------------------------------post_allocate_copy_removal--------------------- // Post-Allocation peephole copy removal. We do this in 1 pass over the
--- a/hotspot/src/share/vm/opto/stringopts.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/opto/stringopts.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1507,10 +1507,12 @@ } case StringConcat::StringMode: { const Type* type = kit.gvn().type(arg); + Node* count = NULL; if (type == TypePtr::NULL_PTR) { // replace the argument with the null checked version arg = null_string; sc->set_argument(argi, arg); + count = kit.load_String_length(kit.control(), arg); } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) { // s = s != null ? s : "null"; // length = length + (s.count - s.offset); @@ -1533,10 +1535,13 @@ // replace the argument with the null checked version arg = phi; sc->set_argument(argi, arg); + count = kit.load_String_length(kit.control(), arg); + } else { + // A corresponding nullcheck will be connected during IGVN MemNode::Ideal_common_DU_postCCP + // kit.control might be a different test, that can be hoisted above the actual nullcheck + // in case, that the control input is not null, Ideal_common_DU_postCCP will not look for a nullcheck. + count = kit.load_String_length(NULL, arg); } - - Node* count = kit.load_String_length(kit.control(), arg); - length = __ AddI(length, count); string_sizes->init_req(argi, NULL); break;
--- a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -68,11 +68,11 @@ ~JvmtiConstantPoolReconstituter() { if (_symmap != NULL) { - os::free(_symmap); + delete _symmap; _symmap = NULL; } if (_classmap != NULL) { - os::free(_classmap); + delete _classmap; _classmap = NULL; } }
--- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1046,10 +1046,16 @@ { assert(str->klass() == SystemDictionary::String_klass(), "not a string"); + typeArrayOop s_value = java_lang_String::value(str); + + // JDK-6584008: the value field may be null if a String instance is + // partially constructed. + if (s_value == NULL) { + return 0; + } // get the string value and length // (string value may be offset from the base) int s_len = java_lang_String::length(str); - typeArrayOop s_value = java_lang_String::value(str); int s_offset = java_lang_String::offset(str); jchar* value; if (s_len > 0) {
--- a/hotspot/src/share/vm/prims/perf.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/prims/perf.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -100,6 +100,11 @@ PerfWrapper("Perf_Detach"); + if (!UsePerfData) { + // With -XX:-UsePerfData, detach is just a NOP + return; + } + void* address = 0; jlong capacity = 0;
--- a/hotspot/src/share/vm/prims/unsafe.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/prims/unsafe.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1104,43 +1104,6 @@ -UNSAFE_ENTRY(void, Unsafe_MonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj)) - UnsafeWrapper("Unsafe_MonitorEnter"); - { - if (jobj == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - Handle obj(thread, JNIHandles::resolve_non_null(jobj)); - ObjectSynchronizer::jni_enter(obj, CHECK); - } -UNSAFE_END - - -UNSAFE_ENTRY(jboolean, Unsafe_TryMonitorEnter(JNIEnv *env, jobject unsafe, jobject jobj)) - UnsafeWrapper("Unsafe_TryMonitorEnter"); - { - if (jobj == NULL) { - THROW_(vmSymbols::java_lang_NullPointerException(), JNI_FALSE); - } - Handle obj(thread, JNIHandles::resolve_non_null(jobj)); - bool res = ObjectSynchronizer::jni_try_enter(obj, CHECK_0); - return (res ? JNI_TRUE : JNI_FALSE); - } -UNSAFE_END - - -UNSAFE_ENTRY(void, Unsafe_MonitorExit(JNIEnv *env, jobject unsafe, jobject jobj)) - UnsafeWrapper("Unsafe_MonitorExit"); - { - if (jobj == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - Handle obj(THREAD, JNIHandles::resolve_non_null(jobj)); - ObjectSynchronizer::jni_exit(obj(), CHECK); - } -UNSAFE_END - - UNSAFE_ENTRY(void, Unsafe_ThrowException(JNIEnv *env, jobject unsafe, jthrowable thr)) UnsafeWrapper("Unsafe_ThrowException"); { @@ -1365,8 +1328,6 @@ {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)} }; @@ -1411,8 +1372,6 @@ {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)} }; @@ -1461,8 +1420,6 @@ {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, @@ -1515,9 +1472,6 @@ {CC"defineClass", CC"("DC0_Args")"CLS, FN_PTR(Unsafe_DefineClass0)}, {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, - {CC"tryMonitorEnter", CC"("OBJ")Z", FN_PTR(Unsafe_TryMonitorEnter)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, @@ -1571,9 +1525,6 @@ {CC"defineClass", CC"("DC_Args")"CLS, FN_PTR(Unsafe_DefineClass)}, {CC"allocateInstance", CC"("CLS")"OBJ, FN_PTR(Unsafe_AllocateInstance)}, - {CC"monitorEnter", CC"("OBJ")V", FN_PTR(Unsafe_MonitorEnter)}, - {CC"monitorExit", CC"("OBJ")V", FN_PTR(Unsafe_MonitorExit)}, - {CC"tryMonitorEnter", CC"("OBJ")Z", FN_PTR(Unsafe_TryMonitorEnter)}, {CC"throwException", CC"("THR")V", FN_PTR(Unsafe_ThrowException)}, {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)},
--- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -155,7 +155,7 @@ if (mdo != NULL) { int i = mdo->invocation_count_delta(); int b = mdo->backedge_count_delta(); - return call_predicate_helper<CompLevel_full_profile>(i, b, 1); + return call_predicate_helper<CompLevel_full_profile>(i, b, 1, method); } return false; } @@ -229,32 +229,32 @@ // Tier?LoadFeedback is basically a coefficient that determines of // how many methods per compiler thread can be in the queue before // the threshold values double. -bool AdvancedThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level) { +bool AdvancedThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return loop_predicate_helper<CompLevel_none>(i, b, k); + return loop_predicate_helper<CompLevel_none>(i, b, k, method); } case CompLevel_full_profile: { double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); - return loop_predicate_helper<CompLevel_full_profile>(i, b, k); + return loop_predicate_helper<CompLevel_full_profile>(i, b, k, method); } default: return true; } } -bool AdvancedThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level) { +bool AdvancedThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { double k = threshold_scale(CompLevel_full_profile, Tier3LoadFeedback); - return call_predicate_helper<CompLevel_none>(i, b, k); + return call_predicate_helper<CompLevel_none>(i, b, k, method); } case CompLevel_full_profile: { double k = threshold_scale(CompLevel_full_optimization, Tier4LoadFeedback); - return call_predicate_helper<CompLevel_full_profile>(i, b, k); + return call_predicate_helper<CompLevel_full_profile>(i, b, k, method); } default: return true; @@ -271,7 +271,7 @@ int i = method->invocation_count(); int b = method->backedge_count(); double k = Tier0ProfilingStartPercentage / 100.0; - return call_predicate_helper<CompLevel_none>(i, b, k) || loop_predicate_helper<CompLevel_none>(i, b, k); + return call_predicate_helper<CompLevel_none>(i, b, k, method) || loop_predicate_helper<CompLevel_none>(i, b, k, method); } return false; } @@ -348,7 +348,7 @@ // If we were at full profile level, would we switch to full opt? if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; - } else if ((this->*p)(i, b, cur_level)) { + } else if ((this->*p)(i, b, cur_level, method)) { // C1-generated fully profiled code is about 30% slower than the limited profile // code that has only invocation and backedge counters. The observation is that // if C2 queue is large enough we can spend too much time in the fully profiled code @@ -374,7 +374,7 @@ if (mdo->would_profile()) { if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - (this->*p)(i, b, cur_level))) { + (this->*p)(i, b, cur_level, method))) { next_level = CompLevel_full_profile; } } else { @@ -390,7 +390,7 @@ if (mdo->would_profile()) { int mdo_i = mdo->invocation_count_delta(); int mdo_b = mdo->backedge_count_delta(); - if ((this->*p)(mdo_i, mdo_b, cur_level)) { + if ((this->*p)(mdo_i, mdo_b, cur_level, method)) { next_level = CompLevel_full_optimization; } } else {
--- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -84,7 +84,7 @@ * invocation and backedge notifications. Basically every n-th invocation or backedge a mutator thread * makes a call into the runtime. * - * - Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control + * - Tier?InvocationThreshold, Tier?CompileThreshold, Tier?BackEdgeThreshold, Tier?MinInvocationThreshold control * compilation thresholds. * Level 2 thresholds are not used and are provided for option-compatibility and potential future use. * Other thresholds work as follows: @@ -100,7 +100,9 @@ * The same predicate is used to control the transition from level 3 to level 4 (C2). It should be * noted though that the thresholds are relative. Moreover i and b for the 0->3 transition come * from Method* and for 3->4 transition they come from MDO (since profiled invocations are - * counted separately). + * counted separately). Finally, if a method does not contain anything worth profiling, a transition + * from level 3 to level 4 occurs without considering thresholds (e.g., with fewer invocations than + * what is specified by Tier4InvocationThreshold). * * OSR transitions are controlled simply with b > TierXBackEdgeThreshold * s predicates. * @@ -164,9 +166,9 @@ // Call and loop predicates determine whether a transition to a higher compilation // level should be performed (pointers to predicate functions are passed to common(). // Predicates also take compiler load into account. - typedef bool (AdvancedThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level); - bool call_predicate(int i, int b, CompLevel cur_level); - bool loop_predicate(int i, int b, CompLevel cur_level); + typedef bool (AdvancedThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method); + bool call_predicate(int i, int b, CompLevel cur_level, Method* method); + bool loop_predicate(int i, int b, CompLevel cur_level, Method* method); // Common transition function. Given a predicate determines if a method should transition to another level. CompLevel common(Predicate p, Method* method, CompLevel cur_level, bool disable_feedback = false); // Transition functions.
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1126,16 +1126,35 @@ } #endif -// Returns threshold scaled with CompileThresholdScaling -intx Arguments::get_scaled_compile_threshold(intx threshold) { - return (intx)(threshold * CompileThresholdScaling); +intx Arguments::scaled_compile_threshold(intx threshold, double scale) { + if (scale == 1.0 || scale < 0.0) { + return threshold; + } else { + return (intx)(threshold * scale); + } } // Returns freq_log scaled with CompileThresholdScaling -intx Arguments::get_scaled_freq_log(intx freq_log) { - intx scaled_freq = get_scaled_compile_threshold((intx)1 << freq_log); - if (scaled_freq == 0) { - return 0; +intx Arguments::scaled_freq_log(intx freq_log, double scale) { + // Check if scaling is necessary or negative value was specified. + if (scale == 1.0 || scale < 0.0) { + return freq_log; + } + + // Check value to avoid calculating log2 of 0. + if (scale == 0.0) { + return 1; + } + + intx scaled_freq = scaled_compile_threshold((intx)1 << freq_log, scale); + // Determine the maximum notification frequency value currently supported. + // The largest mask value that the interpreter/C1 can handle is + // of length InvocationCounter::number_of_count_bits. Mask values are always + // one bit shorter then the value of the notification frequency. Set + // max_freq_bits accordingly. + intx max_freq_bits = InvocationCounter::number_of_count_bits + 1; + if (scaled_freq > nth_bit(max_freq_bits)) { + return max_freq_bits; } else { return log2_intptr(scaled_freq); } @@ -1180,31 +1199,36 @@ Tier3InvokeNotifyFreqLog = 0; Tier4InvocationThreshold = 0; } + + if (CompileThresholdScaling < 0) { + vm_exit_during_initialization("Negative value specified for CompileThresholdScaling", NULL); + } + // Scale tiered compilation thresholds if (!FLAG_IS_DEFAULT(CompileThresholdScaling)) { - FLAG_SET_ERGO(intx, Tier0InvokeNotifyFreqLog, get_scaled_freq_log(Tier0InvokeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier0BackedgeNotifyFreqLog, get_scaled_freq_log(Tier0BackedgeNotifyFreqLog)); - - FLAG_SET_ERGO(intx, Tier3InvocationThreshold, get_scaled_compile_threshold(Tier3InvocationThreshold)); - FLAG_SET_ERGO(intx, Tier3MinInvocationThreshold, get_scaled_compile_threshold(Tier3MinInvocationThreshold)); - FLAG_SET_ERGO(intx, Tier3CompileThreshold, get_scaled_compile_threshold(Tier3CompileThreshold)); - FLAG_SET_ERGO(intx, Tier3BackEdgeThreshold, get_scaled_compile_threshold(Tier3BackEdgeThreshold)); + FLAG_SET_ERGO(intx, Tier0InvokeNotifyFreqLog, scaled_freq_log(Tier0InvokeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier0BackedgeNotifyFreqLog, scaled_freq_log(Tier0BackedgeNotifyFreqLog)); + + FLAG_SET_ERGO(intx, Tier3InvocationThreshold, scaled_compile_threshold(Tier3InvocationThreshold)); + FLAG_SET_ERGO(intx, Tier3MinInvocationThreshold, scaled_compile_threshold(Tier3MinInvocationThreshold)); + FLAG_SET_ERGO(intx, Tier3CompileThreshold, scaled_compile_threshold(Tier3CompileThreshold)); + FLAG_SET_ERGO(intx, Tier3BackEdgeThreshold, scaled_compile_threshold(Tier3BackEdgeThreshold)); // Tier2{Invocation,MinInvocation,Compile,Backedge}Threshold should be scaled here // once these thresholds become supported. - FLAG_SET_ERGO(intx, Tier2InvokeNotifyFreqLog, get_scaled_freq_log(Tier2InvokeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier2BackedgeNotifyFreqLog, get_scaled_freq_log(Tier2BackedgeNotifyFreqLog)); - - FLAG_SET_ERGO(intx, Tier3InvokeNotifyFreqLog, get_scaled_freq_log(Tier3InvokeNotifyFreqLog)); - FLAG_SET_ERGO(intx, Tier3BackedgeNotifyFreqLog, get_scaled_freq_log(Tier3BackedgeNotifyFreqLog)); - - FLAG_SET_ERGO(intx, Tier23InlineeNotifyFreqLog, get_scaled_freq_log(Tier23InlineeNotifyFreqLog)); - - FLAG_SET_ERGO(intx, Tier4InvocationThreshold, get_scaled_compile_threshold(Tier4InvocationThreshold)); - FLAG_SET_ERGO(intx, Tier4MinInvocationThreshold, get_scaled_compile_threshold(Tier4MinInvocationThreshold)); - FLAG_SET_ERGO(intx, Tier4CompileThreshold, get_scaled_compile_threshold(Tier4CompileThreshold)); - FLAG_SET_ERGO(intx, Tier4BackEdgeThreshold, get_scaled_compile_threshold(Tier4BackEdgeThreshold)); + FLAG_SET_ERGO(intx, Tier2InvokeNotifyFreqLog, scaled_freq_log(Tier2InvokeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier2BackedgeNotifyFreqLog, scaled_freq_log(Tier2BackedgeNotifyFreqLog)); + + FLAG_SET_ERGO(intx, Tier3InvokeNotifyFreqLog, scaled_freq_log(Tier3InvokeNotifyFreqLog)); + FLAG_SET_ERGO(intx, Tier3BackedgeNotifyFreqLog, scaled_freq_log(Tier3BackedgeNotifyFreqLog)); + + FLAG_SET_ERGO(intx, Tier23InlineeNotifyFreqLog, scaled_freq_log(Tier23InlineeNotifyFreqLog)); + + FLAG_SET_ERGO(intx, Tier4InvocationThreshold, scaled_compile_threshold(Tier4InvocationThreshold)); + FLAG_SET_ERGO(intx, Tier4MinInvocationThreshold, scaled_compile_threshold(Tier4MinInvocationThreshold)); + FLAG_SET_ERGO(intx, Tier4CompileThreshold, scaled_compile_threshold(Tier4CompileThreshold)); + FLAG_SET_ERGO(intx, Tier4BackEdgeThreshold, scaled_compile_threshold(Tier4BackEdgeThreshold)); } } @@ -3456,7 +3480,7 @@ } if ((TieredCompilation && CompileThresholdScaling == 0) - || (!TieredCompilation && get_scaled_compile_threshold(CompileThreshold) == 0)) { + || (!TieredCompilation && scaled_compile_threshold(CompileThreshold) == 0)) { set_mode_flags(_int); } @@ -3896,7 +3920,7 @@ } // Scale CompileThreshold if (!FLAG_IS_DEFAULT(CompileThresholdScaling)) { - FLAG_SET_ERGO(intx, CompileThreshold, get_scaled_compile_threshold(CompileThreshold)); + FLAG_SET_ERGO(intx, CompileThreshold, scaled_compile_threshold(CompileThreshold)); } }
--- a/hotspot/src/share/vm/runtime/arguments.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/arguments.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -328,9 +328,6 @@ static bool _ClipInlining; static bool _CIDynamicCompilePriority; - // Scale compile thresholds - static intx get_scaled_compile_threshold(intx threshold); - static intx get_scaled_freq_log(intx freq_log); // Tiered static void set_tiered_flags(); static int get_min_number_of_compiler_threads(); @@ -452,6 +449,18 @@ static char* SharedArchivePath; public: + // Scale compile thresholds + // Returns threshold scaled with CompileThresholdScaling + static intx scaled_compile_threshold(intx threshold, double scale); + static intx scaled_compile_threshold(intx threshold) { + return scaled_compile_threshold(threshold, CompileThresholdScaling); + } + // Returns freq_log scaled with CompileThresholdScaling + static intx scaled_freq_log(intx freq_log, double scale); + static intx scaled_freq_log(intx freq_log) { + return scaled_freq_log(freq_log, CompileThresholdScaling); + } + // Parses the arguments, first phase static jint parse(const JavaVMInitArgs* args); // Apply ergonomics
--- a/hotspot/src/share/vm/runtime/globals.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -2477,7 +2477,7 @@ "Number of compiler threads to run") \ \ product(intx, CompilationPolicyChoice, 0, \ - "which compilation policy (0/1)") \ + "which compilation policy (0-3)") \ \ develop(bool, UseStackBanging, true, \ "use stack banging for stack overflow checks (required for " \ @@ -3528,7 +3528,16 @@ \ product(double, CompileThresholdScaling, 1.0, \ "Factor to control when first compilation happens " \ - "(both with and without tiered compilation)") \ + "(both with and without tiered compilation): " \ + "values greater than 1.0 delay counter overflow, " \ + "values between 0 and 1.0 rush counter overflow, " \ + "value of 1.0 leave compilation thresholds unchanged " \ + "value of 0.0 is equivalent to -Xint. " \ + "" \ + "Flag can be set as per-method option. " \ + "If a value is specified for a method, compilation thresholds " \ + "for that method are scaled by both the value of the global flag "\ + "and the value of the per-method flag.") \ \ product(intx, Tier0InvokeNotifyFreqLog, 7, \ "Interpreter (tier 0) invocation notification frequency") \
--- a/hotspot/src/share/vm/runtime/os.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1401,15 +1401,17 @@ return (sp > (stack_limit + reserved_area)); } -size_t os::page_size_for_region(size_t region_size, size_t min_pages) { +size_t os::page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned) { assert(min_pages > 0, "sanity"); if (UseLargePages) { const size_t max_page_size = region_size / min_pages; for (size_t i = 0; _page_sizes[i] != 0; ++i) { const size_t page_size = _page_sizes[i]; - if (page_size <= max_page_size && is_size_aligned(region_size, page_size)) { - return page_size; + if (page_size <= max_page_size) { + if (!must_be_aligned || is_size_aligned(region_size, page_size)) { + return page_size; + } } } } @@ -1417,6 +1419,14 @@ return vm_page_size(); } +size_t os::page_size_for_region_aligned(size_t region_size, size_t min_pages) { + return page_size_for_region(region_size, min_pages, true); +} + +size_t os::page_size_for_region_unaligned(size_t region_size, size_t min_pages) { + return page_size_for_region(region_size, min_pages, false); +} + #ifndef PRODUCT void os::trace_page_sizes(const char* str, const size_t* page_sizes, int count) { @@ -1665,17 +1675,17 @@ static size_t large_page_size() { const size_t large_page_size_example = 4 * M; - return os::page_size_for_region(large_page_size_example, 1); + return os::page_size_for_region_aligned(large_page_size_example, 1); } - static void test_page_size_for_region() { + static void test_page_size_for_region_aligned() { if (UseLargePages) { const size_t small_page = small_page_size(); const size_t large_page = large_page_size(); if (large_page > small_page) { size_t num_small_pages_in_large = large_page / small_page; - size_t page = os::page_size_for_region(large_page, num_small_pages_in_large); + size_t page = os::page_size_for_region_aligned(large_page, num_small_pages_in_large); assert_eq(page, small_page); } @@ -1688,21 +1698,53 @@ const size_t large_page = large_page_size(); if (large_page > small_page) { const size_t unaligned_region = large_page + 17; - size_t page = os::page_size_for_region(unaligned_region, 1); + size_t page = os::page_size_for_region_aligned(unaligned_region, 1); assert_eq(page, small_page); const size_t num_pages = 5; const size_t aligned_region = large_page * num_pages; - page = os::page_size_for_region(aligned_region, num_pages); + page = os::page_size_for_region_aligned(aligned_region, num_pages); assert_eq(page, large_page); } } } + static void test_page_size_for_region_unaligned() { + if (UseLargePages) { + // Given exact page size, should return that page size. + for (size_t i = 0; os::_page_sizes[i] != 0; i++) { + size_t expected = os::_page_sizes[i]; + size_t actual = os::page_size_for_region_unaligned(expected, 1); + assert_eq(expected, actual); + } + + // Given slightly larger size than a page size, return the page size. + for (size_t i = 0; os::_page_sizes[i] != 0; i++) { + size_t expected = os::_page_sizes[i]; + size_t actual = os::page_size_for_region_unaligned(expected + 17, 1); + assert_eq(expected, actual); + } + + // Given a slightly smaller size than a page size, + // return the next smaller page size. + if (os::_page_sizes[1] > os::_page_sizes[0]) { + size_t expected = os::_page_sizes[0]; + size_t actual = os::page_size_for_region_unaligned(os::_page_sizes[1] - 17, 1); + assert_eq(actual, expected); + } + + // Return small page size for values less than a small page. + size_t small_page = small_page_size(); + size_t actual = os::page_size_for_region_unaligned(small_page - 17, 1); + assert_eq(small_page, actual); + } + } + public: static void run_tests() { - test_page_size_for_region(); + test_page_size_for_region_aligned(); test_page_size_for_region_alignment(); + test_page_size_for_region_unaligned(); } };
--- a/hotspot/src/share/vm/runtime/os.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -148,6 +148,7 @@ static void pd_free_memory(char *addr, size_t bytes, size_t alignment_hint); static void pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint); + static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned); public: static void init(void); // Called before command line parsing @@ -267,8 +268,13 @@ // Returns the page size to use for a region of memory. // region_size / min_pages will always be greater than or equal to the - // returned value. - static size_t page_size_for_region(size_t region_size, size_t min_pages); + // returned value. The returned value will divide region_size. + static size_t page_size_for_region_aligned(size_t region_size, size_t min_pages); + + // Returns the page size to use for a region of memory. + // region_size / min_pages will always be greater than or equal to the + // returned value. The returned value might not divide region_size. + static size_t page_size_for_region_unaligned(size_t region_size, size_t min_pages); // Return the largest page size that can be used static size_t max_page_size() {
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -257,28 +257,28 @@ // Call and loop predicates determine whether a transition to a higher // compilation level should be performed (pointers to predicate functions // are passed to common() transition function). -bool SimpleThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level) { +bool SimpleThresholdPolicy::loop_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { - return loop_predicate_helper<CompLevel_none>(i, b, 1.0); + return loop_predicate_helper<CompLevel_none>(i, b, 1.0, method); } case CompLevel_full_profile: { - return loop_predicate_helper<CompLevel_full_profile>(i, b, 1.0); + return loop_predicate_helper<CompLevel_full_profile>(i, b, 1.0, method); } default: return true; } } -bool SimpleThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level) { +bool SimpleThresholdPolicy::call_predicate(int i, int b, CompLevel cur_level, Method* method) { switch(cur_level) { case CompLevel_none: case CompLevel_limited_profile: { - return call_predicate_helper<CompLevel_none>(i, b, 1.0); + return call_predicate_helper<CompLevel_none>(i, b, 1.0, method); } case CompLevel_full_profile: { - return call_predicate_helper<CompLevel_full_profile>(i, b, 1.0); + return call_predicate_helper<CompLevel_full_profile>(i, b, 1.0, method); } default: return true; @@ -293,8 +293,8 @@ int i = mdo->invocation_count(); int b = mdo->backedge_count(); double k = ProfileMaturityPercentage / 100.0; - return call_predicate_helper<CompLevel_full_profile>(i, b, k) || - loop_predicate_helper<CompLevel_full_profile>(i, b, k); + return call_predicate_helper<CompLevel_full_profile>(i, b, k, method) || + loop_predicate_helper<CompLevel_full_profile>(i, b, k, method); } return false; } @@ -313,7 +313,7 @@ // If we were at full profile level, would we switch to full opt? if (common(p, method, CompLevel_full_profile) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; - } else if ((this->*p)(i, b, cur_level)) { + } else if ((this->*p)(i, b, cur_level, method)) { next_level = CompLevel_full_profile; } break; @@ -325,7 +325,7 @@ if (mdo->would_profile()) { int mdo_i = mdo->invocation_count_delta(); int mdo_b = mdo->backedge_count_delta(); - if ((this->*p)(mdo_i, mdo_b, cur_level)) { + if ((this->*p)(mdo_i, mdo_b, cur_level, method)) { next_level = CompLevel_full_optimization; } } else {
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -43,9 +43,9 @@ // Call and loop predicates determine whether a transition to a higher compilation // level should be performed (pointers to predicate functions are passed to common_TF(). // Predicates also take compiler load into account. - typedef bool (SimpleThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level); - bool call_predicate(int i, int b, CompLevel cur_level); - bool loop_predicate(int i, int b, CompLevel cur_level); + typedef bool (SimpleThresholdPolicy::*Predicate)(int i, int b, CompLevel cur_level, Method* method); + bool call_predicate(int i, int b, CompLevel cur_level, Method* method); + bool loop_predicate(int i, int b, CompLevel cur_level, Method* method); // Common transition function. Given a predicate determines if a method should transition to another level. CompLevel common(Predicate p, Method* method, CompLevel cur_level); // Transition functions. @@ -76,8 +76,8 @@ // Predicate helpers are used by .*_predicate() methods as well as others. // They check the given counter values, multiplied by the scale against the thresholds. - template<CompLevel level> static inline bool call_predicate_helper(int i, int b, double scale); - template<CompLevel level> static inline bool loop_predicate_helper(int i, int b, double scale); + template<CompLevel level> static inline bool call_predicate_helper(int i, int b, double scale, Method* method); + template<CompLevel level> static inline bool loop_predicate_helper(int i, int b, double scale, Method* method); // Get a compilation level for a given method. static CompLevel comp_level(Method* method) {
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -25,8 +25,14 @@ #ifndef SHARE_VM_RUNTIME_SIMPLETHRESHOLDPOLICY_INLINE_HPP #define SHARE_VM_RUNTIME_SIMPLETHRESHOLDPOLICY_INLINE_HPP +#include "compiler/compilerOracle.hpp" + template<CompLevel level> -bool SimpleThresholdPolicy::call_predicate_helper(int i, int b, double scale) { +bool SimpleThresholdPolicy::call_predicate_helper(int i, int b, double scale, Method* method) { + double threshold_scaling; + if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { + scale *= threshold_scaling; + } switch(level) { case CompLevel_none: case CompLevel_limited_profile: @@ -40,7 +46,11 @@ } template<CompLevel level> -bool SimpleThresholdPolicy::loop_predicate_helper(int i, int b, double scale) { +bool SimpleThresholdPolicy::loop_predicate_helper(int i, int b, double scale, Method* method) { + double threshold_scaling; + if (CompilerOracle::has_option_value(method, "CompileThresholdScaling", threshold_scaling)) { + scale *= threshold_scaling; + } switch(level) { case CompLevel_none: case CompLevel_limited_profile:
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -276,18 +276,6 @@ THREAD->set_current_pending_monitor_is_from_java(true); } -// NOTE: must use heavy weight monitor to handle jni monitor enter -bool ObjectSynchronizer::jni_try_enter(Handle obj, Thread* THREAD) { - if (UseBiasedLocking) { - BiasedLocking::revoke_and_rebias(obj, false, THREAD); - assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); - } - - ObjectMonitor* monitor = ObjectSynchronizer::inflate_helper(obj()); - return monitor->try_enter(THREAD); -} - - // NOTE: must use heavy weight monitor to handle jni monitor exit void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) { TEVENT(jni_exit);
--- a/hotspot/src/share/vm/runtime/synchronizer.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/synchronizer.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,6 @@ // Used only to handle jni locks or other unmatched monitor enter/exit // Internally they will use heavy weight monitor. static void jni_enter(Handle obj, TRAPS); - static bool jni_try_enter(Handle obj, Thread* THREAD); // Implements Unsafe.tryMonitorEnter static void jni_exit(oop obj, Thread* THREAD); // Handle all interpreter, compiler and jni cases
--- a/hotspot/src/share/vm/runtime/virtualspace.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -38,7 +38,8 @@ } ReservedSpace::ReservedSpace(size_t size) { - size_t page_size = os::page_size_for_region(size, 1); + // Want to use large pages where possible and pad with small pages. + size_t page_size = os::page_size_for_region_unaligned(size, 1); bool large_pages = page_size != (size_t)os::vm_page_size(); // Don't force the alignment to be large page aligned, // since that will waste memory. @@ -617,7 +618,7 @@ bool VirtualSpace::initialize(ReservedSpace rs, size_t committed_size) { - const size_t max_commit_granularity = os::page_size_for_region(rs.size(), 1); + const size_t max_commit_granularity = os::page_size_for_region_unaligned(rs.size(), 1); return initialize_with_granularity(rs, committed_size, max_commit_granularity); } @@ -1239,7 +1240,7 @@ case Disable: return vs.initialize_with_granularity(rs, 0, os::vm_page_size()); case Commit: - return vs.initialize_with_granularity(rs, 0, os::page_size_for_region(rs.size(), 1)); + return vs.initialize_with_granularity(rs, 0, os::page_size_for_region_unaligned(rs.size(), 1)); } }
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 20:17:15 2017 +0200 @@ -351,11 +351,18 @@ nonstatic_field(MethodData, _arg_stack, intx) \ nonstatic_field(MethodData, _arg_returned, intx) \ nonstatic_field(MethodData, _tenure_traps, uint) \ + nonstatic_field(MethodData, _invoke_mask, int) \ + nonstatic_field(MethodData, _backedge_mask, int) \ nonstatic_field(DataLayout, _header._struct._tag, u1) \ nonstatic_field(DataLayout, _header._struct._flags, u1) \ nonstatic_field(DataLayout, _header._struct._bci, u2) \ nonstatic_field(DataLayout, _cells[0], intptr_t) \ nonstatic_field(MethodCounters, _nmethod_age, int) \ + nonstatic_field(MethodCounters, _interpreter_invocation_limit, int) \ + nonstatic_field(MethodCounters, _interpreter_backward_branch_limit, int) \ + nonstatic_field(MethodCounters, _interpreter_profile_limit, int) \ + nonstatic_field(MethodCounters, _invoke_mask, int) \ + nonstatic_field(MethodCounters, _backedge_mask, int) \ nonstatic_field(MethodCounters, _interpreter_invocation_count, int) \ nonstatic_field(MethodCounters, _interpreter_throwout_count, u2) \ nonstatic_field(MethodCounters, _number_of_breakpoints, u2) \
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Wed Jul 05 20:17:15 2017 +0200 @@ -1142,17 +1142,18 @@ return ((x != NoLongBits) && (mask_long_bits(x, x - 1) == NoLongBits)); } -//* largest i such that 2^i <= x -// A negative value of 'x' will return '31' +// Returns largest i such that 2^i <= x. +// If x < 0, the function returns 31 on a 32-bit machine and 63 on a 64-bit machine. +// If x == 0, the function returns -1. inline int log2_intptr(intptr_t x) { int i = -1; - uintptr_t p = 1; + uintptr_t p = 1; while (p != 0 && p <= (uintptr_t)x) { // p = 2^(i+1) && p <= x (i.e., 2^(i+1) <= x) i++; p *= 2; } // p = 2^(i+1) && x < p (i.e., 2^i <= x < 2^(i+1)) - // (if p = 0 then overflow occurred and i = 31) + // If p = 0, overflow has occurred and i = 31 or i = 63 (depending on the machine word size). return i; }
--- a/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/compiler/arguments/CheckCompileThresholdScaling.java Wed Jul 05 20:17:15 2017 +0200 @@ -54,7 +54,7 @@ // // Tier0InvokeNotifyFreqLog, Tier0BackedgeNotifyFreqLog, // Tier3InvocationThreshold, Tier3MinInvocationThreshold, - // Tier3CompileThreshold, and Tier3BackEdgeThreshold, + // Tier3CompileThreshold, Tier3BackEdgeThreshold, // Tier2InvokeNotifyFreqLog, Tier2BackedgeNotifyFreqLog, // Tier3InvokeNotifyFreqLog, Tier3BackedgeNotifyFreqLog, // Tier23InlineeNotifyFreqLog, Tier4InvocationThreshold,
--- a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Wed Jul 05 20:17:15 2017 +0200 @@ -98,11 +98,13 @@ return false; }); for (BlobType bt : BlobType.getAvailable()) { - int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0; - Asserts.assertEQ(counters.get(bt.getMemoryPool().getName()).get(), - expectedNotificationsAmount, String.format("Unexpected " - + "amount of notifications for pool: %s", - bt.getMemoryPool().getName())); + if (CodeCacheUtils.isCodeHeapPredictable(bt)) { + int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0; + Asserts.assertEQ(counters.get(bt.getMemoryPool().getName()).get(), + expectedNotificationsAmount, String.format("Unexpected " + + "amount of notifications for pool: %s", + bt.getMemoryPool().getName())); + } } try { ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
--- a/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java Wed Jul 05 20:17:15 2017 +0200 @@ -52,7 +52,9 @@ public static void main(String[] args) { for (BlobType bt : BlobType.getAvailable()) { - new ThresholdNotificationsTest(bt).runTest(); + if (CodeCacheUtils.isCodeHeapPredictable(bt)) { + new ThresholdNotificationsTest(bt).runTest(); + } } }
--- a/hotspot/test/compiler/loopopts/7052494/Test7052494.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/compiler/loopopts/7052494/Test7052494.java Wed Jul 05 20:17:15 2017 +0200 @@ -25,7 +25,6 @@ /** * @test * @bug 7052494 - * @ignore 7154567 * @summary Eclipse test fails on JDK 7 b142 * * @run main/othervm -Xbatch Test7052494
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/stringopts/TestOptimizeStringConcat.java Wed Jul 05 20:17:15 2017 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright 2015 SAP AG. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8068909 + * @key regression + * @summary test that string optimizations produce code, that doesn't lead to a crash. + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestOptimizeStringConcat + * @author axel.siebenborn@sap.com + */ +public class TestOptimizeStringConcat { + + static boolean checkArgumentSyntax(String value, String allowedchars, String notallowedchars, String logmsg) { + String rc = null; + + int maxchar = 99999; + int minchar = 1; + if ((allowedchars != null && notallowedchars != null) || minchar > maxchar) { + rc = "internal error"; + } else { + if (value == null) { + rc = "the value null is not allowed, it is missing"; + } else if (value != null && minchar > 0 && value.trim().equals("")) { + rc = "the value must not be empty"; + } else if (value != null) { + if (value.length() < minchar || value.length() > maxchar) { + if (rc == null) { + rc = "the value length must be between +minchar+ and +maxchar"; + } + } + char[] _value = value.toCharArray(); + boolean dotfound = false; + int i = 1; + if (_value[i] == '.' && !dotfound) { + dotfound = true; + } else if (allowedchars != null && allowedchars.indexOf(_value[i]) == -1) { + if (rc == null) { + rc = "the value contains an illegal character: '" + _value[i] + "', only following characters are allowed: '+allowedchars+'"; + } else { + rc += " / the value contains an illegal character: '" + _value[i] + "', only following characters are allowed: '+allowedchars+'"; + } + } else if (notallowedchars != null && notallowedchars.indexOf(_value[i]) != -1) { + if (rc == null) { + rc = "the value contains an illegal character: '" + _value[i] + "', following characters are not allowed '+notallowedchars+'"; + } else { + rc += " / the value contains an illegal character: '" + _value[i] + "', following characters are not allowed '+notallowedchars+'"; + } + } + } + } + + if (rc != null) { + System.out.println(logmsg + " ==> " + rc); + return false; + } + return true; + } + + public static void main(String[] args) { + boolean failed = false; + for (int i = 0; i < 10000; i++) { + failed |= !checkArgumentSyntax("theName", null, "\"<&", "Error consistencyCheck: name in component definition"); + failed |= !checkArgumentSyntax(null, null, "\"<&", "Error consistencyCheck: name in component definition"); + failed |= !checkArgumentSyntax("42", "0123456789.", null, "Error consistencyCheck: counter in component definition"); + } + System.out.println(failed); + } +}
--- a/hotspot/test/compiler/testlibrary/rtm/BusyLock.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/compiler/testlibrary/rtm/BusyLock.java Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,6 @@ package rtm; -import com.oracle.java.testlibrary.Utils; -import sun.misc.Unsafe; - import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; @@ -42,7 +39,6 @@ // Following field have to be static in order to avoid escape analysis. @SuppressWarnings("UnsuedDeclaration") private static int field = 0; - private static final Unsafe UNSAFE = Utils.getUnsafe(); protected final Object monitor; protected final int timeout; @@ -59,18 +55,9 @@ @Override public void run() { try { - // wait until forceAbort leave monitor - barrier.await(); - if (UNSAFE.tryMonitorEnter(monitor)) { - try { - barrier.await(); - Thread.sleep(timeout); - } finally { - UNSAFE.monitorExit(monitor); - } - } else { - throw new RuntimeException("Monitor should be entered by " + - "::run() first."); + synchronized (monitor) { + barrier.await(); + Thread.sleep(timeout); } } catch (InterruptedException | BrokenBarrierException e) { throw new RuntimeException("Synchronization error happened.", e); @@ -79,7 +66,6 @@ public void syncAndTest() { try { - barrier.await(); // wait until monitor is locked by a ::run method barrier.await(); } catch (InterruptedException | BrokenBarrierException e) {
--- a/hotspot/test/gc/TestNUMAPageSize.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/gc/TestNUMAPageSize.java Wed Jul 05 20:17:15 2017 +0200 @@ -25,6 +25,7 @@ * @test TestNUMAPageSize * @summary Make sure that start up with NUMA support does not cause problems. * @bug 8061467 + * @requires (vm.opt.AggressiveOpts == null) | (vm.opt.AggressiveOpts == false) * @key gc * @key regression * @run main/othervm -Xmx8M -XX:+UseNUMA TestNUMAPageSize
--- a/hotspot/test/gc/TestSmallHeap.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/gc/TestSmallHeap.java Wed Jul 05 20:17:15 2017 +0200 @@ -25,6 +25,7 @@ * @test TestSmallHeap * @bug 8067438 * @requires vm.gc=="null" + * @requires (vm.opt.AggressiveOpts=="null") | (vm.opt.AggressiveOpts=="false") * @summary Verify that starting the VM with a small heap works * @library /testlibrary /../../test/lib * @build TestSmallHeap @@ -33,8 +34,9 @@ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseSerialGC TestSmallHeap * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseG1GC TestSmallHeap * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseConcMarkSweepGC TestSmallHeap - * - * Note: It would be nice to verify the minimal supported heap size (2m) here, + */ + +/* Note: It would be nice to verify the minimal supported heap size (2m) here, * but we align the heap size based on the card table size. And the card table * size is aligned based on the minimal pages size provided by the os. This * means that on most platforms, where the minimal page size is 4k, we get a
--- a/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/gc/g1/TestHumongousCodeCacheRoots.java Wed Jul 05 20:17:15 2017 +0200 @@ -116,7 +116,14 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(finalargs.toArray(new String[0])); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); + try { + output.shouldHaveExitValue(0); + } catch (RuntimeException e) { + // It's ok if there is no client vm in the jdk. + if (output.firstMatch("Unrecognized option: -client") == null) { + throw e; + } + } return output; }
--- a/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/runtime/ErrorHandling/ProblematicFrameTest.java Wed Jul 05 20:17:15 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-Xmx64m", "-XX:-TransmitErrorReport", Crasher.class.getName()); + "-Xmx64m", "-XX:-TransmitErrorReport", "-XX:-CreateMinidumpOnCrash", Crasher.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotMatch("error occurred during error reporting \\(printing problematic frame\\)"); }
--- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java Thu Jan 29 15:36:12 2015 -0800 +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java Wed Jul 05 20:17:15 2017 +0200 @@ -25,6 +25,7 @@ * @test CompilerQueueTest * @bug 8054889 * @library .. + * @ignore 8069160 * @build DcmdUtil CompilerQueueTest * @run main CompilerQueueTest * @run main/othervm -XX:-TieredCompilation CompilerQueueTest
--- a/jdk/.hgtags Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/.hgtags Wed Jul 05 20:17:15 2017 +0200 @@ -290,3 +290,4 @@ 9acaa4f57b0b9e3757a7b4576ca9418a75ea8287 jdk9-b45 efedac7f44ed41cea2b1038138047271f55aacba jdk9-b46 b641c14730ac05d9ec8b4f66e6fca3dc21adb403 jdk9-b47 +ebb2eb7f1aec78eb6d8cc4c96f018afa11093cde jdk9-b48
--- a/jdk/make/Tools.gmk Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/make/Tools.gmk Wed Jul 05 20:17:15 2017 +0200 @@ -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)
--- a/jdk/make/data/checkdeps/refs.allowed Thu Jan 29 15:36:12 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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
--- a/jdk/make/gensrc/GensrcMisc.gmk Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/make/gensrc/GensrcMisc.gmk Wed Jul 05 20:17:15 2017 +0200 @@ -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)
--- a/jdk/make/lib/CoreLibraries.gmk Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/make/lib/CoreLibraries.gmk Wed Jul 05 20:17:15 2017 +0200 @@ -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 + + LIBJLI_CFLAGS += -DPACKAGE_PATH=\"$(PACKAGE_PATH)\" 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) 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)
--- a/jdk/make/lib/Lib-jdk.attach.gmk Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/make/lib/Lib-jdk.attach.gmk Wed Jul 05 20:17:15 2017 +0200 @@ -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) \
--- a/jdk/make/lib/Lib-jdk.security.auth.gmk Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/make/lib/Lib-jdk.security.auth.gmk Wed Jul 05 20:17:15 2017 +0200 @@ -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" \
--- a/jdk/make/lib/NetworkingLibraries.gmk Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/make/lib/NetworkingLibraries.gmk Wed Jul 05 20:17:15 2017 +0200 @@ -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), \
--- a/jdk/make/lib/NioLibraries.gmk Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/make/lib/NioLibraries.gmk Wed Jul 05 20:17:15 2017 +0200 @@ -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) \
--- a/jdk/make/mapfiles/libjava/mapfile-vers Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/make/mapfiles/libjava/mapfile-vers Wed Jul 05 20:17:15 2017 +0200 @@ -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;
--- a/jdk/make/src/classes/build/tools/deps/CheckDeps.java Thu Jan 29 15:36:12 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/aix/native/libnet/aix_close.c Wed Jul 05 20:17:15 2017 +0200 @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +/* + * This file contains implementations of NET_... functions. The NET_.. functions are + * wrappers for common file- and socket functions plus provisions for non-blocking IO. + * + * (basically, the layers remember all file descriptors waiting for a particular fd; + * all threads waiting on a certain fd can be woken up by sending them a signal; this + * is done e.g. when the fd is closed.) + * + * This was originally copied from the linux_close.c implementation. + * + * Side Note: This coding needs initialization. Under Linux this is done + * automatically via __attribute((constructor)), on AIX this is done manually + * (see aix_close_init). + * + */ + +/* + AIX needs a workaround for I/O cancellation, see: + http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm + ... + The close subroutine is blocked until all subroutines which use the file + descriptor return to usr space. For example, when a thread is calling close + and another thread is calling select with the same file descriptor, the + close subroutine does not return until the select call returns. + ... +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/uio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/poll.h> + +/* + * Stack allocated by thread when doing blocking operation + */ +typedef struct threadEntry { + pthread_t thr; /* this thread */ + struct threadEntry *next; /* next thread */ + int intr; /* interrupted */ +} threadEntry_t; + +/* + * Heap allocated during initialized - one entry per fd + */ +typedef struct { + pthread_mutex_t lock; /* fd lock */ + threadEntry_t *threads; /* threads blocked on fd */ +} fdEntry_t; + +/* + * Signal to unblock thread + */ +static int sigWakeup = (SIGRTMAX - 1); + +/* + * The fd table and the number of file descriptors + */ +static fdEntry_t *fdTable = NULL; +static int fdCount = 0; + +/* + * Null signal handler + */ +static void sig_wakeup(int sig) { +} + +/* + * Initialization routine (executed when library is loaded) + * Allocate fd tables and sets up signal handler. + * + * On AIX we don't have __attribute((constructor)) so we need to initialize + * manually (from JNI_OnLoad() in 'src/share/native/java/net/net_util.c') + */ +void aix_close_init() { + struct rlimit nbr_files; + sigset_t sigset; + struct sigaction sa; + + /* Check already initialized */ + if (fdCount > 0 && fdTable != NULL) { + return; + } + + /* + * Allocate table based on the maximum number of + * file descriptors. + */ + if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { + fprintf(stderr, "library initialization failed - " + "unable to get max # of allocated fds\n"); + abort(); + } + fdCount = nbr_files.rlim_max; + /* + * We have a conceptual problem here, when the number of files is + * unlimited. As a kind of workaround, we ensure the table is big + * enough for handle even a large number of files. Since SAP itself + * recommends a limit of 32000 files, we just use 64000 as 'infinity'. + */ + if (nbr_files.rlim_max == RLIM_INFINITY) { + fdCount = 64000; + } + fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + if (fdTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor table - out of memory"); + abort(); + } + + { + int i; + for (i=0; i < fdCount; i++) { + pthread_mutex_init(&fdTable[i].lock, NULL); + } + } + + /* + * Setup the signal handler + */ + sa.sa_handler = sig_wakeup; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sigWakeup, &sa, NULL); + + sigemptyset(&sigset); + sigaddset(&sigset, sigWakeup); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); +} + +/* + * Return the fd table for this fd or NULL is fd out + * of range. + */ +static inline fdEntry_t *getFdEntry(int fd) +{ + if (fd < 0 || fd >= fdCount) { + return NULL; + } + return &fdTable[fd]; +} + +/* + * Start a blocking operation :- + * Insert thread onto thread list for the fd. + */ +static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) +{ + self->thr = pthread_self(); + self->intr = 0; + + pthread_mutex_lock(&(fdEntry->lock)); + { + self->next = fdEntry->threads; + fdEntry->threads = self; + } + pthread_mutex_unlock(&(fdEntry->lock)); +} + +/* + * End a blocking operation :- + * Remove thread from thread list for the fd + * If fd has been interrupted then set errno to EBADF + */ +static inline void endOp + (fdEntry_t *fdEntry, threadEntry_t *self) +{ + int orig_errno = errno; + pthread_mutex_lock(&(fdEntry->lock)); + { + threadEntry_t *curr, *prev=NULL; + curr = fdEntry->threads; + while (curr != NULL) { + if (curr == self) { + if (curr->intr) { + orig_errno = EBADF; + } + if (prev == NULL) { + fdEntry->threads = curr->next; + } else { + prev->next = curr->next; + } + break; + } + prev = curr; + curr = curr->next; + } + } + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; +} + +/* + * Close or dup2 a file descriptor ensuring that all threads blocked on + * the file descriptor are notified via a wakeup signal. + * + * fd1 < 0 => close(fd2) + * fd1 >= 0 => dup2(fd1, fd2) + * + * Returns -1 with errno set if operation fails. + */ +static int closefd(int fd1, int fd2) { + int rv, orig_errno; + fdEntry_t *fdEntry = getFdEntry(fd2); + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Lock the fd to hold-off additional I/O on this fd. + */ + pthread_mutex_lock(&(fdEntry->lock)); + + { + /* On fast machines we see that we enter dup2 before the + * accepting thread had a chance to get and process the signal. + * So in case we woke a thread up, give it some time to cope. + * Also see https://bugs.openjdk.java.net/browse/JDK-8006395 */ + int num_woken = 0; + + /* + * Send a wakeup signal to all threads blocked on this + * file descriptor. + */ + threadEntry_t *curr = fdEntry->threads; + while (curr != NULL) { + curr->intr = 1; + pthread_kill( curr->thr, sigWakeup ); + num_woken ++; + curr = curr->next; + } + + if (num_woken > 0) { + usleep(num_woken * 50); + } + + /* + * And close/dup the file descriptor + * (restart if interrupted by signal) + */ + do { + if (fd1 < 0) { + rv = close(fd2); + } else { + rv = dup2(fd1, fd2); + } + } while (rv == -1 && errno == EINTR); + } + + /* + * Unlock without destroying errno + */ + orig_errno = errno; + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; + + return rv; +} + +/* + * Wrapper for dup2 - same semantics as dup2 system call except + * that any threads blocked in an I/O system call on fd2 will be + * preempted and return -1/EBADF; + */ +int NET_Dup2(int fd, int fd2) { + if (fd < 0) { + errno = EBADF; + return -1; + } + return closefd(fd, fd2); +} + +/* + * Wrapper for close - same semantics as close system call + * except that any threads blocked in an I/O on fd will be + * preempted and the I/O system call will return -1/EBADF. + */ +int NET_SocketClose(int fd) { + return closefd(-1, fd); +} + +/************** Basic I/O operations here ***************/ + +/* + * Macro to perform a blocking IO operation. Restarts + * automatically if interrupted by signal (other than + * our wakeup signal) + */ +#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ + int ret; \ + threadEntry_t self; \ + fdEntry_t *fdEntry = getFdEntry(FD); \ + if (fdEntry == NULL) { \ + errno = EBADF; \ + return -1; \ + } \ + do { \ + startOp(fdEntry, &self); \ + ret = FUNC; \ + endOp(fdEntry, &self); \ + } while (ret == -1 && errno == EINTR); \ + return ret; \ +} + +int NET_Read(int s, void* buf, size_t len) { + BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); +} + +int NET_ReadV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, int *fromlen) { + socklen_t socklen = *fromlen; + BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, &socklen) ); + *fromlen = socklen; +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); +} + +int NET_WriteV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int + flags, const struct sockaddr *to, int tolen) { + BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); +} + +int NET_Accept(int s, struct sockaddr *addr, int *addrlen) { + socklen_t socklen = *addrlen; + BLOCKING_IO_RETURN_INT( s, accept(s, addr, &socklen) ); + *addrlen = socklen; +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + int crc = -1, prc = -1; + threadEntry_t self; + fdEntry_t* fdEntry = getFdEntry(s); + + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* On AIX, when the system call connect() is interrupted, the connection + * is not aborted and it will be established asynchronously by the kernel. + * Hence, no need to restart connect() when EINTR is received + */ + startOp(fdEntry, &self); + crc = connect(s, addr, addrlen); + endOp(fdEntry, &self); + + if (crc == -1 && errno == EINTR) { + struct pollfd s_pollfd; + int sockopt_arg = 0; + socklen_t len; + + s_pollfd.fd = s; + s_pollfd.events = POLLOUT | POLLERR; + + /* poll the file descriptor */ + do { + startOp(fdEntry, &self); + prc = poll(&s_pollfd, 1, -1); + endOp(fdEntry, &self); + } while (prc == -1 && errno == EINTR); + + if (prc < 0) + return prc; + + len = sizeof(sockopt_arg); + + /* Check whether the connection has been established */ + if (getsockopt(s, SOL_SOCKET, SO_ERROR, &sockopt_arg, &len) == -1) + return -1; + + if (sockopt_arg != 0 ) { + errno = sockopt_arg; + return -1; + } + } else { + return crc; + } + + /* At this point, fd is connected. Set successful return code */ + return 0; +} + +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); +} + +/* + * Wrapper for poll(s, timeout). + * Auto restarts with adjusted timeout if interrupted by + * signal other than our wakeup signal. + */ +int NET_Timeout(int s, long timeout) { + long prevtime = 0, newtime; + struct timeval t; + fdEntry_t *fdEntry = getFdEntry(s); + + /* + * Check that fd hasn't been closed. + */ + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Pick up current time as may need to adjust timeout + */ + if (timeout > 0) { + gettimeofday(&t, NULL); + prevtime = t.tv_sec * 1000 + t.tv_usec / 1000; + } + + for(;;) { + struct pollfd pfd; + int rv; + threadEntry_t self; + + /* + * Poll the fd. If interrupted by our wakeup signal + * errno will be set to EBADF. + */ + pfd.fd = s; + pfd.events = POLLIN | POLLERR; + + startOp(fdEntry, &self); + rv = poll(&pfd, 1, timeout); + endOp(fdEntry, &self); + + /* + * If interrupted then adjust timeout. If timeout + * has expired return 0 (indicating timeout expired). + */ + if (rv < 0 && errno == EINTR) { + if (timeout > 0) { + gettimeofday(&t, NULL); + newtime = t.tv_sec * 1000 + t.tv_usec / 1000; + timeout -= newtime - prevtime; + if (timeout <= 0) { + return 0; + } + prevtime = newtime; + } + } else { + return rv; + } + + } +}
--- a/jdk/src/java.base/aix/native/libnet/java/net/aix_close.c Thu Jan 29 15:36:12 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,491 +0,0 @@ -/* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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. - */ - -/* - * This file contains implementations of NET_... functions. The NET_.. functions are - * wrappers for common file- and socket functions plus provisions for non-blocking IO. - * - * (basically, the layers remember all file descriptors waiting for a particular fd; - * all threads waiting on a certain fd can be woken up by sending them a signal; this - * is done e.g. when the fd is closed.) - * - * This was originally copied from the linux_close.c implementation. - * - * Side Note: This coding needs initialization. Under Linux this is done - * automatically via __attribute((constructor)), on AIX this is done manually - * (see aix_close_init). - * - */ - -/* - AIX needs a workaround for I/O cancellation, see: - http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/close.htm - ... - The close subroutine is blocked until all subroutines which use the file - descriptor return to usr space. For example, when a thread is calling close - and another thread is calling select with the same file descriptor, the - close subroutine does not return until the select call returns. - ... -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <pthread.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/uio.h> -#include <unistd.h> -#include <errno.h> -#include <sys/poll.h> - -/* - * Stack allocated by thread when doing blocking operation - */ -typedef struct threadEntry { - pthread_t thr; /* this thread */ - struct threadEntry *next; /* next thread */ - int intr; /* interrupted */ -} threadEntry_t; - -/* - * Heap allocated during initialized - one entry per fd - */ -typedef struct { - pthread_mutex_t lock; /* fd lock */ - threadEntry_t *threads; /* threads blocked on fd */ -} fdEntry_t; - -/* - * Signal to unblock thread - */ -static int sigWakeup = (SIGRTMAX - 1); - -/* - * The fd table and the number of file descriptors - */ -static fdEntry_t *fdTable = NULL; -static int fdCount = 0; - -/* - * Null signal handler - */ -static void sig_wakeup(int sig) { -} - -/* - * Initialization routine (executed when library is loaded) - * Allocate fd tables and sets up signal handler. - * - * On AIX we don't have __attribute((constructor)) so we need to initialize - * manually (from JNI_OnLoad() in 'src/share/native/java/net/net_util.c') - */ -void aix_close_init() { - struct rlimit nbr_files; - sigset_t sigset; - struct sigaction sa; - - /* Check already initialized */ - if (fdCount > 0 && fdTable != NULL) { - return; - } - - /* - * Allocate table based on the maximum number of - * file descriptors. - */ - if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { - fprintf(stderr, "library initialization failed - " - "unable to get max # of allocated fds\n"); - abort(); - } - fdCount = nbr_files.rlim_max; - /* - * We have a conceptual problem here, when the number of files is - * unlimited. As a kind of workaround, we ensure the table is big - * enough for handle even a large number of files. Since SAP itself - * recommends a limit of 32000 files, we just use 64000 as 'infinity'. - */ - if (nbr_files.rlim_max == RLIM_INFINITY) { - fdCount = 64000; - } - fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); - if (fdTable == NULL) { - fprintf(stderr, "library initialization failed - " - "unable to allocate file descriptor table - out of memory"); - abort(); - } - - { - int i; - for (i=0; i < fdCount; i++) { - pthread_mutex_init(&fdTable[i].lock, NULL); - } - } - - /* - * Setup the signal handler - */ - sa.sa_handler = sig_wakeup; - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - sigaction(sigWakeup, &sa, NULL); - - sigemptyset(&sigset); - sigaddset(&sigset, sigWakeup); - sigprocmask(SIG_UNBLOCK, &sigset, NULL); -} - -/* - * Return the fd table for this fd or NULL is fd out - * of range. - */ -static inline fdEntry_t *getFdEntry(int fd) -{ - if (fd < 0 || fd >= fdCount) { - return NULL; - } - return &fdTable[fd]; -} - -/* - * Start a blocking operation :- - * Insert thread onto thread list for the fd. - */ -static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) -{ - self->thr = pthread_self(); - self->intr = 0; - - pthread_mutex_lock(&(fdEntry->lock)); - { - self->next = fdEntry->threads; - fdEntry->threads = self; - } - pthread_mutex_unlock(&(fdEntry->lock)); -} - -/* - * End a blocking operation :- - * Remove thread from thread list for the fd - * If fd has been interrupted then set errno to EBADF - */ -static inline void endOp - (fdEntry_t *fdEntry, threadEntry_t *self) -{ - int orig_errno = errno; - pthread_mutex_lock(&(fdEntry->lock)); - { - threadEntry_t *curr, *prev=NULL; - curr = fdEntry->threads; - while (curr != NULL) { - if (curr == self) { - if (curr->intr) { - orig_errno = EBADF; - } - if (prev == NULL) { - fdEntry->threads = curr->next; - } else { - prev->next = curr->next; - } - break; - } - prev = curr; - curr = curr->next; - } - } - pthread_mutex_unlock(&(fdEntry->lock)); - errno = orig_errno; -} - -/* - * Close or dup2 a file descriptor ensuring that all threads blocked on - * the file descriptor are notified via a wakeup signal. - * - * fd1 < 0 => close(fd2) - * fd1 >= 0 => dup2(fd1, fd2) - * - * Returns -1 with errno set if operation fails. - */ -static int closefd(int fd1, int fd2) { - int rv, orig_errno; - fdEntry_t *fdEntry = getFdEntry(fd2); - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* - * Lock the fd to hold-off additional I/O on this fd. - */ - pthread_mutex_lock(&(fdEntry->lock)); - - { - /* On fast machines we see that we enter dup2 before the - * accepting thread had a chance to get and process the signal. - * So in case we woke a thread up, give it some time to cope. - * Also see https://bugs.openjdk.java.net/browse/JDK-8006395 */ - int num_woken = 0; - - /* - * Send a wakeup signal to all threads blocked on this - * file descriptor. - */ - threadEntry_t *curr = fdEntry->threads; - while (curr != NULL) { - curr->intr = 1; - pthread_kill( curr->thr, sigWakeup ); - num_woken ++; - curr = curr->next; - } - - if (num_woken > 0) { - usleep(num_woken * 50); - } - - /* - * And close/dup the file descriptor - * (restart if interrupted by signal) - */ - do { - if (fd1 < 0) { - rv = close(fd2); - } else { - rv = dup2(fd1, fd2); - } - } while (rv == -1 && errno == EINTR); - } - - /* - * Unlock without destroying errno - */ - orig_errno = errno; - pthread_mutex_unlock(&(fdEntry->lock)); - errno = orig_errno; - - return rv; -} - -/* - * Wrapper for dup2 - same semantics as dup2 system call except - * that any threads blocked in an I/O system call on fd2 will be - * preempted and return -1/EBADF; - */ -int NET_Dup2(int fd, int fd2) { - if (fd < 0) { - errno = EBADF; - return -1; - } - return closefd(fd, fd2); -} - -/* - * Wrapper for close - same semantics as close system call - * except that any threads blocked in an I/O on fd will be - * preempted and the I/O system call will return -1/EBADF. - */ -int NET_SocketClose(int fd) { - return closefd(-1, fd); -} - -/************** Basic I/O operations here ***************/ - -/* - * Macro to perform a blocking IO operation. Restarts - * automatically if interrupted by signal (other than - * our wakeup signal) - */ -#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ - int ret; \ - threadEntry_t self; \ - fdEntry_t *fdEntry = getFdEntry(FD); \ - if (fdEntry == NULL) { \ - errno = EBADF; \ - return -1; \ - } \ - do { \ - startOp(fdEntry, &self); \ - ret = FUNC; \ - endOp(fdEntry, &self); \ - } while (ret == -1 && errno == EINTR); \ - return ret; \ -} - -int NET_Read(int s, void* buf, size_t len) { - BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); -} - -int NET_ReadV(int s, const struct iovec * vector, int count) { - BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); -} - -int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, - struct sockaddr *from, int *fromlen) { - socklen_t socklen = *fromlen; - BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, &socklen) ); - *fromlen = socklen; -} - -int NET_Send(int s, void *msg, int len, unsigned int flags) { - BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); -} - -int NET_WriteV(int s, const struct iovec * vector, int count) { - BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); -} - -int NET_SendTo(int s, const void *msg, int len, unsigned int - flags, const struct sockaddr *to, int tolen) { - BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); -} - -int NET_Accept(int s, struct sockaddr *addr, int *addrlen) { - socklen_t socklen = *addrlen; - BLOCKING_IO_RETURN_INT( s, accept(s, addr, &socklen) ); - *addrlen = socklen; -} - -int NET_Connect(int s, struct sockaddr *addr, int addrlen) { - int crc = -1, prc = -1; - threadEntry_t self; - fdEntry_t* fdEntry = getFdEntry(s); - - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* On AIX, when the system call connect() is interrupted, the connection - * is not aborted and it will be established asynchronously by the kernel. - * Hence, no need to restart connect() when EINTR is received - */ - startOp(fdEntry, &self); - crc = connect(s, addr, addrlen); - endOp(fdEntry, &self); - - if (crc == -1 && errno == EINTR) { - struct pollfd s_pollfd; - int sockopt_arg = 0; - socklen_t len; - - s_pollfd.fd = s; - s_pollfd.events = POLLOUT | POLLERR; - - /* poll the file descriptor */ - do { - startOp(fdEntry, &self); - prc = poll(&s_pollfd, 1, -1); - endOp(fdEntry, &self); - } while (prc == -1 && errno == EINTR); - - if (prc < 0) - return prc; - - len = sizeof(sockopt_arg); - - /* Check whether the connection has been established */ - if (getsockopt(s, SOL_SOCKET, SO_ERROR, &sockopt_arg, &len) == -1) - return -1; - - if (sockopt_arg != 0 ) { - errno = sockopt_arg; - return -1; - } - } else { - return crc; - } - - /* At this point, fd is connected. Set successful return code */ - return 0; -} - -int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { - BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); -} - -/* - * Wrapper for poll(s, timeout). - * Auto restarts with adjusted timeout if interrupted by - * signal other than our wakeup signal. - */ -int NET_Timeout(int s, long timeout) { - long prevtime = 0, newtime; - struct timeval t; - fdEntry_t *fdEntry = getFdEntry(s); - - /* - * Check that fd hasn't been closed. - */ - if (fdEntry == NULL) { - errno = EBADF; - return -1; - } - - /* - * Pick up current time as may need to adjust timeout - */ - if (timeout > 0) { - gettimeofday(&t, NULL); - prevtime = t.tv_sec * 1000 + t.tv_usec / 1000; - } - - for(;;) { - struct pollfd pfd; - int rv; - threadEntry_t self; - - /* - * Poll the fd. If interrupted by our wakeup signal - * errno will be set to EBADF. - */ - pfd.fd = s; - pfd.events = POLLIN | POLLERR; - - startOp(fdEntry, &self); - rv = poll(&pfd, 1, timeout); - endOp(fdEntry, &self); - - /* - * If interrupted then adjust timeout. If timeout - * has expired return 0 (indicating timeout expired). - */ - if (rv < 0 && errno == EINTR) { - if (timeout > 0) { - gettimeofday(&t, NULL); - newtime = t.tv_sec * 1000 + t.tv_usec / 1000; - timeout -= newtime - prevtime; - if (timeout <= 0) { - return 0; - } - prevtime = newtime; - } - } else { - return rv; - } - - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/linux/native/libnet/linux_close.c Wed Jul 05 20:17:15 2017 +0200 @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/uio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/poll.h> + +/* + * Stack allocated by thread when doing blocking operation + */ +typedef struct threadEntry { + pthread_t thr; /* this thread */ + struct threadEntry *next; /* next thread */ + int intr; /* interrupted */ +} threadEntry_t; + +/* + * Heap allocated during initialized - one entry per fd + */ +typedef struct { + pthread_mutex_t lock; /* fd lock */ + threadEntry_t *threads; /* threads blocked on fd */ +} fdEntry_t; + +/* + * Signal to unblock thread + */ +static int sigWakeup = (__SIGRTMAX - 2); + +/* + * The fd table and the number of file descriptors + */ +static fdEntry_t *fdTable; +static int fdCount; + +/* + * Null signal handler + */ +static void sig_wakeup(int sig) { +} + +/* + * Initialization routine (executed when library is loaded) + * Allocate fd tables and sets up signal handler. + */ +static void __attribute((constructor)) init() { + struct rlimit nbr_files; + sigset_t sigset; + struct sigaction sa; + + /* + * Allocate table based on the maximum number of + * file descriptors. + */ + getrlimit(RLIMIT_NOFILE, &nbr_files); + fdCount = nbr_files.rlim_max; + fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + if (fdTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor table - out of memory"); + abort(); + } + + /* + * Setup the signal handler + */ + sa.sa_handler = sig_wakeup; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sigWakeup, &sa, NULL); + + sigemptyset(&sigset); + sigaddset(&sigset, sigWakeup); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); +} + +/* + * Return the fd table for this fd or NULL is fd out + * of range. + */ +static inline fdEntry_t *getFdEntry(int fd) +{ + if (fd < 0 || fd >= fdCount) { + return NULL; + } + return &fdTable[fd]; +} + +/* + * Start a blocking operation :- + * Insert thread onto thread list for the fd. + */ +static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) +{ + self->thr = pthread_self(); + self->intr = 0; + + pthread_mutex_lock(&(fdEntry->lock)); + { + self->next = fdEntry->threads; + fdEntry->threads = self; + } + pthread_mutex_unlock(&(fdEntry->lock)); +} + +/* + * End a blocking operation :- + * Remove thread from thread list for the fd + * If fd has been interrupted then set errno to EBADF + */ +static inline void endOp + (fdEntry_t *fdEntry, threadEntry_t *self) +{ + int orig_errno = errno; + pthread_mutex_lock(&(fdEntry->lock)); + { + threadEntry_t *curr, *prev=NULL; + curr = fdEntry->threads; + while (curr != NULL) { + if (curr == self) { + if (curr->intr) { + orig_errno = EBADF; + } + if (prev == NULL) { + fdEntry->threads = curr->next; + } else { + prev->next = curr->next; + } + break; + } + prev = curr; + curr = curr->next; + } + } + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; +} + +/* + * Close or dup2 a file descriptor ensuring that all threads blocked on + * the file descriptor are notified via a wakeup signal. + * + * fd1 < 0 => close(fd2) + * fd1 >= 0 => dup2(fd1, fd2) + * + * Returns -1 with errno set if operation fails. + */ +static int closefd(int fd1, int fd2) { + int rv, orig_errno; + fdEntry_t *fdEntry = getFdEntry(fd2); + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Lock the fd to hold-off additional I/O on this fd. + */ + pthread_mutex_lock(&(fdEntry->lock)); + + { + /* + * And close/dup the file descriptor + * (restart if interrupted by signal) + */ + do { + if (fd1 < 0) { + rv = close(fd2); + } else { + rv = dup2(fd1, fd2); + } + } while (rv == -1 && errno == EINTR); + + /* + * Send a wakeup signal to all threads blocked on this + * file descriptor. + */ + threadEntry_t *curr = fdEntry->threads; + while (curr != NULL) { + curr->intr = 1; + pthread_kill( curr->thr, sigWakeup ); + curr = curr->next; + } + } + + /* + * Unlock without destroying errno + */ + orig_errno = errno; + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; + + return rv; +} + +/* + * Wrapper for dup2 - same semantics as dup2 system call except + * that any threads blocked in an I/O system call on fd2 will be + * preempted and return -1/EBADF; + */ +int NET_Dup2(int fd, int fd2) { + if (fd < 0) { + errno = EBADF; + return -1; + } + return closefd(fd, fd2); +} + +/* + * Wrapper for close - same semantics as close system call + * except that any threads blocked in an I/O on fd will be + * preempted and the I/O system call will return -1/EBADF. + */ +int NET_SocketClose(int fd) { + return closefd(-1, fd); +} + +/************** Basic I/O operations here ***************/ + +/* + * Macro to perform a blocking IO operation. Restarts + * automatically if interrupted by signal (other than + * our wakeup signal) + */ +#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ + int ret; \ + threadEntry_t self; \ + fdEntry_t *fdEntry = getFdEntry(FD); \ + if (fdEntry == NULL) { \ + errno = EBADF; \ + return -1; \ + } \ + do { \ + startOp(fdEntry, &self); \ + ret = FUNC; \ + endOp(fdEntry, &self); \ + } while (ret == -1 && errno == EINTR); \ + return ret; \ +} + +int NET_Read(int s, void* buf, size_t len) { + BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); +} + +int NET_ReadV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen) { + BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) ); +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); +} + +int NET_WriteV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int + flags, const struct sockaddr *to, int tolen) { + BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); +} + +int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) ); +} + +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); +} + +/* + * Wrapper for poll(s, timeout). + * Auto restarts with adjusted timeout if interrupted by + * signal other than our wakeup signal. + */ +int NET_Timeout(int s, long timeout) { + long prevtime = 0, newtime; + struct timeval t; + fdEntry_t *fdEntry = getFdEntry(s); + + /* + * Check that fd hasn't been closed. + */ + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Pick up current time as may need to adjust timeout + */ + if (timeout > 0) { + gettimeofday(&t, NULL); + prevtime = t.tv_sec * 1000 + t.tv_usec / 1000; + } + + for(;;) { + struct pollfd pfd; + int rv; + threadEntry_t self; + + /* + * Poll the fd. If interrupted by our wakeup signal + * errno will be set to EBADF. + */ + pfd.fd = s; + pfd.events = POLLIN | POLLERR; + + startOp(fdEntry, &self); + rv = poll(&pfd, 1, timeout); + endOp(fdEntry, &self); + + /* + * If interrupted then adjust timeout. If timeout + * has expired return 0 (indicating timeout expired). + */ + if (rv < 0 && errno == EINTR) { + if (timeout > 0) { + gettimeofday(&t, NULL); + newtime = t.tv_sec * 1000 + t.tv_usec / 1000; + timeout -= newtime - prevtime; + if (timeout <= 0) { + return 0; + } + prevtime = newtime; + } + } else { + return rv; + } + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/macosx/native/libjava/java_props_macosx.c Wed Jul 05 20:17:15 2017 +0200 @@ -0,0 +1,349 @@ +/* + * Copyright (c) 1998, 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. + */ + +#include <dlfcn.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <Security/AuthSession.h> +#include <CoreFoundation/CoreFoundation.h> +#include <SystemConfiguration/SystemConfiguration.h> +#include <Foundation/Foundation.h> + +#include "java_props_macosx.h" + + +// need dlopen/dlsym trick to avoid pulling in JavaRuntimeSupport before libjava.dylib is loaded +static void *getJRSFramework() { + static void *jrsFwk = NULL; + if (jrsFwk == NULL) { + jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL); + } + return jrsFwk; +} + +char *getPosixLocale(int cat) { + char *lc = setlocale(cat, NULL); + if ((lc == NULL) || (strcmp(lc, "C") == 0)) { + lc = getenv("LANG"); + } + if (lc == NULL) return NULL; + return strdup(lc); +} + +#define LOCALEIDLENGTH 128 +char *getMacOSXLocale(int cat) { + switch (cat) { + case LC_MESSAGES: + { + void *jrsFwk = getJRSFramework(); + if (jrsFwk == NULL) return NULL; + + char *(*JRSCopyPrimaryLanguage)() = dlsym(jrsFwk, "JRSCopyPrimaryLanguage"); + char *primaryLanguage = JRSCopyPrimaryLanguage ? JRSCopyPrimaryLanguage() : NULL; + if (primaryLanguage == NULL) return NULL; + + char *(*JRSCopyCanonicalLanguageForPrimaryLanguage)(char *) = dlsym(jrsFwk, "JRSCopyCanonicalLanguageForPrimaryLanguage"); + char *canonicalLanguage = JRSCopyCanonicalLanguageForPrimaryLanguage ? JRSCopyCanonicalLanguageForPrimaryLanguage(primaryLanguage) : NULL; + free (primaryLanguage); + + return canonicalLanguage; + } + break; + default: + { + char localeString[LOCALEIDLENGTH]; + if (CFStringGetCString(CFLocaleGetIdentifier(CFLocaleCopyCurrent()), + localeString, LOCALEIDLENGTH, CFStringGetSystemEncoding())) { + return strdup(localeString); + } + } + break; + } + + return NULL; +} + +char *setupMacOSXLocale(int cat) { + char * ret = getMacOSXLocale(cat); + + if (cat == LC_MESSAGES && ret != NULL) { + void *jrsFwk = getJRSFramework(); + if (jrsFwk != NULL) { + void (*JRSSetDefaultLocalization)(char *) = dlsym(jrsFwk, "JRSSetDefaultLocalization"); + if (JRSSetDefaultLocalization) JRSSetDefaultLocalization(ret); + } + } + + if (ret == NULL) { + return getPosixLocale(cat); + } else { + return ret; + } +} + +int isInAquaSession() { + // environment variable to bypass the aqua session check + char *ev = getenv("AWT_FORCE_HEADFUL"); + if (ev && (strncasecmp(ev, "true", 4) == 0)) { + // if "true" then tell the caller we're in an Aqua session without actually checking + return 1; + } + // Is the WindowServer available? + SecuritySessionId session_id; + SessionAttributeBits session_info; + OSStatus status = SessionGetInfo(callerSecuritySession, &session_id, &session_info); + if (status == noErr) { + if (session_info & sessionHasGraphicAccess) { + return 1; + } + } + return 0; +} + +void setOSNameAndVersion(java_props_t *sprops) { + /* Don't rely on JRSCopyOSName because there's no guarantee the value will + * remain the same, or even if the JRS functions will continue to be part of + * Mac OS X. So hardcode os_name, and fill in os_version if we can. + */ + sprops->os_name = strdup("Mac OS X"); + + void *jrsFwk = getJRSFramework(); + if (jrsFwk != NULL) { + char *(*copyOSVersion)() = dlsym(jrsFwk, "JRSCopyOSVersion"); + if (copyOSVersion != NULL) { + sprops->os_version = copyOSVersion(); + return; + } + } + sprops->os_version = strdup("Unknown"); +} + + +static Boolean getProxyInfoForProtocol(CFDictionaryRef inDict, CFStringRef inEnabledKey, CFStringRef inHostKey, CFStringRef inPortKey, CFStringRef *outProxyHost, int *ioProxyPort) { + /* See if the proxy is enabled. */ + CFNumberRef cf_enabled = CFDictionaryGetValue(inDict, inEnabledKey); + if (cf_enabled == NULL) { + return false; + } + + int isEnabled = false; + if (!CFNumberGetValue(cf_enabled, kCFNumberIntType, &isEnabled)) { + return isEnabled; + } + + if (!isEnabled) return false; + *outProxyHost = CFDictionaryGetValue(inDict, inHostKey); + + // If cf_host is null, that means the checkbox is set, + // but no host was entered. We'll treat that as NOT ENABLED. + // If cf_port is null or cf_port isn't a number, that means + // no port number was entered. Treat this as ENABLED with the + // protocol's default port. + if (*outProxyHost == NULL) { + return false; + } + + if (CFStringGetLength(*outProxyHost) == 0) { + return false; + } + + int newPort = 0; + CFNumberRef cf_port = NULL; + if ((cf_port = CFDictionaryGetValue(inDict, inPortKey)) != NULL && + CFNumberGetValue(cf_port, kCFNumberIntType, &newPort) && + newPort > 0) { + *ioProxyPort = newPort; + } else { + // bad port or no port - leave *ioProxyPort unchanged + } + + return true; +} + +static char *createUTF8CString(const CFStringRef theString) { + if (theString == NULL) return NULL; + + const CFIndex stringLength = CFStringGetLength(theString); + const CFIndex bufSize = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 1; + char *returnVal = (char *)malloc(bufSize); + + if (CFStringGetCString(theString, returnVal, bufSize, kCFStringEncodingUTF8)) { + return returnVal; + } + + free(returnVal); + return NULL; +} + +// Return TRUE if str is a syntactically valid IP address. +// Using inet_pton() instead of inet_aton() for IPv6 support. +// len is only a hint; cstr must still be nul-terminated +static int looksLikeIPAddress(char *cstr, size_t len) { + if (len == 0 || (len == 1 && cstr[0] == '.')) return FALSE; + + char dst[16]; // big enough for INET6 + return (1 == inet_pton(AF_INET, cstr, dst) || + 1 == inet_pton(AF_INET6, cstr, dst)); +} + + + +// Convert Mac OS X proxy exception entry to Java syntax. +// See Radar #3441134 for details. +// Returns NULL if this exception should be ignored by Java. +// May generate a string with multiple exceptions separated by '|'. +static char * createConvertedException(CFStringRef cf_original) { + // This is done with char* instead of CFString because inet_pton() + // needs a C string. + char *c_exception = createUTF8CString(cf_original); + if (!c_exception) return NULL; + + int c_len = strlen(c_exception); + + // 1. sanitize exception prefix + if (c_len >= 1 && 0 == strncmp(c_exception, ".", 1)) { + memmove(c_exception, c_exception+1, c_len); + c_len -= 1; + } else if (c_len >= 2 && 0 == strncmp(c_exception, "*.", 2)) { + memmove(c_exception, c_exception+2, c_len-1); + c_len -= 2; + } + + // 2. pre-reject other exception wildcards + if (strchr(c_exception, '*')) { + free(c_exception); + return NULL; + } + + // 3. no IP wildcarding + if (looksLikeIPAddress(c_exception, c_len)) { + return c_exception; + } + + // 4. allow domain suffixes + // c_exception is now "str\0" - change to "str|*.str\0" + c_exception = reallocf(c_exception, c_len+3+c_len+1); + if (!c_exception) return NULL; + + strncpy(c_exception+c_len, "|*.", 3); + strncpy(c_exception+c_len+3, c_exception, c_len); + c_exception[c_len+3+c_len] = '\0'; + return c_exception; +} + +/* + * Method for fetching the user.home path and storing it in the property list. + * For signed .apps running in the Mac App Sandbox, user.home is set to the + * app's sandbox container. + */ +void setUserHome(java_props_t *sprops) { + if (sprops == NULL) { return; } + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + sprops->user_home = createUTF8CString((CFStringRef)NSHomeDirectory()); + [pool drain]; +} + +/* + * Method for fetching proxy info and storing it in the property list. + */ +void setProxyProperties(java_props_t *sProps) { + if (sProps == NULL) return; + + char buf[16]; /* Used for %d of an int - 16 is plenty */ + CFStringRef + cf_httpHost = NULL, + cf_httpsHost = NULL, + cf_ftpHost = NULL, + cf_socksHost = NULL, + cf_gopherHost = NULL; + int + httpPort = 80, // Default proxy port values + httpsPort = 443, + ftpPort = 21, + socksPort = 1080, + gopherPort = 70; + + CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL); + if (dict == NULL) return; + + /* Read the proxy exceptions list */ + CFArrayRef cf_list = CFDictionaryGetValue(dict, kSCPropNetProxiesExceptionsList); + + CFMutableStringRef cf_exceptionList = NULL; + if (cf_list != NULL) { + CFIndex len = CFArrayGetCount(cf_list), idx; + + cf_exceptionList = CFStringCreateMutable(NULL, 0); + for (idx = (CFIndex)0; idx < len; idx++) { + CFStringRef cf_ehost; + if ((cf_ehost = CFArrayGetValueAtIndex(cf_list, idx))) { + /* Convert this exception from Mac OS X syntax to Java syntax. + See Radar #3441134 for details. This may generate a string + with multiple Java exceptions separated by '|'. */ + char *c_exception = createConvertedException(cf_ehost); + if (c_exception) { + /* Append the host to the list of exclusions. */ + if (CFStringGetLength(cf_exceptionList) > 0) { + CFStringAppendCString(cf_exceptionList, "|", kCFStringEncodingMacRoman); + } + CFStringAppendCString(cf_exceptionList, c_exception, kCFStringEncodingMacRoman); + free(c_exception); + } + } + } + } + + if (cf_exceptionList != NULL) { + if (CFStringGetLength(cf_exceptionList) > 0) { + sProps->exceptionList = createUTF8CString(cf_exceptionList); + } + CFRelease(cf_exceptionList); + } + +#define CHECK_PROXY(protocol, PROTOCOL) \ + sProps->protocol##ProxyEnabled = \ + getProxyInfoForProtocol(dict, kSCPropNetProxies##PROTOCOL##Enable, \ + kSCPropNetProxies##PROTOCOL##Proxy, \ + kSCPropNetProxies##PROTOCOL##Port, \ + &cf_##protocol##Host, &protocol##Port); \ + if (sProps->protocol##ProxyEnabled) { \ + sProps->protocol##Host = createUTF8CString(cf_##protocol##Host); \ + snprintf(buf, sizeof(buf), "%d", protocol##Port); \ + sProps->protocol##Port = malloc(strlen(buf) + 1); \ + strcpy(sProps->protocol##Port, buf); \ + } + + CHECK_PROXY(http, HTTP); + CHECK_PROXY(https, HTTPS); + CHECK_PROXY(ftp, FTP); + CHECK_PROXY(socks, SOCKS); + CHECK_PROXY(gopher, Gopher); + +#undef CHECK_PROXY + + CFRelease(dict); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/macosx/native/libjava/java_props_macosx.h Wed Jul 05 20:17:15 2017 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1998, 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. + */ + +#include "java_props.h" + +char *setupMacOSXLocale(int cat); +void setOSNameAndVersion(java_props_t *sprops); +void setUserHome(java_props_t *sprops); +void setProxyProperties(java_props_t *sProps); +int isInAquaSession();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/macosx/native/libnet/bsd_close.c Wed Jul 05 20:17:15 2017 +0200 @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/param.h> +#include <signal.h> +#include <pthread.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/uio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/poll.h> + +/* + * Stack allocated by thread when doing blocking operation + */ +typedef struct threadEntry { + pthread_t thr; /* this thread */ + struct threadEntry *next; /* next thread */ + int intr; /* interrupted */ +} threadEntry_t; + +/* + * Heap allocated during initialized - one entry per fd + */ +typedef struct { + pthread_mutex_t lock; /* fd lock */ + threadEntry_t *threads; /* threads blocked on fd */ +} fdEntry_t; + +/* + * Signal to unblock thread + */ +static int sigWakeup = SIGIO; + +/* + * The fd table and the number of file descriptors + */ +static fdEntry_t *fdTable; +static int fdCount; + +/* + * This limit applies if getlimit() returns unlimited. + * Unfortunately, this means if someone wants a higher limit + * then they have to set an explicit limit, higher than this, + * which is probably counter-intuitive. + */ +#define MAX_FD_COUNT 4096 + +/* + * Null signal handler + */ +static void sig_wakeup(int sig) { +} + +/* + * Initialization routine (executed when library is loaded) + * Allocate fd tables and sets up signal handler. + */ +static void __attribute((constructor)) init() { + struct rlimit nbr_files; + sigset_t sigset; + struct sigaction sa; + int i; + + /* + * Allocate table based on the maximum number of + * file descriptors. + */ + getrlimit(RLIMIT_NOFILE, &nbr_files); + if (nbr_files.rlim_max == RLIM_INFINITY) { + fdCount = MAX_FD_COUNT; + } else { + fdCount = nbr_files.rlim_max; + } + fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t)); + if (fdTable == NULL) { + fprintf(stderr, "library initialization failed - " + "unable to allocate file descriptor table - out of memory"); + abort(); + } + for (i=0; i<fdCount; i++) { + pthread_mutex_init(&fdTable[i].lock, NULL); + } + + /* + * Setup the signal handler + */ + sa.sa_handler = sig_wakeup; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sigWakeup, &sa, NULL); + + sigemptyset(&sigset); + sigaddset(&sigset, sigWakeup); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); +} + +/* + * Return the fd table for this fd or NULL is fd out + * of range. + */ +static inline fdEntry_t *getFdEntry(int fd) +{ + if (fd < 0 || fd >= fdCount) { + return NULL; + } + return &fdTable[fd]; +} + +/* + * Start a blocking operation :- + * Insert thread onto thread list for the fd. + */ +static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) +{ + self->thr = pthread_self(); + self->intr = 0; + + pthread_mutex_lock(&(fdEntry->lock)); + { + self->next = fdEntry->threads; + fdEntry->threads = self; + } + pthread_mutex_unlock(&(fdEntry->lock)); +} + +/* + * End a blocking operation :- + * Remove thread from thread list for the fd + * If fd has been interrupted then set errno to EBADF + */ +static inline void endOp + (fdEntry_t *fdEntry, threadEntry_t *self) +{ + int orig_errno = errno; + pthread_mutex_lock(&(fdEntry->lock)); + { + threadEntry_t *curr, *prev=NULL; + curr = fdEntry->threads; + while (curr != NULL) { + if (curr == self) { + if (curr->intr) { + orig_errno = EBADF; + } + if (prev == NULL) { + fdEntry->threads = curr->next; + } else { + prev->next = curr->next; + } + break; + } + prev = curr; + curr = curr->next; + } + } + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; +} + +/* + * Close or dup2 a file descriptor ensuring that all threads blocked on + * the file descriptor are notified via a wakeup signal. + * + * fd1 < 0 => close(fd2) + * fd1 >= 0 => dup2(fd1, fd2) + * + * Returns -1 with errno set if operation fails. + */ +static int closefd(int fd1, int fd2) { + int rv, orig_errno; + fdEntry_t *fdEntry = getFdEntry(fd2); + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Lock the fd to hold-off additional I/O on this fd. + */ + pthread_mutex_lock(&(fdEntry->lock)); + + { + /* + * Send a wakeup signal to all threads blocked on this + * file descriptor. + */ + threadEntry_t *curr = fdEntry->threads; + while (curr != NULL) { + curr->intr = 1; + pthread_kill( curr->thr, sigWakeup ); + curr = curr->next; + } + + /* + * And close/dup the file descriptor + * (restart if interrupted by signal) + */ + do { + if (fd1 < 0) { + rv = close(fd2); + } else { + rv = dup2(fd1, fd2); + } + } while (rv == -1 && errno == EINTR); + + } + + /* + * Unlock without destroying errno + */ + orig_errno = errno; + pthread_mutex_unlock(&(fdEntry->lock)); + errno = orig_errno; + + return rv; +} + +/* + * Wrapper for dup2 - same semantics as dup2 system call except + * that any threads blocked in an I/O system call on fd2 will be + * preempted and return -1/EBADF; + */ +int NET_Dup2(int fd, int fd2) { + if (fd < 0) { + errno = EBADF; + return -1; + } + return closefd(fd, fd2); +} + +/* + * Wrapper for close - same semantics as close system call + * except that any threads blocked in an I/O on fd will be + * preempted and the I/O system call will return -1/EBADF. + */ +int NET_SocketClose(int fd) { + return closefd(-1, fd); +} + +/************** Basic I/O operations here ***************/ + +/* + * Macro to perform a blocking IO operation. Restarts + * automatically if interrupted by signal (other than + * our wakeup signal) + */ +#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ + int ret; \ + threadEntry_t self; \ + fdEntry_t *fdEntry = getFdEntry(FD); \ + if (fdEntry == NULL) { \ + errno = EBADF; \ + return -1; \ + } \ + do { \ + startOp(fdEntry, &self); \ + ret = FUNC; \ + endOp(fdEntry, &self); \ + } while (ret == -1 && errno == EINTR); \ + return ret; \ +} + +int NET_Read(int s, void* buf, size_t len) { + BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); +} + +int NET_ReadV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) ); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen) { + BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) ); +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); +} + +int NET_WriteV(int s, const struct iovec * vector, int count) { + BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) ); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int + flags, const struct sockaddr *to, int tolen) { + BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); +} + +int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) ); +} + +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); +} + +/* + * Wrapper for select(s, timeout). We are using select() on Mac OS due to Bug 7131399. + * Auto restarts with adjusted timeout if interrupted by + * signal other than our wakeup signal. + */ +int NET_Timeout(int s, long timeout) { + long prevtime = 0, newtime; + struct timeval t, *tp = &t; + fd_set fds; + fd_set* fdsp = NULL; + int allocated = 0; + threadEntry_t self; + fdEntry_t *fdEntry = getFdEntry(s); + + /* + * Check that fd hasn't been closed. + */ + if (fdEntry == NULL) { + errno = EBADF; + return -1; + } + + /* + * Pick up current time as may need to adjust timeout + */ + if (timeout > 0) { + /* Timed */ + struct timeval now; + gettimeofday(&now, NULL); + prevtime = now.tv_sec * 1000 + now.tv_usec / 1000; + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + } else if (timeout < 0) { + /* Blocking */ + tp = 0; + } else { + /* Poll */ + t.tv_sec = 0; + t.tv_usec = 0; + } + + if (s < FD_SETSIZE) { + fdsp = &fds; + FD_ZERO(fdsp); + } else { + int length = (howmany(s+1, NFDBITS)) * sizeof(int); + fdsp = (fd_set *) calloc(1, length); + if (fdsp == NULL) { + return -1; // errno will be set to ENOMEM + } + allocated = 1; + } + FD_SET(s, fdsp); + + for(;;) { + int rv; + + /* + * call select on the fd. If interrupted by our wakeup signal + * errno will be set to EBADF. + */ + + startOp(fdEntry, &self); + rv = select(s+1, fdsp, 0, 0, tp); + endOp(fdEntry, &self); + + /* + * If interrupted then adjust timeout. If timeout + * has expired return 0 (indicating timeout expired). + */ + if (rv < 0 && errno == EINTR) { + if (timeout > 0) { + struct timeval now; + gettimeofday(&now, NULL); + newtime = now.tv_sec * 1000 + now.tv_usec / 1000; + timeout -= newtime - prevtime; + if (timeout <= 0) { + if (allocated != 0) + free(fdsp); + return 0; + } + prevtime = newtime; + t.tv_sec = timeout / 1000; + t.tv_usec = (timeout % 1000) * 1000; + } + } else { + if (allocated != 0) + free(fdsp); + return rv; + } + + } +}
--- a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Wed Jul 05 20:17:15 2017 +0200 @@ -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() {
--- a/jdk/src/java.base/share/classes/java/lang/Object.java Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/Object.java Wed Jul 05 20:17:15 2017 +0200 @@ -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
--- a/jdk/src/java.base/share/classes/java/lang/String.java Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/String.java Wed Jul 05 20:17:15 2017 +0200 @@ -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. *
--- a/jdk/src/java.base/share/classes/java/lang/System.java Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/System.java Wed Jul 05 20:17:15 2017 +0200 @@ -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
--- a/jdk/src/java.base/share/classes/java/util/Spliterator.java Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/util/Spliterator.java Wed Jul 05 20:17:15 2017 +0200 @@ -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
--- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Wed Jul 05 20:17:15 2017 +0200 @@ -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);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/solaris/native/libnet/solaris_close.c Wed Jul 05 20:17:15 2017 +0200 @@ -0,0 +1,117 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include <errno.h> +#include <sys/socket.h> +#include <stropts.h> +#include <unistd.h> + +/* Support for restartable system calls on Solaris. */ + +#define RESTARTABLE_RETURN_INT(_cmd) do { \ + int _result; \ + if (1) { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ + return _result; \ + } \ +} while(0) + +int NET_Read(int s, void* buf, size_t len) { + RESTARTABLE_RETURN_INT(recv(s, buf, len, 0)); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen) { + RESTARTABLE_RETURN_INT(recvfrom(s, buf, len, flags, from, fromlen)); +} + +int NET_ReadV(int s, const struct iovec * vector, int count) { + RESTARTABLE_RETURN_INT(readv(s, vector, count)); +} + +int NET_WriteV(int s, const struct iovec * vector, int count) { + RESTARTABLE_RETURN_INT(writev(s, vector, count)); +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + RESTARTABLE_RETURN_INT(send(s, msg, len, flags)); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int flags, + const struct sockaddr *to, int tolen) { + RESTARTABLE_RETURN_INT(sendto(s, msg, len, flags, to, tolen)); +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + RESTARTABLE_RETURN_INT(connect(s, addr, addrlen)); +} + +int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + RESTARTABLE_RETURN_INT(accept(s, addr, addrlen)); +} + +int NET_SocketClose(int fd) { + return close(fd); +} + +int NET_Dup2(int fd, int fd2) { + return dup2(fd, fd2); +} + +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + RESTARTABLE_RETURN_INT(poll(ufds, nfds, timeout)); +} + +int NET_Timeout(int s, long timeout) { + int result; + struct timeval t; + long prevtime, newtime; + struct pollfd pfd; + pfd.fd = s; + pfd.events = POLLIN; + + if (timeout > 0) { + gettimeofday(&t, NULL); + prevtime = (t.tv_sec * 1000) + t.tv_usec / 1000; + } + + for(;;) { + result = poll(&pfd, 1, timeout); + if (result < 0 && errno == EINTR) { + if (timeout > 0) { + gettimeofday(&t, NULL); + newtime = (t.tv_sec * 1000) + t.tv_usec /1000; + timeout -= newtime - prevtime; + if (timeout <= 0) + return 0; + prevtime = newtime; + } + } else { + return result; + } + } +}
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java Thu Jan 29 15:36:12 2015 -0800 +++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java Wed Jul 05 20:17:15 2017 +0200 @@ -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; + } + } + } + } }
--- a/jdk/src/java.base/unix/classes/java/lang/UNIXProcess.java Thu Jan 29 15:36:12 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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. - */