# HG changeset patch # User duke # Date 1499277710 -7200 # Node ID 1b1ec4291abc0ba6da7bf79b754f08dd759a4a0c # Parent 66b7d29b75f7933b63988392385425018738fd5f# Parent 89a653341cf255db3544fc238b78d7ea7fe7e035 Merge diff -r 89a653341cf2 -r 1b1ec4291abc .hgtags-top-repo --- a/.hgtags-top-repo Wed Jul 05 20:01:05 2017 +0200 +++ b/.hgtags-top-repo Wed Jul 05 20:01:50 2017 +0200 @@ -273,3 +273,4 @@ ea2f7981236f3812436958748ab3d26e80a35130 jdk9-b28 9e6581aeda388a23fbee021fc33e6aa152a60657 jdk9-b29 36e9bc875325813ac9c44ac0c617a463091fa9f5 jdk9-b30 +69a84c16d9c28e0e3d504b9c8766c24bafcd58f6 jdk9-b31 diff -r 89a653341cf2 -r 1b1ec4291abc Makefile --- a/Makefile Wed Jul 05 20:01:05 2017 +0200 +++ b/Makefile Wed Jul 05 20:01:50 2017 +0200 @@ -70,8 +70,8 @@ # Run the makefile with an arbitrary SPEC using -p -q (quiet dry-run and dump rules) to find # available PHONY targets. Use this list as valid targets to pass on to the repeated calls. all_phony_targets := $(sort $(filter-out $(global_targets), $(strip $(shell \ - cd $(root_dir)/make && $(MAKE) -f Main.gmk -p -q FRC SPEC=$(firstword $(SPEC)) | \ - grep "^.PHONY:" | head -n 1 | cut -d " " -f 2-)))) + cd $(root_dir)/make && $(MAKE) -f Main.gmk -p -q FRC SPEC=$(firstword $(SPEC)) \ + -I $(root_dir)/make/common | grep "^.PHONY:" | head -n 1 | cut -d " " -f 2-)))) # Loop through the configurations and call the main-wrapper for each one. The wrapper # target will execute with a single configuration loaded. @@ -115,12 +115,12 @@ main-wrapper: ifneq ($(SEQUENTIAL_TARGETS), ) - (cd $(root_dir)/make && $(MAKE) -f Main.gmk SPEC=$(SPEC) -j 1 \ + (cd $(SRC_ROOT)/make && $(MAKE) -f Main.gmk SPEC=$(SPEC) -j 1 \ $(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $(SEQUENTIAL_TARGETS)) endif ifneq ($(PARALLEL_TARGETS), ) @$(call AtMakeStart) - (cd $(root_dir)/make && $(BUILD_LOG_WRAPPER) $(MAKE) -f Main.gmk SPEC=$(SPEC) -j $(JOBS) \ + (cd $(SRC_ROOT)/make && $(BUILD_LOG_WRAPPER) $(MAKE) -f Main.gmk SPEC=$(SPEC) -j $(JOBS) \ $(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $(PARALLEL_TARGETS) \ $(if $(filter true, $(OUTPUT_SYNC_SUPPORTED)), -O$(OUTPUT_SYNC))) @$(call AtMakeEnd) diff -r 89a653341cf2 -r 1b1ec4291abc common/autoconf/generated-configure.sh --- a/common/autoconf/generated-configure.sh Wed Jul 05 20:01:05 2017 +0200 +++ b/common/autoconf/generated-configure.sh Wed Jul 05 20:01:50 2017 +0200 @@ -4327,7 +4327,7 @@ #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1410377275 +DATE_WHEN_GENERATED=1410791401 ############################################################################### # @@ -14642,7 +14642,7 @@ FASTDEBUG="false" DEBUG_CLASSFILES="true" BUILD_VARIANT_RELEASE="-debug" - HOTSPOT_DEBUG_LEVEL="jvmg" + HOTSPOT_DEBUG_LEVEL="debug" HOTSPOT_EXPORT="debug" ;; optimized ) diff -r 89a653341cf2 -r 1b1ec4291abc common/autoconf/hotspot-spec.gmk.in --- a/common/autoconf/hotspot-spec.gmk.in Wed Jul 05 20:01:05 2017 +0200 +++ b/common/autoconf/hotspot-spec.gmk.in Wed Jul 05 20:01:50 2017 +0200 @@ -97,8 +97,6 @@ endif HOTSPOT_MAKE_ARGS:=@HOTSPOT_MAKE_ARGS@ @STATIC_CXX_SETTING@ -# This is used from the libjvm build for C/C++ code. -HOTSPOT_BUILD_JOBS:=$(JOBS) # Control wether Hotspot runs Queens test after building TEST_IN_BUILD=@TEST_IN_BUILD@ diff -r 89a653341cf2 -r 1b1ec4291abc common/autoconf/jdk-options.m4 --- a/common/autoconf/jdk-options.m4 Wed Jul 05 20:01:05 2017 +0200 +++ b/common/autoconf/jdk-options.m4 Wed Jul 05 20:01:50 2017 +0200 @@ -234,7 +234,7 @@ FASTDEBUG="false" DEBUG_CLASSFILES="true" BUILD_VARIANT_RELEASE="-debug" - HOTSPOT_DEBUG_LEVEL="jvmg" + HOTSPOT_DEBUG_LEVEL="debug" HOTSPOT_EXPORT="debug" ;; optimized ) diff -r 89a653341cf2 -r 1b1ec4291abc common/autoconf/spec.gmk.in --- a/common/autoconf/spec.gmk.in Wed Jul 05 20:01:05 2017 +0200 +++ b/common/autoconf/spec.gmk.in Wed Jul 05 20:01:50 2017 +0200 @@ -245,6 +245,7 @@ NASHORN_OUTPUTDIR=$(BUILD_OUTPUT)/nashorn IMAGES_OUTPUTDIR=$(BUILD_OUTPUT)/images TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/testmake +MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/make-support LANGTOOLS_DIST=$(LANGTOOLS_OUTPUTDIR)/dist CORBA_DIST=$(CORBA_OUTPUTDIR)/dist diff -r 89a653341cf2 -r 1b1ec4291abc common/bin/unshuffle_list.txt --- a/common/bin/unshuffle_list.txt Wed Jul 05 20:01:05 2017 +0200 +++ b/common/bin/unshuffle_list.txt Wed Jul 05 20:01:50 2017 +0200 @@ -1216,14 +1216,13 @@ jdk/src/java.security.acl/share/classes/sun/security/acl : jdk/src/share/classes/sun/security/acl jdk/src/java.security.jgss/macosx/native/libosxkrb5/nativeccache.c : jdk/src/share/native/sun/security/krb5/nativeccache.c jdk/src/java.security.jgss/macosx/native/libosxkrb5/SCDynamicStoreConfig.m : jdk/src/macosx/native/sun/security/krb5/SCDynamicStoreConfig.m -jdk/src/java.security.jgss/share/classes/com/sun/security/jgss : jdk/src/share/classes/com/sun/security/jgss -jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb : jdk/src/share/classes/com/sun/security/sasl/gsskerb jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos : jdk/src/share/classes/javax/security/auth/kerberos jdk/src/java.security.jgss/share/classes/jgss-overview.html : jdk/src/share/classes/com/sun/security/jgss/jgss-overview.html jdk/src/java.security.jgss/share/classes/org/ietf/jgss : jdk/src/share/classes/org/ietf/jgss jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego : jdk/src/share/classes/sun/net/www/protocol/http/spnego jdk/src/java.security.jgss/share/classes/sun/security/jgss : jdk/src/share/classes/sun/security/jgss jdk/src/java.security.jgss/share/classes/sun/security/krb5 : jdk/src/share/classes/sun/security/krb5 +jdk/src/java.security.jgss/windows/classes/sun/security/krb5 : jdk/src/windows/classes/sun/security/krb5 jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5 : jdk/src/share/classes/sun/security/ssl/krb5 jdk/src/java.security.jgss/share/native/libj2gss : jdk/src/share/native/sun/security/jgss/wrapper jdk/src/java.security.jgss/unix/native/libj2gss : jdk/src/solaris/native/sun/security/jgss/wrapper @@ -1477,6 +1476,8 @@ jdk/src/jdk.security.auth/share/classes/jaas-overview.html : jdk/src/share/classes/com/sun/security/auth/jaas-overview.html jdk/src/jdk.security.auth/unix/native/libjaas : jdk/src/solaris/native/com/sun/security/auth/module jdk/src/jdk.security.auth/windows/native/libjaas : jdk/src/windows/native/com/sun/security/auth/module +jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss : jdk/src/share/classes/com/sun/security/jgss +jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb : jdk/src/share/classes/com/sun/security/sasl/gsskerb jdk/src/jdk.snmp/share/classes/com/sun/jmx/snmp : jdk/src/share/classes/com/sun/jmx/snmp jdk/src/jdk.snmp/share/classes/sun/management/snmp : jdk/src/share/classes/sun/management/snmp jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs : jdk/src/share/classes/jdk/nio/zipfs diff -r 89a653341cf2 -r 1b1ec4291abc corba/.hgtags --- a/corba/.hgtags Wed Jul 05 20:01:05 2017 +0200 +++ b/corba/.hgtags Wed Jul 05 20:01:50 2017 +0200 @@ -273,3 +273,4 @@ a00b04ef067e39f50b9a0fea6f1904e35d632a73 jdk9-b28 163a9cd806fd09970baf1f5f42b92a3cfe7ee945 jdk9-b29 98967ae6ae53ebf15615e07cd5a6b1ae04dfd84c jdk9-b30 +c432b80aadd0cb2b2361b02add4d671957d4cec9 jdk9-b31 diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/.hgtags --- a/hotspot/.hgtags Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/.hgtags Wed Jul 05 20:01:50 2017 +0200 @@ -433,3 +433,4 @@ 657294869d7ff063e055f5492cab7ce5612ca851 jdk9-b28 deb29e92f68ace2808a36ecfa18c7d61dcb645bb jdk9-b29 5c722dffbc0f34eb8d903dca7b261e52248fa17e jdk9-b30 +9f7d155d28e519f3e4645dc21cf185c25f3176ed jdk9-b31 diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/agent/src/os/win32/windbg/sawindbg.cpp --- a/hotspot/agent/src/os/win32/windbg/sawindbg.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/agent/src/os/win32/windbg/sawindbg.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -112,7 +112,9 @@ return;} static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) { - env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg); + jclass clazz = env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"); + CHECK_EXCEPTION; + env->ThrowNew(clazz, errMsg); } /* @@ -310,15 +312,18 @@ static bool setImageAndSymbolPath(JNIEnv* env, jobject obj) { jboolean isCopy; jclass clazz = env->GetObjectClass(obj); + CHECK_EXCEPTION_(false); jstring path; const char* buf; path = (jstring) env->GetStaticObjectField(clazz, imagePath_ID); + CHECK_EXCEPTION_(false); buf = env->GetStringUTFChars(path, &isCopy); CHECK_EXCEPTION_(false); AutoJavaString imagePath(env, path, buf); path = (jstring) env->GetStaticObjectField(clazz, symbolPath_ID); + CHECK_EXCEPTION_(false); buf = env->GetStringUTFChars(path, &isCopy); CHECK_EXCEPTION_(false); AutoJavaString symbolPath(env, path, buf); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/Makefile --- a/hotspot/make/Makefile Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/Makefile Wed Jul 05 20:01:50 2017 +0200 @@ -95,6 +95,7 @@ COMMON_VM_PRODUCT_TARGETS=product product1 docs export_product COMMON_VM_FASTDEBUG_TARGETS=fastdebug fastdebug1 docs export_fastdebug COMMON_VM_DEBUG_TARGETS=debug debug1 docs export_debug +COMMON_VM_OPTIMIZED_TARGETS=optimized optimized1 docs export_optimized # JDK directory list JDK_DIRS=bin include jre lib demo @@ -111,20 +112,21 @@ all_product: product1 docs export_product all_fastdebug: fastdebug1 docs export_fastdebug all_debug: debug1 docs export_debug +all_optimized: optimized1 docs export_optimized else ifeq ($(MACOSX_UNIVERSAL),true) all_product: universal_product all_fastdebug: universal_fastdebug all_debug: universal_debug +all_optimized: universal_optimized else all_product: $(COMMON_VM_PRODUCT_TARGETS) all_fastdebug: $(COMMON_VM_FASTDEBUG_TARGETS) all_debug: $(COMMON_VM_DEBUG_TARGETS) +all_optimized: $(COMMON_VM_OPTIMIZED_TARGETS) endif endif -all_optimized: optimized optimized1 docs export_optimized - allzero: all_productzero all_fastdebugzero all_productzero: productzero docs export_product all_fastdebugzero: fastdebugzero docs export_fastdebug @@ -890,3 +892,5 @@ create_jdk copy_jdk update_jdk test_jdk \ copy_product_jdk copy_fastdebug_jdk copy_debug_jdk \ $(HS_ALT_MAKE)/Makefile.make remove_old_debuginfo + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/aix/Makefile --- a/hotspot/make/aix/Makefile Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/aix/Makefile Wed Jul 05 20:01:50 2017 +0200 @@ -256,36 +256,36 @@ $(SUBDIRS_TIERED): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=tiered + +$(BUILDTREE) VARIANT=tiered $(SUBDIRS_C2): $(BUILDTREE_MAKE) ifeq ($(FORCE_TIERED),1) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 + +$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 else $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=compiler2 + +$(BUILDTREE) VARIANT=compiler2 endif $(SUBDIRS_C1): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=compiler1 + +$(BUILDTREE) VARIANT=compiler1 $(SUBDIRS_CORE): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=core + +$(BUILDTREE) VARIANT=core $(SUBDIRS_ZERO): $(BUILDTREE_MAKE) platform_zero $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH) + +$(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH) $(SUBDIRS_SHARK): $(BUILDTREE_MAKE) platform_zero $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH) + +$(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH) $(SUBDIRS_MINIMAL1): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=minimal1 + +$(BUILDTREE) VARIANT=minimal1 platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in @@ -379,3 +379,5 @@ .PHONY: all compiler1 compiler2 core zero shark .PHONY: clean clean_compiler1 clean_compiler2 clean_core clean_zero clean_shark docs clean_docs .PHONY: checks check_os_version check_j2se_version + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/aix/makefiles/buildtree.make --- a/hotspot/make/aix/makefiles/buildtree.make Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/aix/makefiles/buildtree.make Wed Jul 05 20:01:50 2017 +0200 @@ -173,7 +173,7 @@ # Run make in each subdirectory recursively. $(SUBMAKE_DIRS): $(SIMPLE_DIRS) FORCE $(QUIETLY) [ -d $@ ] || { mkdir -p $@; } - $(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F) + +$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F) $(QUIETLY) touch $@ $(SIMPLE_DIRS): @@ -364,3 +364,5 @@ FORCE: .PHONY: all FORCE + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/aix/makefiles/top.make --- a/hotspot/make/aix/makefiles/top.make Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/aix/makefiles/top.make Wed Jul 05 20:01:50 2017 +0200 @@ -69,7 +69,13 @@ # Wierd argument adjustment for "gnumake -j..." adjust-mflags = $(GENERATED)/adjust-mflags -MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"` +# If SPEC is set, it's from configure and it's already controlling concurrency +# for us. Skip setting -j with HOTSPOT_BUILD_JOBS. +ifeq ($(SPEC), ) + MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"` +else + MFLAGS-adjusted = -r $(MFLAGS) +endif # default target: update lists, make vm @@ -116,7 +122,7 @@ @+mv $@+ $@ the_vm: vm_build_preliminaries $(adjust-mflags) - @$(UpdatePCH) + +@$(UpdatePCH) @$(MAKE) -f vm.make $(MFLAGS-adjusted) install gamma: the_vm @@ -125,7 +131,7 @@ # next rules support "make foo.[ois]" %.o %.i %.s: - $(UpdatePCH) + +$(UpdatePCH) $(MAKE) -f vm.make $(MFLAGS) $@ #$(MAKE) -f vm.make $@ @@ -142,3 +148,5 @@ .PHONY: default vm_build_preliminaries .PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean .PHONY: checks check_os_version install + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/bsd/Makefile --- a/hotspot/make/bsd/Makefile Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/bsd/Makefile Wed Jul 05 20:01:50 2017 +0200 @@ -250,36 +250,36 @@ $(SUBDIRS_TIERED): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=tiered + +$(BUILDTREE) VARIANT=tiered $(SUBDIRS_C2): $(BUILDTREE_MAKE) ifeq ($(FORCE_TIERED),1) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 + +$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 else $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=compiler2 + +$(BUILDTREE) VARIANT=compiler2 endif $(SUBDIRS_C1): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=compiler1 + +$(BUILDTREE) VARIANT=compiler1 $(SUBDIRS_CORE): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=core + +$(BUILDTREE) VARIANT=core $(SUBDIRS_ZERO): $(BUILDTREE_MAKE) platform_zero $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH) + +$(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH) $(SUBDIRS_SHARK): $(BUILDTREE_MAKE) platform_zero $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH) + +$(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH) $(SUBDIRS_MINIMAL1): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=minimal1 + +$(BUILDTREE) VARIANT=minimal1 platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in $(SED) 's/@ZERO_ARCHDEF@/$(ZERO_ARCHDEF)/g;s/@ZERO_LIBARCH@/$(ZERO_LIBARCH)/g;' < $< > $@ @@ -392,3 +392,5 @@ .PHONY: clean clean_compiler1 clean_compiler2 clean_core clean_zero clean_shark docs clean_docs .PHONY: checks check_os_version check_j2se_version .PHONY: $(HS_ALT_MAKE)/$(OSNAME)/Makefile.make + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/bsd/makefiles/buildtree.make --- a/hotspot/make/bsd/makefiles/buildtree.make Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/bsd/makefiles/buildtree.make Wed Jul 05 20:01:50 2017 +0200 @@ -178,7 +178,7 @@ # Run make in each subdirectory recursively. $(SUBMAKE_DIRS): $(SIMPLE_DIRS) FORCE $(QUIETLY) [ -d $@ ] || { mkdir -p $@; } - $(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F) + +$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F) $(QUIETLY) touch $@ $(SIMPLE_DIRS): @@ -378,3 +378,5 @@ FORCE: .PHONY: all FORCE + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/bsd/makefiles/top.make --- a/hotspot/make/bsd/makefiles/top.make Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/bsd/makefiles/top.make Wed Jul 05 20:01:50 2017 +0200 @@ -69,7 +69,13 @@ # Wierd argument adjustment for "gnumake -j..." adjust-mflags = $(GENERATED)/adjust-mflags -MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"` +# If SPEC is set, it's from configure and it's already controlling concurrency +# for us. Skip setting -j with HOTSPOT_BUILD_JOBS. +ifeq ($(SPEC), ) + MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"` +else + MFLAGS-adjusted = -r $(MFLAGS) +endif # default target: update lists, make vm @@ -125,7 +131,7 @@ @+mv $@+ $@ the_vm: vm_build_preliminaries $(adjust-mflags) - @$(UpdatePCH) + +@$(UpdatePCH) @$(MAKE) -f vm.make $(MFLAGS-adjusted) install : the_vm @@ -134,7 +140,7 @@ # next rules support "make foo.[ois]" %.o %.i %.s: - $(UpdatePCH) + +$(UpdatePCH) $(MAKE) -f vm.make $(MFLAGS) $@ #$(MAKE) -f vm.make $@ @@ -151,3 +157,5 @@ .PHONY: default vm_build_preliminaries .PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean .PHONY: checks check_os_version install + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/bsd/makefiles/universal.gmk --- a/hotspot/make/bsd/makefiles/universal.gmk Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/bsd/makefiles/universal.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -25,6 +25,8 @@ # macosx universal builds universal_product: $(MAKE) MACOSX_UNIVERSAL=true all_product_universal +universal_optimized: + $(MAKE) MACOSX_UNIVERSAL=true all_optimized_universal universal_fastdebug: $(MAKE) MACOSX_UNIVERSAL=true all_fastdebug_universal universal_debug: @@ -36,6 +38,10 @@ # $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_PRODUCT_TARGETS) $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_PRODUCT_TARGETS) $(QUIETLY) $(MAKE) BUILD_FLAVOR=product EXPORT_SUBDIR= universalize +all_optimized_universal: +# $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_OPTIMIZED_TARGETS) + $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_OPTIMIZED_TARGETS) + $(QUIETLY) $(MAKE) BUILD_FLAVOR=optimized EXPORT_SUBDIR=/optimized universalize all_fastdebug_universal: # $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_FASTDEBUG_TARGETS) $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_FASTDEBUG_TARGETS) @@ -98,13 +104,15 @@ export_product_jdk:: $(MAKE) EXPORT_SUBDIR= export_universal export_optimized_jdk:: - $(MAKE) EXPORT_SUBDIR= export_universal + $(MAKE) EXPORT_SUBDIR=/optimized export_universal export_fastdebug_jdk:: $(MAKE) EXPORT_SUBDIR=/fastdebug export_universal export_debug_jdk:: $(MAKE) EXPORT_SUBDIR=/debug export_universal copy_product_jdk:: $(MAKE) COPY_SUBDIR= copy_universal +copy_optimized_jdk:: + $(MAKE) COPY_SUBDIR=/optimized copy_universal copy_fastdebug_jdk:: $(MAKE) COPY_SUBDIR=/fastdebug copy_universal copy_debug_jdk:: @@ -112,5 +120,6 @@ .PHONY: universal_product universal_fastdebug universal_debug \ all_product_universal all_fastdebug_universal all_debug_universal \ + universal_optimized all_optimized_universal \ universalize export_universal copy_universal \ $(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST) diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/linux/Makefile --- a/hotspot/make/linux/Makefile Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/linux/Makefile Wed Jul 05 20:01:50 2017 +0200 @@ -256,36 +256,36 @@ $(SUBDIRS_TIERED): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=tiered + +$(BUILDTREE) VARIANT=tiered $(SUBDIRS_C2): $(BUILDTREE_MAKE) ifeq ($(FORCE_TIERED),1) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 + +$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 else $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=compiler2 + +$(BUILDTREE) VARIANT=compiler2 endif $(SUBDIRS_C1): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=compiler1 + +$(BUILDTREE) VARIANT=compiler1 $(SUBDIRS_CORE): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=core + +$(BUILDTREE) VARIANT=core $(SUBDIRS_ZERO): $(BUILDTREE_MAKE) platform_zero $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH) + +$(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH) $(SUBDIRS_SHARK): $(BUILDTREE_MAKE) platform_zero $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH) + +$(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH) $(SUBDIRS_MINIMAL1): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=minimal1 + +$(BUILDTREE) VARIANT=minimal1 platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in @@ -399,3 +399,5 @@ .PHONY: clean clean_compiler1 clean_compiler2 clean_core clean_zero clean_shark docs clean_docs .PHONY: checks check_os_version check_j2se_version .PHONY: $(HS_ALT_MAKE)/$(OSNAME)/Makefile.make + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/linux/makefiles/buildtree.make --- a/hotspot/make/linux/makefiles/buildtree.make Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/linux/makefiles/buildtree.make Wed Jul 05 20:01:50 2017 +0200 @@ -172,7 +172,7 @@ # Run make in each subdirectory recursively. $(SUBMAKE_DIRS): $(SIMPLE_DIRS) FORCE $(QUIETLY) [ -d $@ ] || { mkdir -p $@; } - $(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F) + +$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F) $(QUIETLY) touch $@ $(SIMPLE_DIRS): @@ -377,3 +377,5 @@ FORCE: .PHONY: all FORCE + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/linux/makefiles/top.make --- a/hotspot/make/linux/makefiles/top.make Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/linux/makefiles/top.make Wed Jul 05 20:01:50 2017 +0200 @@ -69,7 +69,13 @@ # Wierd argument adjustment for "gnumake -j..." adjust-mflags = $(GENERATED)/adjust-mflags -MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"` +# If SPEC is set, it's from configure and it's already controlling concurrency +# for us. Skip setting -j with HOTSPOT_BUILD_JOBS. +ifeq ($(SPEC), ) + MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"` +else + MFLAGS-adjusted = -r $(MFLAGS) +endif # default target: update lists, make vm @@ -119,7 +125,7 @@ @+mv $@+ $@ the_vm: vm_build_preliminaries $(adjust-mflags) - @$(UpdatePCH) + +@$(UpdatePCH) @$(MAKE) -f vm.make $(MFLAGS-adjusted) install: the_vm @@ -128,7 +134,7 @@ # next rules support "make foo.[ois]" %.o %.i %.s: - $(UpdatePCH) + +$(UpdatePCH) $(MAKE) -f vm.make $(MFLAGS) $@ #$(MAKE) -f vm.make $@ @@ -145,3 +151,5 @@ .PHONY: default vm_build_preliminaries .PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean .PHONY: checks check_os_version install + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/solaris/Makefile --- a/hotspot/make/solaris/Makefile Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/solaris/Makefile Wed Jul 05 20:01:50 2017 +0200 @@ -200,24 +200,24 @@ $(SUBDIRS_TIERED): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=tiered + +$(BUILDTREE) VARIANT=tiered $(SUBDIRS_C2): $(BUILDTREE_MAKE) ifeq ($(FORCE_TIERED),1) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 + +$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 else $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=compiler2 + +$(BUILDTREE) VARIANT=compiler2 endif $(SUBDIRS_C1): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=compiler1 + +$(BUILDTREE) VARIANT=compiler1 $(SUBDIRS_CORE): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=core + +$(BUILDTREE) VARIANT=core # Define INSTALL=y at command line to automatically copy JVM into JAVA_HOME @@ -292,3 +292,5 @@ .PHONY: all compiler1 compiler2 core .PHONY: clean clean_compiler1 clean_compiler2 clean_core docs clean_docs .PHONY: checks check_os_version check_j2se_version + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/solaris/makefiles/buildtree.make --- a/hotspot/make/solaris/makefiles/buildtree.make Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/solaris/makefiles/buildtree.make Wed Jul 05 20:01:50 2017 +0200 @@ -165,7 +165,7 @@ # Run make in each subdirectory recursively. $(SUBMAKE_DIRS): $(SIMPLE_DIRS) FORCE $(QUIETLY) [ -d $@ ] || { mkdir -p $@; } - $(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F) + +$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F) $(QUIETLY) touch $@ $(SIMPLE_DIRS): @@ -364,3 +364,5 @@ FORCE: .PHONY: all FORCE + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/solaris/makefiles/top.make --- a/hotspot/make/solaris/makefiles/top.make Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/solaris/makefiles/top.make Wed Jul 05 20:01:50 2017 +0200 @@ -62,7 +62,13 @@ # Wierd argument adjustment for "gnumake -j..." adjust-mflags = $(GENERATED)/adjust-mflags -MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"` +# If SPEC is set, it's from configure and it's already controlling concurrency +# for us. Skip setting -j with HOTSPOT_BUILD_JOBS. +ifeq ($(SPEC), ) + MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"` +else + MFLAGS-adjusted = -r $(MFLAGS) +endif # default target: update lists, make vm @@ -136,3 +142,5 @@ .PHONY: default vm_build_preliminaries .PHONY: lists ad_stuff jvmti_stuff trace_stuff sa_stuff the_vm clean realclean .PHONY: checks check_os_version install + +.NOTPARALLEL: diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/make/solaris/makefiles/vm.make --- a/hotspot/make/solaris/makefiles/vm.make Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/make/solaris/makefiles/vm.make Wed Jul 05 20:01:50 2017 +0200 @@ -143,7 +143,7 @@ LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle endif # sparcWorks -LIBS += -lkstat +LIBS += -lkstat -lpicl # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -32,6 +32,7 @@ int VM_Version::_features = VM_Version::unknown_m; const char* VM_Version::_features_str = ""; +unsigned int VM_Version::_L2_cache_line_size = 0; void VM_Version::initialize() { _features = determine_features(); @@ -192,7 +193,7 @@ } assert(BlockZeroingLowLimit > 0, "invalid value"); - if (has_block_zeroing()) { + if (has_block_zeroing() && cache_line_size > 0) { if (FLAG_IS_DEFAULT(UseBlockZeroing)) { FLAG_SET_DEFAULT(UseBlockZeroing, true); } @@ -202,7 +203,7 @@ } assert(BlockCopyLowLimit > 0, "invalid value"); - if (has_block_zeroing()) { // has_blk_init() && is_T4(): core's local L2 cache + if (has_block_zeroing() && cache_line_size > 0) { // has_blk_init() && is_T4(): core's local L2 cache if (FLAG_IS_DEFAULT(UseBlockCopy)) { FLAG_SET_DEFAULT(UseBlockCopy, true); } @@ -252,49 +253,6 @@ // buf is started with ", " or is empty _features_str = os::strdup(strlen(buf) > 2 ? buf + 2 : buf); - // There are three 64-bit SPARC families that do not overlap, e.g., - // both is_ultra3() and is_sparc64() cannot be true at the same time. - // Within these families, there can be more than one chip, e.g., - // is_T4() and is_T7() machines are also is_niagara(). - if (is_ultra3()) { - assert(_L1_data_cache_line_size == 0, "overlap with Ultra3 family"); - // Ref: UltraSPARC III Cu Processor - _L1_data_cache_line_size = 64; - } - if (is_niagara()) { - assert(_L1_data_cache_line_size == 0, "overlap with niagara family"); - // All Niagara's are sun4v's, but not all sun4v's are Niagaras, e.g., - // Fujitsu SPARC64 is sun4v, but we don't want it in this block. - // - // Ref: UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005 - // Appendix F.1.3.1 Cacheable Accesses - // -> 16-byte L1 cache line size - // - // Ref: UltraSPARC T2: A Highly-Threaded, Power-Efficient, SPARC SOC - // Section III: SPARC Processor Core - // -> 16-byte L1 cache line size - // - // Ref: Oracle's SPARC T4-1, SPARC T4-2, SPARC T4-4, and SPARC T4-1B Server Architecture - // Section SPARC T4 Processor Cache Architecture - // -> 32-byte L1 cache line size (no longer see that info on this ref) - // - // XXX - still need a T7 reference here - // - if (is_T7()) { // T7 or newer - _L1_data_cache_line_size = 64; - } else if (is_T4()) { // T4 or newer (until T7) - _L1_data_cache_line_size = 32; - } else { // T1 or newer (until T4) - _L1_data_cache_line_size = 16; - } - } - if (is_sparc64()) { - guarantee(_L1_data_cache_line_size == 0, "overlap with SPARC64 family"); - // Ref: Fujitsu SPARC64 VII Processor - // Section 4 Cache System - _L1_data_cache_line_size = 64; - } - // UseVIS is set to the smallest of what hardware supports and what // the command line requires. I.e., you cannot set UseVIS to 3 on // older UltraSparc which do not support it. @@ -401,6 +359,7 @@ #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); + tty->print_cr("L2 cache line size: %u", L2_cache_line_size()); tty->print("Allocation"); if (AllocatePrefetchStyle <= 0) { tty->print_cr(": no prefetching"); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -96,6 +96,9 @@ static int _features; static const char* _features_str; + static unsigned int _L2_cache_line_size; + static unsigned int L2_cache_line_size() { return _L2_cache_line_size; } + static void print_features(); static int determine_features(); static int platform_features(int features); @@ -167,9 +170,8 @@ static const char* cpu_features() { return _features_str; } - static intx prefetch_data_size() { - return is_T4() && !is_T7() ? 32 : 64; // default prefetch block size on sparc - } + // default prefetch block size on sparc + static intx prefetch_data_size() { return L2_cache_line_size(); } // Prefetch static intx prefetch_copy_interval_in_bytes() { diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/cpu/x86/vm/assembler_x86.hpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -26,6 +26,7 @@ #define CPU_X86_VM_ASSEMBLER_X86_HPP #include "asm/register.hpp" +#include "vm_version_x86.hpp" class BiasedLockingCounters; @@ -1292,14 +1293,34 @@ if (order_constraint & StoreLoad) { // All usable chips support "locked" instructions which suffice // as barriers, and are much faster than the alternative of - // using cpuid instruction. We use here a locked add [esp],0. + // using cpuid instruction. We use here a locked add [esp-C],0. // This is conveniently otherwise a no-op except for blowing - // flags. + // flags, and introducing a false dependency on target memory + // location. We can't do anything with flags, but we can avoid + // memory dependencies in the current method by locked-adding + // somewhere else on the stack. Doing [esp+C] will collide with + // something on stack in current method, hence we go for [esp-C]. + // It is convenient since it is almost always in data cache, for + // any small C. We need to step back from SP to avoid data + // dependencies with other things on below SP (callee-saves, for + // example). Without a clear way to figure out the minimal safe + // distance from SP, it makes sense to step back the complete + // cache line, as this will also avoid possible second-order effects + // with locked ops against the cache line. Our choice of offset + // is bounded by x86 operand encoding, which should stay within + // [-128; +127] to have the 8-byte displacement encoding. + // // Any change to this code may need to revisit other places in // the code where this idiom is used, in particular the // orderAccess code. + + int offset = -VM_Version::L1_line_size(); + if (offset < -128) { + offset = -128; + } + lock(); - addl(Address(rsp, 0), 0);// Assert the lock# signal here + addl(Address(rsp, offset), 0);// Assert the lock# signal here } } } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -820,14 +820,10 @@ } address InterpreterGenerator::generate_native_entry(bool synchronized) { - assert(synchronized == false, "should be"); - return generate_entry((address) CppInterpreter::native_entry); } address InterpreterGenerator::generate_normal_entry(bool synchronized) { - assert(synchronized == false, "should be"); - return generate_entry((address) CppInterpreter::normal_entry); } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os/bsd/vm/os_bsd.cpp --- a/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -1644,8 +1644,20 @@ return true; } +int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) { + outputStream * out = (outputStream *) param; + out->print_cr(PTR_FORMAT " \t%s", base_address, name); + return 0; +} + void os::print_dll_info(outputStream *st) { st->print_cr("Dynamic libraries:"); + if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) { + st->print_cr("Error: Cannot print dynamic libraries."); + } +} + +int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { #ifdef RTLD_DI_LINKMAP Dl_info dli; void *handle; @@ -1654,36 +1666,41 @@ if (dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli) == 0 || dli.dli_fname == NULL) { - st->print_cr("Error: Cannot print dynamic libraries."); - return; + return 1; } handle = dlopen(dli.dli_fname, RTLD_LAZY); if (handle == NULL) { - st->print_cr("Error: Cannot print dynamic libraries."); - return; + return 1; } dlinfo(handle, RTLD_DI_LINKMAP, &map); if (map == NULL) { - st->print_cr("Error: Cannot print dynamic libraries."); - return; + dlclose(handle); + return 1; } while (map->l_prev != NULL) map = map->l_prev; while (map != NULL) { - st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name); + // Value for top_address is returned as 0 since we don't have any information about module size + if (callback(map->l_name, (address)map->l_addr, (address)0, param)) { + dlclose(handle); + return 1; + } map = map->l_next; } dlclose(handle); #elif defined(__APPLE__) for (uint32_t i = 1; i < _dyld_image_count(); i++) { - st->print_cr(PTR_FORMAT " \t%s", _dyld_get_image_header(i), - _dyld_get_image_name(i)); + // Value for top_address is returned as 0 since we don't have any information about module size + if (callback(_dyld_get_image_name(i), (address)_dyld_get_image_header(i), (address)0, param)) { + return 1; + } } + return 0; #else - st->print_cr("Error: Cannot print dynamic libraries."); + return 1; #endif } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -2120,6 +2120,40 @@ } } +int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { + FILE *procmapsFile = NULL; + + // Open the procfs maps file for the current process + if ((procmapsFile = fopen("/proc/self/maps", "r")) != NULL) { + // Allocate PATH_MAX for file name plus a reasonable size for other fields. + char line[PATH_MAX + 100]; + + // Read line by line from 'file' + while (fgets(line, sizeof(line), procmapsFile) != NULL) { + u8 base, top, offset, inode; + char permissions[5]; + char device[6]; + char name[PATH_MAX + 1]; + + // Parse fields from line + sscanf(line, "%lx-%lx %4s %lx %5s %ld %s", &base, &top, permissions, &offset, device, &inode, name); + + // Filter by device id '00:00' so that we only get file system mapped files. + if (strcmp(device, "00:00") != 0) { + + // Call callback with the fields of interest + if(callback(name, (address)base, (address)top, param)) { + // Oops abort, callback aborted + fclose(procmapsFile); + return 1; + } + } + } + fclose(procmapsFile); + } + return 0; +} + void os::print_os_info_brief(outputStream* st) { os::Linux::print_distro_info(st); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os/posix/vm/os_posix.cpp --- a/hotspot/src/os/posix/vm/os_posix.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os/posix/vm/os_posix.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -215,6 +215,9 @@ struct utsname name; uname(&name); st->print("%s ", name.sysname); +#ifdef ASSERT + st->print("%s ", name.nodename); +#endif st->print("%s ", name.release); st->print("%s ", name.version); st->print("%s", name.machine); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -1722,41 +1722,54 @@ return false; } -// Prints the names and full paths of all opened dynamic libraries -// for current process -void os::print_dll_info(outputStream * st) { +int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { Dl_info dli; - void *handle; + // Sanity check? + if (dladdr(CAST_FROM_FN_PTR(void *, os::get_loaded_modules_info), &dli) == 0 || + dli.dli_fname == NULL) { + return 1; + } + + void * handle = dlopen(dli.dli_fname, RTLD_LAZY); + if (handle == NULL) { + return 1; + } + Link_map *map; - Link_map *p; - - st->print_cr("Dynamic libraries:"); st->flush(); - - if (dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli) == 0 || - dli.dli_fname == NULL) { - st->print_cr("Error: Cannot print dynamic libraries."); - return; - } - handle = dlopen(dli.dli_fname, RTLD_LAZY); - if (handle == NULL) { - st->print_cr("Error: Cannot print dynamic libraries."); - return; - } dlinfo(handle, RTLD_DI_LINKMAP, &map); if (map == NULL) { - st->print_cr("Error: Cannot print dynamic libraries."); - return; - } - - while (map->l_prev != NULL) + dlclose(handle); + return 1; + } + + while (map->l_prev != NULL) { map = map->l_prev; + } while (map != NULL) { - st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name); + // Iterate through all map entries and call callback with fields of interest + if(callback(map->l_name, (address)map->l_addr, (address)0, param)) { + dlclose(handle); + return 1; + } map = map->l_next; } dlclose(handle); + return 0; +} + +int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) { + outputStream * out = (outputStream *) param; + out->print_cr(PTR_FORMAT " \t%s", base_address, name); + return 0; +} + +void os::print_dll_info(outputStream * st) { + st->print_cr("Dynamic libraries:"); st->flush(); + if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) { + st->print_cr("Error: Cannot print dynamic libraries."); + } } // Loads .dll/.so and diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -1301,120 +1301,6 @@ } #endif - -// Enumerate all modules for a given process ID -// -// Notice that Windows 95/98/Me and Windows NT/2000/XP have -// different API for doing this. We use PSAPI.DLL on NT based -// Windows and ToolHelp on 95/98/Me. - -// Callback function that is called by enumerate_modules() on -// every DLL module. -// Input parameters: -// int pid, -// char* module_file_name, -// address module_base_addr, -// unsigned module_size, -// void* param -typedef int (*EnumModulesCallbackFunc)(int, char *, address, unsigned, void *); - -// enumerate_modules for Windows NT, using PSAPI -static int _enumerate_modules_winnt( int pid, EnumModulesCallbackFunc func, void * param) -{ - HANDLE hProcess; - -# define MAX_NUM_MODULES 128 - HMODULE modules[MAX_NUM_MODULES]; - static char filename[MAX_PATH]; - int result = 0; - - if (!os::PSApiDll::PSApiAvailable()) { - return 0; - } - - hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - FALSE, pid); - if (hProcess == NULL) return 0; - - DWORD size_needed; - if (!os::PSApiDll::EnumProcessModules(hProcess, modules, - sizeof(modules), &size_needed)) { - CloseHandle(hProcess); - return 0; - } - - // number of modules that are currently loaded - int num_modules = size_needed / sizeof(HMODULE); - - for (int i = 0; i < MIN2(num_modules, MAX_NUM_MODULES); i++) { - // Get Full pathname: - if (!os::PSApiDll::GetModuleFileNameEx(hProcess, modules[i], - filename, sizeof(filename))) { - filename[0] = '\0'; - } - - MODULEINFO modinfo; - if (!os::PSApiDll::GetModuleInformation(hProcess, modules[i], - &modinfo, sizeof(modinfo))) { - modinfo.lpBaseOfDll = NULL; - modinfo.SizeOfImage = 0; - } - - // Invoke callback function - result = func(pid, filename, (address)modinfo.lpBaseOfDll, - modinfo.SizeOfImage, param); - if (result) break; - } - - CloseHandle(hProcess); - return result; -} - - -// enumerate_modules for Windows 95/98/ME, using TOOLHELP -static int _enumerate_modules_windows( int pid, EnumModulesCallbackFunc func, void *param) -{ - HANDLE hSnapShot; - static MODULEENTRY32 modentry; - int result = 0; - - if (!os::Kernel32Dll::HelpToolsAvailable()) { - return 0; - } - - // Get a handle to a Toolhelp snapshot of the system - hSnapShot = os::Kernel32Dll::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); - if (hSnapShot == INVALID_HANDLE_VALUE) { - return FALSE; - } - - // iterate through all modules - modentry.dwSize = sizeof(MODULEENTRY32); - bool not_done = os::Kernel32Dll::Module32First( hSnapShot, &modentry ) != 0; - - while (not_done) { - // invoke the callback - result=func(pid, modentry.szExePath, (address)modentry.modBaseAddr, - modentry.modBaseSize, param); - if (result) break; - - modentry.dwSize = sizeof(MODULEENTRY32); - not_done = os::Kernel32Dll::Module32Next( hSnapShot, &modentry ) != 0; - } - - CloseHandle(hSnapShot); - return result; -} - -int enumerate_modules( int pid, EnumModulesCallbackFunc func, void * param ) -{ - // Get current process ID if caller doesn't provide it. - if (!pid) pid = os::current_process_id(); - - if (os::win32::is_nt()) return _enumerate_modules_winnt (pid, func, param); - else return _enumerate_modules_windows(pid, func, param); -} - struct _modinfo { address addr; char* full_path; // point to a char buffer @@ -1422,13 +1308,13 @@ address base_addr; }; -static int _locate_module_by_addr(int pid, char * mod_fname, address base_addr, - unsigned size, void * param) { +static int _locate_module_by_addr(const char * mod_fname, address base_addr, + address top_address, void * param) { struct _modinfo *pmod = (struct _modinfo *)param; if (!pmod) return -1; - if (base_addr <= pmod->addr && - base_addr+size > pmod->addr) { + if (base_addr <= pmod->addr && + top_address > pmod->addr) { // if a buffer is provided, copy path name to the buffer if (pmod->full_path) { jio_snprintf(pmod->full_path, pmod->buflen, "%s", mod_fname); @@ -1453,8 +1339,7 @@ mi.addr = addr; mi.full_path = buf; mi.buflen = buflen; - int pid = os::current_process_id(); - if (enumerate_modules(pid, _locate_module_by_addr, (void *)&mi)) { + if (get_loaded_modules_info(_locate_module_by_addr, (void *)&mi)) { // buf already contains path name if (offset) *offset = addr - mi.base_addr; return true; @@ -1479,14 +1364,14 @@ } // save the start and end address of jvm.dll into param[0] and param[1] -static int _locate_jvm_dll(int pid, char* mod_fname, address base_addr, - unsigned size, void * param) { +static int _locate_jvm_dll(const char* mod_fname, address base_addr, + address top_address, void * param) { if (!param) return -1; - if (base_addr <= (address)_locate_jvm_dll && - base_addr+size > (address)_locate_jvm_dll) { + if (base_addr <= (address)_locate_jvm_dll && + top_address > (address)_locate_jvm_dll) { ((address*)param)[0] = base_addr; - ((address*)param)[1] = base_addr + size; + ((address*)param)[1] = top_address; return 1; } return 0; @@ -1497,8 +1382,7 @@ // check if addr is inside jvm.dll bool os::address_is_in_vm(address addr) { if (!vm_lib_location[0] || !vm_lib_location[1]) { - int pid = os::current_process_id(); - if (!enumerate_modules(pid, _locate_jvm_dll, (void *)vm_lib_location)) { + if (!get_loaded_modules_info(_locate_jvm_dll, (void *)vm_lib_location)) { assert(false, "Can't find jvm module."); return false; } @@ -1508,14 +1392,13 @@ } // print module info; param is outputStream* -static int _print_module(int pid, char* fname, address base, - unsigned size, void* param) { +static int _print_module(const char* fname, address base_address, + address top_address, void* param) { if (!param) return -1; outputStream* st = (outputStream*)param; - address end_addr = base + size; - st->print(PTR_FORMAT " - " PTR_FORMAT " \t%s\n", base, end_addr, fname); + st->print(PTR_FORMAT " - " PTR_FORMAT " \t%s\n", base_address, top_address, fname); return 0; } @@ -1644,11 +1527,60 @@ return NULL; } - void os::print_dll_info(outputStream *st) { - int pid = os::current_process_id(); st->print_cr("Dynamic libraries:"); - enumerate_modules(pid, _print_module, (void *)st); + get_loaded_modules_info(_print_module, (void *)st); +} + +int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { + HANDLE hProcess; + +# define MAX_NUM_MODULES 128 + HMODULE modules[MAX_NUM_MODULES]; + static char filename[MAX_PATH]; + int result = 0; + + if (!os::PSApiDll::PSApiAvailable()) { + return 0; + } + + int pid = os::current_process_id(); + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + FALSE, pid); + if (hProcess == NULL) return 0; + + DWORD size_needed; + if (!os::PSApiDll::EnumProcessModules(hProcess, modules, + sizeof(modules), &size_needed)) { + CloseHandle(hProcess); + return 0; + } + + // number of modules that are currently loaded + int num_modules = size_needed / sizeof(HMODULE); + + for (int i = 0; i < MIN2(num_modules, MAX_NUM_MODULES); i++) { + // Get Full pathname: + if (!os::PSApiDll::GetModuleFileNameEx(hProcess, modules[i], + filename, sizeof(filename))) { + filename[0] = '\0'; + } + + MODULEINFO modinfo; + if (!os::PSApiDll::GetModuleInformation(hProcess, modules[i], + &modinfo, sizeof(modinfo))) { + modinfo.lpBaseOfDll = NULL; + modinfo.SizeOfImage = 0; + } + + // Invoke callback function + result = callback(filename, (address)modinfo.lpBaseOfDll, + (address)((u8)modinfo.lpBaseOfDll + (u8)modinfo.SizeOfImage), param); + if (result) break; + } + + CloseHandle(hProcess); + return result; } void os::print_os_info_brief(outputStream* st) { @@ -1656,8 +1588,17 @@ } void os::print_os_info(outputStream* st) { - st->print("OS:"); - +#ifdef ASSERT + char buffer[1024]; + DWORD size = sizeof(buffer); + st->print(" HostName: "); + if (GetComputerNameEx(ComputerNameDnsHostname, buffer, &size)) { + st->print("%s", buffer); + } else { + st->print("N/A"); + } +#endif + st->print(" OS:"); os::win32::print_windows_version(st); } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp --- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -563,3 +563,8 @@ assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); } #endif + +int os::extra_bang_size_in_bytes() { + // PPC does not require the additional stack bang. + return 0; +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -1030,3 +1030,8 @@ void os::verify_stack_alignment() { } #endif + +int os::extra_bang_size_in_bytes() { + // JDK-8050147 requires the full cache line bang for x86. + return VM_Version::L1_line_size(); +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp --- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -465,3 +465,8 @@ void os::verify_stack_alignment() { } #endif + +int os::extra_bang_size_in_bytes() { + // Zero does not require an additional stack bang. + return 0; +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp --- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -612,3 +612,8 @@ assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); } #endif + +int os::extra_bang_size_in_bytes() { + // PPC does not require the additional stack bang. + return 0; +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -752,3 +752,8 @@ void os::verify_stack_alignment() { } #endif + +int os::extra_bang_size_in_bytes() { + // SPARC does not require the additional stack bang. + return 0; +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -930,3 +930,8 @@ // keep the page mapped so CS limit isn't reduced. #endif } + +int os::extra_bang_size_in_bytes() { + // JDK-8050147 requires the full cache line bang for x86. + return VM_Version::L1_line_size(); +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp --- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -495,3 +495,8 @@ void os::verify_stack_alignment() { } #endif + +int os::extra_bang_size_in_bytes() { + // Zero does not require an additional stack banging. + return 0; +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -774,3 +774,8 @@ void os::verify_stack_alignment() { } #endif + +int os::extra_bang_size_in_bytes() { + // SPARC does not require an additional stack bang. + return 0; +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -28,10 +28,140 @@ #include "runtime/os.hpp" #include "vm_version_sparc.hpp" -# include -# include -# include -# include +#include +#include +#include +#include +#include + +extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result); +extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result); + +class PICL { + // Get a value of the integer property. The value in the tree can be either 32 or 64 bit + // depending on the platform. The result is converted to int. + static int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) { + picl_propinfo_t pinfo; + picl_prophdl_t proph; + if (picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS || + picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) { + return PICL_FAILURE; + } + + if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) { + assert(false, "Invalid property type"); + return PICL_FAILURE; + } + if (pinfo.size == sizeof(int64_t)) { + int64_t val; + if (picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) { + return PICL_FAILURE; + } + *result = static_cast(val); + } else if (pinfo.size == sizeof(int32_t)) { + int32_t val; + if (picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) { + return PICL_FAILURE; + } + *result = static_cast(val); + } else { + assert(false, "Unexpected integer property size"); + return PICL_FAILURE; + } + return PICL_SUCCESS; + } + + // Visitor and a state machine that visits integer properties and verifies that the + // values are the same. Stores the unique value observed. + class UniqueValueVisitor { + enum { + INITIAL, // Start state, no assignments happened + ASSIGNED, // Assigned a value + INCONSISTENT // Inconsistent value seen + } _state; + int _value; + public: + UniqueValueVisitor() : _state(INITIAL) { } + int value() { + assert(_state == ASSIGNED, "Precondition"); + return _value; + } + void set_value(int value) { + assert(_state == INITIAL, "Precondition"); + _value = value; + _state = ASSIGNED; + } + bool is_initial() { return _state == INITIAL; } + bool is_assigned() { return _state == ASSIGNED; } + bool is_inconsistent() { return _state == INCONSISTENT; } + void set_inconsistent() { _state = INCONSISTENT; } + + static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) { + UniqueValueVisitor *state = static_cast(arg); + assert(!state->is_inconsistent(), "Precondition"); + int curr; + if (PICL::get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { + if (!state->is_assigned()) { // first iteration + state->set_value(curr); + } else if (curr != state->value()) { // following iterations + state->set_inconsistent(); + } + } + if (state->is_inconsistent()) { + return PICL_WALK_TERMINATE; + } + return PICL_WALK_CONTINUE; + } + }; + + int _L1_data_cache_line_size; + int _L2_cache_line_size; +public: + static int get_l1_data_cache_line_size(picl_nodehdl_t nodeh, void *state) { + return UniqueValueVisitor::visit(nodeh, "l1-dcache-line-size", state); + } + static int get_l2_cache_line_size(picl_nodehdl_t nodeh, void *state) { + return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state); + } + + PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0) { + if (picl_initialize() == PICL_SUCCESS) { + picl_nodehdl_t rooth; + if (picl_get_root(&rooth) == PICL_SUCCESS) { + UniqueValueVisitor L1_state; + // Visit all "cpu" class instances + picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper); + if (L1_state.is_initial()) { // Still initial, iteration found no values + // Try walk all "core" class instances, it might be a Fujitsu machine + picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper); + } + if (L1_state.is_assigned()) { // Is there a value? + _L1_data_cache_line_size = L1_state.value(); + } + + UniqueValueVisitor L2_state; + picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper); + if (L2_state.is_initial()) { + picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper); + } + if (L2_state.is_assigned()) { + _L2_cache_line_size = L2_state.value(); + } + } + picl_shutdown(); + } + } + + unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } + unsigned int L2_cache_line_size() const { return _L2_cache_line_size; } +}; + +extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) { + return PICL::get_l1_data_cache_line_size(nodeh, result); +} +extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) { + return PICL::get_l2_cache_line_size(nodeh, result); +} // We need to keep these here as long as we have to build on Solaris // versions before 10. @@ -211,5 +341,10 @@ kstat_close(kc); } + // Figure out cache line sizes using PICL + PICL picl; + _L1_data_cache_line_size = picl.L1_data_cache_line_size(); + _L2_cache_line_size = picl.L2_cache_line_size(); + return features; } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -918,3 +918,8 @@ #endif } #endif + +int os::extra_bang_size_in_bytes() { + // JDK-8050147 requires the full cache line bang for x86. + return VM_Version::L1_line_size(); +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -639,3 +639,8 @@ #endif } #endif + +int os::extra_bang_size_in_bytes() { + // JDK-8050147 requires the full cache line bang for x86. + return VM_Version::L1_line_size(); +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/c1/c1_LIRAssembler.cpp --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -170,7 +170,7 @@ // removes the need to bang the stack in the deoptimization blob which // in turn simplifies stack overflow handling. int LIR_Assembler::bang_size_in_bytes() const { - return MAX2(initial_frame_size_in_bytes(), _compilation->interpreter_frame_size()); + return MAX2(initial_frame_size_in_bytes() + os::extra_bang_size_in_bytes(), _compilation->interpreter_frame_size()); } void LIR_Assembler::emit_exception_entries(ExceptionInfoList* info_list) { diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/ci/ciEnv.cpp --- a/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -926,7 +926,7 @@ #ifdef ASSERT if (!counter_changed && !PrintCompilation) { // Print out the compile task that failed - _task->print_line(); + _task->print_tty(); } #endif assert(counter_changed, "failed dependencies, but counter didn't change"); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/classfile/classLoader.cpp --- a/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -1528,7 +1528,7 @@ if (TieredCompilation && TieredStopAtLevel >= CompLevel_full_optimization) { // Clobber the first compile and force second tier compilation nmethod* nm = m->code(); - if (nm != NULL) { + if (nm != NULL && !m->is_method_handle_intrinsic()) { // Throw out the code so that the code cache doesn't fill up nm->make_not_entrant(); m->clear_code(); @@ -1547,7 +1547,7 @@ } nmethod* nm = m->code(); - if (nm != NULL) { + if (nm != NULL && !m->is_method_handle_intrinsic()) { // Throw out the code so that the code cache doesn't fill up nm->make_not_entrant(); m->clear_code(); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/classfile/classLoaderData.cpp --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -746,7 +746,7 @@ // mark metadata seen on the stack and code cache so we can delete // unneeded entries. bool has_redefined_a_class = JvmtiExport::has_redefined_a_class(); - MetadataOnStackMark md_on_stack; + MetadataOnStackMark md_on_stack(has_redefined_a_class); if (has_redefined_a_class) { // purge_previous_versions also cleans weak method links. Because // one method's MDO can reference another method from another diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/classfile/metadataOnStackMark.cpp --- a/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ // Walk metadata on the stack and mark it so that redefinition doesn't delete // it. Class unloading also walks the previous versions and might try to // delete it, so this class is used by class unloading also. -MetadataOnStackMark::MetadataOnStackMark() { +MetadataOnStackMark::MetadataOnStackMark(bool has_redefined_a_class) { assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); NOT_PRODUCT(_is_active = true;) if (_marked_objects == NULL) { @@ -49,7 +49,7 @@ } Threads::metadata_do(Metadata::mark_on_stack); - if (JvmtiExport::has_redefined_a_class()) { + if (has_redefined_a_class) { CodeCache::alive_nmethods_do(nmethod::mark_on_stack); } CompileBroker::mark_on_stack(); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/classfile/metadataOnStackMark.hpp --- a/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ class MetadataOnStackMark : public StackObj { NOT_PRODUCT(static bool _is_active;) public: - MetadataOnStackMark(); + MetadataOnStackMark(bool has_redefined_a_class); ~MetadataOnStackMark(); static void record(Metadata* m); }; diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -52,6 +52,7 @@ #include "oops/typeArrayKlass.hpp" #include "prims/jvmtiEnvBase.hpp" #include "prims/methodHandles.hpp" +#include "runtime/arguments.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/fieldType.hpp" #include "runtime/handles.inline.hpp" @@ -2274,7 +2275,11 @@ m = Method::make_method_handle_intrinsic(iid, signature, CHECK_(empty)); CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_highest_tier, methodHandle(), CompileThreshold, "MH", CHECK_(empty)); - + // Check if we need to have compiled code but we don't. + if (!Arguments::is_interpreter_only() && !m->has_compiled_code()) { + THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(), + "out of space in CodeCache for method handle intrinsic", empty); + } // Now grab the lock. We might have to throw away the new method, // if a racing thread has managed to install one at the same time. { @@ -2288,6 +2293,9 @@ } assert(spe != NULL && spe->method() != NULL, ""); + assert(Arguments::is_interpreter_only() || (spe->method()->has_compiled_code() && + spe->method()->code()->entry_point() == spe->method()->from_compiled_entry()), + "MH intrinsic invariant"); return spe->method(); } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -249,6 +249,7 @@ #define FOR_ALL_BLOBS(var) for (CodeBlob *var = first() ; var != NULL; var = next(var) ) #define FOR_ALL_ALIVE_BLOBS(var) for (CodeBlob *var = alive(first()); var != NULL; var = alive(next(var))) #define FOR_ALL_ALIVE_NMETHODS(var) for (nmethod *var = alive_nmethod(first()); var != NULL; var = alive_nmethod(next(var))) +#define FOR_ALL_NMETHODS(var) for (nmethod *var = first_nmethod(); var != NULL; var = next_nmethod(var)) bool CodeCache::contains(void *p) { @@ -687,7 +688,9 @@ void CodeCache::mark_all_nmethods_for_deoptimization() { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); FOR_ALL_ALIVE_NMETHODS(nm) { - nm->mark_for_deoptimization(); + if (!nm->method()->is_method_handle_intrinsic()) { + nm->mark_for_deoptimization(); + } } } @@ -967,6 +970,25 @@ } } +void CodeCache::print_codelist(outputStream* st) { + assert_locked_or_safepoint(CodeCache_lock); + + FOR_ALL_NMETHODS(p) { + ResourceMark rm; + char *method_name = p->method()->name_and_sig_as_C_string(); + st->print_cr("%d %d %s ["INTPTR_FORMAT", "INTPTR_FORMAT" - "INTPTR_FORMAT"]", + p->compile_id(), p->comp_level(), method_name, (intptr_t)p->header_begin(), + (intptr_t)p->code_begin(), (intptr_t)p->code_end()); + } +} + +void CodeCache::print_layout(outputStream* st) { + assert_locked_or_safepoint(CodeCache_lock); + ResourceMark rm; + + print_summary(st, true); +} + void CodeCache::log_state(outputStream* st) { st->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'" " adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'", diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/code/codeCache.hpp --- a/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -152,6 +152,10 @@ static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage static void log_state(outputStream* st); + // Dcmd (Diagnostic commands) + static void print_codelist(outputStream* st); + static void print_layout(outputStream* st); + // The full limits of the codeCache static address low_bound() { return (address) _heap->low_boundary(); } static address high_bound() { return (address) _heap->high_boundary(); } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/code/compiledIC.cpp --- a/hotspot/src/share/vm/code/compiledIC.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/code/compiledIC.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -595,6 +595,7 @@ } else { // Callee is interpreted code. In any case entering the interpreter // puts a converter-frame on the stack to save arguments. + assert(!m->is_method_handle_intrinsic(), "Compiled code should never call interpreter MH intrinsics"); info._to_interpreter = true; info._entry = m()->get_c2i_entry(); } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -2062,7 +2062,7 @@ "metadata must be found in exactly one place"); if (r->metadata_is_immediate() && r->metadata_value() != NULL) { Metadata* md = r->metadata_value(); - f(md); + if (md != _method) f(md); } } else if (iter.type() == relocInfo::virtual_call_type) { // Check compiledIC holders associated with this nmethod diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/code/nmethod.hpp --- a/hotspot/src/share/vm/code/nmethod.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/code/nmethod.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -448,7 +448,10 @@ // alive. It is used when an uncommon trap happens. Returns true // if this thread changed the state of the nmethod or false if // another thread performed the transition. - bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); } + bool make_not_entrant() { + assert(!method()->is_method_handle_intrinsic(), "Cannot make MH intrinsic not entrant"); + return make_not_entrant_or_zombie(not_entrant); + } bool make_zombie() { return make_not_entrant_or_zombie(zombie); } // used by jvmti to track if the unload event has been reported diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/compiler/compileBroker.cpp --- a/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -166,7 +166,7 @@ StringLogMessage lm; stringStream sstr = lm.stream(); // msg.time_stamp().update_to(tty->time_stamp().ticks()); - task->print_compilation(&sstr, NULL, true); + task->print_compilation(&sstr, NULL, true, false); log(thread, "%s", (const char*)lm); } @@ -328,7 +328,6 @@ if (nm == NULL) _code_handle = NULL; // drop the handle also } - void CompileTask::mark_on_stack() { // Mark these methods as something redefine classes cannot remove. _method->set_on_stack(true); @@ -338,18 +337,6 @@ } // ------------------------------------------------------------------ -// CompileTask::print -void CompileTask::print() { - tty->print("print("method="); - _method->print_name(tty); - tty->print_cr(" osr_bci=%d is_blocking=%s is_complete=%s is_success=%s>", - _osr_bci, bool_to_str(_is_blocking), - bool_to_str(_is_complete), bool_to_str(_is_success)); -} - - -// ------------------------------------------------------------------ // CompileTask::print_line_on_error // // This function is called by fatal error handler when the thread @@ -367,19 +354,18 @@ // ------------------------------------------------------------------ // CompileTask::print_line -void CompileTask::print_line() { +void CompileTask::print_tty() { ttyLocker ttyl; // keep the following output all in one block // print compiler name if requested if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level())); - print_compilation(); + print_compilation(tty); } - // ------------------------------------------------------------------ // CompileTask::print_compilation_impl void CompileTask::print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level, bool is_osr_method, int osr_bci, bool is_blocking, - const char* msg, bool short_form) { + const char* msg, bool short_form, bool cr) { if (!short_form) { st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp } @@ -428,7 +414,7 @@ if (msg != NULL) { st->print(" %s", msg); } - if (!short_form) { + if (cr) { st->cr(); } } @@ -494,9 +480,9 @@ // ------------------------------------------------------------------ // CompileTask::print_compilation -void CompileTask::print_compilation(outputStream* st, const char* msg, bool short_form) { +void CompileTask::print_compilation(outputStream* st, const char* msg, bool short_form, bool cr) { bool is_osr_method = osr_bci() != InvocationEntryBci; - print_compilation_impl(st, method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form); + print_compilation_impl(st, method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form, cr); } // ------------------------------------------------------------------ @@ -621,7 +607,9 @@ // Mark the method as being in the compile queue. task->method()->set_queued_for_compilation(); - NOT_PRODUCT(print();) + if (CIPrintCompileQueue) { + print_tty(); + } if (LogCompilation && xtty != NULL) { task->log_task_queued(); @@ -786,24 +774,40 @@ } } -#ifndef PRODUCT -/** - * Print entire compilation queue. - */ -void CompileQueue::print() { - if (CIPrintCompileQueue) { - ttyLocker ttyl; - tty->print_cr("Contents of %s", name()); - tty->print_cr("----------------------"); - CompileTask* task = _first; + +CompileQueue* CompileBroker::compile_queue(int comp_level) { + if (is_c2_compile(comp_level)) return _c2_compile_queue; + if (is_c1_compile(comp_level)) return _c1_compile_queue; + return NULL; +} + + +void CompileBroker::print_compile_queues(outputStream* st) { + _c1_compile_queue->print(st); + _c2_compile_queue->print(st); +} + + +void CompileQueue::print(outputStream* st) { + assert_locked_or_safepoint(lock()); + st->print_cr("Contents of %s", name()); + st->print_cr("----------------------------"); + CompileTask* task = _first; + if (task == NULL) { + st->print_cr("Empty");; + } else { while (task != NULL) { - task->print_line(); + task->print_compilation(st, NULL, true, true); task = task->next(); } - tty->print_cr("----------------------"); } + st->print_cr("----------------------------"); } -#endif // PRODUCT + +void CompileQueue::print_tty() { + ttyLocker ttyl; + print(tty); +} CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) { @@ -1068,11 +1072,11 @@ #endif // !ZERO && !SHARK // Initialize the compilation queue if (c2_compiler_count > 0) { - _c2_compile_queue = new CompileQueue("C2 CompileQueue", MethodCompileQueue_lock); + _c2_compile_queue = new CompileQueue("C2 compile queue", MethodCompileQueue_lock); _compilers[1]->set_num_compiler_threads(c2_compiler_count); } if (c1_compiler_count > 0) { - _c1_compile_queue = new CompileQueue("C1 CompileQueue", MethodCompileQueue_lock); + _c1_compile_queue = new CompileQueue("C1 compile queue", MethodCompileQueue_lock); _compilers[0]->set_num_compiler_threads(c1_compiler_count); } @@ -1892,7 +1896,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { if (PrintCompilation) { ResourceMark rm; - task->print_line(); + task->print_tty(); } elapsedTimer time; diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/compiler/compileBroker.hpp --- a/hotspot/src/share/vm/compiler/compileBroker.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -111,14 +111,14 @@ private: static void print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level, bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false, - const char* msg = NULL, bool short_form = false); + const char* msg = NULL, bool short_form = false, bool cr = true); public: - void print_compilation(outputStream* st = tty, const char* msg = NULL, bool short_form = false); - static void print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false) { + void print_compilation(outputStream* st = tty, const char* msg = NULL, bool short_form = false, bool cr = true); + static void print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false, bool cr = true) { print_compilation_impl(st, nm->method(), nm->compile_id(), nm->comp_level(), nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false, - msg, short_form); + msg, short_form, cr); } static void print_inlining(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg = NULL); @@ -131,8 +131,7 @@ static void print_inline_indent(int inline_level, outputStream* st = tty); - void print(); - void print_line(); + void print_tty(); void print_line_on_error(outputStream* st, char* buf, int buflen); void log_task(xmlStream* log); @@ -234,7 +233,8 @@ // Redefine Classes support void mark_on_stack(); void free_all(); - NOT_PRODUCT (void print();) + void print_tty(); + void print(outputStream* st = tty); ~CompileQueue() { assert (is_empty(), " Compile Queue must be empty"); @@ -341,7 +341,7 @@ static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count); static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level); static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level); - static bool is_compile_blocking (); + static bool is_compile_blocking(); static void preload_classes (methodHandle method, TRAPS); static CompileTask* create_compile_task(CompileQueue* queue, @@ -369,11 +369,8 @@ int hot_count, const char* comment, Thread* thread); - static CompileQueue* compile_queue(int comp_level) { - if (is_c2_compile(comp_level)) return _c2_compile_queue; - if (is_c1_compile(comp_level)) return _c1_compile_queue; - return NULL; - } + + static CompileQueue* compile_queue(int comp_level); static bool init_compiler_runtime(); static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread); @@ -390,6 +387,7 @@ } static bool compilation_is_in_queue(methodHandle method); + static void print_compile_queues(outputStream* st); static int queue_size(int comp_level) { CompileQueue *q = compile_queue(comp_level); return q != NULL ? q->size() : 0; diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -369,33 +369,45 @@ #endif } -bool -G1BlockOffsetArray::verify_for_object(HeapWord* obj_start, - size_t word_size) const { - size_t first_card = _array->index_for(obj_start); - size_t last_card = _array->index_for(obj_start + word_size - 1); - if (!_array->is_card_boundary(obj_start)) { - // If the object is not on a card boundary the BOT entry of the - // first card should point to another object so we should not - // check that one. - first_card += 1; - } - for (size_t card = first_card; card <= last_card; card += 1) { - HeapWord* card_addr = _array->address_for_index(card); - HeapWord* block_start = block_start_const(card_addr); - if (block_start != obj_start) { - gclog_or_tty->print_cr("block start: "PTR_FORMAT" is incorrect - " - "card index: "SIZE_FORMAT" " - "card addr: "PTR_FORMAT" BOT entry: %u " - "obj: "PTR_FORMAT" word size: "SIZE_FORMAT" " - "cards: ["SIZE_FORMAT","SIZE_FORMAT"]", - p2i(block_start), card, p2i(card_addr), - _array->offset_array(card), - p2i(obj_start), word_size, first_card, last_card); - return false; +void G1BlockOffsetArray::verify() const { + assert(gsp()->bottom() < gsp()->top(), "Only non-empty regions should be verified."); + size_t start_card = _array->index_for(gsp()->bottom()); + size_t end_card = _array->index_for(gsp()->top() - 1); + + for (size_t current_card = start_card; current_card < end_card; current_card++) { + u_char entry = _array->offset_array(current_card); + if (entry < N_words) { + // The entry should point to an object before the current card. Verify that + // it is possible to walk from that object in to the current card by just + // iterating over the objects following it. + HeapWord* card_address = _array->address_for_index(current_card); + HeapWord* obj_end = card_address - entry; + while (obj_end < card_address) { + HeapWord* obj = obj_end; + size_t obj_size = block_size(obj); + obj_end = obj + obj_size; + guarantee(obj_end > obj && obj_end <= gsp()->top(), + err_msg("Invalid object end. obj: " PTR_FORMAT " obj_size: " SIZE_FORMAT " obj_end: " PTR_FORMAT " top: " PTR_FORMAT, + p2i(obj), obj_size, p2i(obj_end), p2i(gsp()->top()))); + } + } else { + // Because we refine the BOT based on which cards are dirty there is not much we can verify here. + // We need to make sure that we are going backwards and that we don't pass the start of the + // corresponding heap region. But that is about all we can verify. + size_t backskip = BlockOffsetArray::entry_to_cards_back(entry); + guarantee(backskip >= 1, "Must be going back at least one card."); + + size_t max_backskip = current_card - start_card; + guarantee(backskip <= max_backskip, + err_msg("Going backwards beyond the start_card. start_card: " SIZE_FORMAT " current_card: " SIZE_FORMAT " backskip: " SIZE_FORMAT, + start_card, current_card, backskip)); + + HeapWord* backskip_address = _array->address_for_index(current_card - backskip); + guarantee(backskip_address >= gsp()->bottom(), + err_msg("Going backwards beyond bottom of the region: bottom: " PTR_FORMAT ", backskip_address: " PTR_FORMAT, + p2i(gsp()->bottom()), p2i(backskip_address))); } } - return true; } #ifndef PRODUCT diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -304,13 +304,9 @@ virtual HeapWord* block_start_unsafe(const void* addr); virtual HeapWord* block_start_unsafe_const(const void* addr) const; - // Used by region verification. Checks that the contents of the - // BOT reflect that there's a single object that spans the address - // range [obj_start, obj_start + word_size); returns true if this is - // the case, returns false if it's not. - bool verify_for_object(HeapWord* obj_start, size_t word_size) const; + void check_all_cards(size_t left_card, size_t right_card) const; - void check_all_cards(size_t left_card, size_t right_card) const; + void verify() const; virtual void print_on(outputStream* out) PRODUCT_RETURN; }; diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -48,6 +48,7 @@ return hash ^ (hash >> 7); // code heap blocks are 128byte aligned } + void remove_entry(Entry* e, Entry* previous); Entry* new_entry(nmethod* nm); public: @@ -67,7 +68,7 @@ void nmethods_do(CodeBlobClosure* blk); template - void remove_if(CB& should_remove); + int remove_if(CB& should_remove); static void purge_list_append(CodeRootSetTable* tbl); static void purge(); @@ -91,6 +92,18 @@ return entry; } +void CodeRootSetTable::remove_entry(Entry* e, Entry* previous) { + int index = hash_to_index(e->hash()); + assert((e == bucket(index)) == (previous == NULL), "if e is the first entry then previous should be null"); + + if (previous == NULL) { + set_entry(index, e->next()); + } else { + previous->set_next(e->next()); + } + free_entry(e); +} + CodeRootSetTable::~CodeRootSetTable() { for (int index = 0; index < table_size(); ++index) { for (Entry* e = bucket(index); e != NULL; ) { @@ -133,12 +146,7 @@ Entry* previous = NULL; for (Entry* e = bucket(index); e != NULL; previous = e, e = e->next()) { if (e->literal() == nm) { - if (previous != NULL) { - previous->set_next(e->next()); - } else { - set_entry(index, e->next()); - } - free_entry(e); + remove_entry(e, previous); return true; } } @@ -163,25 +171,23 @@ } template -void CodeRootSetTable::remove_if(CB& should_remove) { +int CodeRootSetTable::remove_if(CB& should_remove) { + int num_removed = 0; for (int index = 0; index < table_size(); ++index) { Entry* previous = NULL; Entry* e = bucket(index); while (e != NULL) { Entry* next = e->next(); if (should_remove(e->literal())) { - if (previous != NULL) { - previous->set_next(next); - } else { - set_entry(index, next); - } - free_entry(e); + remove_entry(e, previous); + ++num_removed; } else { previous = e; } e = next; } } + return num_removed; } G1CodeRootSet::~G1CodeRootSet() { @@ -320,14 +326,19 @@ bool operator() (nmethod* nm) { _detector._points_into = false; _blobs.do_code_blob(nm); - return _detector._points_into; + return !_detector._points_into; } }; void G1CodeRootSet::clean(HeapRegion* owner) { CleanCallback should_clean(owner); if (_table != NULL) { - _table->remove_if(should_clean); + int removed = _table->remove_if(should_clean); + assert((size_t)removed <= _length, "impossible"); + _length -= removed; + } + if (_length == 0) { + clear(); } } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -861,7 +861,6 @@ HeapWord* prev_p = NULL; VerifyLiveClosure vl_cl(g1, vo); bool is_humongous = isHumongous(); - bool do_bot_verify = !is_young(); size_t object_num = 0; while (p < top()) { oop obj = oop(p); @@ -878,15 +877,6 @@ return; } - // If it returns false, verify_for_object() will output the - // appropriate message. - if (do_bot_verify && - !g1->is_obj_dead(obj, this) && - !_offsets.verify_for_object(p, obj_size)) { - *failures = true; - return; - } - if (!g1->is_obj_dead_cond(obj, this, vo)) { if (obj->is_oop()) { Klass* klass = obj->klass(); @@ -924,6 +914,10 @@ p += obj_size; } + if (!is_young() && !is_empty()) { + _offsets.verify(); + } + if (p != top()) { gclog_or_tty->print_cr("end of last object "PTR_FORMAT" " "does not match top "PTR_FORMAT, p, top()); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/memory/universe.cpp diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -460,6 +460,8 @@ oop InstanceKlass::init_lock() const { // return the init lock from the mirror oop lock = java_lang_Class::init_lock(java_mirror()); + // Prevent reordering with any access of initialization state + OrderAccess::loadload(); assert((oop)lock != NULL || !is_not_initialized(), // initialized or in_error state "only fully initialized state can have a null lock"); return lock; @@ -2437,16 +2439,6 @@ assert(breakpoints() == 0x0, "should have cleared breakpoints"); } - // deallocate information about previous versions - if (_previous_versions != NULL) { - for (int i = _previous_versions->length() - 1; i >= 0; i--) { - PreviousVersionNode * pv_node = _previous_versions->at(i); - delete pv_node; - } - delete _previous_versions; - _previous_versions = NULL; - } - // deallocate the cached class file if (_cached_class_file != NULL) { os::free(_cached_class_file, mtClass); @@ -3020,16 +3012,17 @@ st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr(); { bool have_pv = false; - PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this); - for (PreviousVersionNode * pv_node = pvw.next_previous_version(); - pv_node != NULL; pv_node = pvw.next_previous_version()) { + // previous versions are linked together through the InstanceKlass + for (InstanceKlass* pv_node = _previous_versions; + pv_node != NULL; + pv_node = pv_node->previous_versions()) { if (!have_pv) st->print(BULLET"previous version: "); have_pv = true; - pv_node->prev_constant_pool()->print_value_on(st); + pv_node->constants()->print_value_on(st); } if (have_pv) st->cr(); - } // pvw is cleaned up + } if (generic_signature() != NULL) { st->print(BULLET"generic signature: "); @@ -3443,92 +3436,92 @@ // RedefineClasses() support for previous versions: // Purge previous versions -static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_count) { +void InstanceKlass::purge_previous_versions(InstanceKlass* ik) { if (ik->previous_versions() != NULL) { // This klass has previous versions so see what we can cleanup // while it is safe to do so. int deleted_count = 0; // leave debugging breadcrumbs int live_count = 0; - ClassLoaderData* loader_data = ik->class_loader_data() == NULL ? - ClassLoaderData::the_null_class_loader_data() : - ik->class_loader_data(); + ClassLoaderData* loader_data = ik->class_loader_data(); + assert(loader_data != NULL, "should never be null"); // RC_TRACE macro has an embedded ResourceMark - RC_TRACE(0x00000200, ("purge: %s: previous version length=%d", - ik->external_name(), ik->previous_versions()->length())); - - for (int i = ik->previous_versions()->length() - 1; i >= 0; i--) { - // check the previous versions array - PreviousVersionNode * pv_node = ik->previous_versions()->at(i); - ConstantPool* cp_ref = pv_node->prev_constant_pool(); - assert(cp_ref != NULL, "cp ref was unexpectedly cleared"); - - ConstantPool* pvcp = cp_ref; + RC_TRACE(0x00000200, ("purge: %s: previous versions", ik->external_name())); + + // previous versions are linked together through the InstanceKlass + InstanceKlass* pv_node = ik->previous_versions(); + InstanceKlass* last = ik; + int version = 0; + + // check the previous versions list + for (; pv_node != NULL; ) { + + ConstantPool* pvcp = pv_node->constants(); + assert(pvcp != NULL, "cp ref was unexpectedly cleared"); + if (!pvcp->on_stack()) { // If the constant pool isn't on stack, none of the methods - // are executing. Delete all the methods, the constant pool and - // and this previous version node. - GrowableArray* method_refs = pv_node->prev_EMCP_methods(); - if (method_refs != NULL) { - for (int j = method_refs->length() - 1; j >= 0; j--) { - Method* method = method_refs->at(j); - assert(method != NULL, "method ref was unexpectedly cleared"); - method_refs->remove_at(j); - // method will be freed with associated class. - } - } - // Remove the constant pool - delete pv_node; - // Since we are traversing the array backwards, we don't have to - // do anything special with the index. - ik->previous_versions()->remove_at(i); + // are executing. Unlink this previous_version. + // The previous version InstanceKlass is on the ClassLoaderData deallocate list + // so will be deallocated during the next phase of class unloading. + pv_node = pv_node->previous_versions(); + last->link_previous_versions(pv_node); deleted_count++; + version++; continue; } else { - RC_TRACE(0x00000200, ("purge: previous version @%d is alive", i)); + RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is alive", + pv_node)); assert(pvcp->pool_holder() != NULL, "Constant pool with no holder"); guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack"); live_count++; } - // At least one method is live in this previous version, clean out - // the others or mark them as obsolete. - GrowableArray* method_refs = pv_node->prev_EMCP_methods(); + // At least one method is live in this previous version so clean its MethodData. + // Reset dead EMCP methods not to get breakpoints. + // All methods are deallocated when all of the methods for this class are no + // longer running. + Array* method_refs = pv_node->methods(); if (method_refs != NULL) { RC_TRACE(0x00000200, ("purge: previous methods length=%d", method_refs->length())); - for (int j = method_refs->length() - 1; j >= 0; j--) { + for (int j = 0; j < method_refs->length(); j++) { Method* method = method_refs->at(j); - assert(method != NULL, "method ref was unexpectedly cleared"); - - // Remove the emcp method if it's not executing - // If it's been made obsolete by a redefinition of a non-emcp - // method, mark it as obsolete but leave it to clean up later. + if (!method->on_stack()) { - method_refs->remove_at(j); - } else if (emcp_method_count == 0) { - method->set_is_obsolete(); + // no breakpoints for non-running methods + if (method->is_running_emcp()) { + method->set_running_emcp(false); + } } else { + assert (method->is_obsolete() || method->is_running_emcp(), + "emcp method cannot run after emcp bit is cleared"); // RC_TRACE macro has an embedded ResourceMark RC_TRACE(0x00000200, ("purge: %s(%s): prev method @%d in version @%d is alive", method->name()->as_C_string(), - method->signature()->as_C_string(), j, i)); + method->signature()->as_C_string(), j, version)); if (method->method_data() != NULL) { - // Clean out any weak method links + // Clean out any weak method links for running methods + // (also should include not EMCP methods) method->method_data()->clean_weak_method_links(); } } } } + // next previous version + last = pv_node; + pv_node = pv_node->previous_versions(); + version++; } - assert(ik->previous_versions()->length() == live_count, "sanity check"); RC_TRACE(0x00000200, ("purge: previous version stats: live=%d, deleted=%d", live_count, deleted_count)); } + // Clean MethodData of this class's methods so they don't refer to + // old methods that are no longer running. Array* methods = ik->methods(); int num_methods = methods->length(); for (int index2 = 0; index2 < num_methods; ++index2) { @@ -3538,122 +3531,30 @@ } } -// External interface for use during class unloading. -void InstanceKlass::purge_previous_versions(InstanceKlass* ik) { - // Call with >0 emcp methods since they are not currently being redefined. - purge_previous_versions_internal(ik, 1); -} - - -// Potentially add an information node that contains pointers to the -// interesting parts of the previous version of the_class. -// This is also where we clean out any unused references. -// Note that while we delete nodes from the _previous_versions -// array, we never delete the array itself until the klass is -// unloaded. The has_been_redefined() query depends on that fact. -// -void InstanceKlass::add_previous_version(instanceKlassHandle ikh, - BitMap* emcp_methods, int emcp_method_count) { - assert(Thread::current()->is_VM_thread(), - "only VMThread can add previous versions"); - - if (_previous_versions == NULL) { - // This is the first previous version so make some space. - // Start with 2 elements under the assumption that the class - // won't be redefined much. - _previous_versions = new (ResourceObj::C_HEAP, mtClass) - GrowableArray(2, true); - } - - ConstantPool* cp_ref = ikh->constants(); - - // RC_TRACE macro has an embedded ResourceMark - RC_TRACE(0x00000400, ("adding previous version ref for %s @%d, EMCP_cnt=%d " - "on_stack=%d", - ikh->external_name(), _previous_versions->length(), emcp_method_count, - cp_ref->on_stack())); - - // If the constant pool for this previous version of the class - // is not marked as being on the stack, then none of the methods - // in this previous version of the class are on the stack so - // we don't need to create a new PreviousVersionNode. However, - // we still need to examine older previous versions below. - Array* old_methods = ikh->methods(); - - if (cp_ref->on_stack()) { - PreviousVersionNode * pv_node = NULL; - if (emcp_method_count == 0) { - // non-shared ConstantPool gets a reference - pv_node = new PreviousVersionNode(cp_ref, NULL); - RC_TRACE(0x00000400, - ("add: all methods are obsolete; flushing any EMCP refs")); - } else { - int local_count = 0; - GrowableArray* method_refs = new (ResourceObj::C_HEAP, mtClass) - GrowableArray(emcp_method_count, true); - for (int i = 0; i < old_methods->length(); i++) { - if (emcp_methods->at(i)) { - // this old method is EMCP. Save it only if it's on the stack - Method* old_method = old_methods->at(i); - if (old_method->on_stack()) { - method_refs->append(old_method); - } - if (++local_count >= emcp_method_count) { - // no more EMCP methods so bail out now - break; - } - } - } - // non-shared ConstantPool gets a reference - pv_node = new PreviousVersionNode(cp_ref, method_refs); - } - // append new previous version. - _previous_versions->append(pv_node); - } - - // Since the caller is the VMThread and we are at a safepoint, this - // is a good time to clear out unused references. - - RC_TRACE(0x00000400, ("add: previous version length=%d", - _previous_versions->length())); - - // Purge previous versions not executing on the stack - purge_previous_versions_internal(this, emcp_method_count); - +void InstanceKlass::mark_newly_obsolete_methods(Array* old_methods, + int emcp_method_count) { int obsolete_method_count = old_methods->length() - emcp_method_count; if (emcp_method_count != 0 && obsolete_method_count != 0 && - _previous_versions->length() > 0) { + _previous_versions != NULL) { // We have a mix of obsolete and EMCP methods so we have to // clear out any matching EMCP method entries the hard way. int local_count = 0; for (int i = 0; i < old_methods->length(); i++) { - if (!emcp_methods->at(i)) { + Method* old_method = old_methods->at(i); + if (old_method->is_obsolete()) { // only obsolete methods are interesting - Method* old_method = old_methods->at(i); Symbol* m_name = old_method->name(); Symbol* m_signature = old_method->signature(); - // we might not have added the last entry - for (int j = _previous_versions->length() - 1; j >= 0; j--) { - // check the previous versions array for non executing obsolete methods - PreviousVersionNode * pv_node = _previous_versions->at(j); - - GrowableArray* method_refs = pv_node->prev_EMCP_methods(); - if (method_refs == NULL) { - // We have run into a PreviousVersion generation where - // all methods were made obsolete during that generation's - // RedefineClasses() operation. At the time of that - // operation, all EMCP methods were flushed so we don't - // have to go back any further. - // - // A NULL method_refs is different than an empty method_refs. - // We cannot infer any optimizations about older generations - // from an empty method_refs for the current generation. - break; - } - - for (int k = method_refs->length() - 1; k >= 0; k--) { + // previous versions are linked together through the InstanceKlass + int j = 0; + for (InstanceKlass* prev_version = _previous_versions; + prev_version != NULL; + prev_version = prev_version->previous_versions(), j++) { + + Array* method_refs = prev_version->methods(); + for (int k = 0; k < method_refs->length(); k++) { Method* method = method_refs->at(k); if (!method->is_obsolete() && @@ -3661,14 +3562,11 @@ method->signature() == m_signature) { // The current RedefineClasses() call has made all EMCP // versions of this method obsolete so mark it as obsolete - // and remove the reference. RC_TRACE(0x00000400, ("add: %s(%s): flush obsolete method @%d in version @%d", m_name->as_C_string(), m_signature->as_C_string(), k, j)); method->set_is_obsolete(); - // Leave obsolete methods on the previous version list to - // clean up later. break; } } @@ -3676,9 +3574,9 @@ // The previous loop may not find a matching EMCP method, but // that doesn't mean that we can optimize and not go any // further back in the PreviousVersion generations. The EMCP - // method for this generation could have already been deleted, + // method for this generation could have already been made obsolete, // but there still may be an older EMCP method that has not - // been deleted. + // been made obsolete. } if (++local_count >= obsolete_method_count) { @@ -3688,15 +3586,69 @@ } } } +} + +// Save the scratch_class as the previous version if any of the methods are running. +// The previous_versions are used to set breakpoints in EMCP methods and they are +// also used to clean MethodData links to redefined methods that are no longer running. +void InstanceKlass::add_previous_version(instanceKlassHandle scratch_class, + int emcp_method_count) { + assert(Thread::current()->is_VM_thread(), + "only VMThread can add previous versions"); + + // RC_TRACE macro has an embedded ResourceMark + RC_TRACE(0x00000400, ("adding previous version ref for %s, EMCP_cnt=%d", + scratch_class->external_name(), emcp_method_count)); + + // Clean out old previous versions + purge_previous_versions(this); + + // Mark newly obsolete methods in remaining previous versions. An EMCP method from + // a previous redefinition may be made obsolete by this redefinition. + Array* old_methods = scratch_class->methods(); + mark_newly_obsolete_methods(old_methods, emcp_method_count); + + // If the constant pool for this previous version of the class + // is not marked as being on the stack, then none of the methods + // in this previous version of the class are on the stack so + // we don't need to add this as a previous version. + ConstantPool* cp_ref = scratch_class->constants(); + if (!cp_ref->on_stack()) { + RC_TRACE(0x00000400, ("add: scratch class not added; no methods are running")); + return; + } + + if (emcp_method_count != 0) { + // At least one method is still running, check for EMCP methods + for (int i = 0; i < old_methods->length(); i++) { + Method* old_method = old_methods->at(i); + if (!old_method->is_obsolete() && old_method->on_stack()) { + // if EMCP method (not obsolete) is on the stack, mark as EMCP so that + // we can add breakpoints for it. + + // We set the method->on_stack bit during safepoints for class redefinition and + // class unloading and use this bit to set the is_running_emcp bit. + // After the safepoint, the on_stack bit is cleared and the running emcp + // method may exit. If so, we would set a breakpoint in a method that + // is never reached, but this won't be noticeable to the programmer. + old_method->set_running_emcp(true); + RC_TRACE(0x00000400, ("add: EMCP method %s is on_stack " INTPTR_FORMAT, + old_method->name_and_sig_as_C_string(), old_method)); + } else if (!old_method->is_obsolete()) { + RC_TRACE(0x00000400, ("add: EMCP method %s is NOT on_stack " INTPTR_FORMAT, + old_method->name_and_sig_as_C_string(), old_method)); + } + } + } + + // Add previous version if any methods are still running. + RC_TRACE(0x00000400, ("add: scratch class added; one of its methods is on_stack")); + assert(scratch_class->previous_versions() == NULL, "shouldn't have a previous version"); + scratch_class->link_previous_versions(previous_versions()); + link_previous_versions(scratch_class()); } // end add_previous_version() -// Determine if InstanceKlass has a previous version. -bool InstanceKlass::has_previous_version() const { - return (_previous_versions != NULL && _previous_versions->length() > 0); -} // end has_previous_version() - - Method* InstanceKlass::method_with_idnum(int idnum) { Method* m = NULL; if (idnum < methods()->length()) { @@ -3722,61 +3674,3 @@ unsigned char * InstanceKlass::get_cached_class_file_bytes() { return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file); } - - -// Construct a PreviousVersionNode entry for the array hung off -// the InstanceKlass. -PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool, - GrowableArray* prev_EMCP_methods) { - - _prev_constant_pool = prev_constant_pool; - _prev_EMCP_methods = prev_EMCP_methods; -} - - -// Destroy a PreviousVersionNode -PreviousVersionNode::~PreviousVersionNode() { - if (_prev_constant_pool != NULL) { - _prev_constant_pool = NULL; - } - - if (_prev_EMCP_methods != NULL) { - delete _prev_EMCP_methods; - } -} - -// Construct a helper for walking the previous versions array -PreviousVersionWalker::PreviousVersionWalker(Thread* thread, InstanceKlass *ik) { - _thread = thread; - _previous_versions = ik->previous_versions(); - _current_index = 0; - _current_p = NULL; - _current_constant_pool_handle = constantPoolHandle(thread, ik->constants()); -} - - -// Return the interesting information for the next previous version -// of the klass. Returns NULL if there are no more previous versions. -PreviousVersionNode* PreviousVersionWalker::next_previous_version() { - if (_previous_versions == NULL) { - // no previous versions so nothing to return - return NULL; - } - - _current_p = NULL; // reset to NULL - _current_constant_pool_handle = NULL; - - int length = _previous_versions->length(); - - while (_current_index < length) { - PreviousVersionNode * pv_node = _previous_versions->at(_current_index++); - - // Save a handle to the constant pool for this previous version, - // which keeps all the methods from being deallocated. - _current_constant_pool_handle = constantPoolHandle(_thread, pv_node->prev_constant_pool()); - _current_p = pv_node; - return pv_node; - } - - return NULL; -} // end next_previous_version() diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -59,7 +59,6 @@ class fieldDescriptor; class DepChange; class nmethodBucket; -class PreviousVersionNode; class JvmtiCachedClassFieldMap; class MemberNameTable; @@ -205,7 +204,8 @@ _misc_should_verify_class = 1 << 2, // allow caching of preverification _misc_is_anonymous = 1 << 3, // has embedded _host_klass field _misc_is_contended = 1 << 4, // marked with contended annotation - _misc_has_default_methods = 1 << 5 // class/superclass/implemented interfaces has default methods + _misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods + _misc_has_been_redefined = 1 << 6 // class has been redefined }; u2 _misc_flags; u2 _minor_version; // minor version number of class file @@ -220,9 +220,8 @@ nmethodBucket* _dependencies; // list of dependent nmethods nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class BreakpointInfo* _breakpoints; // bpt lists, managed by Method* - // Array of interesting part(s) of the previous version(s) of this - // InstanceKlass. See PreviousVersionWalker below. - GrowableArray* _previous_versions; + // Linked instanceKlasses of previous versions + InstanceKlass* _previous_versions; // JVMTI fields can be moved to their own structure - see 6315920 // JVMTI: cached class file, before retransformable agent modified it in CFLH JvmtiCachedClassFileData* _cached_class_file; @@ -608,19 +607,20 @@ } // RedefineClasses() support for previous versions: - void add_previous_version(instanceKlassHandle ikh, BitMap *emcp_methods, - int emcp_method_count); - // If the _previous_versions array is non-NULL, then this klass - // has been redefined at least once even if we aren't currently - // tracking a previous version. - bool has_been_redefined() const { return _previous_versions != NULL; } - bool has_previous_version() const; + void add_previous_version(instanceKlassHandle ikh, int emcp_method_count); + + InstanceKlass* previous_versions() const { return _previous_versions; } + + bool has_been_redefined() const { + return (_misc_flags & _misc_has_been_redefined) != 0; + } + void set_has_been_redefined() { + _misc_flags |= _misc_has_been_redefined; + } + void init_previous_versions() { _previous_versions = NULL; } - GrowableArray* previous_versions() const { - return _previous_versions; - } static void purge_previous_versions(InstanceKlass* ik); @@ -1042,6 +1042,10 @@ // Free CHeap allocated fields. void release_C_heap_structures(); + + // RedefineClasses support + void link_previous_versions(InstanceKlass* pv) { _previous_versions = pv; } + void mark_newly_obsolete_methods(Array* old_methods, int emcp_method_count); public: // CDS support - remove and restore oops from metadata. Oops are not shared. virtual void remove_unshareable_info(); @@ -1141,62 +1145,6 @@ }; -// If breakpoints are more numerous than just JVMTI breakpoints, -// consider compressing this data structure. -// It is currently a simple linked list defined in method.hpp. - -class BreakpointInfo; - - -// A collection point for interesting information about the previous -// version(s) of an InstanceKlass. A GrowableArray of PreviousVersionNodes -// is attached to the InstanceKlass as needed. See PreviousVersionWalker below. -class PreviousVersionNode : public CHeapObj { - private: - ConstantPool* _prev_constant_pool; - - // If the previous version of the InstanceKlass doesn't have any - // EMCP methods, then _prev_EMCP_methods will be NULL. If all the - // EMCP methods have been collected, then _prev_EMCP_methods can - // have a length of zero. - GrowableArray* _prev_EMCP_methods; - -public: - PreviousVersionNode(ConstantPool* prev_constant_pool, - GrowableArray* prev_EMCP_methods); - ~PreviousVersionNode(); - ConstantPool* prev_constant_pool() const { - return _prev_constant_pool; - } - GrowableArray* prev_EMCP_methods() const { - return _prev_EMCP_methods; - } -}; - - -// Helper object for walking previous versions. -class PreviousVersionWalker : public StackObj { - private: - Thread* _thread; - GrowableArray* _previous_versions; - int _current_index; - - // A pointer to the current node object so we can handle the deletes. - PreviousVersionNode* _current_p; - - // The constant pool handle keeps all the methods in this class from being - // deallocated from the metaspace during class unloading. - constantPoolHandle _current_constant_pool_handle; - - public: - PreviousVersionWalker(Thread* thread, InstanceKlass *ik); - - // Return the interesting information for the next previous version - // of the klass. Returns NULL if there are no more previous versions. - PreviousVersionNode* next_previous_version(); -}; - - // // nmethodBucket is used to record dependent nmethods for // deoptimization. nmethod dependencies are actually diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/oops/method.cpp --- a/hotspot/src/share/vm/oops/method.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/oops/method.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -1635,34 +1635,34 @@ } int Method::highest_comp_level() const { - const MethodData* mdo = method_data(); - if (mdo != NULL) { - return mdo->highest_comp_level(); + const MethodCounters* mcs = method_counters(); + if (mcs != NULL) { + return mcs->highest_comp_level(); } else { return CompLevel_none; } } int Method::highest_osr_comp_level() const { - const MethodData* mdo = method_data(); - if (mdo != NULL) { - return mdo->highest_osr_comp_level(); + const MethodCounters* mcs = method_counters(); + if (mcs != NULL) { + return mcs->highest_osr_comp_level(); } else { return CompLevel_none; } } void Method::set_highest_comp_level(int level) { - MethodData* mdo = method_data(); - if (mdo != NULL) { - mdo->set_highest_comp_level(level); + MethodCounters* mcs = method_counters(); + if (mcs != NULL) { + mcs->set_highest_comp_level(level); } } void Method::set_highest_osr_comp_level(int level) { - MethodData* mdo = method_data(); - if (mdo != NULL) { - mdo->set_highest_osr_comp_level(level); + MethodCounters* mcs = method_counters(); + if (mcs != NULL) { + mcs->set_highest_osr_comp_level(level); } } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/oops/method.hpp --- a/hotspot/src/share/vm/oops/method.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/oops/method.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -80,7 +80,8 @@ _caller_sensitive = 1 << 1, _force_inline = 1 << 2, _dont_inline = 1 << 3, - _hidden = 1 << 4 + _hidden = 1 << 4, + _running_emcp = 1 << 5 }; u1 _flags; @@ -688,6 +689,21 @@ void set_is_obsolete() { _access_flags.set_is_obsolete(); } bool is_deleted() const { return access_flags().is_deleted(); } void set_is_deleted() { _access_flags.set_is_deleted(); } + + bool is_running_emcp() const { + // EMCP methods are old but not obsolete or deleted. Equivalent + // Modulo Constant Pool means the method is equivalent except + // the constant pool and instructions that access the constant + // pool might be different. + // If a breakpoint is set in a redefined method, its EMCP methods that are + // still running must have a breakpoint also. + return (_flags & _running_emcp) != 0; + } + + void set_running_emcp(bool x) { + _flags = x ? (_flags | _running_emcp) : (_flags & ~_running_emcp); + } + bool on_stack() const { return access_flags().on_stack(); } void set_on_stack(const bool value); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/oops/methodCounters.cpp --- a/hotspot/src/share/vm/oops/methodCounters.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/oops/methodCounters.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -35,4 +35,40 @@ set_interpreter_throwout_count(0); set_interpreter_invocation_count(0); set_nmethod_age(INT_MAX); +#ifdef TIERED + set_prev_time(0); + set_rate(0); + set_highest_comp_level(0); + set_highest_osr_comp_level(0); +#endif } + + +int MethodCounters::highest_comp_level() const { +#ifdef TIERED + return _highest_comp_level; +#else + return CompLevel_none; +#endif +} + +void MethodCounters::set_highest_comp_level(int level) { +#ifdef TIERED + _highest_comp_level = level; +#endif +} + +int MethodCounters::highest_osr_comp_level() const { +#ifdef TIERED + return _highest_osr_comp_level; +#else + return CompLevel_none; +#endif +} + +void MethodCounters::set_highest_osr_comp_level(int level) { +#ifdef TIERED + _highest_osr_comp_level = level; +#endif +} + diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/oops/methodCounters.hpp --- a/hotspot/src/share/vm/oops/methodCounters.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/oops/methodCounters.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -49,6 +49,8 @@ #ifdef TIERED float _rate; // Events (invocation and backedge counter increments) per millisecond jlong _prev_time; // Previous time the rate was acquired + u1 _highest_comp_level; // Highest compile level this method has ever seen. + u1 _highest_osr_comp_level; // Same for OSR level #endif MethodCounters() : _interpreter_invocation_count(0), @@ -57,7 +59,9 @@ _nmethod_age(INT_MAX) #ifdef TIERED , _rate(0), - _prev_time(0) + _prev_time(0), + _highest_comp_level(0), + _highest_osr_comp_level(0) #endif { invocation_counter()->init(); @@ -114,6 +118,11 @@ void set_rate(float rate) { _rate = rate; } #endif + int highest_comp_level() const; + void set_highest_comp_level(int level); + int highest_osr_comp_level() const; + void set_highest_osr_comp_level(int level); + // invocation counter InvocationCounter* invocation_counter() { return &_invocation_counter; } InvocationCounter* backedge_counter() { return &_backedge_counter; } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/oops/methodData.cpp --- a/hotspot/src/share/vm/oops/methodData.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/oops/methodData.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -1134,8 +1134,6 @@ _tenure_traps = 0; _num_loops = 0; _num_blocks = 0; - _highest_comp_level = 0; - _highest_osr_comp_level = 0; _would_profile = true; #if INCLUDE_RTM_OPT diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/oops/methodData.hpp --- a/hotspot/src/share/vm/oops/methodData.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/oops/methodData.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -2095,10 +2095,6 @@ // time with C1. It is used to determine if method is trivial. short _num_loops; short _num_blocks; - // Highest compile level this method has ever seen. - u1 _highest_comp_level; - // Same for OSR level - u1 _highest_osr_comp_level; // Does this method contain anything worth profiling? bool _would_profile; @@ -2277,11 +2273,6 @@ void set_would_profile(bool p) { _would_profile = p; } bool would_profile() const { return _would_profile; } - int highest_comp_level() const { return _highest_comp_level; } - void set_highest_comp_level(int level) { _highest_comp_level = level; } - int highest_osr_comp_level() const { return _highest_osr_comp_level; } - void set_highest_osr_comp_level(int level) { _highest_osr_comp_level = level; } - int num_loops() const { return _num_loops; } void set_num_loops(int n) { _num_loops = n; } int num_blocks() const { return _num_blocks; } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/opto/compile.cpp --- a/hotspot/src/share/vm/opto/compile.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/opto/compile.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -430,7 +430,7 @@ // removes the need to bang the stack in the deoptimization blob which // in turn simplifies stack overflow handling. int Compile::bang_size_in_bytes() const { - return MAX2(_interpreter_frame_size, frame_size_in_bytes()); + return MAX2(frame_size_in_bytes() + os::extra_bang_size_in_bytes(), _interpreter_frame_size); } // ============================================================================ diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -4968,7 +4968,8 @@ // Allocate the result array Node* zlen = _gvn.transform(new AddINode(xlen, ylen)); - Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_INT))); + ciKlass* klass = ciTypeArrayKlass::make(T_INT); + Node* klass_node = makecon(TypeKlassPtr::make(klass)); IdealKit ideal(this); @@ -5002,7 +5003,8 @@ sync_kit(ideal); z = __ value(z_alloc); - _gvn.set_type(z, TypeAryPtr::INTS); + // Can't use TypeAryPtr::INTS which uses Bottom offset. + _gvn.set_type(z, TypeOopPtr::make_from_klass(klass)); // Final sync IdealKit and GraphKit. final_sync(ideal); #undef __ diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/prims/jvmtiImpl.cpp --- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -282,39 +282,22 @@ void JvmtiBreakpoint::each_method_version_do(method_action meth_act) { ((Method*)_method->*meth_act)(_bci); - // add/remove breakpoint to/from versions of the method that - // are EMCP. Directly or transitively obsolete methods are - // not saved in the PreviousVersionNodes. + // add/remove breakpoint to/from versions of the method that are EMCP. Thread *thread = Thread::current(); instanceKlassHandle ikh = instanceKlassHandle(thread, _method->method_holder()); Symbol* m_name = _method->name(); Symbol* m_signature = _method->signature(); // search previous versions if they exist - PreviousVersionWalker pvw(thread, (InstanceKlass *)ikh()); - for (PreviousVersionNode * pv_node = pvw.next_previous_version(); - pv_node != NULL; pv_node = pvw.next_previous_version()) { - GrowableArray* methods = pv_node->prev_EMCP_methods(); - - if (methods == NULL) { - // We have run into a PreviousVersion generation where - // all methods were made obsolete during that generation's - // RedefineClasses() operation. At the time of that - // operation, all EMCP methods were flushed so we don't - // have to go back any further. - // - // A NULL methods array is different than an empty methods - // array. We cannot infer any optimizations about older - // generations from an empty methods array for the current - // generation. - break; - } + for (InstanceKlass* pv_node = ikh->previous_versions(); + pv_node != NULL; + pv_node = pv_node->previous_versions()) { + Array* methods = pv_node->methods(); for (int i = methods->length() - 1; i >= 0; i--) { Method* method = methods->at(i); - // obsolete methods that are running are not deleted from - // previous version array, but they are skipped here. - if (!method->is_obsolete() && + // Only set breakpoints in running EMCP methods. + if (method->is_running_emcp() && method->name() == m_name && method->signature() == m_signature) { RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)", diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -135,7 +135,7 @@ // Mark methods seen on stack and everywhere else so old methods are not // cleaned up if they're on the stack. - MetadataOnStackMark md_on_stack; + MetadataOnStackMark md_on_stack(true); HandleMark hm(thread); // make sure any handles created are deleted // before the stack walk again. @@ -2826,11 +2826,10 @@ } // the previous versions' constant pool caches may need adjustment - PreviousVersionWalker pvw(_thread, ik); - for (PreviousVersionNode * pv_node = pvw.next_previous_version(); - pv_node != NULL; pv_node = pvw.next_previous_version()) { - other_cp = pv_node->prev_constant_pool(); - cp_cache = other_cp->cache(); + for (InstanceKlass* pv_node = ik->previous_versions(); + pv_node != NULL; + pv_node = pv_node->previous_versions()) { + cp_cache = pv_node->constants()->cache(); if (cp_cache != NULL) { cp_cache->adjust_method_entries(_matching_old_methods, _matching_new_methods, @@ -2855,9 +2854,8 @@ } } -void VM_RedefineClasses::check_methods_and_mark_as_obsolete( - BitMap *emcp_methods, int * emcp_method_count_p) { - *emcp_method_count_p = 0; +int VM_RedefineClasses::check_methods_and_mark_as_obsolete() { + int emcp_method_count = 0; int obsolete_count = 0; int old_index = 0; for (int j = 0; j < _matching_methods_length; ++j, ++old_index) { @@ -2931,9 +2929,9 @@ // that we get from effectively overwriting the old methods // when the new methods are attached to the_class. - // track which methods are EMCP for add_previous_version() call - emcp_methods->set_bit(old_index); - (*emcp_method_count_p)++; + // Count number of methods that are EMCP. The method will be marked + // old but not obsolete if it is EMCP. + emcp_method_count++; // An EMCP method is _not_ obsolete. An obsolete method has a // different jmethodID than the current method. An EMCP method @@ -2982,10 +2980,11 @@ old_method->name()->as_C_string(), old_method->signature()->as_C_string())); } - assert((*emcp_method_count_p + obsolete_count) == _old_methods->length(), + assert((emcp_method_count + obsolete_count) == _old_methods->length(), "sanity check"); - RC_TRACE(0x00000100, ("EMCP_cnt=%d, obsolete_cnt=%d", *emcp_method_count_p, + RC_TRACE(0x00000100, ("EMCP_cnt=%d, obsolete_cnt=%d", emcp_method_count, obsolete_count)); + return emcp_method_count; } // This internal class transfers the native function registration from old methods @@ -3379,11 +3378,8 @@ old_constants->set_pool_holder(scratch_class()); #endif - // track which methods are EMCP for add_previous_version() call below - BitMap emcp_methods(_old_methods->length()); - int emcp_method_count = 0; - emcp_methods.clear(); // clears 0..(length() - 1) - check_methods_and_mark_as_obsolete(&emcp_methods, &emcp_method_count); + // track number of methods that are EMCP for add_previous_version() call below + int emcp_method_count = check_methods_and_mark_as_obsolete(); transfer_old_native_function_registrations(the_class); // The class file bytes from before any retransformable agents mucked @@ -3471,9 +3467,10 @@ scratch_class->enclosing_method_method_index()); scratch_class->set_enclosing_method_indices(old_class_idx, old_method_idx); + the_class->set_has_been_redefined(); + // keep track of previous versions of this class - the_class->add_previous_version(scratch_class, &emcp_methods, - emcp_method_count); + the_class->add_previous_version(scratch_class, emcp_method_count); RC_TIMER_STOP(_timer_rsc_phase1); RC_TIMER_START(_timer_rsc_phase2); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -403,14 +403,9 @@ // Change jmethodIDs to point to the new methods void update_jmethod_ids(); - // In addition to marking methods as obsolete, this routine - // records which methods are EMCP (Equivalent Module Constant - // Pool) in the emcp_methods BitMap and returns the number of - // EMCP methods via emcp_method_count_p. This information is - // used when information about the previous version of the_class - // is squirreled away. - void check_methods_and_mark_as_obsolete(BitMap *emcp_methods, - int * emcp_method_count_p); + // In addition to marking methods as old and/or obsolete, this routine + // counts the number of methods that are EMCP (Equivalent Module Constant Pool). + int check_methods_and_mark_as_obsolete(); void transfer_old_native_function_registrations(instanceKlassHandle the_class); // Install the redefinition of a class diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/runtime/arguments.hpp --- a/hotspot/src/share/vm/runtime/arguments.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/runtime/arguments.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -590,7 +590,9 @@ static void fix_appclasspath(); // Operation modi - static Mode mode() { return _mode; } + static Mode mode() { return _mode; } + static bool is_interpreter_only() { return mode() == _int; } + // Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid. static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -2473,7 +2473,7 @@ develop(bool, CIPrintCompilerName, false, \ "when CIPrint is active, print the name of the active compiler") \ \ - develop(bool, CIPrintCompileQueue, false, \ + diagnostic(bool, CIPrintCompileQueue, false, \ "display the contents of the compile queue whenever a " \ "compilation is enqueued") \ \ diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -53,6 +53,7 @@ #include "runtime/vm_version.hpp" #include "services/attachListener.hpp" #include "services/nmtCommon.hpp" +#include "services/mallocTracker.hpp" #include "services/memTracker.hpp" #include "services/threadService.hpp" #include "utilities/defaultStream.hpp" @@ -570,6 +571,17 @@ NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); +#if INCLUDE_NMT + // NMT can not track malloc allocation size > MAX_MALLOC_SIZE, which is + // (1GB - 1) on 32-bit system. It is not an issue on 64-bit system, where + // MAX_MALLOC_SIZE = ((1 << 62) - 1). + // VM code does not have such large malloc allocation. However, it can come + // Unsafe call. + if (MemTracker::tracking_level() >= NMT_summary && size > MAX_MALLOC_SIZE) { + return NULL; + } +#endif + #ifdef ASSERT // checking for the WatcherThread and crash_protection first // since os::malloc can be called when the libjvm.{dll,so} is @@ -640,6 +652,13 @@ } void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) { +#if INCLUDE_NMT + // See comments in os::malloc() above + if (MemTracker::tracking_level() >= NMT_summary && size > MAX_MALLOC_SIZE) { + return NULL; + } +#endif + #ifndef ASSERT NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/runtime/os.hpp --- a/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -557,6 +557,16 @@ // Unload library static void dll_unload(void *lib); + // Callback for loaded module information + // Input parameters: + // char* module_file_name, + // address module_base_addr, + // address module_top_addr, + // void* param + typedef int (*LoadedModulesCallbackFunc)(const char *, address, address, void *); + + static int get_loaded_modules_info(LoadedModulesCallbackFunc callback, void *param); + // Return the handle of this process static void* get_default_process_handle(); @@ -761,6 +771,9 @@ // Hook for os specific jvm options that we don't want to abort on seeing static bool obsolete_option(const JavaVMOption *option); + // Amount beyond the callee frame size that we bang the stack. + static int extra_bang_size_in_bytes(); + // Extensions #include "runtime/os_ext.hpp" diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/runtime/sweeper.cpp --- a/hotspot/src/share/vm/runtime/sweeper.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/runtime/sweeper.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -618,7 +618,7 @@ if (mc == NULL) { // Sometimes we can get here without MethodCounters. For example if we run with -Xcomp. // Try to allocate them. - mc = Method::build_method_counters(nm->method(), Thread::current()); + mc = nm->method()->get_method_counters(Thread::current()); } if (mc != NULL) { // Snapshot the value as it's changed concurrently diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/runtime/vm_operations.cpp --- a/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -470,3 +470,15 @@ ShouldNotReachHere(); } } + +void VM_PrintCompileQueue::doit() { + CompileBroker::print_compile_queues(_out); +} + +void VM_PrintCodeList::doit() { + CodeCache::print_codelist(_out); +} + +void VM_PrintCodeCache::doit() { + CodeCache::print_layout(_out); +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/runtime/vm_operations.hpp --- a/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -99,6 +99,9 @@ template(RotateGCLog) \ template(WhiteBoxOperation) \ template(ClassLoaderStatsOperation) \ + template(PrintCompileQueue) \ + template(PrintCodeList) \ + template(PrintCodeCache) \ class VM_Operation: public CHeapObj { public: @@ -413,4 +416,35 @@ void doit() { gclog_or_tty->rotate_log(true, _out); } }; +class VM_PrintCompileQueue: public VM_Operation { + private: + outputStream* _out; + + public: + VM_PrintCompileQueue(outputStream* st) : _out(st) {} + VMOp_Type type() const { return VMOp_PrintCompileQueue; } + void doit(); +}; + +class VM_PrintCodeList: public VM_Operation { + private: + outputStream* _out; + + public: + VM_PrintCodeList(outputStream* st) : _out(st) {} + VMOp_Type type() const { return VMOp_PrintCodeList; } + void doit(); +}; + +class VM_PrintCodeCache: public VM_Operation { + private: + outputStream* _out; + + public: + VM_PrintCodeCache(outputStream* st) : _out(st) {} + VMOp_Type type() const { return VMOp_PrintCodeCache; } + void doit(); +}; + + #endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/services/diagnosticCommand.cpp --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Jul 05 20:01:50 2017 +0200 @@ -60,6 +60,9 @@ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); // Enhanced JMX Agent Support // These commands won't be exported via the DiagnosticCommandMBean until an @@ -674,3 +677,18 @@ } } +void CompileQueueDCmd::execute(DCmdSource source, TRAPS) { + VM_PrintCompileQueue printCompileQueueOp(output()); + VMThread::execute(&printCompileQueueOp); +} + +void CodeListDCmd::execute(DCmdSource source, TRAPS) { + VM_PrintCodeList printCodeListOp(output()); + VMThread::execute(&printCodeListOp); +} + +void CodeCacheDCmd::execute(DCmdSource source, TRAPS) { + VM_PrintCodeCache printCodeCacheOp(output()); + VMThread::execute(&printCodeCacheOp); +} + diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/src/share/vm/services/diagnosticCommand.hpp --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Jul 05 20:01:50 2017 +0200 @@ -399,4 +399,68 @@ } }; +class CompileQueueDCmd : public DCmd { +public: + CompileQueueDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} + static const char* name() { + return "Compiler.queue"; + } + static const char* description() { + return "Print methods queued for compilation."; + } + static const char* impact() { + return "Low"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; + +class CodeListDCmd : public DCmd { +public: + CodeListDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} + static const char* name() { + return "Compiler.codelist"; + } + static const char* description() { + return "Print all compiled methods in code cache."; + } + static const char* impact() { + return "Medium"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; + + +class CodeCacheDCmd : public DCmd { +public: + CodeCacheDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} + static const char* name() { + return "Compiler.codecache"; + } + static const char* description() { + return "Print code cache layout and bounds."; + } + static const char* impact() { + return "Low"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; + #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/TEST.groups --- a/hotspot/test/TEST.groups Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/test/TEST.groups Wed Jul 05 20:01:50 2017 +0200 @@ -80,6 +80,7 @@ runtime/NMT/MallocSiteHashOverflow.java \ runtime/NMT/MallocStressTest.java \ runtime/NMT/MallocTestType.java \ + runtime/NMT/MallocTrackingVerify.java \ runtime/NMT/ReleaseCommittedMemory.java \ runtime/NMT/ReleaseNoCommit.java \ runtime/NMT/ShutdownTwice.java \ @@ -87,6 +88,7 @@ runtime/NMT/SummarySanityCheck.java \ runtime/NMT/ThreadedMallocTestType.java \ runtime/NMT/ThreadedVirtualAllocTestType.java \ + runtime/NMT/UnsafeMallocLimit.java \ runtime/NMT/VirtualAllocCommitUncommitRecommit.java \ runtime/NMT/VirtualAllocTestType.java \ runtime/RedefineObject/TestRedefineObject.java \ diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java --- a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java Wed Jul 05 20:01:50 2017 +0200 @@ -22,7 +22,7 @@ */ /* - * @ignore 8027915 + * @ignore 8049864 * @test TestParallelHeapSizeFlags * @key gc * @bug 8006088 diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java --- a/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java Wed Jul 05 20:01:50 2017 +0200 @@ -22,7 +22,6 @@ */ /* - * @ignore 8025645 * @test TestUseCompressedOopsErgo * @key gc * @bug 8010722 diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java --- a/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java Wed Jul 05 20:01:50 2017 +0200 @@ -22,7 +22,7 @@ */ /** - * @ignore 8042051 + * @ignore 8019361 * @test TestDynShrinkHeap * @bug 8016479 * @summary Verify that the heap shrinks after full GC according to the current values of the Min/MaxHeapFreeRatio flags diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/runtime/NMT/MallocTrackingVerify.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/NMT/MallocTrackingVerify.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8054836 + * @summary Test to verify correctness of malloc tracking + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build MallocTrackingVerify + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocTrackingVerify + * + */ + +import java.util.ArrayList; +import java.util.Random; + +import com.oracle.java.testlibrary.*; + +import sun.hotspot.WhiteBox; + +public class MallocTrackingVerify { + private static int MAX_ALLOC = 4 * 1024; + + static ArrayList mallocd_memory = new ArrayList(); + static long mallocd_total = 0; + public static WhiteBox wb = WhiteBox.getWhiteBox(); + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + Random random = new Random(); + // Allocate small amounts of memory with random pseudo call stack + while (mallocd_total < MAX_ALLOC) { + int size = random.nextInt(31) + 1; + long addr = wb.NMTMallocWithPseudoStack(size, random.nextInt()); + if (addr != 0) { + MallocMemory mem = new MallocMemory(addr, size); + mallocd_memory.add(mem); + mallocd_total += size; + } else { + System.out.println("Out of malloc memory"); + break; + } + } + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary" }); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=4KB, committed=4KB)"); + + // Free + for (MallocMemory mem : mallocd_memory) { + wb.NMTFree(mem.addr()); + } + + // Run 'jcmd VM.native_memory summary', check for expected output + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, + "VM.native_memory", "summary" }); + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + } + + static class MallocMemory { + private long addr; + private int size; + + MallocMemory(long addr, int size) { + this.addr = addr; + this.size = size; + } + + long addr() { + return this.addr; + } + + int size() { + return this.size; + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/runtime/NMT/UnsafeMallocLimit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/NMT/UnsafeMallocLimit.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8055289 + * @library /testlibrary + * @build UnsafeMallocLimit + * @run main/othervm -Xmx32m -XX:NativeMemoryTracking=summary UnsafeMallocLimit + */ + +import com.oracle.java.testlibrary.*; +import sun.misc.Unsafe; + +public class UnsafeMallocLimit { + + public static void main(String args[]) throws Exception { + if (Platform.is32bit()) { + Unsafe unsafe = Utils.getUnsafe(); + try { + unsafe.allocateMemory(1 << 30); + throw new RuntimeException("Did not get expected OOME"); + } catch (OutOfMemoryError e) { + // Expected exception + } + } else { + System.out.println("Test only valid on 32-bit platforms"); + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/runtime/RedefineFinalizer/RedefineFinalizer.java --- a/hotspot/test/runtime/RedefineFinalizer/RedefineFinalizer.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 6904403 - * @summary Don't assert if we redefine finalize method - * @library /testlibrary - * @build RedefineClassHelper - * @run main RedefineClassHelper - * @run main/othervm -javaagent:redefineagent.jar RedefineFinalizer - */ - -/* - * Regression test for hitting: - * - * assert(f == k->has_finalizer()) failed: inconsistent has_finalizer - * - * when redefining finalizer method - */ -public class RedefineFinalizer { - - public static String newB = - "class RedefineFinalizer$B {" + - " protected void finalize() { " + - " System.out.println(\"Finalizer called\");" + - " }" + - "}"; - - public static void main(String[] args) throws Exception { - RedefineClassHelper.redefineClass(B.class, newB); - - A a = new A(); - } - - static class A extends B { - } - - static class B { - protected void finalize() { - // should be empty - } - } -} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/runtime/RedefineTests/RedefineFinalizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineTests/RedefineFinalizer.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6904403 + * @summary Don't assert if we redefine finalize method + * @library /testlibrary + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar RedefineFinalizer + */ + +/* + * Regression test for hitting: + * + * assert(f == k->has_finalizer()) failed: inconsistent has_finalizer + * + * when redefining finalizer method + */ +public class RedefineFinalizer { + + public static String newB = + "class RedefineFinalizer$B {" + + " protected void finalize() { " + + " System.out.println(\"Finalizer called\");" + + " }" + + "}"; + + public static void main(String[] args) throws Exception { + RedefineClassHelper.redefineClass(B.class, newB); + + A a = new A(); + } + + static class A extends B { + } + + static class B { + protected void finalize() { + // should be empty + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/runtime/RedefineTests/RedefineRunningMethods.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineTests/RedefineRunningMethods.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8055008 + * @summary Redefine EMCP and non-EMCP methods that are running in an infinite loop + * @library /testlibrary + * @build RedefineClassHelper + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar -XX:TraceRedefineClasses=0x600 RedefineRunningMethods + */ +public class RedefineRunningMethods { + + public static String newB = + "class RedefineRunningMethods$B {" + + " static int count1 = 0;" + + " static int count2 = 0;" + + " public static volatile boolean stop = false;" + + " static void localSleep() { " + + " try{ " + + " Thread.currentThread().sleep(10);" + + " } catch(InterruptedException ie) { " + + " } " + + " } " + + " public static void infinite() { " + + " System.out.println(\"infinite called\");" + + " }" + + " public static void infinite_emcp() { " + + " while (!stop) { count2++; localSleep(); }" + + " }" + + "}"; + + public static String evenNewerB = + "class RedefineRunningMethods$B {" + + " static int count1 = 0;" + + " static int count2 = 0;" + + " public static volatile boolean stop = false;" + + " static void localSleep() { " + + " try{ " + + " Thread.currentThread().sleep(1);" + + " } catch(InterruptedException ie) { " + + " } " + + " } " + + " public static void infinite() { }" + + " public static void infinite_emcp() { " + + " System.out.println(\"infinite_emcp now obsolete called\");" + + " }" + + "}"; + + static class B { + static int count1 = 0; + static int count2 = 0; + public static volatile boolean stop = false; + static void localSleep() { + try{ + Thread.currentThread().sleep(10);//sleep for 10 ms + } catch(InterruptedException ie) { + } + } + + public static void infinite() { + while (!stop) { count1++; localSleep(); } + } + public static void infinite_emcp() { + while (!stop) { count2++; localSleep(); } + } + } + + + public static void main(String[] args) throws Exception { + + new Thread() { + public void run() { + B.infinite(); + } + }.start(); + + new Thread() { + public void run() { + B.infinite_emcp(); + } + }.start(); + + RedefineClassHelper.redefineClass(B.class, newB); + + System.gc(); + + B.infinite(); + + // Start a thread with the second version of infinite_emcp running + new Thread() { + public void run() { + B.infinite_emcp(); + } + }.start(); + + for (int i = 0; i < 20 ; i++) { + String s = new String("some garbage"); + System.gc(); + } + + RedefineClassHelper.redefineClass(B.class, evenNewerB); + System.gc(); + + for (int i = 0; i < 20 ; i++) { + B.infinite(); + String s = new String("some garbage"); + System.gc(); + } + + B.infinite_emcp(); + + // purge should clean everything up. + B.stop = true; + + for (int i = 0; i < 20 ; i++) { + B.infinite(); + String s = new String("some garbage"); + System.gc(); + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/runtime/SharedArchiveFile/ArchiveDoesNotExist.java --- a/hotspot/test/runtime/SharedArchiveFile/ArchiveDoesNotExist.java Wed Jul 05 20:01:05 2017 +0200 +++ b/hotspot/test/runtime/SharedArchiveFile/ArchiveDoesNotExist.java Wed Jul 05 20:01:50 2017 +0200 @@ -61,7 +61,7 @@ "-version"); output = new OutputAnalyzer(pb.start()); - output.shouldContain("java version"); + output.shouldMatch("(java|openjdk) version"); output.shouldNotContain("sharing"); output.shouldHaveExitValue(0); } diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/serviceability/dcmd/CodeCacheTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/CodeCacheTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test CodeCacheTest + * @bug 8054889 + * @build DcmdUtil CodeCacheTest + * @run main CodeCacheTest + * @summary Test of diagnostic command Compiler.codecache + */ + +import java.io.BufferedReader; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CodeCacheTest { + + /** + * This test calls Jcmd (diagnostic command tool) Compiler.codecache and then parses the output, + * making sure that all number look ok + * + * + * Expected output: + * + * CodeCache: size=245760Kb used=4680Kb max_used=4680Kb free=241079Kb + * bounds [0x00007f5bd9000000, 0x00007f5bd94a0000, 0x00007f5be8000000] + * total_blobs=575 nmethods=69 adapters=423 + * compilation: enabled + */ + + static Pattern line1 = Pattern.compile("CodeCache: size=(\\p{Digit}*)Kb used=(\\p{Digit}*)Kb max_used=(\\p{Digit}*)Kb free=(\\p{Digit}*)Kb"); + static Pattern line2 = Pattern.compile(" bounds \\[0x(\\p{XDigit}*), 0x(\\p{XDigit}*), 0x(\\p{XDigit}*)\\]"); + static Pattern line3 = Pattern.compile(" total_blobs=(\\p{Digit}*) nmethods=(\\p{Digit}*) adapters=(\\p{Digit}*)"); + static Pattern line4 = Pattern.compile(" compilation: (\\w*)"); + + public static void main(String arg[]) throws Exception { + + // Get output from dcmd (diagnostic command) + String result = DcmdUtil.executeDcmd("Compiler.codecache"); + BufferedReader r = new BufferedReader(new StringReader(result)); + + // Validate first line + String line; + line = r.readLine(); + Matcher m = line1.matcher(line); + if (m.matches()) { + for(int i = 1; i <= 4; i++) { + int val = Integer.parseInt(m.group(i)); + if (val < 0) { + throw new Exception("Failed parsing dcmd codecache output"); + } + } + } else { + throw new Exception("Regexp 1 failed"); + } + + // Validate second line + line = r.readLine(); + m = line2.matcher(line); + if (m.matches()) { + long start = Long.parseLong(m.group(1), 16); + if (start < 0) { + throw new Exception("Failed parsing dcmd codecache output"); + } + long mark = Long.parseLong(m.group(2), 16); + if (mark < 0) { + throw new Exception("Failed parsing dcmd codecache output"); + } + long top = Long.parseLong(m.group(3), 16); + if (top < 0) { + throw new Exception("Failed parsing dcmd codecache output"); + } + if (start > mark) { + throw new Exception("Failed parsing dcmd codecache output"); + } + if (mark > top) { + throw new Exception("Failed parsing dcmd codecache output"); + } + } else { + throw new Exception("Regexp 2 failed line: " + line); + } + + // Validate third line + line = r.readLine(); + m = line3.matcher(line); + if (m.matches()) { + int blobs = Integer.parseInt(m.group(1)); + if (blobs <= 0) { + throw new Exception("Failed parsing dcmd codecache output"); + } + int nmethods = Integer.parseInt(m.group(2)); + if (nmethods <= 0) { + throw new Exception("Failed parsing dcmd codecache output"); + } + int adapters = Integer.parseInt(m.group(3)); + if (adapters <= 0) { + throw new Exception("Failed parsing dcmd codecache output"); + } + if (blobs < (nmethods + adapters)) { + throw new Exception("Failed parsing dcmd codecache output"); + } + } else { + throw new Exception("Regexp 3 failed"); + } + + // Validate fourth line + line = r.readLine(); + m = line4.matcher(line); + if (m.matches()) { + if (!m.group(1).equals("enabled")) { + throw new Exception("Invalid message: '" + m.group(1) + "'"); + } + } else { + throw new Exception("Regexp 4 failed"); + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/serviceability/dcmd/CodelistTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/CodelistTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test CodelistTest + * @bug 8054889 + * @build DcmdUtil MethodIdentifierParser CodelistTest + * @run main CodelistTest + * @summary Test of diagnostic command Compiler.codelist + */ + +import java.io.BufferedReader; +import java.io.StringReader; +import java.lang.reflect.Method; + +public class CodelistTest { + + /** + * This test calls Jcmd (diagnostic command tool) Compiler.codelist and then parses the output, + * making sure that the first methods in the list is valid by reflection. + * + * Output example: + * + * 6 0 java.lang.System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V [0x00007f7b49200910, 0x00007f7b49200aa0 - 0x00007f7b49200d30] + * 2 3 java.lang.String.indexOf(II)I [0x00007f7b49200d90, 0x00007f7b49200f60 - 0x00007f7b49201490] + * 7 3 java.lang.Math.min(II)I [0x00007f7b4922f010, 0x00007f7b4922f180 - 0x00007f7b4922f338] + * 8 3 java.lang.String.equals(Ljava/lang/Object;)Z [0x00007f7b4922fb10, 0x00007f7b4922fd40 - 0x00007f7b49230698] + * 9 3 java.lang.AbstractStringBuilder.ensureCapacityInternal(I)V [0x00007f7b49232010, 0x00007f7b492321a0 - 0x00007f7b49232510] + * 10 1 java.lang.Object.()V [0x00007f7b49233e90, 0x00007f7b49233fe0 - 0x00007f7b49234118] + * + */ + + public static void main(String arg[]) throws Exception { + int ok = 0; + int fail = 0; + + // Get output from dcmd (diagnostic command) + String result = DcmdUtil.executeDcmd("Compiler.codelist"); + BufferedReader r = new BufferedReader(new StringReader(result)); + + // Grab a method name from the output + String line; + int count = 0; + + while((line = r.readLine()) != null) { + count++; + + String[] parts = line.split(" "); + // int compileID = Integer.parseInt(parts[0]); + // int compileLevel = Integer.parseInt(parts[1]); + String methodPrintedInLogFormat = parts[2]; + + // skip inits and clinits - they can not be reflected + if (methodPrintedInLogFormat.contains("")) { + continue; + } + if (methodPrintedInLogFormat.contains("")) { + continue; + } + + MethodIdentifierParser mf = new MethodIdentifierParser(methodPrintedInLogFormat); + Method m; + try { + m = mf.getMethod(); + } catch (NoSuchMethodException e) { + m = null; + } + if (m == null) { + throw new Exception("Test failed"); + } + if (count > 10) { + // Testing 10 entries is enough. Lets not waste time. + break; + } + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/serviceability/dcmd/CompilerQueueTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/CompilerQueueTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test CompilerQueueTest + * @bug 8054889 + * @build DcmdUtil CompilerQueueTest + * @run main CompilerQueueTest + * @summary Test of diagnostic command Compiler.queue + */ + +import java.io.BufferedReader; +import java.io.StringReader; + +public class CompilerQueueTest { + + /** + * This test calls Jcmd (diagnostic command tool) Compiler.queue and + * then parses the output, making sure that the output look ok. + * + * + * Output example: + * + * Contents of C1 compile queue + * ---------------------------- + * 73 3 java.lang.AbstractStringBuilder::append (50 bytes) + * 74 1 java.util.TreeMap::size (5 bytes) + * 75 3 java.lang.StringBuilder::append (8 bytes) + * 83 3 java.util.TreeMap$ValueIterator::next (8 bytes) + * 84 1 javax.management.MBeanFeatureInfo::getName (5 bytes) + * ---------------------------- + * Contents of C2 compile queue + * ---------------------------- + * Empty + * ---------------------------- + * + **/ + + public static void main(String arg[]) throws Exception { + + // Get output from dcmd (diagnostic command) + String result = DcmdUtil.executeDcmd("Compiler.queue"); + BufferedReader r = new BufferedReader(new StringReader(result)); + + String line; + match(r.readLine(), "Contents of C1 compile queue"); + match(r.readLine(), "----------------------------"); + String str = r.readLine(); + if (!str.equals("Empty")) { + while (str.charAt(0) != '-') { + validateMethodLine(str); + str = r.readLine(); + } + } else { + str = r.readLine(); + } + + match(str, "----------------------------"); + match(r.readLine(), "Contents of C2 compile queue"); + match(r.readLine(), "----------------------------"); + str = r.readLine(); + if (!str.equals("Empty")) { + while (str.charAt(0) != '-') { + validateMethodLine(str); + str = r.readLine(); + } + } else { + str = r.readLine(); + } + match(str, "----------------------------"); + } + + private static void validateMethodLine(String str) throws Exception { + String name = str.substring(19); + int sep = name.indexOf("::"); + try { + Class.forName(name.substring(0, sep)); + } catch (ClassNotFoundException e) { + throw new Exception("Failed parsing dcmd queue"); + } + } + + public static void match(String line, String str) throws Exception { + if (!line.equals(str)) { + throw new Exception("String equals: " + line + ", " + str); + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc hotspot/test/serviceability/dcmd/MethodIdentifierParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/MethodIdentifierParser.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Method; +import java.util.ArrayList; + +public class MethodIdentifierParser { + + private String logString; + private String className; + private String methodName; + private String methodDescriptor; + + /** + * This is a utility class for parsing the log entries for a method. It supplies + * a few select methods for reflecting the class and method from that information. + * + * Example log entries: + * "java.util.TreeMap.successor(Ljava/util/TreeMap$Entry;)Ljava/util/TreeMap$Entry;" + */ + + public MethodIdentifierParser(String logString) { + this.logString = logString; + + int i = logString.lastIndexOf("."); // find start of method name + className = logString.substring(0, i); // classname is everything before + int i2 = logString.indexOf("("); // Signature starts with an '(' + methodName = logString.substring(i+1, i2); + methodDescriptor = logString.substring(i2, logString.length()); + + // Add sanity check for extracted fields + } + + public Method getMethod() throws NoSuchMethodException, SecurityException, ClassNotFoundException, Exception { + try { + return Class.forName(className).getDeclaredMethod(methodName, getParamenterDescriptorArray()); + } catch (UnexpectedTokenException e) { + throw new Exception("Parse failed"); + } + } + + public Class[] getParamenterDescriptorArray() throws ClassNotFoundException, UnexpectedTokenException { + ParameterDecriptorIterator s = new ParameterDecriptorIterator(methodDescriptor); + Class paramType; + ArrayList> list = new ArrayList>(); + while ((paramType = s.nextParamType()) != null) { + list.add(paramType); + } + if (list.size() > 0) { + return list.toArray(new Class[list.size()]); + } else { + return null; + } + } + + class ParameterDecriptorIterator { + + // This class uses charAt() indexing for startMark and i + // That is when i points to the last char it can be retrieved with + // charAt(i). Including the last char for a subString requires + // substring(startMark, i+1); + + private String methodDescriptor; + private int startMark; + + public ParameterDecriptorIterator(String signature) { + this.methodDescriptor = signature; + this.startMark = 0; + if (signature.charAt(0) == '(') { + this.startMark = 1; + } + } + + public Class nextParamType() throws UnexpectedTokenException { + int i = startMark; + while (methodDescriptor.length() > i) { + switch (methodDescriptor.charAt(i)) { + case 'C': + case 'B': + case 'I': + case 'J': + case 'Z': + case 'F': + case 'D': + case 'S': + // Primitive class case, but we may have gotten here with [ as first token + break; + case 'L': + // Internal class name suffixed by ';' + while (methodDescriptor.charAt(i) != ';') { + i++; + } + break; + case '[': + i++; // arrays -> do another pass + continue; + case ')': + return null; // end found + case 'V': + case ';': + default: + throw new UnexpectedTokenException(methodDescriptor, i); + } + break; + } + if (i == startMark) { + // Single char -> primitive class case + startMark++; // Update for next iteration + switch (methodDescriptor.charAt(i)) { + case 'C': + return char.class; + case 'B': + return byte.class; + case 'I': + return int.class; + case 'J': + return long.class; + case 'F': + return float.class; + case 'D': + return double.class; + case 'S': + return short.class; + case 'Z': + return boolean.class; + default: + throw new UnexpectedTokenException(methodDescriptor, i); + } + } else { + // Multi char case + String nextParam; + if (methodDescriptor.charAt(startMark) == 'L') { + // When reflecting a class the leading 'L' and trailing';' must be removed. + // (When reflecting an array of classes, they must remain...) + nextParam = methodDescriptor.substring(startMark+1, i); + } else { + // Any kind of array - simple case, use whole descriptor when reflecting. + nextParam = methodDescriptor.substring(startMark, i+1); + } + startMark = ++i; // Update for next iteration + try { + // The parameter descriptor uses JVM internal class identifier with '/' as + // package separator, but Class.forName expects '.'. + nextParam = nextParam.replace('/', '.'); + return Class.forName(nextParam); + } catch (ClassNotFoundException e) { + System.out.println("Class not Found: " + nextParam); + return null; + } + } + } + } + + class UnexpectedTokenException extends Exception { + String descriptor; + int i; + public UnexpectedTokenException(String descriptor, int i) { + this.descriptor = descriptor; + this.i = i; + } + + @Override + public String toString() { + return "Unexpected token at: " + i + " in signature: " + descriptor; + } + + private static final long serialVersionUID = 1L; + } + + public void debugPrint() { + System.out.println("mlf in: " + logString); + System.out.println("mlf class: " + className); + System.out.println("mlf method: " + methodName); + System.out.println("mlf methodDescriptor: " + methodDescriptor); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jaxp/.hgtags --- a/jaxp/.hgtags Wed Jul 05 20:01:05 2017 +0200 +++ b/jaxp/.hgtags Wed Jul 05 20:01:50 2017 +0200 @@ -273,3 +273,4 @@ dc1e26434b3fd7e9b8eeab149103c1e30965f95c jdk9-b28 30adcd13a313ea91e81164801a2f89282756d933 jdk9-b29 d181d4002214e4914d5525bd5ee13369311c765c jdk9-b30 +292317ebc7dbaca6b3965f0bc7b38a2cee733b7a jdk9-b31 diff -r 89a653341cf2 -r 1b1ec4291abc jaxws/.hgtags --- a/jaxws/.hgtags Wed Jul 05 20:01:05 2017 +0200 +++ b/jaxws/.hgtags Wed Jul 05 20:01:50 2017 +0200 @@ -276,3 +276,4 @@ 5282a14f131f897cc9575872c0fae72d47dc4e65 jdk9-b28 3d1a4bfb6abbf5011ba6d8896301ee3b6ef3ba72 jdk9-b29 e58d3ea638c3824f01547596b2a98aa5f77c4a5c jdk9-b30 +7af228ae847f3c02aaafb7b01cdbb3bdc2e89e77 jdk9-b31 diff -r 89a653341cf2 -r 1b1ec4291abc jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ApClassLoader.java --- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ApClassLoader.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -/* - * Copyright (c) 1997, 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. - */ - -package com.sun.tools.internal.xjc.api.util; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.File; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.MalformedURLException; - -import com.sun.istack.internal.Nullable; - -/** - * {@link ClassLoader} that loads Annotation Processing and specified classes - * both into the same classloader, so that they can reference each other. - * - * @author Bhakti Mehta - * @since 2.0 beta - */ -public final class ApClassLoader extends URLClassLoader { - /** - * List of package prefixes we want to mask the - * parent classLoader from loading - */ - private final String[] packagePrefixes; - - /** - * - * @param packagePrefixes - * The package prefixes that are forced to resolve within this class loader. - * @param parent - * The parent class loader to delegate to. Null to indicate bootstrap classloader. - */ - public ApClassLoader(@Nullable ClassLoader parent, String[] packagePrefixes) throws ToolsJarNotFoundException { - super(getToolsJar(parent),parent); - if(getURLs().length==0) - // if tools.jar was found in our classloader, no need to create - // a parallel classes - this.packagePrefixes = new String[0]; - else - this.packagePrefixes = packagePrefixes; - } - - public Class loadClass(String className) throws ClassNotFoundException { - for( String prefix : packagePrefixes ) { - if (className.startsWith(prefix) ) { - // we need to load those classes in this class loader - // without delegation. - return findClass(className); - } - } - - return super.loadClass(className); - - } - - protected Class findClass(String name) throws ClassNotFoundException { - - StringBuilder sb = new StringBuilder(name.length() + 6); - sb.append(name.replace('.','/')).append(".class"); - - InputStream is = getResourceAsStream(sb.toString()); - if (is==null) - throw new ClassNotFoundException("Class not found" + sb); - - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buf = new byte[1024]; - int len; - while((len=is.read(buf))>=0) - baos.write(buf,0,len); - - buf = baos.toByteArray(); - - // define package if not defined yet - int i = name.lastIndexOf('.'); - if (i != -1) { - String pkgname = name.substring(0, i); - Package pkg = getPackage(pkgname); - if(pkg==null) - definePackage(pkgname, null, null, null, null, null, null, null); - } - - return defineClass(name,buf,0,buf.length); - } catch (IOException e) { - throw new ClassNotFoundException(name,e); - } finally { - try { - is.close(); - } catch (IOException ioe) { - //ignore - } - } - } - - /** - * Returns a class loader that can load classes from JDK tools.jar. - * @param parent - */ - private static URL[] getToolsJar(@Nullable ClassLoader parent) throws ToolsJarNotFoundException { - - try { - Class.forName("com.sun.tools.javac.Main", false, parent); - return new URL[0]; - // we can already load them in the parent class loader. - // so no need to look for tools.jar. - // this happens when we are run inside IDE/Ant, or - // in Mac OS. - } catch (ClassNotFoundException e) { - // otherwise try to find tools.jar - } - - File jreHome = new File(System.getProperty("java.home")); - File toolsJar = new File( jreHome.getParent(), "lib/tools.jar" ); - - if (!toolsJar.exists()) { - throw new ToolsJarNotFoundException(toolsJar); - } - - try { - return new URL[]{toolsJar.toURL()}; - } catch (MalformedURLException e) { - // impossible - throw new AssertionError(e); - } - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ToolsJarNotFoundException.java --- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/api/util/ToolsJarNotFoundException.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 1997, 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. - */ - -package com.sun.tools.internal.xjc.api.util; - -import java.io.File; - -/** - * Signals an error when tools.jar was not found. - * - * Simply print out the message obtained by {@link #getMessage()}. - * - * @author Kohsuke Kawaguchi - */ -public final class ToolsJarNotFoundException extends Exception { - /** - * Location where we expected to find tools.jar - */ - public final File toolsJar; - - public ToolsJarNotFoundException(File toolsJar) { - super(calcMessage(toolsJar)); - this.toolsJar = toolsJar; - } - - private static String calcMessage(File toolsJar) { - return Messages.TOOLS_JAR_NOT_FOUND.format(toolsJar.getPath()); - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/Invoker.java --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/Invoker.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/Invoker.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -29,19 +29,16 @@ import com.sun.istack.internal.tools.ParallelWorldClassLoader; import com.sun.tools.internal.ws.resources.WscompileMessages; import com.sun.tools.internal.ws.wscompile.Options; -import com.sun.tools.internal.xjc.api.util.ToolsJarNotFoundException; import com.sun.xml.internal.bind.util.Which; import javax.xml.ws.Service; import javax.xml.ws.WebServiceFeature; import javax.xml.namespace.QName; -import java.io.File; import java.io.OutputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -59,7 +56,7 @@ /** * The list of package prefixes we want the * {@link MaskingClassLoader} to prevent the parent - * classLoader from loading + * class loader from loading */ static final String[] maskedPackages = new String[]{ "com.sun.istack.internal.tools.", @@ -130,24 +127,6 @@ return -1; } - //find and load tools.jar - List urls = new ArrayList(); - findToolsJar(cl, urls); - - if(urls.size() > 0){ - List mask = new ArrayList(Arrays.asList(maskedPackages)); - - // first create a protected area so that we load JAXB/WS 2.1 API - // and everything that depends on them inside - cl = new MaskingClassLoader(cl,mask); - - // then this classloader loads the API and tools.jar - cl = new URLClassLoader(urls.toArray(new URL[urls.size()]), cl); - - // finally load the rest of the RI. The actual class files are loaded from ancestors - cl = new ParallelWorldClassLoader(cl,""); - } - } Thread.currentThread().setContextClassLoader(cl); @@ -158,8 +137,6 @@ Method runMethod = compileTool.getMethod("run",String[].class); boolean r = (Boolean)runMethod.invoke(tool,new Object[]{args}); return r ? 0 : 1; - } catch (ToolsJarNotFoundException e) { - System.err.println(e.getMessage()); } catch (InvocationTargetException e) { throw e.getCause(); } catch(ClassNotFoundException e){ @@ -167,8 +144,6 @@ }finally { Thread.currentThread().setContextClassLoader(oldcc); } - - return -1; } /** @@ -203,10 +178,10 @@ /** - * Creates a classloader that can load JAXB/WS 2.2 API and tools.jar, - * and then return a classloader that can RI classes, which can see all those APIs and tools.jar. + * Creates a class loader that can load JAXB/WS 2.2 API, + * and then return a class loader that can RI classes, which can see all those APIs. */ - public static ClassLoader createClassLoader(ClassLoader cl) throws ClassNotFoundException, IOException, ToolsJarNotFoundException { + public static ClassLoader createClassLoader(ClassLoader cl) throws ClassNotFoundException, IOException { URL[] urls = findIstack22APIs(cl); if(urls.length==0) @@ -223,7 +198,7 @@ // and everything that depends on them inside cl = new MaskingClassLoader(cl,mask); - // then this classloader loads the API and tools.jar + // then this class loader loads the API cl = new URLClassLoader(urls, cl); // finally load the rest of the RI. The actual class files are loaded from ancestors @@ -233,13 +208,13 @@ } /** - * Creates a classloader for loading JAXB/WS 2.2 jar and tools.jar + * Creates a class loader for loading JAXB/WS 2.2 jar */ - private static URL[] findIstack22APIs(ClassLoader cl) throws ClassNotFoundException, IOException, ToolsJarNotFoundException { + private static URL[] findIstack22APIs(ClassLoader cl) throws ClassNotFoundException, IOException { List urls = new ArrayList(); if(Service.class.getClassLoader()==null) { - // JAX-WS API is loaded from bootstrap classloader + // JAX-WS API is loaded from bootstrap class loader URL res = cl.getResource("javax/xml/ws/EndpointContext.class"); if(res==null) throw new ClassNotFoundException("There's no JAX-WS 2.2 API in the classpath"); @@ -250,28 +225,7 @@ urls.add(ParallelWorldClassLoader.toJarUrl(res)); } - findToolsJar(cl, urls); - return urls.toArray(new URL[urls.size()]); } - private static void findToolsJar(ClassLoader cl, List urls) throws ToolsJarNotFoundException, MalformedURLException { - try { - Class.forName("com.sun.tools.javac.Main",false,cl); - // we can already load them in the parent class loader. - // so no need to look for tools.jar. - // this happens when we are run inside IDE/Ant, or - // in Mac OS. - } catch (ClassNotFoundException e) { - // otherwise try to find tools.jar - File jreHome = new File(System.getProperty("java.home")); - File toolsJar = new File( jreHome.getParent(), "lib/tools.jar" ); - - if (!toolsJar.exists()) { - throw new ToolsJarNotFoundException(toolsJar); - } - urls.add(toolsJar.toURL()); - } - } - } diff -r 89a653341cf2 -r 1b1ec4291abc jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsGen.java --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsGen.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsGen.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -35,8 +35,7 @@ */ public class WsGen { /** - * CLI entry point. Use {@link Invoker} to - * load tools.jar + * CLI entry point. Use {@link Invoker} to load proper API version */ public static void main(String[] args) throws Throwable { System.exit(Invoker.invoke("com.sun.tools.internal.ws.wscompile.WsgenTool", args)); @@ -50,7 +49,7 @@ * it doesn't invoke {@link System#exit(int)}. This method * also doesn't play with classloaders. It's the caller's * responsibility to set up the classloader to load all jars - * needed to run the tool, including $JAVA_HOME/lib/tools.jar + * needed to run the tool. * * @return * 0 if the tool runs successfully. diff -r 89a653341cf2 -r 1b1ec4291abc jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsImport.java --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsImport.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/WsImport.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -35,8 +35,7 @@ */ public class WsImport { /** - * CLI entry point. Use {@link Invoker} to - * load tools.jar + * CLI entry point. Use {@link Invoker} to load proper API version */ public static void main(String[] args) throws Throwable { System.exit(Invoker.invoke("com.sun.tools.internal.ws.wscompile.WsimportTool", args)); @@ -50,7 +49,7 @@ * it doesn't invoke {@link System#exit(int)}. This method * also doesn't play with classloaders. It's the caller's * responsibility to set up the classloader to load all jars - * needed to run the tool, including $JAVA_HOME/lib/tools.jar + * needed to run the tool. * * @return * 0 if the tool runs successfully. diff -r 89a653341cf2 -r 1b1ec4291abc jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/JavacompilerMessages.java --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/JavacompilerMessages.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/JavacompilerMessages.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -39,40 +39,16 @@ private final static LocalizableMessageFactory messageFactory = new LocalizableMessageFactory("com.sun.tools.internal.ws.resources.javacompiler"); private final static Localizer localizer = new Localizer(); - public static Localizable localizableJAVACOMPILER_CLASSPATH_ERROR(Object arg0) { - return messageFactory.getMessage("javacompiler.classpath.error", arg0); - } - - /** - * {0} is not available in the classpath, requires Sun's JDK version 5.0 or latter. - * - */ - public static String JAVACOMPILER_CLASSPATH_ERROR(Object arg0) { - return localizer.localize(localizableJAVACOMPILER_CLASSPATH_ERROR(arg0)); - } - - public static Localizable localizableJAVACOMPILER_NOSUCHMETHOD_ERROR(Object arg0) { - return messageFactory.getMessage("javacompiler.nosuchmethod.error", arg0); + public static Localizable localizableNO_JAVACOMPILER_ERROR() { + return messageFactory.getMessage("no.javacompiler.error"); } /** - * There is no such method {0} available, requires Sun's JDK version 5.0 or latter. + * No system compiler found, check your jdk. * */ - public static String JAVACOMPILER_NOSUCHMETHOD_ERROR(Object arg0) { - return localizer.localize(localizableJAVACOMPILER_NOSUCHMETHOD_ERROR(arg0)); - } - - public static Localizable localizableJAVACOMPILER_ERROR(Object arg0) { - return messageFactory.getMessage("javacompiler.error", arg0); - } - - /** - * error : {0}. - * - */ - public static String JAVACOMPILER_ERROR(Object arg0) { - return localizer.localize(localizableJAVACOMPILER_ERROR(arg0)); + public static String NO_JAVACOMPILER_ERROR() { + return localizer.localize(localizableNO_JAVACOMPILER_ERROR()); } } diff -r 89a653341cf2 -r 1b1ec4291abc jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/javacompiler.properties --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/javacompiler.properties Wed Jul 05 20:01:05 2017 +0200 +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/resources/javacompiler.properties Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 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 @@ -26,6 +26,4 @@ # # Generic Messages # -javacompiler.classpath.error={0} is not available in the classpath, requires Sun's JDK version 5.0 or latter. -javacompiler.nosuchmethod.error=There is no such method {0} available, requires Sun's JDK version 5.0 or latter. -javacompiler.error=error : {0}. +no.javacompiler.error=No system compiler found, check your jdk. diff -r 89a653341cf2 -r 1b1ec4291abc jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/wscompile/JavaCompilerHelper.java --- a/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/wscompile/JavaCompilerHelper.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jaxws/src/jdk.xml.ws/share/classes/com/sun/tools/internal/ws/wscompile/JavaCompilerHelper.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -28,14 +28,13 @@ import com.sun.istack.internal.tools.ParallelWorldClassLoader; import com.sun.tools.internal.ws.resources.JavacompilerMessages; +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; import java.io.File; import java.io.OutputStream; -import java.io.PrintWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; -import java.net.URISyntaxException; /** * A helper class to invoke javac. @@ -61,34 +60,17 @@ } static boolean compile(String[] args, OutputStream out, ErrorReceiver receiver){ - ClassLoader cl = Thread.currentThread().getContextClassLoader(); try { - /* try to use the new compiler */ - Class comSunToolsJavacMainClass = - cl.loadClass("com.sun.tools.javac.Main"); - try { - Method compileMethod = - comSunToolsJavacMainClass.getMethod( - "compile", - compileMethodSignature); - Object result = - compileMethod.invoke( - null, args, new PrintWriter(out)); - return result instanceof Integer && (Integer) result == 0; - } catch (NoSuchMethodException e2) { - receiver.error(JavacompilerMessages.JAVACOMPILER_NOSUCHMETHOD_ERROR("getMethod(\"compile\", Class[])"), e2); - } catch (IllegalAccessException e) { - receiver.error(e); - } catch (InvocationTargetException e) { - receiver.error(e); + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + if (comp == null) { + receiver.error(JavacompilerMessages.NO_JAVACOMPILER_ERROR(), null); + return false; } - } catch (ClassNotFoundException e) { - receiver.error(JavacompilerMessages.JAVACOMPILER_CLASSPATH_ERROR("com.sun.tools.javac.Main"), e); + return 0 == comp.run(null, out, out, args); } catch (SecurityException e) { receiver.error(e); } return false; } - private static final Class[] compileMethodSignature = {String[].class, PrintWriter.class}; } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/.hgtags --- a/jdk/.hgtags Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/.hgtags Wed Jul 05 20:01:50 2017 +0200 @@ -273,3 +273,4 @@ 1828f73b35cfe35e460e41fd6e087ab1f83e0621 jdk9-b28 2da27e8e2c865e154f0c2eb9009f011a44649b11 jdk9-b29 8d24fb4493f13d380a2adf62d444e1e5a4451f37 jdk9-b30 +71e99dae28f9791287b88d46e16a266b564f22be jdk9-b31 diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/CreateJars.gmk --- a/jdk/make/CreateJars.gmk Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/make/CreateJars.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -220,7 +220,6 @@ sun/tools/serialver \ sun/tools/tree \ sun/tools/util \ - sun/util/cldr/CLDRLocaleDataMetaInfo.class \ sun/util/resources/provider/NonEnLocaleDataMetaInfo.class \ META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo \ sun/util/resources/cldr \ @@ -452,11 +451,9 @@ $(eval $(call SetupArchive,BUILD_CLDRDATA_JAR, \ $(CLDR_METAINF_SERVICES), \ SRCS := $(JDK_OUTPUTDIR)/modules/jdk.localedata \ - $(JDK_OUTPUTDIR)/modules/java.base \ $(CLDR_SERVICES_DIR), \ SUFFIXES := .class, \ INCLUDES := sun/text/resources/cldr \ - sun/util/cldr/CLDRLocaleDataMetaInfo.class \ sun/util/resources/cldr, \ EXTRA_FILES := META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo, \ JAR := $(CLDRDATA_JAR_DST), \ diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/gensrc/Gensrc-java.base.gmk --- a/jdk/make/gensrc/Gensrc-java.base.gmk Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/make/gensrc/Gensrc-java.base.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -29,14 +29,13 @@ include GensrcProperties.gmk GENSRC_JAVA_BASE += $(GENSRC_PROPERTIES) -include GensrcLocaleDataMetaInfo.gmk +include GensrcLocaleData.gmk include GensrcCharacterData.gmk include GensrcMisc.gmk include GensrcCharsetMapping.gmk include GensrcCharsetCoder.gmk include GensrcBuffer.gmk include GensrcExceptions.gmk -include GensrcCLDR.gmk java.base: $(GENSRC_JAVA_BASE) diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/gensrc/Gensrc-jdk.localedata.gmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/gensrc/Gensrc-jdk.localedata.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,38 @@ +# +# 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 GensrcCommon.gmk + +# Hook to include the corresponding custom file, if present. +$(eval $(call IncludeCustomExtension, jdk, gensrc/Gensrc-jdk.localedata.gmk)) + +include GensrcLocaleData.gmk +include GensrcCLDR.gmk + +jdk.localedata: $(GENSRC_JDK_LOCALEDATA) + +all: jdk.localedata + +.PHONY: all jdk.localedata diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/gensrc/GensrcCLDR.gmk --- a/jdk/make/gensrc/GensrcCLDR.gmk Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/make/gensrc/GensrcCLDR.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -27,9 +27,8 @@ CLDRSRCDIR := $(JDK_TOPDIR)/src/jdk.localedata/share/classes/sun/util/cldr/resources/$(subst .,_,$(CLDRVERSION)) GENSRC_DIR := $(JDK_OUTPUTDIR)/gensrc/jdk.localedata -BASE_GENSRC_DIR := $(JDK_OUTPUTDIR)/gensrc/java.base -CLDR_METAINFO_FILE := $(BASE_GENSRC_DIR)/sun/util/cldr/CLDRLocaleDataMetaInfo.java +CLDR_METAINFO_FILE := $(GENSRC_DIR)/sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo.java $(CLDR_METAINFO_FILE): $(wildcard $(CLDRSRCDIR)/common/dtd/*.dtd) \ $(wildcard $(CLDRSRCDIR)/common/main/*.xml) \ @@ -37,16 +36,6 @@ $(BUILD_TOOLS_JDK) $(MKDIR) -p $(GENSRC_DIR) $(TOOL_CLDRCONVERTER) -base $(CLDRSRCDIR) -o $(GENSRC_DIR) - $(MKDIR) -p $(BASE_GENSRC_DIR)/sun/text/resources/cldr - $(MKDIR) -p $(BASE_GENSRC_DIR)/sun/util/resources/cldr - $(RM) -r $(BASE_GENSRC_DIR)/sun/text/resources/cldr/en \ - $(BASE_GENSRC_DIR)/sun/util/resources/cldr/en - $(MV) $(GENSRC_DIR)/sun/text/resources/cldr/en $(BASE_GENSRC_DIR)/sun/text/resources/cldr/en - $(MV) $(GENSRC_DIR)/sun/util/resources/cldr/en $(BASE_GENSRC_DIR)/sun/util/resources/cldr/en - $(MV) $(GENSRC_DIR)/sun/text/resources/cldr/*.java $(BASE_GENSRC_DIR)/sun/text/resources/cldr - $(MV) $(GENSRC_DIR)/sun/util/resources/cldr/*.java $(BASE_GENSRC_DIR)/sun/util/resources/cldr - $(MKDIR) -p $(@D) - $(MV) $(GENSRC_DIR)/sun/util/cldr/CLDRLocaleDataMetaInfo.java $@ GENSRC_CLDR := $(CLDR_METAINFO_FILE) -GENSRC_JAVA_BASE += $(GENSRC_CLDR) +GENSRC_JDK_LOCALEDATA += $(GENSRC_CLDR) diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/gensrc/GensrcLocaleData.gmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/gensrc/GensrcLocaleData.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,152 @@ +# +# Copyright (c) 2011, 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. +# + +# Scan for all locale resources and extract for which locales there exists +# resources. Then put this meta information about existing (supported?) locales +# into LocaleDataMetaInfo.java + +# First go look for all locale files +LOCALE_FILES := $(shell $(FIND) $(JDK_TOPDIR)/src/java.base/share/classes \ + $(JDK_TOPDIR)/src/jdk.localedata/share/classes \ + -name "FormatData_*.java" -o -name "FormatData_*.properties" -o \ + -name "CollationData_*.java" -o -name "CollationData_*.properties" -o \ + -name "TimeZoneNames_*.java" -o -name "TimeZoneNames_*.properties" -o \ + -name "LocaleNames_*.java" -o -name "LocaleNames_*.properties" -o \ + -name "CurrencyNames_*.java" -o -name "CurrencyNames_*.properties" -o \ + -name "CalendarData_*.java" -o -name "CalendarData_*.properties" -o \ + -name "BreakIteratorInfo_*.java" -o -name "BreakIteratorRules_*.java") + +# Then translate the locale files into for example: FormatData_sv +LOCALE_RESOURCES := $(sort $(subst .properties,,$(subst .java,,$(notdir $(LOCALE_FILES))))) + +# Include the list of resources found during the previous compile. +-include $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources + +MISSING_RESOURCES := $(filter-out $(LOCALE_RESOURCES), $(PREV_LOCALE_RESOURCES)) +NEW_RESOURCES := $(filter-out $(PREV_LOCALE_RESOURCES), $(LOCALE_RESOURCES)) + +ifneq (, $(MISSING_RESOURCES)$(NEW_RESOURCES)) + # There is a difference in the number of supported resources. Trigger a regeneration. + $(shell $(RM) $(JDK_OUTPUTDIR)/gensrc/sun/util/locale/provider/LocaleDataMetaInfo.java) +endif + +# The EN locales +EN_LOCALES := en% + +# Locales that don't have any resource files should be included here. +ALL_NON_EN_LOCALES := ja-JP-JP nb-NO nn-NO th-TH-TH + +SED_ENARGS := -e 's|$(HASH)warn This file is preprocessed before being compiled|// -- This file was mechanically generated: Do not edit! -- //|g' +SED_NONENARGS := $(SED_ENARGS) + +# Fill in the languages and package names +SED_ENARGS += -e 's/$(HASH)Lang$(HASH)/En/' \ + -e 's/$(HASH)Package$(HASH)/sun.util.locale.provider/' +SED_NONENARGS += -e 's/$(HASH)Lang$(HASH)/NonEn/' \ + -e 's/$(HASH)Package$(HASH)/sun.util.resources.provider/' + +# This macro creates a sed expression that substitues for example: +# #FormatData_ENLocales# with: en% locales. +define CaptureLocale + $1_LOCALES := $$(subst _,-,$$(filter-out $1, $$(subst $1_,,$$(filter $1_%, $(LOCALE_RESOURCES))))) + $1_EN_LOCALES := $$(filter $(EN_LOCALES), $$($1_LOCALES)) + $1_NON_EN_LOCALES := $$(filter-out $(EN_LOCALES), $$($1_LOCALES)) + + # Special handling for Chinese locales to include implicit scripts + $1_NON_EN_LOCALES := $$(subst zh-CN,zh-CN$$(SPACE)zh-Hans-CN, $$($1_NON_EN_LOCALES)) + $1_NON_EN_LOCALES := $$(subst zh-SG,zh-SG$$(SPACE)zh-Hans-SG, $$($1_NON_EN_LOCALES)) + $1_NON_EN_LOCALES := $$(subst zh-HK,zh-HK$$(SPACE)zh-Hant-HK, $$($1_NON_EN_LOCALES)) + $1_NON_EN_LOCALES := $$(subst zh-MO,zh-MO$$(SPACE)zh-Hant-MO, $$($1_NON_EN_LOCALES)) + $1_NON_EN_LOCALES := $$(subst zh-TW,zh-TW$$(SPACE)zh-Hant-TW, $$($1_NON_EN_LOCALES)) + + ALL_EN_LOCALES += $$($1_EN_LOCALES) + ALL_NON_EN_LOCALES += $$($1_NON_EN_LOCALES) + + # Don't sed in a space if there are no locales. + SED_ENARGS += -e 's/$$(HASH)$1_Locales$$(HASH)/$$(if $$($1_EN_LOCALES),$$(SPACE)$$($1_EN_LOCALES),)/g' + SED_NONENARGS += -e 's/$$(HASH)$1_Locales$$(HASH)/$$(if $$($1_NON_EN_LOCALES),$$(SPACE)$$($1_NON_EN_LOCALES),)/g' +endef + +#sun.text.resources.FormatData +$(eval $(call CaptureLocale,FormatData)) + +#sun.text.resources.CollationData +$(eval $(call CaptureLocale,CollationData)) + +#sun.text.resources.BreakIteratorInfo +$(eval $(call CaptureLocale,BreakIteratorInfo)) + +#sun.text.resources.BreakIteratorRules +$(eval $(call CaptureLocale,BreakIteratorRules)) + +#sun.util.resources.TimeZoneNames +$(eval $(call CaptureLocale,TimeZoneNames)) + +#sun.util.resources.LocaleNames +$(eval $(call CaptureLocale,LocaleNames)) + +#sun.util.resources.CurrencyNames +$(eval $(call CaptureLocale,CurrencyNames)) + +#sun.util.resources.CalendarData +$(eval $(call CaptureLocale,CalendarData)) + +SED_ENARGS += -e 's/$(HASH)AvailableLocales_Locales$(HASH)/$(sort $(ALL_EN_LOCALES))/g' +SED_NONENARGS += -e 's/$(HASH)AvailableLocales_Locales$(HASH)/$(sort $(ALL_NON_EN_LOCALES))/g' + +$(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java: \ + $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template + $(MKDIR) -p $(@D) + $(ECHO) Creating sun/util/locale/provider/EnLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources. + $(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources + $(SED) $(SED_ENARGS) $< > $@ + +$(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java: \ + $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template + $(MKDIR) -p $(@D) + $(ECHO) Creating sun/util/resources/provider/NonEnLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources. + $(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources + $(SED) $(SED_NONENARGS) $< > $@ + +GENSRC_BASELOCALEDATA := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java +GENSRC_LOCALEDATA := $(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java + +################################################################################ + +GENSRC_CRBC_DST := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/CoreResourceBundleControl.java +GENSRC_CRBC_CMD := $(JDK_TOPDIR)/make/scripts/localelist.sh + +JRE_NONEXIST_LOCALES := en en_US de_DE es_ES fr_FR it_IT ja_JP ko_KR sv_SE zh + +$(GENSRC_CRBC_DST): $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/CoreResourceBundleControl-XLocales.java.template \ + $(GENSRC_CRBC_CMD) + $(MKDIR) -p $(@D) + NAWK="$(NAWK)" SED="$(SED)" $(SH) $(GENSRC_CRBC_CMD) "$(JRE_NONEXIST_LOCALES)" $< $@ + +GENSRC_BASELOCALEDATA += $(GENSRC_CRBC_DST) +GENSRC_JAVA_BASE += $(GENSRC_BASELOCALEDATA) +GENSRC_JDK_LOCALEDATA += $(GENSRC_LOCALEDATA) + +################################################################################ diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk --- a/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -# -# Copyright (c) 2011, 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. -# - -# Scan for all locale resources and extract for which locales there exists -# resources. Then put this meta information about existing (supported?) locales -# into LocaleDataMetaInfo.java - -# First go look for all locale files -LOCALE_FILES := $(shell $(FIND) $(JDK_TOPDIR)/src/java.base/share/classes \ - $(JDK_TOPDIR)/src/jdk.localedata/share/classes \ - -name "FormatData_*.java" -o -name "FormatData_*.properties" -o \ - -name "CollationData_*.java" -o -name "CollationData_*.properties" -o \ - -name "TimeZoneNames_*.java" -o -name "TimeZoneNames_*.properties" -o \ - -name "LocaleNames_*.java" -o -name "LocaleNames_*.properties" -o \ - -name "CurrencyNames_*.java" -o -name "CurrencyNames_*.properties" -o \ - -name "CalendarData_*.java" -o -name "CalendarData_*.properties" -o \ - -name "BreakIteratorInfo_*.java" -o -name "BreakIteratorRules_*.java") - -# Then translate the locale files into for example: FormatData_sv -LOCALE_RESOURCES := $(sort $(subst .properties,,$(subst .java,,$(notdir $(LOCALE_FILES))))) - -# Include the list of resources found during the previous compile. --include $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources - -MISSING_RESOURCES := $(filter-out $(LOCALE_RESOURCES), $(PREV_LOCALE_RESOURCES)) -NEW_RESOURCES := $(filter-out $(PREV_LOCALE_RESOURCES), $(LOCALE_RESOURCES)) - -ifneq (, $(MISSING_RESOURCES)$(NEW_RESOURCES)) - # There is a difference in the number of supported resources. Trigger a regeneration. - $(shell $(RM) $(JDK_OUTPUTDIR)/gensrc/sun/util/locale/provider/LocaleDataMetaInfo.java) -endif - -# The EN locales -EN_LOCALES := en% - -# Locales that don't have any resource files should be included here. -ALL_NON_EN_LOCALES := ja-JP-JP nb-NO nn-NO th-TH-TH - -SED_ENARGS := -e 's|$(HASH)warn This file is preprocessed before being compiled|// -- This file was mechanically generated: Do not edit! -- //|g' -SED_NONENARGS := $(SED_ENARGS) - -# Fill in the languages and package names -SED_ENARGS += -e 's/$(HASH)Lang$(HASH)/En/' \ - -e 's/$(HASH)Package$(HASH)/sun.util.locale.provider/' -SED_NONENARGS += -e 's/$(HASH)Lang$(HASH)/NonEn/' \ - -e 's/$(HASH)Package$(HASH)/sun.util.resources.provider/' - -# This macro creates a sed expression that substitues for example: -# #FormatData_ENLocales# with: en% locales. -define CaptureLocale - $1_LOCALES := $$(subst _,-,$$(filter-out $1, $$(subst $1_,,$$(filter $1_%, $(LOCALE_RESOURCES))))) - $1_EN_LOCALES := $$(filter $(EN_LOCALES), $$($1_LOCALES)) - $1_NON_EN_LOCALES := $$(filter-out $(EN_LOCALES), $$($1_LOCALES)) - - # Special handling for Chinese locales to include implicit scripts - $1_NON_EN_LOCALES := $$(subst zh-CN,zh-CN$$(SPACE)zh-Hans-CN, $$($1_NON_EN_LOCALES)) - $1_NON_EN_LOCALES := $$(subst zh-SG,zh-SG$$(SPACE)zh-Hans-SG, $$($1_NON_EN_LOCALES)) - $1_NON_EN_LOCALES := $$(subst zh-HK,zh-HK$$(SPACE)zh-Hant-HK, $$($1_NON_EN_LOCALES)) - $1_NON_EN_LOCALES := $$(subst zh-MO,zh-MO$$(SPACE)zh-Hant-MO, $$($1_NON_EN_LOCALES)) - $1_NON_EN_LOCALES := $$(subst zh-TW,zh-TW$$(SPACE)zh-Hant-TW, $$($1_NON_EN_LOCALES)) - - ALL_EN_LOCALES += $$($1_EN_LOCALES) - ALL_NON_EN_LOCALES += $$($1_NON_EN_LOCALES) - - # Don't sed in a space if there are no locales. - SED_ENARGS += -e 's/$$(HASH)$1_Locales$$(HASH)/$$(if $$($1_EN_LOCALES),$$(SPACE)$$($1_EN_LOCALES),)/g' - SED_NONENARGS += -e 's/$$(HASH)$1_Locales$$(HASH)/$$(if $$($1_NON_EN_LOCALES),$$(SPACE)$$($1_NON_EN_LOCALES),)/g' -endef - -#sun.text.resources.FormatData -$(eval $(call CaptureLocale,FormatData)) - -#sun.text.resources.CollationData -$(eval $(call CaptureLocale,CollationData)) - -#sun.text.resources.BreakIteratorInfo -$(eval $(call CaptureLocale,BreakIteratorInfo)) - -#sun.text.resources.BreakIteratorRules -$(eval $(call CaptureLocale,BreakIteratorRules)) - -#sun.util.resources.TimeZoneNames -$(eval $(call CaptureLocale,TimeZoneNames)) - -#sun.util.resources.LocaleNames -$(eval $(call CaptureLocale,LocaleNames)) - -#sun.util.resources.CurrencyNames -$(eval $(call CaptureLocale,CurrencyNames)) - -#sun.util.resources.CalendarData -$(eval $(call CaptureLocale,CalendarData)) - -SED_ENARGS += -e 's/$(HASH)AvailableLocales_Locales$(HASH)/$(sort $(ALL_EN_LOCALES))/g' -SED_NONENARGS += -e 's/$(HASH)AvailableLocales_Locales$(HASH)/$(sort $(ALL_NON_EN_LOCALES))/g' - -$(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java: \ - $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template - $(MKDIR) -p $(@D) - $(ECHO) Creating sun/util/locale/provider/EnLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources. - $(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources - $(SED) $(SED_ENARGS) $< > $@ - -$(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java: \ - $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template - $(MKDIR) -p $(@D) - $(ECHO) Creating sun/util/resources/provider/NonEnLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources. - $(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" > $(JDK_OUTPUTDIR)/gensrc/_the.locale_resources - $(SED) $(SED_NONENARGS) $< > $@ - -GENSRC_LOCALEDATAMETAINFO := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/EnLocaleDataMetaInfo.java \ - $(JDK_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonEnLocaleDataMetaInfo.java - -################################################################################ - -GENSRC_CRBC_DST := $(JDK_OUTPUTDIR)/gensrc/java.base/sun/util/CoreResourceBundleControl.java -GENSRC_CRBC_CMD := $(JDK_TOPDIR)/make/scripts/localelist.sh - -JRE_NONEXIST_LOCALES := en en_US de_DE es_ES fr_FR it_IT ja_JP ko_KR sv_SE zh - -$(GENSRC_CRBC_DST): $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/CoreResourceBundleControl-XLocales.java.template \ - $(GENSRC_CRBC_CMD) - $(MKDIR) -p $(@D) - NAWK="$(NAWK)" SED="$(SED)" $(SH) $(GENSRC_CRBC_CMD) "$(JRE_NONEXIST_LOCALES)" $< $@ - -GENSRC_LOCALEDATAMETAINFO += $(GENSRC_CRBC_DST) -GENSRC_JAVA_BASE += $(GENSRC_LOCALEDATAMETAINFO) - -################################################################################ diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/lib/Awt2dLibraries.gmk --- a/jdk/make/lib/Awt2dLibraries.gmk Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/make/lib/Awt2dLibraries.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -217,10 +217,8 @@ -I$(JDK_OUTPUTDIR)/gensrc_headers/java.base \ # LIBAWT_EXFILES += \ - sun/java2d/d3d/D3DPipeline.cpp \ sun/java2d/d3d/D3DShaderGen.c \ sun/awt/image/cvutils/img_colors.c \ - sun/windows/WBufferStrategy.cpp \ # LIBAWT_LANG := C++ diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java --- a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java Wed Jul 05 20:01:50 2017 +0200 @@ -143,8 +143,9 @@ @Override public void generateMetaInfo(Map> metaInfo) throws IOException { - String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator + "util" + File.separator - + "cldr" + File.separator; + String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator + "util" + + File.separator + "resources" + File.separator + "cldr" + File.separator + + "provider" + File.separator ; File dir = new File(dirName); if (!dir.exists()) { dir.mkdirs(); @@ -158,7 +159,7 @@ try (PrintWriter out = new PrintWriter(file, "us-ascii")) { out.println(CopyrightHeaders.getOpenJDKCopyright()); - out.println("package sun.util.cldr;\n\n" + out.println("package sun.util.resources.cldr.provider;\n\n" + "import java.util.ListResourceBundle;\n" + "import sun.util.locale.provider.LocaleProviderAdapter;\n" + "import sun.util.locale.provider.LocaleDataMetaInfo;\n"); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java --- a/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java Wed Jul 05 20:01:50 2017 +0200 @@ -25,29 +25,17 @@ package build.tools.module; -import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; -import java.util.Objects; import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import javax.xml.namespace.QName; -import javax.xml.stream.*; -import javax.xml.stream.events.Attribute; -import javax.xml.stream.events.XMLEvent; +import java.util.stream.Collectors; /** * GenJdepsModulesXml augments the input modules.xml file(s) @@ -97,14 +85,14 @@ Set modules = new HashSet<>(); for (; i < args.length; i++) { Path p = Paths.get(args[i]); - try (InputStream in = new BufferedInputStream(Files.newInputStream(p))) { - Set mods = gentool.load(in); - modules.addAll(mods); - } + modules.addAll(ModulesXmlReader.readModules(p) + .stream() + .map(gentool::buildIncludes) + .collect(Collectors.toSet())); } Files.createDirectories(outfile.getParent()); - gentool.writeXML(modules, outfile); + ModulesXmlWriter.writeModules(modules, outfile); } final Path modulepath; @@ -112,228 +100,21 @@ this.modulepath = modulepath; } - private static final String MODULES = "modules"; - private static final String MODULE = "module"; - private static final String NAME = "name"; - private static final String DEPEND = "depend"; - private static final String EXPORT = "export"; - private static final String TO = "to"; - private static final String INCLUDE = "include"; - private static final QName REEXPORTS = new QName("re-exports"); - private Set load(InputStream in) throws XMLStreamException, IOException { - Set modules = new HashSet<>(); - XMLInputFactory factory = XMLInputFactory.newInstance(); - XMLEventReader stream = factory.createXMLEventReader(in); - Module.Builder mb = null; - String modulename = null; - String pkg = null; - Set permits = new HashSet<>(); - while (stream.hasNext()) { - XMLEvent event = stream.nextEvent(); - if (event.isStartElement()) { - String startTag = event.asStartElement().getName().getLocalPart(); - switch (startTag) { - case MODULES: - break; - case MODULE: - if (mb != null) { - throw new RuntimeException("end tag for module is missing"); - } - modulename = getNextTag(stream, NAME); - mb = new Module.Builder(); - mb.name(modulename); - break; - case NAME: - throw new RuntimeException(event.toString()); - case DEPEND: - boolean reexports = false; - Attribute attr = event.asStartElement().getAttributeByName(REEXPORTS); - if (attr != null) { - String value = attr.getValue(); - if (value.equals("true") || value.equals("false")) { - reexports = Boolean.parseBoolean(value); - } else { - throw new RuntimeException("unexpected attribute " + attr.toString()); - } - } - mb.require(getData(stream), reexports); - break; - case INCLUDE: - throw new RuntimeException("unexpected " + event); - case EXPORT: - pkg = getNextTag(stream, NAME); - break; - case TO: - permits.add(getData(stream)); - break; - default: - } - } else if (event.isEndElement()) { - String endTag = event.asEndElement().getName().getLocalPart(); - switch (endTag) { - case MODULE: - buildIncludes(mb, modulename); - modules.add(mb.build()); - mb = null; - break; - case EXPORT: - if (pkg == null) { - throw new RuntimeException("export-to is malformed"); - } - mb.exportTo(pkg, permits); - pkg = null; - permits.clear(); - break; - default: - } - } else if (event.isCharacters()) { - String s = event.asCharacters().getData(); - if (!s.trim().isEmpty()) { - throw new RuntimeException("export-to is malformed"); - } - } - } - return modules; - } - - private String getData(XMLEventReader reader) throws XMLStreamException { - XMLEvent e = reader.nextEvent(); - if (e.isCharacters()) { - return e.asCharacters().getData(); - } - throw new RuntimeException(e.toString()); - } - - private String getNextTag(XMLEventReader reader, String tag) throws XMLStreamException { - XMLEvent e = reader.nextTag(); - if (e.isStartElement()) { - String t = e.asStartElement().getName().getLocalPart(); - if (!tag.equals(t)) { - throw new RuntimeException(e + " expected: " + tag); - } - return getData(reader); - } - throw new RuntimeException("export-to name is missing:" + e); - } - private void writeXML(Set modules, Path path) - throws IOException, XMLStreamException - { - XMLOutputFactory xof = XMLOutputFactory.newInstance(); - try (OutputStream out = Files.newOutputStream(path)) { - int depth = 0; - XMLStreamWriter xtw = xof.createXMLStreamWriter(out, "UTF-8"); - xtw.writeStartDocument("utf-8","1.0"); - writeStartElement(xtw, MODULES, depth); - modules.stream() - .sorted(Comparator.comparing(Module::name)) - .forEach(m -> writeModuleElement(xtw, m, depth+1)); - writeEndElement(xtw, depth); - xtw.writeCharacters("\n"); - xtw.writeEndDocument(); - xtw.flush(); - xtw.close(); - } - } - - private void writeElement(XMLStreamWriter xtw, String element, String value, int depth) { - try { - writeStartElement(xtw, element, depth); - xtw.writeCharacters(value); - xtw.writeEndElement(); - } catch (XMLStreamException e) { - throw new RuntimeException(e); - } - } - - private void writeDependElement(XMLStreamWriter xtw, Module.Dependence d, int depth) { - try { - writeStartElement(xtw, DEPEND, depth); - if (d.reexport) { - xtw.writeAttribute("re-exports", "true"); - } - xtw.writeCharacters(d.name); - xtw.writeEndElement(); - } catch (XMLStreamException e) { - throw new RuntimeException(e); - } - } - - private void writeExportElement(XMLStreamWriter xtw, String pkg, int depth) { - writeExportElement(xtw, pkg, Collections.emptySet(), depth); - } - - private void writeExportElement(XMLStreamWriter xtw, String pkg, - Set permits, int depth) { - try { - writeStartElement(xtw, EXPORT, depth); - writeElement(xtw, NAME, pkg, depth+1); - if (!permits.isEmpty()) { - permits.stream().sorted() - .forEach(m -> writeElement(xtw, TO, m, depth + 1)); - } - writeEndElement(xtw, depth); - } catch (XMLStreamException e) { - throw new RuntimeException(e); - } - } - private void writeModuleElement(XMLStreamWriter xtw, Module m, int depth) { - try { - writeStartElement(xtw, MODULE, depth); - writeElement(xtw, NAME, m.name(), depth+1); - m.requires().stream().sorted(Comparator.comparing(d -> d.name)) - .forEach(d -> writeDependElement(xtw, d, depth+1)); - m.exports().keySet().stream() - .filter(pn -> m.exports().get(pn).isEmpty()) - .sorted() - .forEach(pn -> writeExportElement(xtw, pn, depth+1)); - m.exports().entrySet().stream() - .filter(e -> !e.getValue().isEmpty()) - .sorted(Map.Entry.comparingByKey()) - .forEach(e -> writeExportElement(xtw, e.getKey(), e.getValue(), depth+1)); - m.packages().stream().sorted() - .forEach(p -> writeElement(xtw, INCLUDE, p, depth+1)); - writeEndElement(xtw, depth); - } catch (XMLStreamException e) { - throw new RuntimeException(e); - - } - } - - /** Two spaces; the default indentation. */ - public static final String DEFAULT_INDENT = " "; - - /** stack[depth] indicates what's been written into the current scope. */ - private static String[] stack = new String[] { "\n", - "\n" + DEFAULT_INDENT, - "\n" + DEFAULT_INDENT + DEFAULT_INDENT, - "\n" + DEFAULT_INDENT + DEFAULT_INDENT + DEFAULT_INDENT}; - - private void writeStartElement(XMLStreamWriter xtw, String name, int depth) - throws XMLStreamException - { - xtw.writeCharacters(stack[depth]); - xtw.writeStartElement(name); - } - - private void writeEndElement(XMLStreamWriter xtw, int depth) throws XMLStreamException { - xtw.writeCharacters(stack[depth]); - xtw.writeEndElement(); - } - - private String packageName(Path p) { + private static String packageName(Path p) { return packageName(p.toString().replace(File.separatorChar, '/')); } - private String packageName(String name) { + private static String packageName(String name) { int i = name.lastIndexOf('/'); return (i > 0) ? name.substring(0, i).replace('/', '.') : ""; } - private boolean includes(String name) { - return name.endsWith(".class") && !name.equals("module-info.class"); + private static boolean includes(String name) { + return name.endsWith(".class"); } - public void buildIncludes(Module.Builder mb, String modulename) throws IOException { - Path mclasses = modulepath.resolve(modulename); + public Module buildIncludes(Module module) { + Module.Builder mb = new Module.Builder(module); + Path mclasses = modulepath.resolve(module.name()); try { Files.find(mclasses, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr) -> includes(p.getFileName().toString())) @@ -341,145 +122,9 @@ .forEach(mb::include); } catch (NoSuchFileException e) { // aggregate module may not have class - } - } - - static class Module { - static class Dependence { - final String name; - final boolean reexport; - Dependence(String name) { - this(name, false); - } - Dependence(String name, boolean reexport) { - this.name = name; - this.reexport = reexport; - } - - @Override - public int hashCode() { - int hash = 5; - hash = 11 * hash + Objects.hashCode(this.name); - hash = 11 * hash + (this.reexport ? 1 : 0); - return hash; - } - - public boolean equals(Object o) { - Dependence d = (Dependence)o; - return this.name.equals(d.name) && this.reexport == d.reexport; - } - } - private final String moduleName; - private final Set requires; - private final Map> exports; - private final Set packages; - - private Module(String name, - Set requires, - Map> exports, - Set packages) { - this.moduleName = name; - this.requires = Collections.unmodifiableSet(requires); - this.exports = Collections.unmodifiableMap(exports); - this.packages = Collections.unmodifiableSet(packages); - } - - public String name() { - return moduleName; - } - - public Set requires() { - return requires; - } - - public Map> exports() { - return exports; - } - - public Set packages() { - return packages; - } - - @Override - public boolean equals(Object ob) { - if (!(ob instanceof Module)) { - return false; - } - Module that = (Module) ob; - return (moduleName.equals(that.moduleName) - && requires.equals(that.requires) - && exports.equals(that.exports) - && packages.equals(that.packages)); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); } - - @Override - public int hashCode() { - int hc = moduleName.hashCode(); - hc = hc * 43 + requires.hashCode(); - hc = hc * 43 + exports.hashCode(); - hc = hc * 43 + packages.hashCode(); - return hc; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("module ").append(moduleName).append(" {").append("\n"); - requires.stream().sorted().forEach(d -> - sb.append(String.format(" requires %s%s%n", d.reexport ? "public " : "", d.name))); - exports.entrySet().stream().filter(e -> e.getValue().isEmpty()) - .sorted(Map.Entry.comparingByKey()) - .forEach(e -> sb.append(String.format(" exports %s%n", e.getKey()))); - exports.entrySet().stream().filter(e -> !e.getValue().isEmpty()) - .sorted(Map.Entry.comparingByKey()) - .forEach(e -> sb.append(String.format(" exports %s to %s%n", e.getKey(), e.getValue()))); - packages.stream().sorted().forEach(pn -> sb.append(String.format(" includes %s%n", pn))); - sb.append("}"); - return sb.toString(); - } - - static class Builder { - private String name; - private final Set requires = new HashSet<>(); - private final Map> exports = new HashMap<>(); - private final Set packages = new HashSet<>(); - - public Builder() { - } - - public Builder name(String n) { - name = n; - return this; - } - - public Builder require(String d, boolean reexport) { - requires.add(new Dependence(d, reexport)); - return this; - } - - public Builder include(String p) { - packages.add(p); - return this; - } - - public Builder export(String p) { - return exportTo(p, Collections.emptySet()); - } - - public Builder exportTo(String p, Set ms) { - Objects.requireNonNull(p); - Objects.requireNonNull(ms); - if (exports.containsKey(p)) { - throw new RuntimeException(name + " already exports " + p); - } - exports.put(p, new HashSet<>(ms)); - return this; - } - - public Module build() { - Module m = new Module(name, requires, exports, packages); - return m; - } - } + return mb.build(); } } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/src/classes/build/tools/module/GenModulesList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/src/classes/build/tools/module/GenModulesList.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,159 @@ +/* + * 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. + */ + +package build.tools.module; + +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.stream.Collectors; + +/** + * $ java build.tools.module.GenModulesList \ + * -o modules.list \ + * top/modules.xml ... + */ +public final class GenModulesList { + private final static String USAGE = + "Usage: GenModulesList -o path-to-modules-xml"; + + private Set modules = new HashSet<>(); + private HashMap nameToModule = new HashMap<>(); + + public static void main(String[] args) throws Exception { + GenModulesList gen = new GenModulesList(); + gen.run(args); + } + + void run(String[] args) throws Exception { + Path outfile = null; + int i = 0; + while (i < args.length) { + String arg = args[i]; + if (arg.equals("-o")) { + outfile = Paths.get(args[i+1]); + i = i+2; + } else { + break; + } + } + if (outfile == null || i >= args.length) { + System.err.println(USAGE); + System.exit(-1); + } + + for (; i < args.length; i++) { + Path p = Paths.get(args[i]); + modules.addAll(ModulesXmlReader.readModules(p)); + } + + modules.stream() + .forEach(m -> nameToModule.put(m.name(), m)); + + Path parent = outfile.getParent(); + if (parent != null) + Files.createDirectories(parent); + + Iterable sortedModules = (new TopoSorter(modules)).result(); + try (PrintWriter writer = new PrintWriter(outfile.toFile())) { + for (Module m : sortedModules) { + if (isNotAggregator(m)) { + String deps = getModuleDependences(m).stream() + .filter(GenModulesList::isNotAggregator) + .map(Module::name) + .collect(Collectors.joining(" ")); + writer.format("%s: %s%n", m.name(), deps); + } + } + } + } + + private Module nameToModule(String name) { + return nameToModule.get(name); + } + + private Set getModuleDependences(Module m) { + return m.requires().stream() + .map(d -> d.name()) + .map(this::nameToModule) + .collect(Collectors.toSet()); + } + + static boolean isNotAggregator(Module m) { + return isNotAggregator(m.name()); + } + + static boolean isNotAggregator(String name) { + return AGGREGATORS.contains(name) ? false : true; + } + + static final List AGGREGATORS = Arrays.asList(new String[] { + "java.se", "java.compact1", "java.compact2", + "java.compact3", "jdk.compact3"}); + + class TopoSorter { + final Deque result = new LinkedList<>(); + final Deque nodes = new LinkedList<>(); + + TopoSorter(Collection nodes) { + nodes.stream() + .forEach(m -> this.nodes.add(m)); + + sort(); + } + + public Iterable result() { + return result; + } + + private void sort() { + Deque visited = new LinkedList<>(); + Deque done = new LinkedList<>(); + Module node; + while ((node = nodes.poll()) != null) { + if (!visited.contains(node)) { + visit(node, visited, done); + } + } + } + + private void visit(Module m, Deque visited, Deque done) { + if (visited.contains(m)) { + if (!done.contains(m)) { + throw new IllegalArgumentException("Cyclic detected: " + + m + " " + getModuleDependences(m)); + } + return; + } + visited.add(m); + getModuleDependences(m).stream() + .forEach(x -> visit(x, visited, done)); + done.add(m); + result.addLast(m); + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/src/classes/build/tools/module/Module.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/src/classes/build/tools/module/Module.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,178 @@ +/* + * 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. + */ + +package build.tools.module; + +import java.util.*; + +public class Module { + static class Dependence { + final String name; + final boolean reexport; + Dependence(String name) { + this(name, false); + } + Dependence(String name, boolean reexport) { + this.name = name; + this.reexport = reexport; + } + + public String name() { + return name; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 11 * hash + Objects.hashCode(this.name); + hash = 11 * hash + (this.reexport ? 1 : 0); + return hash; + } + + public boolean equals(Object o) { + Dependence d = (Dependence)o; + return this.name.equals(d.name) && this.reexport == d.reexport; + } + } + private final String moduleName; + private final Set requires; + private final Map> exports; + private final Set packages; + + private Module(String name, + Set requires, + Map> exports, + Set packages) { + this.moduleName = name; + this.requires = Collections.unmodifiableSet(requires); + this.exports = Collections.unmodifiableMap(exports); + this.packages = Collections.unmodifiableSet(packages); + } + + public String name() { + return moduleName; + } + + public Set requires() { + return requires; + } + + public Map> exports() { + return exports; + } + + public Set packages() { + return packages; + } + + @Override + public boolean equals(Object ob) { + if (!(ob instanceof Module)) { + return false; + } + Module that = (Module) ob; + return (moduleName.equals(that.moduleName) + && requires.equals(that.requires) + && exports.equals(that.exports) + && packages.equals(that.packages)); + } + + @Override + public int hashCode() { + int hc = moduleName.hashCode(); + hc = hc * 43 + requires.hashCode(); + hc = hc * 43 + exports.hashCode(); + hc = hc * 43 + packages.hashCode(); + return hc; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("module ").append(moduleName).append(" {").append("\n"); + requires.stream().sorted().forEach(d -> + sb.append(String.format(" requires %s%s%n", d.reexport ? "public " : "", d.name))); + exports.entrySet().stream().filter(e -> e.getValue().isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> sb.append(String.format(" exports %s%n", e.getKey()))); + exports.entrySet().stream().filter(e -> !e.getValue().isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> sb.append(String.format(" exports %s to %s%n", e.getKey(), e.getValue()))); + packages.stream().sorted().forEach(pn -> sb.append(String.format(" includes %s%n", pn))); + sb.append("}"); + return sb.toString(); + } + + static class Builder { + private String name; + private final Set requires = new HashSet<>(); + private final Map> exports = new HashMap<>(); + private final Set packages = new HashSet<>(); + + public Builder() { + } + + public Builder(Module module) { + name = module.name(); + requires.addAll(module.requires()); + exports.putAll(module.exports()); + packages.addAll(module.packages()); + } + + public Builder name(String n) { + name = n; + return this; + } + + public Builder require(String d, boolean reexport) { + requires.add(new Dependence(d, reexport)); + return this; + } + + public Builder include(String p) { + packages.add(p); + return this; + } + + public Builder export(String p) { + return exportTo(p, Collections.emptySet()); + } + + public Builder exportTo(String p, Set ms) { + Objects.requireNonNull(p); + Objects.requireNonNull(ms); + if (exports.containsKey(p)) { + throw new RuntimeException(name + " already exports " + p); + } + exports.put(p, new HashSet<>(ms)); + return this; + } + + public Module build() { + Module m = new Module(name, requires, exports, packages); + return m; + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/src/classes/build/tools/module/ModulesXmlReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/src/classes/build/tools/module/ModulesXmlReader.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,165 @@ +/* + * 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. + */ + +package build.tools.module; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.XMLEvent; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; + +public class ModulesXmlReader { + + private ModulesXmlReader() {} + + public static Set readModules(Path modulesXml) + throws XMLStreamException, IOException + { + Set modules = new HashSet<>(); + try (InputStream in = new BufferedInputStream(Files.newInputStream(modulesXml))) { + Set mods = ModulesXmlReader.load(in); + modules.addAll(mods); + } + return modules; + } + + private static final String MODULES = "modules"; + private static final String MODULE = "module"; + private static final String NAME = "name"; + private static final String DEPEND = "depend"; + private static final String EXPORT = "export"; + private static final String TO = "to"; + private static final String INCLUDE = "include"; + private static final QName REEXPORTS = new QName("re-exports"); + private static Set load(InputStream in) + throws XMLStreamException, IOException + { + Set modules = new HashSet<>(); + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLEventReader stream = factory.createXMLEventReader(in); + Module.Builder mb = null; + String modulename = null; + String pkg = null; + Set permits = new HashSet<>(); + while (stream.hasNext()) { + XMLEvent event = stream.nextEvent(); + if (event.isStartElement()) { + String startTag = event.asStartElement().getName().getLocalPart(); + switch (startTag) { + case MODULES: + break; + case MODULE: + if (mb != null) { + throw new RuntimeException("end tag for module is missing"); + } + modulename = getNextTag(stream, NAME); + mb = new Module.Builder(); + mb.name(modulename); + break; + case NAME: + throw new RuntimeException(event.toString()); + case DEPEND: + boolean reexports = false; + Attribute attr = event.asStartElement().getAttributeByName(REEXPORTS); + if (attr != null) { + String value = attr.getValue(); + if (value.equals("true") || value.equals("false")) { + reexports = Boolean.parseBoolean(value); + } else { + throw new RuntimeException("unexpected attribute " + attr.toString()); + } + } + mb.require(getData(stream), reexports); + break; + case INCLUDE: + throw new RuntimeException("unexpected " + event); + case EXPORT: + pkg = getNextTag(stream, NAME); + break; + case TO: + permits.add(getData(stream)); + break; + default: + } + } else if (event.isEndElement()) { + String endTag = event.asEndElement().getName().getLocalPart(); + switch (endTag) { + case MODULE: + modules.add(mb.build()); + mb = null; + break; + case EXPORT: + if (pkg == null) { + throw new RuntimeException("export-to is malformed"); + } + mb.exportTo(pkg, permits); + pkg = null; + permits.clear(); + break; + default: + } + } else if (event.isCharacters()) { + String s = event.asCharacters().getData(); + if (!s.trim().isEmpty()) { + throw new RuntimeException("export-to is malformed"); + } + } + } + return modules; + } + + private static String getData(XMLEventReader reader) + throws XMLStreamException + { + XMLEvent e = reader.nextEvent(); + if (e.isCharacters()) + return e.asCharacters().getData(); + + throw new RuntimeException(e.toString()); + } + + private static String getNextTag(XMLEventReader reader, String tag) + throws XMLStreamException + { + XMLEvent e = reader.nextTag(); + if (e.isStartElement()) { + String t = e.asStartElement().getName().getLocalPart(); + if (!tag.equals(t)) { + throw new RuntimeException(e + " expected: " + tag); + } + return getData(reader); + } + throw new RuntimeException("export-to name is missing:" + e); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/make/src/classes/build/tools/module/ModulesXmlWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/src/classes/build/tools/module/ModulesXmlWriter.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,179 @@ +/* + * 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. + */ + +package build.tools.module; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; +import java.util.Set; + +public final class ModulesXmlWriter { + + private ModulesXmlWriter() {} + + public static void writeModules(Set modules, Path path) + throws IOException, XMLStreamException + { + writeXML(modules, path); + } + + private static final String MODULES = "modules"; + private static final String MODULE = "module"; + private static final String NAME = "name"; + private static final String DEPEND = "depend"; + private static final String EXPORT = "export"; + private static final String TO = "to"; + private static final String INCLUDE = "include"; + private static final QName REEXPORTS = new QName("re-exports"); + + private static void writeXML(Set modules, Path path) + throws IOException, XMLStreamException + { + XMLOutputFactory xof = XMLOutputFactory.newInstance(); + try (OutputStream out = Files.newOutputStream(path)) { + int depth = 0; + XMLStreamWriter xtw = xof.createXMLStreamWriter(out, "UTF-8"); + xtw.writeStartDocument("utf-8","1.0"); + writeStartElement(xtw, MODULES, depth); + modules.stream() + .sorted(Comparator.comparing(Module::name)) + .forEach(m -> writeModuleElement(xtw, m, depth+1)); + writeEndElement(xtw, depth); + xtw.writeCharacters("\n"); + xtw.writeEndDocument(); + xtw.flush(); + xtw.close(); + } + } + + private static void writeElement(XMLStreamWriter xtw, + String element, + String value, + int depth) { + try { + writeStartElement(xtw, element, depth); + xtw.writeCharacters(value); + xtw.writeEndElement(); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + + private static void writeDependElement(XMLStreamWriter xtw, + Module.Dependence d, + int depth) { + try { + writeStartElement(xtw, DEPEND, depth); + if (d.reexport) { + xtw.writeAttribute("re-exports", "true"); + } + xtw.writeCharacters(d.name); + xtw.writeEndElement(); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + + private static void writeExportElement(XMLStreamWriter xtw, + String pkg, + int depth) { + writeExportElement(xtw, pkg, Collections.emptySet(), depth); + } + + private static void writeExportElement(XMLStreamWriter xtw, + String pkg, + Set permits, + int depth) { + try { + writeStartElement(xtw, EXPORT, depth); + writeElement(xtw, NAME, pkg, depth+1); + if (!permits.isEmpty()) { + permits.stream().sorted() + .forEach(m -> writeElement(xtw, TO, m, depth + 1)); + } + writeEndElement(xtw, depth); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + private static void writeModuleElement(XMLStreamWriter xtw, + Module m, + int depth) { + try { + writeStartElement(xtw, MODULE, depth); + writeElement(xtw, NAME, m.name(), depth+1); + m.requires().stream().sorted(Comparator.comparing(d -> d.name)) + .forEach(d -> writeDependElement(xtw, d, depth+1)); + m.exports().keySet().stream() + .filter(pn -> m.exports().get(pn).isEmpty()) + .sorted() + .forEach(pn -> writeExportElement(xtw, pn, depth+1)); + m.exports().entrySet().stream() + .filter(e -> !e.getValue().isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> writeExportElement(xtw, e.getKey(), e.getValue(), depth+1)); + m.packages().stream().sorted() + .forEach(p -> writeElement(xtw, INCLUDE, p, depth+1)); + writeEndElement(xtw, depth); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + + } + } + + /** Two spaces; the default indentation. */ + public static final String DEFAULT_INDENT = " "; + + /** stack[depth] indicates what's been written into the current scope. */ + private static String[] stack = new String[] { "\n", + "\n" + DEFAULT_INDENT, + "\n" + DEFAULT_INDENT + DEFAULT_INDENT, + "\n" + DEFAULT_INDENT + DEFAULT_INDENT + DEFAULT_INDENT}; + + private static void writeStartElement(XMLStreamWriter xtw, + String name, + int depth) + throws XMLStreamException + { + xtw.writeCharacters(stack[depth]); + xtw.writeStartElement(name); + } + + private static void writeEndElement(XMLStreamWriter xtw, int depth) + throws XMLStreamException + { + xtw.writeCharacters(stack[depth]); + xtw.writeEndElement(); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Jul 05 20:01:50 2017 +0200 @@ -62,7 +62,7 @@ private static final String CLL_SIG = "(L" + CLS + ";L" + OBJ + ";)L" + OBJ + ";"; /** Name of its super class*/ - private static final String superName = LF; + private static final String superName = OBJ; /** Name of new class */ private final String className; @@ -97,7 +97,7 @@ if (DUMP_CLASS_FILES) { className = makeDumpableClassName(className); } - this.className = superName + "$" + className; + this.className = LF + "$" + className; this.sourceFile = "LambdaForm$" + className; this.lambdaForm = lambdaForm; this.invokerName = invokerName; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Jul 05 20:01:50 2017 +0200 @@ -188,7 +188,6 @@ static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, boolean strict, boolean monobox) { MethodType dstType = target.type(); - assert(dstType.parameterCount() == target.type().parameterCount()); if (srcType == dstType) return target; if (USE_LAMBDA_FORM_EDITOR) { @@ -265,6 +264,7 @@ static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType, boolean strict, boolean monobox) { + assert(target.type().parameterCount() == srcType.parameterCount()); // Calculate extra arguments (temporaries) required in the names array. Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox); final int INARG_COUNT = srcType.parameterCount(); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Jul 05 20:01:50 2017 +0200 @@ -2023,8 +2023,9 @@ */ public static MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) { + explicitCastArgumentsChecks(target, newType); + // use the asTypeCache when possible: MethodType oldType = target.type(); - // use the asTypeCache when possible: if (oldType == newType) return target; if (oldType.explicitCastEquivalentToAsType(newType)) { return target.asType(newType); @@ -2032,6 +2033,12 @@ return MethodHandleImpl.makePairwiseConvert(target, newType, false); } + private static void explicitCastArgumentsChecks(MethodHandle target, MethodType newType) { + if (target.type().parameterCount() != newType.parameterCount()) { + throw new WrongMethodTypeException("cannot explicitly cast " + target + " to " + newType); + } + } + /** * Produces a method handle which adapts the calling sequence of the * given method handle to a new type, by reordering the arguments. @@ -2164,7 +2171,7 @@ // dropIdx is missing from reorder; add it in at the end int oldArity = reorder.length; target = dropArguments(target, oldArity, newType.parameterType(dropIdx)); - reorder = Arrays.copyOf(reorder, oldArity+1); + reorder = Arrays.copyOf(reorder, oldArity + 1); reorder[oldArity] = dropIdx; } assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type())); @@ -2182,9 +2189,9 @@ long mask = 0; for (int arg : reorder) { assert(arg < newArity); - mask |= (1 << arg); + mask |= (1L << arg); } - if (mask == (1 << newArity) - 1) { + if (mask == (1L << newArity) - 1) { assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity); return -1; } @@ -2193,16 +2200,18 @@ int zeroPos = Long.numberOfTrailingZeros(zeroBit); assert(zeroPos < newArity); return zeroPos; + } else { + BitSet mask = new BitSet(newArity); + for (int arg : reorder) { + assert (arg < newArity); + mask.set(arg); + } + int zeroPos = mask.nextClearBit(0); + assert(zeroPos <= newArity); + if (zeroPos == newArity) + return -1; + return zeroPos; } - BitSet mask = new BitSet(newArity); - for (int arg : reorder) { - assert(arg < newArity); - mask.set(arg); - } - int zeroPos = mask.nextClearBit(0); - if (zeroPos == newArity) - return -1; - return zeroPos; } /** @@ -2218,32 +2227,42 @@ long mask = 0; for (int i = 0; i < reorder.length; i++) { int arg = reorder[i]; - if (arg >= newArity) return reorder.length; - int bit = 1 << arg; - if ((mask & bit) != 0) + if (arg >= newArity) { + return reorder.length; + } + long bit = 1L << arg; + if ((mask & bit) != 0) { return i; // >0 indicates a dup + } mask |= bit; } - if (mask == (1 << newArity) - 1) { + if (mask == (1L << newArity) - 1) { assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity); return 0; } // find first zero long zeroBit = Long.lowestOneBit(~mask); int zeroPos = Long.numberOfTrailingZeros(zeroBit); - assert(zeroPos < newArity); + assert(zeroPos <= newArity); + if (zeroPos == newArity) { + return 0; + } return ~zeroPos; } else { // same algorithm, different bit set BitSet mask = new BitSet(newArity); for (int i = 0; i < reorder.length; i++) { int arg = reorder[i]; - if (arg >= newArity) return reorder.length; - if (mask.get(arg)) + if (arg >= newArity) { + return reorder.length; + } + if (mask.get(arg)) { return i; // >0 indicates a dup + } mask.set(arg); } int zeroPos = mask.nextClearBit(0); + assert(zeroPos <= newArity); if (zeroPos == newArity) { return 0; } @@ -2479,6 +2498,7 @@ MethodHandle dropArguments(MethodHandle target, int pos, List> valueTypes) { MethodType oldType = target.type(); // get NPE int dropped = dropArgumentChecks(oldType, pos, valueTypes); + MethodType newType = oldType.insertParameterTypes(pos, valueTypes); if (dropped == 0) return target; BoundMethodHandle result = target.rebind(); LambdaForm lform = result.form; @@ -2490,7 +2510,6 @@ } else { lform = lform.addArguments(pos, valueTypes); } - MethodType newType = oldType.insertParameterTypes(pos, valueTypes); result = result.copyWith(newType, lform); return result; } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Jul 05 20:01:50 2017 +0200 @@ -869,9 +869,7 @@ if (dstTypes == srcTypes) { return true; } - if (dstTypes.length != srcTypes.length) { - return false; - } + assert(dstTypes.length == srcTypes.length); for (int i = 0; i < dstTypes.length; i++) { if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) { return false; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.base/share/classes/java/math/MutableBigInteger.java --- a/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java Wed Jul 05 20:01:50 2017 +0200 @@ -1261,19 +1261,20 @@ int sigma = (int) Math.max(0, n32 - b.bitLength()); // step 3: sigma = max{T | (2^T)*B < beta^n} MutableBigInteger bShifted = new MutableBigInteger(b); bShifted.safeLeftShift(sigma); // step 4a: shift b so its length is a multiple of n - safeLeftShift(sigma); // step 4b: shift this by the same amount + MutableBigInteger aShifted = new MutableBigInteger (this); + aShifted.safeLeftShift(sigma); // step 4b: shift a by the same amount - // step 5: t is the number of blocks needed to accommodate this plus one additional bit - int t = (int) ((bitLength()+n32) / n32); + // step 5: t is the number of blocks needed to accommodate a plus one additional bit + int t = (int) ((aShifted.bitLength()+n32) / n32); if (t < 2) { t = 2; } - // step 6: conceptually split this into blocks a[t-1], ..., a[0] - MutableBigInteger a1 = getBlock(t-1, t, n); // the most significant block of this + // step 6: conceptually split a into blocks a[t-1], ..., a[0] + MutableBigInteger a1 = aShifted.getBlock(t-1, t, n); // the most significant block of a // step 7: z[t-2] = [a[t-1], a[t-2]] - MutableBigInteger z = getBlock(t-2, t, n); // the second to most significant block + MutableBigInteger z = aShifted.getBlock(t-2, t, n); // the second to most significant block z.addDisjoint(a1, n); // z[t-2] // do schoolbook division on blocks, dividing 2-block numbers by 1-block numbers @@ -1284,7 +1285,7 @@ ri = z.divide2n1n(bShifted, qi); // step 8b: z = [ri, a[i-1]] - z = getBlock(i-1, t, n); // a[i-1] + z = aShifted.getBlock(i-1, t, n); // a[i-1] z.addDisjoint(ri, n); quotient.addShifted(qi, i*n); // update q (part of step 9) } @@ -1292,7 +1293,7 @@ ri = z.divide2n1n(bShifted, qi); quotient.add(qi); - ri.rightShift(sigma); // step 9: this and b were shifted, so shift back + ri.rightShift(sigma); // step 9: a and b were shifted, so shift back return ri; } } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.base/share/classes/java/util/zip/ZipInputStream.java --- a/jdk/src/java.base/share/classes/java/util/zip/ZipInputStream.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/util/zip/ZipInputStream.java Wed Jul 05 20:01:50 2017 +0200 @@ -336,8 +336,21 @@ return new ZipEntry(name); } - /* + /** * Reads end of deflated entry as well as EXT descriptor if present. + * + * Local headers for DEFLATED entries may optionally be followed by a + * data descriptor, and that data descriptor may optionally contain a + * leading signature (EXTSIG). + * + * From the zip spec http://www.pkware.com/documents/casestudies/APPNOTE.TXT + * + * """Although not originally assigned a signature, the value 0x08074b50 + * has commonly been adopted as a signature value for the data descriptor + * record. Implementers should be aware that ZIP files may be + * encountered with or without this signature marking data descriptors + * and should account for either case when reading ZIP files to ensure + * compatibility.""" */ private void readEnd(ZipEntry e) throws IOException { int n = inf.getRemaining(); @@ -356,7 +369,7 @@ e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC); e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC); ((PushbackInputStream)in).unread( - tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC - 1, ZIP64_EXTCRC); + tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC, ZIP64_EXTCRC); } else { e.crc = get32(tmpbuf, ZIP64_EXTCRC); e.csize = get64(tmpbuf, ZIP64_EXTSIZ); @@ -370,7 +383,7 @@ e.csize = get32(tmpbuf, EXTSIZ - EXTCRC); e.size = get32(tmpbuf, EXTLEN - EXTCRC); ((PushbackInputStream)in).unread( - tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC); + tmpbuf, EXTHDR - EXTCRC, EXTCRC); } else { e.crc = get32(tmpbuf, EXTCRC); e.csize = get32(tmpbuf, EXTSIZ); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c --- a/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Wed Jul 05 20:01:50 2017 +0200 @@ -34,6 +34,10 @@ #include #include #include +#if defined(__linux__) +#include +#include +#endif #include "nio.h" #include "nio_util.h" @@ -177,10 +181,21 @@ JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo) { + jint fd = fdval(env, fdo); struct stat64 fbuf; - if (fstat64(fdval(env, fdo), &fbuf) < 0) + if (fstat64(fd, &fbuf) < 0) return handle(env, -1, "Size failed"); + +#ifdef BLKGETSIZE64 + if (S_ISBLK(fbuf.st_mode)) { + uint64_t size; + if (ioctl(fd, BLKGETSIZE64, &size) < 0) + return handle(env, -1, "Size failed"); + return (jlong)size; + } +#endif + return fbuf.st_size; } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.base/windows/native/libnet/NetworkInterface.c --- a/jdk/src/java.base/windows/native/libnet/NetworkInterface.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.base/windows/native/libnet/NetworkInterface.c Wed Jul 05 20:01:50 2017 +0200 @@ -990,9 +990,11 @@ case MIB_IF_TYPE_FDDI: case IF_TYPE_IEEE80211: len = ifRowP->dwPhysAddrLen; - ret = (*env)->NewByteArray(env, len); - if (!IS_NULL(ret)) { - (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr); + if (len > 0) { + ret = (*env)->NewByteArray(env, len); + if (!IS_NULL(ret)) { + (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr); + } } break; } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/macosx/classes/sun/awt/datatransfer/flavormap.properties --- a/jdk/src/java.desktop/macosx/classes/sun/awt/datatransfer/flavormap.properties Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -# -# This properties file is used to initialize the default -# java.awt.datatransfer.SystemFlavorMap. It contains the Mac OS X platform-specific, -# default mappings between common Mac OS X selection atoms and platform-independent -# MIME type strings, which will be converted into -# java.awt.datatransfer.DataFlavors. -# -# The standard format is: -# -# =,, ... -# -# should be a string identifier that the native platform will -# recognize as a valid data format. should specify both a MIME -# primary type and a MIME subtype separated by a '/'. The MIME type may include -# parameters, where each parameter is a key/value pair separated by '=', and -# where each parameter to the MIME type is separated by a ';'. -# -# Because SystemFlavorMap implements FlavorTable, developers are free to -# duplicate DataFlavor values and set multiple values for a single native by -# separating them with ",". If a mapping contains a duplicate key or value, -# earlier mappings which included this key or value will be preferred. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", and which support the charset parameter, should specify the exact -# format in which the native platform expects the data. The "charset" -# parameter specifies the char to byte encoding, the "eoln" parameter -# specifies the end-of-line marker, and the "terminators" parameter specifies -# the number of terminating NUL bytes. Note that "eoln" and "terminators" -# are not standardized MIME type parameters. They are specific to this file -# format ONLY. They will not appear in any of the DataFlavors returned by the -# SystemFlavorMap at the Java level. -# -# If the "charset" parameter is omitted, or has zero length, the platform -# default encoding is assumed. If the "eoln" parameter is omitted, or has -# zero length, "\n" is assumed. If the "terminators" parameter is omitted, -# or has a value less than zero, zero is assumed. -# -# Upon initialization, the data transfer subsystem will record the specified -# details of the native text format, but the default SystemFlavorMap will -# present a large set of synthesized DataFlavors which map, in both -# directions, to the native. After receiving data from the application in one -# of the synthetic DataFlavors, the data transfer subsystem will transform -# the data stream into the format specified in this file before passing the -# transformed stream to the native system. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", but which do not support the charset parameter, will be treated as -# opaque, 8-bit data. They will not undergo any transformation process, and -# any "charset", "eoln", or "terminators" parameters specified in this file -# will be ignored. -# -# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of -# text flavors which support the charset parameter. - -UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 - -# The COMPOUND_TEXT support for inter-client text transfer is disabled by -# default. The reason is that many native applications prefer this format over -# other native text formats, but are unable to decode the textual data in this -# format properly. This results in java-to-native text transfer failures. -# To enable the COMPOUND_TEXT support for this JRE installation uncomment -# the line below. - -# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 - -TEXT=text/plain;eoln="\n";terminators=0 -STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 -FILE_NAME=application/x-java-file-list;class=java.util.List -text/uri-list=application/x-java-file-list;class=java.util.List -PNG=image/x-java-image;class=java.awt.Image -JFIF=image/x-java-image;class=java.awt.Image -TIFF=image/x-java-image;class=java.awt.Image -RICH_TEXT=text/rtf -HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1 -URL=application/x-java-url;class=java.net.URL,\ - text/uri-list;eoln="\r\n";terminators=1 diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/macosx/classes/sun/datatransfer/resources/flavormap.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.desktop/macosx/classes/sun/datatransfer/resources/flavormap.properties Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,76 @@ +# +# This properties file is used to initialize the default +# java.awt.datatransfer.SystemFlavorMap. It contains the Mac OS X platform-specific, +# default mappings between common Mac OS X selection atoms and platform-independent +# MIME type strings, which will be converted into +# java.awt.datatransfer.DataFlavors. +# +# The standard format is: +# +# =,, ... +# +# should be a string identifier that the native platform will +# recognize as a valid data format. should specify both a MIME +# primary type and a MIME subtype separated by a '/'. The MIME type may include +# parameters, where each parameter is a key/value pair separated by '=', and +# where each parameter to the MIME type is separated by a ';'. +# +# Because SystemFlavorMap implements FlavorTable, developers are free to +# duplicate DataFlavor values and set multiple values for a single native by +# separating them with ",". If a mapping contains a duplicate key or value, +# earlier mappings which included this key or value will be preferred. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", and which support the charset parameter, should specify the exact +# format in which the native platform expects the data. The "charset" +# parameter specifies the char to byte encoding, the "eoln" parameter +# specifies the end-of-line marker, and the "terminators" parameter specifies +# the number of terminating NUL bytes. Note that "eoln" and "terminators" +# are not standardized MIME type parameters. They are specific to this file +# format ONLY. They will not appear in any of the DataFlavors returned by the +# SystemFlavorMap at the Java level. +# +# If the "charset" parameter is omitted, or has zero length, the platform +# default encoding is assumed. If the "eoln" parameter is omitted, or has +# zero length, "\n" is assumed. If the "terminators" parameter is omitted, +# or has a value less than zero, zero is assumed. +# +# Upon initialization, the data transfer subsystem will record the specified +# details of the native text format, but the default SystemFlavorMap will +# present a large set of synthesized DataFlavors which map, in both +# directions, to the native. After receiving data from the application in one +# of the synthetic DataFlavors, the data transfer subsystem will transform +# the data stream into the format specified in this file before passing the +# transformed stream to the native system. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", but which do not support the charset parameter, will be treated as +# opaque, 8-bit data. They will not undergo any transformation process, and +# any "charset", "eoln", or "terminators" parameters specified in this file +# will be ignored. +# +# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of +# text flavors which support the charset parameter. + +UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 + +# The COMPOUND_TEXT support for inter-client text transfer is disabled by +# default. The reason is that many native applications prefer this format over +# other native text formats, but are unable to decode the textual data in this +# format properly. This results in java-to-native text transfer failures. +# To enable the COMPOUND_TEXT support for this JRE installation uncomment +# the line below. + +# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 + +TEXT=text/plain;eoln="\n";terminators=0 +STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 +FILE_NAME=application/x-java-file-list;class=java.util.List +text/uri-list=application/x-java-file-list;class=java.util.List +PNG=image/x-java-image;class=java.awt.Image +JFIF=image/x-java-image;class=java.awt.Image +TIFF=image/x-java-image;class=java.awt.Image +RICH_TEXT=text/rtf +HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1 +URL=application/x-java-url;class=java.net.URL,\ + text/uri-list;eoln="\r\n";terminators=1 diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java --- a/jdk/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java Wed Jul 05 20:01:50 2017 +0200 @@ -418,7 +418,8 @@ private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { s.defaultReadObject(); if (when == 0) { - when = getMostRecentEventTimeForSource(this.source); + // Can't use getMostRecentEventTimeForSource because source is always null during deserialization + when = EventQueue.getMostRecentEventTime(); } } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/classes/javax/swing/JDesktopPane.java --- a/jdk/src/java.desktop/share/classes/javax/swing/JDesktopPane.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/classes/javax/swing/JDesktopPane.java Wed Jul 05 20:01:50 2017 +0200 @@ -43,6 +43,7 @@ import java.beans.PropertyVetoException; import java.util.Set; import java.util.TreeSet; +import java.util.LinkedHashSet; /** * A container used to create a multiple-document interface or a virtual desktop. * You create JInternalFrame objects and add them to the @@ -271,7 +272,7 @@ private static Collection getAllFrames(Container parent) { int i, count; - Collection results = new ArrayList(); + Collection results = new LinkedHashSet<>(); count = parent.getComponentCount(); for (i = 0; i < count; i++) { Component next = parent.getComponent(i); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceDataProxy.java --- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceDataProxy.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceDataProxy.java Wed Jul 05 20:01:50 2017 +0200 @@ -65,7 +65,11 @@ int w, int h) { if (cachedData == null) { - cachedData = oglgc.createManagedSurface(w, h, transparency); + try { + cachedData = oglgc.createManagedSurface(w, h, transparency); + } catch (OutOfMemoryError er) { + return null; + } } return cachedData; } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c --- a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Wed Jul 05 20:01:50 2017 +0200 @@ -1082,86 +1082,60 @@ return 1; } -static void addToGP(GPData* gpdata, FT_Outline*outline) { - jbyte current_type=SEG_UNKNOWN; - int i, j; - jfloat x, y; +static void addSeg(GPData *gp, jbyte type) { + gp->pointTypes[gp->numTypes++] = type; +} + +static void addCoords(GPData *gp, FT_Vector *p) { + gp->pointCoords[gp->numCoords++] = F26Dot6ToFloat(p->x); + gp->pointCoords[gp->numCoords++] = -F26Dot6ToFloat(p->y); +} - j = 0; - for(i=0; in_points; i++) { - x = F26Dot6ToFloat(outline->points[i].x); - y = -F26Dot6ToFloat(outline->points[i].y); +static int moveTo(FT_Vector *to, GPData *gp) { + if (gp->numCoords) + addSeg(gp, SEG_CLOSE); + addCoords(gp, to); + addSeg(gp, SEG_MOVETO); + return FT_Err_Ok; +} + +static int lineTo(FT_Vector *to, GPData *gp) { + addCoords(gp, to); + addSeg(gp, SEG_LINETO); + return FT_Err_Ok; +} - if (FT_CURVE_TAG(outline->tags[i]) == FT_CURVE_TAG_ON) { - /* If bit 0 is unset, the point is "off" the curve, - i.e., a Bezier control point, while it is "on" when set. */ - if (current_type == SEG_UNKNOWN) { /* special case: - very first point */ - /* add segment */ - gpdata->pointTypes[gpdata->numTypes++] = SEG_MOVETO; - current_type = SEG_LINETO; - } else { - gpdata->pointTypes[gpdata->numTypes++] = current_type; - current_type = SEG_LINETO; - } - } else { - if (current_type == SEG_UNKNOWN) { /* special case: - very first point */ - if (FT_CURVE_TAG(outline->tags[i+1]) == FT_CURVE_TAG_ON) { - /* just skip first point. Adhoc heuristic? */ - continue; - } else { - x = (x + F26Dot6ToFloat(outline->points[i+1].x))/2; - y = (y - F26Dot6ToFloat(outline->points[i+1].y))/2; - gpdata->pointTypes[gpdata->numTypes++] = SEG_MOVETO; - current_type = SEG_LINETO; - } - } else if (FT_CURVE_TAG(outline->tags[i]) == FT_CURVE_TAG_CUBIC) { - /* Bit 1 is meaningful for 'off' points only. - If set, it indicates a third-order Bezier arc control - point; and a second-order control point if unset. */ - current_type = SEG_CUBICTO; - } else { - /* two successive conic "off" points forces the rasterizer - to create (during the scan-line conversion process - exclusively) a virtual "on" point amidst them, at their - exact middle. This greatly facilitates the definition of - successive conic Bezier arcs. Moreover, it is the way - outlines are described in the TrueType specification. */ - if (current_type == SEG_QUADTO) { - gpdata->pointCoords[gpdata->numCoords++] = - F26Dot6ToFloat(outline->points[i].x + - outline->points[i-1].x)/2; - gpdata->pointCoords[gpdata->numCoords++] = - - F26Dot6ToFloat(outline->points[i].y + - outline->points[i-1].y)/2; - gpdata->pointTypes[gpdata->numTypes++] = SEG_QUADTO; - } - current_type = SEG_QUADTO; - } - } - gpdata->pointCoords[gpdata->numCoords++] = x; - gpdata->pointCoords[gpdata->numCoords++] = y; - if (outline->contours[j] == i) { //end of contour - int start = j > 0 ? outline->contours[j-1]+1 : 0; - gpdata->pointTypes[gpdata->numTypes++] = current_type; - if (current_type == SEG_QUADTO && - FT_CURVE_TAG(outline->tags[start]) != FT_CURVE_TAG_ON) { - gpdata->pointCoords[gpdata->numCoords++] = - (F26Dot6ToFloat(outline->points[start].x) + x)/2; - gpdata->pointCoords[gpdata->numCoords++] = - (-F26Dot6ToFloat(outline->points[start].y) + y)/2; - } else { - gpdata->pointCoords[gpdata->numCoords++] = - F26Dot6ToFloat(outline->points[start].x); - gpdata->pointCoords[gpdata->numCoords++] = - -F26Dot6ToFloat(outline->points[start].y); - } - gpdata->pointTypes[gpdata->numTypes++] = SEG_CLOSE; - current_type = SEG_UNKNOWN; - j++; - } - } +static int conicTo(FT_Vector *control, FT_Vector *to, GPData *gp) { + addCoords(gp, control); + addCoords(gp, to); + addSeg(gp, SEG_QUADTO); + return FT_Err_Ok; +} + +static int cubicTo(FT_Vector *control1, + FT_Vector *control2, + FT_Vector *to, + GPData *gp) { + addCoords(gp, control1); + addCoords(gp, control2); + addCoords(gp, to); + addSeg(gp, SEG_CUBICTO); + return FT_Err_Ok; +} + +static void addToGP(GPData* gpdata, FT_Outline*outline) { + static const FT_Outline_Funcs outline_funcs = { + (FT_Outline_MoveToFunc) moveTo, + (FT_Outline_LineToFunc) lineTo, + (FT_Outline_ConicToFunc) conicTo, + (FT_Outline_CubicToFunc) cubicTo, + 0, /* shift */ + 0, /* delta */ + }; + + FT_Outline_Decompose(outline, &outline_funcs, gpdata); + if (gpdata->numCoords) + addSeg(gpdata, SEG_CLOSE); /* If set to 1, the outline will be filled using the even-odd fill rule */ if (outline->flags & FT_OUTLINE_EVEN_ODD_FILL) { diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmscam02.c --- a/jdk/src/java.desktop/share/native/liblcms/cmscam02.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmscam02.c Wed Jul 05 20:01:50 2017 +0200 @@ -467,11 +467,12 @@ CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - memset(&clr, 0, sizeof(clr)); _cmsAssert(lpMod != NULL); _cmsAssert(pIn != NULL); _cmsAssert(pOut != NULL); + memset(&clr, 0, sizeof(clr)); + clr.XYZ[0] = pIn ->X; clr.XYZ[1] = pIn ->Y; clr.XYZ[2] = pIn ->Z; @@ -492,11 +493,12 @@ CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; - memset(&clr, 0, sizeof(clr)); _cmsAssert(lpMod != NULL); _cmsAssert(pIn != NULL); _cmsAssert(pOut != NULL); + memset(&clr, 0, sizeof(clr)); + clr.J = pIn -> J; clr.C = pIn -> C; clr.h = pIn -> h; @@ -511,4 +513,3 @@ pOut ->Y = clr.XYZ[1]; pOut ->Z = clr.XYZ[2]; } - diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmscgats.c --- a/jdk/src/java.desktop/share/native/liblcms/cmscgats.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmscgats.c Wed Jul 05 20:01:50 2017 +0200 @@ -2179,9 +2179,9 @@ if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { - t -> SampleID = idField; - - for (i=0; i < t -> nPatches; i++) { + t -> SampleID = idField; + + for (i=0; i < t -> nPatches; i++) { char *Data = GetData(it8, i, idField); if (Data) { @@ -2196,7 +2196,7 @@ SetData(it8, i, idField, Buffer); } - } + } } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmscnvrt.c --- a/jdk/src/java.desktop/share/native/liblcms/cmscnvrt.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmscnvrt.c Wed Jul 05 20:01:50 2017 +0200 @@ -137,15 +137,68 @@ // A pointer to the begining of the list -static cmsIntentsList *Intents = DefaultIntents; +_cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL }; + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginIntentsList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsIntentsPluginChunkType newHead = { NULL }; + cmsIntentsList* entry; + cmsIntentsList* Anterior = NULL; + _cmsIntentsPluginChunkType* head = (_cmsIntentsPluginChunkType*) src->chunks[IntentPlugin]; + + // Walk the list copying all nodes + for (entry = head->Intents; + entry != NULL; + entry = entry ->Next) { + + cmsIntentsList *newEntry = ( cmsIntentsList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsIntentsList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Intents == NULL) + newHead.Intents = newEntry; + } + + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsIntentsPluginChunkType)); +} + +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginIntentsList(ctx, src); + } + else { + static _cmsIntentsPluginChunkType IntentsPluginChunkType = { NULL }; + ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx ->MemPool, &IntentsPluginChunkType, sizeof(_cmsIntentsPluginChunkType)); + } +} + // Search the list for a suitable intent. Returns NULL if not found static -cmsIntentsList* SearchIntent(cmsUInt32Number Intent) +cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; - for (pt = Intents; pt != NULL; pt = pt -> Next) + for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next) + if (pt ->Intent == Intent) return pt; + + for (pt = DefaultIntents; pt != NULL; pt = pt -> Next) if (pt ->Intent == Intent) return pt; return NULL; @@ -1031,7 +1084,7 @@ // this case would present some issues if the custom intent tries to do things like // preserve primaries. This solution is not perfect, but works well on most cases. - Intent = SearchIntent(TheIntents[0]); + Intent = SearchIntent(ContextID, TheIntents[0]); if (Intent == NULL) { cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]); return NULL; @@ -1046,12 +1099,14 @@ // Get information about available intents. nMax is the maximum space for the supplied "Codes" // and "Descriptions" the function returns the total number of intents, which may be greater // than nMax, although the matrices are not populated beyond this level. -cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin); cmsIntentsList* pt; cmsUInt32Number nIntents; - for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next) + + for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { if (Codes != NULL) @@ -1064,37 +1119,52 @@ nIntents++; } + for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) + { + if (nIntents < nMax) { + if (Codes != NULL) + Codes[nIntents] = pt ->Intent; + + if (Descriptions != NULL) + Descriptions[nIntents] = pt ->Description; + } + + nIntents++; + } return nIntents; } +cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions) +{ + return cmsGetSupportedIntentsTHR(NULL, nMax, Codes, Descriptions); +} + // The plug-in registration. User can add new intents or override default routines cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) { + _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin); cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; cmsIntentsList* fl; - // Do we have to reset the intents? + // Do we have to reset the custom intents? if (Data == NULL) { - Intents = DefaultIntents; - return TRUE; + ctx->Intents = NULL; + return TRUE; } - fl = SearchIntent(Plugin ->Intent); + fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); + if (fl == NULL) return FALSE; - if (fl == NULL) { - fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); - if (fl == NULL) return FALSE; - } fl ->Intent = Plugin ->Intent; - strncpy(fl ->Description, Plugin ->Description, 255); - fl ->Description[255] = 0; + strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1); + fl ->Description[sizeof(fl ->Description)-1] = 0; fl ->Link = Plugin ->Link; - fl ->Next = Intents; - Intents = fl; + fl ->Next = ctx ->Intents; + ctx ->Intents = fl; return TRUE; } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmserr.c --- a/jdk/src/java.desktop/share/native/liblcms/cmserr.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmserr.c Wed Jul 05 20:01:50 2017 +0200 @@ -60,13 +60,14 @@ // compare two strings ignoring case int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2) { - register const unsigned char *us1 = (const unsigned char *)s1, - *us2 = (const unsigned char *)s2; + register const unsigned char *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; - while (toupper(*us1) == toupper(*us2++)) - if (*us1++ == '\0') - return (0); - return (toupper(*us1) - toupper(*--us2)); + while (toupper(*us1) == toupper(*us2++)) + if (*us1++ == '\0') + return 0; + + return (toupper(*us1) - toupper(*--us2)); } // long int because C99 specifies ftell in such way (7.19.9.2) @@ -91,9 +92,8 @@ // // This is the interface to low-level memory management routines. By default a simple // wrapping to malloc/free/realloc is provided, although there is a limit on the max -// amount of memoy that can be reclaimed. This is mostly as a safety feature to -// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms -// would never need. +// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent +// bogus or evil code to allocate huge blocks that otherwise lcms would never need. #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) @@ -103,7 +103,7 @@ // required to be implemented: malloc, realloc and free, although the user may want to // replace the optional mallocZero, calloc and dup as well. -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // ********************************************************************************* @@ -143,7 +143,7 @@ cmsUNUSED_PARAMETER(ContextID); } -// The default realloc function. Again it check for exploits. If Ptr is NULL, +// The default realloc function. Again it checks for exploits. If Ptr is NULL, // realloc behaves the same way as malloc and allocates a new block of size bytes. static void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size) @@ -196,28 +196,73 @@ return mem; } -// Pointers to malloc and _cmsFree functions in current environment -static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocDefaultFn; -static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocZeroDefaultFn; -static void (* FreePtr)(cmsContext ContextID, void *Ptr) = _cmsFreeDefaultFn; -static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize) = _cmsReallocDefaultFn; -static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn; -static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size) = _cmsDupDefaultFn; + +// Pointers to memory manager functions in Context0 +_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, + _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn + }; + + +// Reset and duplicate memory manager +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate + ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); + } + else { + + // To reset it, we use the default allocators, which cannot be overriden + ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager; + } +} + +// Auxiliar to fill memory management functions from plugin (or context 0 defaults) +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) +{ + if (Plugin == NULL) { + + memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk)); + } + else { + + ptr ->MallocPtr = Plugin -> MallocPtr; + ptr ->FreePtr = Plugin -> FreePtr; + ptr ->ReallocPtr = Plugin -> ReallocPtr; + + // Make sure we revert to defaults + ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; + ptr ->CallocPtr = _cmsCallocDefaultFn; + ptr ->DupPtr = _cmsDupDefaultFn; + + if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; + if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; + if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; + + } +} + // Plug-in replacement entry -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data) +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) { cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; + _cmsMemPluginChunkType* ptr; - // NULL forces to reset to defaults + // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. + // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the + // context internal data should be malloce'd by using those functions. if (Data == NULL) { - MallocPtr = _cmsMallocDefaultFn; - MallocZeroPtr= _cmsMallocZeroDefaultFn; - FreePtr = _cmsFreeDefaultFn; - ReallocPtr = _cmsReallocDefaultFn; - CallocPtr = _cmsCallocDefaultFn; - DupPtr = _cmsDupDefaultFn; + struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; + + // Return to the default allocators + if (ContextID != NULL) { + ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; + } return TRUE; } @@ -227,51 +272,56 @@ Plugin -> ReallocPtr == NULL) return FALSE; // Set replacement functions - MallocPtr = Plugin -> MallocPtr; - FreePtr = Plugin -> FreePtr; - ReallocPtr = Plugin -> ReallocPtr; + ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + if (ptr == NULL) + return FALSE; - if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr; - if (Plugin ->CallocPtr != NULL) CallocPtr = Plugin -> CallocPtr; - if (Plugin ->DupPtr != NULL) DupPtr = Plugin -> DupPtr; - + _cmsInstallAllocFunctions(Plugin, ptr); return TRUE; } // Generic allocate void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) { - return MallocPtr(ContextID, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->MallocPtr(ContextID, size); } // Generic allocate & zero void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) { - return MallocZeroPtr(ContextID, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->MallocZeroPtr(ContextID, size); } // Generic calloc void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) { - return CallocPtr(ContextID, num, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->CallocPtr(ContextID, num, size); } // Generic reallocate void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) { - return ReallocPtr(ContextID, Ptr, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr->ReallocPtr(ContextID, Ptr, size); } // Generic free memory void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) { - if (Ptr != NULL) FreePtr(ContextID, Ptr); + if (Ptr != NULL) { + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + ptr ->FreePtr(ContextID, Ptr); + } } // Generic block duplication void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) { - return DupPtr(ContextID, Org, size); + _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); + return ptr ->DupPtr(ContextID, Org, size); } // ******************************************************************************************** @@ -380,6 +430,26 @@ return (void*) ptr; } +// Duplicate in pool +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size) +{ + void *NewPtr; + + // Dup of null pointer is also NULL + if (ptr == NULL) + return NULL; + + NewPtr = _cmsSubAlloc(s, size); + + if (ptr != NULL && NewPtr != NULL) { + memcpy(NewPtr, ptr, size); + } + + return NewPtr; +} + + + // Error logging ****************************************************************** // There is no error handling at all. When a funtion fails, it returns proper value. @@ -401,8 +471,26 @@ // This is our default log error static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); -// The current handler in actual environment -static cmsLogErrorHandlerFunction LogErrorHandler = DefaultLogErrorHandlerFunction; +// Context0 storage, which is global +_cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction }; + +// Allocates and inits error logger container for a given context. If src is NULL, only initializes the value +// to the default. Otherwise, it duplicates the value. The interface is standard across all context clients +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction }; + void* from; + + if (src != NULL) { + from = src ->chunks[Logger]; + } + else { + from = &LogErrorChunk; + } + + ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); +} // The default error logger does nothing. static @@ -416,13 +504,24 @@ cmsUNUSED_PARAMETER(Text); } -// Change log error +// Change log error, context based +void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn) +{ + _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + + if (lhg != NULL) { + + if (Fn == NULL) + lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction; + else + lhg -> LogErrorHandler = Fn; + } +} + +// Change log error, legacy void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn) { - if (Fn == NULL) - LogErrorHandler = DefaultLogErrorHandlerFunction; - else - LogErrorHandler = Fn; + cmsSetLogErrorHandlerTHR(NULL, Fn); } // Log an error @@ -431,13 +530,18 @@ { va_list args; char Buffer[MAX_ERROR_MESSAGE_LEN]; + _cmsLogErrorChunkType* lhg; + va_start(args, ErrorText); vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); va_end(args); - // Call handler - LogErrorHandler(ContextID, ErrorCode, Buffer); + // Check for the context, if specified go there. If not, go for the global + lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); + if (lhg ->LogErrorHandler) { + lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); + } } // Utility function to print signatures @@ -455,3 +559,125 @@ String[4] = 0; } +//-------------------------------------------------------------------------------------------------- + + +static +void* defMtxCreate(cmsContext id) +{ + _cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex)); + _cmsInitMutexPrimitive(ptr_mutex); + return (void*) ptr_mutex; +} + +static +void defMtxDestroy(cmsContext id, void* mtx) +{ + _cmsDestroyMutexPrimitive((_cmsMutex *) mtx); + _cmsFree(id, mtx); +} + +static +cmsBool defMtxLock(cmsContext id, void* mtx) +{ + cmsUNUSED_PARAMETER(id); + return _cmsLockPrimitive((_cmsMutex *) mtx) == 0; +} + +static +void defMtxUnlock(cmsContext id, void* mtx) +{ + cmsUNUSED_PARAMETER(id); + _cmsUnlockPrimitive((_cmsMutex *) mtx); +} + + + +// Pointers to memory manager functions in Context0 +_cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; + void* from; + + if (src != NULL) { + from = src ->chunks[MutexPlugin]; + } + else { + from = &MutexChunk; + } + + ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); +} + +// Register new ways to transform +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) +{ + cmsPluginMutex* Plugin = (cmsPluginMutex*) Data; + _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (Data == NULL) { + + // No lock routines + ctx->CreateMutexPtr = NULL; + ctx->DestroyMutexPtr = NULL; + ctx->LockMutexPtr = NULL; + ctx ->UnlockMutexPtr = NULL; + return TRUE; + } + + // Factory callback is required + if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || + Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; + + + ctx->CreateMutexPtr = Plugin->CreateMutexPtr; + ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr; + ctx ->LockMutexPtr = Plugin ->LockMutexPtr; + ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr; + + // All is ok + return TRUE; +} + +// Generic Mutex fns +void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->CreateMutexPtr == NULL) return NULL; + + return ptr ->CreateMutexPtr(ContextID); +} + +void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->DestroyMutexPtr != NULL) { + + ptr ->DestroyMutexPtr(ContextID, mtx); + } +} + +cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->LockMutexPtr == NULL) return TRUE; + + return ptr ->LockMutexPtr(ContextID, mtx); +} + +void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) +{ + _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); + + if (ptr ->UnlockMutexPtr != NULL) { + + ptr ->UnlockMutexPtr(ContextID, mtx); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsgamma.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsgamma.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsgamma.c Wed Jul 05 20:01:50 2017 +0200 @@ -82,7 +82,6 @@ } _cmsParametricCurvesCollection; - // This is the default (built-in) evaluator static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R); @@ -95,22 +94,77 @@ NULL // Next in chain }; +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginCurvesList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsCurvesPluginChunkType newHead = { NULL }; + _cmsParametricCurvesCollection* entry; + _cmsParametricCurvesCollection* Anterior = NULL; + _cmsCurvesPluginChunkType* head = (_cmsCurvesPluginChunkType*) src->chunks[CurvesPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->ParametricCurves; + entry != NULL; + entry = entry ->Next) { + + _cmsParametricCurvesCollection *newEntry = ( _cmsParametricCurvesCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsParametricCurvesCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.ParametricCurves == NULL) + newHead.ParametricCurves = newEntry; + } + + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsCurvesPluginChunkType)); +} + +// The allocator have to follow the chain +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Copy all linked list + DupPluginCurvesList(ctx, src); + } + else { + static _cmsCurvesPluginChunkType CurvesPluginChunk = { NULL }; + ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx ->MemPool, &CurvesPluginChunk, sizeof(_cmsCurvesPluginChunkType)); + } +} + + // The linked list head -static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves; +_cmsCurvesPluginChunkType _cmsCurvesPluginChunk = { NULL }; // As a way to install new parametric curves -cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Data) { + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data; _cmsParametricCurvesCollection* fl; if (Data == NULL) { - ParametricCurves = &DefaultCurves; + ctx -> ParametricCurves = NULL; return TRUE; } - fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(id, sizeof(_cmsParametricCurvesCollection)); + fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsParametricCurvesCollection)); if (fl == NULL) return FALSE; // Copy the parameters @@ -126,8 +180,8 @@ memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number)); // Keep linked list - fl ->Next = ParametricCurves; - ParametricCurves = fl; + fl ->Next = ctx->ParametricCurves; + ctx->ParametricCurves = fl; // All is ok return TRUE; @@ -149,12 +203,24 @@ // Search for the collection which contains a specific type static -_cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index) +_cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, int Type, int* index) { _cmsParametricCurvesCollection* c; int Position; + _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin); - for (c = ParametricCurves; c != NULL; c = c ->Next) { + for (c = ctx->ParametricCurves; c != NULL; c = c ->Next) { + + Position = IsInSet(Type, c); + + if (Position != -1) { + if (index != NULL) + *index = Position; + return c; + } + } + // If none found, revert for defaults + for (c = &DefaultCurves; c != NULL; c = c ->Next) { Position = IsInSet(Type, c); @@ -251,7 +317,7 @@ p ->Segments[i].SampledPoints = NULL; - c = GetParametricCurveByType(Segments[i].Type, NULL); + c = GetParametricCurveByType(ContextID, Segments[i].Type, NULL); if (c != NULL) p ->Evals[i] = c ->Evaluator; } @@ -677,12 +743,12 @@ cmsCurveSegment Seg0; int Pos = 0; cmsUInt32Number size; - _cmsParametricCurvesCollection* c = GetParametricCurveByType(Type, &Pos); + _cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos); _cmsAssert(Params != NULL); if (c == NULL) { - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type); return NULL; } @@ -872,7 +938,10 @@ _cmsAssert(InCurve != NULL); // Try to reverse it analytically whatever possible - if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) { + + if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && + /* InCurve -> Segments[0].Type <= 5 */ + GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) { return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID, -(InCurve -> Segments[0].Type), diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsgmt.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsgmt.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsgmt.c Wed Jul 05 20:01:50 2017 +0200 @@ -191,7 +191,7 @@ out = ComputeKToLstar(ContextID, nPoints, 1, Intents + (nProfiles - 1), - hProfiles + (nProfiles - 1), + &hProfiles [nProfiles - 1], BPC + (nProfiles - 1), AdaptationStates + (nProfiles - 1), dwFlags); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsintrp.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c Wed Jul 05 20:01:50 2017 +0200 @@ -62,31 +62,57 @@ static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags); // This is the default factory -static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory; +_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL }; + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) +{ + void* from; + + _cmsAssert(ctx != NULL); + + if (src != NULL) { + from = src ->chunks[InterpPlugin]; + } + else { + static _cmsInterpPluginChunkType InterpPluginChunk = { NULL }; + + from = &InterpPluginChunk; + } + + _cmsAssert(from != NULL); + ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType)); +} // Main plug-in entry -cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data; + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); if (Data == NULL) { - Interpolators = DefaultInterpolatorsFactory; + ptr ->Interpolators = NULL; return TRUE; } // Set replacement functions - Interpolators = Plugin ->InterpolatorsFactory; + ptr ->Interpolators = Plugin ->InterpolatorsFactory; return TRUE; } // Set the interpolation method -cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p) { - // Invoke factory, possibly in the Plug-in - p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); + _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin); + + p ->Interpolation.Lerp16 = NULL; + + // Invoke factory, possibly in the Plug-in + if (ptr ->Interpolators != NULL) + p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags); // If unsupported by the plug-in, go for the LittleCMS default. // If happens only if an extern plug-in is being used @@ -97,6 +123,7 @@ if (p ->Interpolation.Lerp16 == NULL) { return FALSE; } + return TRUE; } @@ -141,7 +168,7 @@ p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i]; - if (!_cmsSetInterpolationRoutine(p)) { + if (!_cmsSetInterpolationRoutine(ContextID, p)) { cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan); _cmsFree(ContextID, p); return NULL; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsio0.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsio0.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsio0.c Wed Jul 05 20:01:50 2017 +0200 @@ -229,15 +229,14 @@ if (ResData == NULL) return FALSE; // Housekeeping // Check for available space. Clip. - if (iohandler ->UsedSpace + size > ResData->Size) { - size = ResData ->Size - iohandler ->UsedSpace; + if (ResData->Pointer + size > ResData->Size) { + size = ResData ->Size - ResData->Pointer; } if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing memmove(ResData ->Block + ResData ->Pointer, Ptr, size); ResData ->Pointer += size; - iohandler->UsedSpace += size; if (ResData ->Pointer > iohandler->UsedSpace) iohandler->UsedSpace = ResData ->Pointer; @@ -371,7 +370,7 @@ static cmsUInt32Number FileTell(cmsIOHANDLER* iohandler) { - return ftell((FILE*)iohandler ->stream); + return (cmsUInt32Number) ftell((FILE*)iohandler ->stream); } // Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error @@ -414,7 +413,7 @@ cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName); return NULL; } - iohandler -> ReportedSize = cmsfilelength(fm); + iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm); break; case 'w': @@ -461,7 +460,7 @@ iohandler -> ContextID = ContextID; iohandler -> stream = (void*) Stream; iohandler -> UsedSpace = 0; - iohandler -> ReportedSize = cmsfilelength(Stream); + iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream); iohandler -> PhysicalFile[0] = 0; iohandler ->Read = FileRead; @@ -501,6 +500,9 @@ // Set creation date/time memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); + // Create a mutex if the user provided proper plugin. NULL otherwise + Icc ->UsrMutex = _cmsCreateMutex(ContextID); + // Return the handle return (cmsHPROFILE) Icc; } @@ -579,9 +581,39 @@ return n; } +// Deletes a tag entry -// Create a new tag entry +static +void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i) +{ + _cmsAssert(Icc != NULL); + _cmsAssert(i >= 0); + + + if (Icc -> TagPtrs[i] != NULL) { + + // Free previous version + if (Icc ->TagSaveAsRaw[i]) { + _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); + } + else { + cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; + if (TypeHandler != NULL) { + + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); + Icc ->TagPtrs[i] = NULL; + } + } + + } +} + + +// Creates a new tag entry static cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos) { @@ -589,15 +621,15 @@ // Search for the tag i = _cmsSearchTag(Icc, sig, FALSE); + if (i >= 0) { - // Now let's do it easy. If the tag has been already written, that's an error - if (i >= 0) { - cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig); - return FALSE; + // Already exists? delete it + _cmsDeleteTagByPos(Icc, i); + *NewPos = i; } else { - // New one + // No, make a new one if (Icc -> TagCount >= MAX_TABLE_TAG) { cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); @@ -979,7 +1011,7 @@ // 4.2 -> 0x4200000 - Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16; + Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16; } cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile) @@ -1011,6 +1043,32 @@ return NULL; } +// Create profile from IOhandler +cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write) +{ + _cmsICCPROFILE* NewIcc; + cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID); + + if (hEmpty == NULL) return NULL; + + NewIcc = (_cmsICCPROFILE*) hEmpty; + + NewIcc ->IOhandler = io; + if (write) { + + NewIcc -> IsWrite = TRUE; + return hEmpty; + } + + if (!_cmsReadHeader(NewIcc)) goto Error; + return hEmpty; + +Error: + cmsCloseProfile(hEmpty); + return NULL; +} + + // Create profile from disk file cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess) { @@ -1202,7 +1260,7 @@ else { // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]); if (TagDescriptor == NULL) continue; // Unsupported, ignore it if (TagDescriptor ->DecideType != NULL) { @@ -1214,7 +1272,7 @@ Type = TagDescriptor ->SupportedTypes[0]; } - TypeHandler = _cmsGetTagTypeHandler(Type); + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); @@ -1282,10 +1340,12 @@ { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; _cmsICCPROFILE Keep; - cmsIOHANDLER* PrevIO; + cmsIOHANDLER* PrevIO = NULL; cmsUInt32Number UsedSpace; cmsContext ContextID; + _cmsAssert(hProfile != NULL); + memmove(&Keep, Icc, sizeof(_cmsICCPROFILE)); ContextID = cmsGetProfileContextID(hProfile); @@ -1294,18 +1354,19 @@ // Pass #1 does compute offsets - if (!_cmsWriteHeader(Icc, 0)) return 0; - if (!SaveTags(Icc, &Keep)) return 0; + if (!_cmsWriteHeader(Icc, 0)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; UsedSpace = PrevIO ->UsedSpace; // Pass #2 does save to iohandler if (io != NULL) { + Icc ->IOhandler = io; - if (!SetLinks(Icc)) goto CleanUp; - if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp; - if (!SaveTags(Icc, &Keep)) goto CleanUp; + if (!SetLinks(Icc)) goto Error; + if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error; + if (!SaveTags(Icc, &Keep)) goto Error; } memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); @@ -1314,7 +1375,7 @@ return UsedSpace; -CleanUp: +Error: cmsCloseIOhandler(PrevIO); memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); return 0; @@ -1362,11 +1423,13 @@ cmsIOHANDLER* io; cmsContext ContextID = cmsGetProfileContextID(hProfile); + _cmsAssert(BytesNeeded != NULL); + // Should we just calculate the needed space? if (MemPtr == NULL) { *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); - return (*BytesNeeded == 0 ? FALSE : TRUE); + return (*BytesNeeded == 0) ? FALSE : TRUE; } // That is a real write operation @@ -1419,6 +1482,8 @@ rc &= cmsCloseIOhandler(Icc->IOhandler); } + _cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex); + _cmsFree(Icc ->ContextID, Icc); // Free placeholder memory return rc; @@ -1459,14 +1524,18 @@ cmsUInt32Number ElemCount; int n; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL; + n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) return NULL; // Not found, return NULL + if (n < 0) goto Error; // Not found, return NULL // If the element is already in memory, return the pointer if (Icc -> TagPtrs[n]) { - if (Icc ->TagSaveAsRaw[n]) return NULL; // We don't support read raw tags as cooked + if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc -> TagPtrs[n]; } @@ -1476,23 +1545,32 @@ // Seek to its location if (!io -> Seek(io, Offset)) - return NULL; + goto Error; // Search for support on this tag - TagDescriptor = _cmsGetTagDescriptor(sig); - if (TagDescriptor == NULL) return NULL; // Unsupported. + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); + if (TagDescriptor == NULL) { + + char String[5]; + + _cmsTagSignature2String(String, sig); + + // An unknown element was found. + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String); + goto Error; // Unsupported. + } // if supported, get type and check if in list BaseType = _cmsReadTypeBase(io); - if (BaseType == 0) return NULL; + if (BaseType == 0) goto Error; - if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL; + if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error; TagSize -= 8; // Alredy read by the type base logic // Get type handler - TypeHandler = _cmsGetTagTypeHandler(BaseType); - if (TypeHandler == NULL) return NULL; + TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType); + if (TypeHandler == NULL) goto Error; LocalTypeHandler = *TypeHandler; @@ -1511,7 +1589,7 @@ _cmsTagSignature2String(String, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String); - return NULL; + goto Error; } // This is a weird error that may be a symptom of something more serious, the number of @@ -1527,7 +1605,14 @@ // Return the data + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc -> TagPtrs[n]; + + + // Return error and unlock tha data +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return NULL; } @@ -1561,49 +1646,26 @@ cmsFloat64Number Version; char TypeString[5], SigString[5]; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + // To delete tags. if (data == NULL) { + // Delete the tag i = _cmsSearchTag(Icc, sig, FALSE); - if (i >= 0) + if (i >= 0) { + + // Use zero as a mark of deleted + _cmsDeleteTagByPos(Icc, i); Icc ->TagNames[i] = (cmsTagSignature) 0; - // Unsupported by now, reserved for future ampliations (delete) - return FALSE; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return TRUE; + } + // Didn't find the tag + goto Error; } - i = _cmsSearchTag(Icc, sig, FALSE); - if (i >=0) { - - if (Icc -> TagPtrs[i] != NULL) { - - // Already exists. Free previous version - if (Icc ->TagSaveAsRaw[i]) { - _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); - } - else { - TypeHandler = Icc ->TagTypeHandlers[i]; - - if (TypeHandler != NULL) { - - LocalTypeHandler = *TypeHandler; - LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter - LocalTypeHandler.ICCVersion = Icc ->Version; - LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); - } - } - } - } - else { - // New one - i = Icc -> TagCount; - - if (i >= MAX_TABLE_TAG) { - cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG); - return FALSE; - } - - Icc -> TagCount++; - } + if (!_cmsNewTag(Icc, sig, &i)) goto Error; // This is not raw Icc ->TagSaveAsRaw[i] = FALSE; @@ -1612,10 +1674,10 @@ Icc ->TagLinked[i] = (cmsTagSignature) 0; // Get information about the TAG. - TagDescriptor = _cmsGetTagDescriptor(sig); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); if (TagDescriptor == NULL){ cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig); - return FALSE; + goto Error; } @@ -1633,7 +1695,6 @@ } else { - Type = TagDescriptor ->SupportedTypes[0]; } @@ -1644,18 +1705,18 @@ _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; + goto Error; } // Does we have a handler for this type? - TypeHandler = _cmsGetTagTypeHandler(Type); + TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type); if (TypeHandler == NULL) { _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); - return FALSE; // Should never happen + goto Error; // Should never happen } @@ -1668,7 +1729,7 @@ LocalTypeHandler = *TypeHandler; LocalTypeHandler.ContextID = Icc ->ContextID; LocalTypeHandler.ICCVersion = Icc ->Version; - Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); + Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); if (Icc ->TagPtrs[i] == NULL) { @@ -1676,10 +1737,16 @@ _cmsTagSignature2String(SigString, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString); - return FALSE; + goto Error; } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Read and write raw data. The only way those function would work and keep consistence with normal read and write @@ -1700,9 +1767,11 @@ cmsUInt32Number rc; cmsUInt32Number Offset, TagSize; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + // Search for given tag in ICC profile directory i = _cmsSearchTag(Icc, sig, TRUE); - if (i < 0) return 0; // Not found, return 0 + if (i < 0) goto Error; // Not found, // It is already read? if (Icc -> TagPtrs[i] == NULL) { @@ -1717,12 +1786,14 @@ if (BufferSize < TagSize) TagSize = BufferSize; - if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0; - if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0; + if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error; + if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TagSize; } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } @@ -1738,16 +1809,22 @@ memmove(data, Icc ->TagPtrs[i], TagSize); + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TagSize; } + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return Icc ->TagSizes[i]; } // Already readed, or previously set by cmsWriteTag(). We need to serialize that // data to raw in order to maintain consistency. + + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); Object = cmsReadTag(hProfile, sig); - if (Object == NULL) return 0; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (Object == NULL) goto Error; // Now we need to serialize to a memory block: just use a memory iohandler @@ -1756,17 +1833,18 @@ } else{ MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); } - if (MemIO == NULL) return 0; + if (MemIO == NULL) goto Error; // Obtain type handling for the tag TypeHandler = Icc ->TagTypeHandlers[i]; - TagDescriptor = _cmsGetTagDescriptor(sig); + TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig); if (TagDescriptor == NULL) { cmsCloseIOhandler(MemIO); - return 0; + goto Error; } - // FIXME: No handling for TypeHandler == NULL here? + if (TypeHandler == NULL) goto Error; + // Serialize LocalTypeHandler = *TypeHandler; LocalTypeHandler.ContextID = Icc ->ContextID; @@ -1774,19 +1852,24 @@ if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { cmsCloseIOhandler(MemIO); - return 0; + goto Error; } if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { cmsCloseIOhandler(MemIO); - return 0; + goto Error; } // Get Size and close rc = MemIO ->Tell(MemIO); cmsCloseIOhandler(MemIO); // Ignore return code this time + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return rc; + +Error: + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return 0; } // Similar to the anterior. This function allows to write directly to the ICC profile any data, without @@ -1798,7 +1881,12 @@ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Mark the tag as being written as RAW Icc ->TagSaveAsRaw[i] = TRUE; @@ -1809,6 +1897,7 @@ Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size); Icc ->TagSizes[i] = Size; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } @@ -1818,7 +1907,12 @@ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; - if (!_cmsNewTag(Icc, sig, &i)) return FALSE; + if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE; + + if (!_cmsNewTag(Icc, sig, &i)) { + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); + return FALSE; + } // Keep necessary information Icc ->TagSaveAsRaw[i] = FALSE; @@ -1829,6 +1923,7 @@ Icc ->TagSizes[i] = 0; Icc ->TagOffsets[i] = 0; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return TRUE; } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsio1.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsio1.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsio1.c Wed Jul 05 20:01:50 2017 +0200 @@ -334,7 +334,8 @@ // Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc -// is adjusted here in order to create a LUT that takes care of all those details +// is adjusted here in order to create a LUT that takes care of all those details. +// We add intent = -1 as a way to read matrix shaper always, no matter of other LUT cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) { cmsTagTypeSignature OriginalType; @@ -364,49 +365,54 @@ return Lut; } - if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + // This is an attempt to reuse this funtion to retrieve the matrix-shaper as pipeline no + // matter other LUT are present and have precedence. Intent = -1 means just this. + if (Intent != -1) { - // Floating point LUT are always V4, but the encoding range is no - // longer 0..1.0, so we need to add an stage depending on the color space - return _cmsReadFloatInputTag(hProfile, tagFloat); - } + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + // Floating point LUT are always V4, but the encoding range is no + // longer 0..1.0, so we need to add an stage depending on the color space + return _cmsReadFloatInputTag(hProfile, tagFloat); + } - // Revert to perceptual if no tag is found - if (!cmsIsTag(hProfile, tag16)) { - tag16 = Device2PCS16[0]; - } + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = Device2PCS16[0]; + } - if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - // Check profile version and LUT type. Do the necessary adjustments if needed + // Check profile version and LUT type. Do the necessary adjustments if needed - // First read the tag - cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); - if (Lut == NULL) return NULL; + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; - // After reading it, we have now info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); + // After reading it, we have now info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); - // The profile owns the Lut, so we need to copy it - Lut = cmsPipelineDup(Lut); + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); - // We need to adjust data only for Lab16 on output - if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) - return Lut; + // We need to adjust data only for Lab16 on output + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; - // If the input is Lab, add also a conversion at the begin - if (cmsGetColorSpace(hProfile) == cmsSigLabData && - !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) - goto Error; + // If the input is Lab, add also a conversion at the begin + if (cmsGetColorSpace(hProfile) == cmsSigLabData && + !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; - // Add a matrix for conversion V2 to V4 Lab PCS - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) - goto Error; + // Add a matrix for conversion V2 to V4 Lab PCS + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; - return Lut; + return Lut; Error: - cmsPipelineFree(Lut); - return NULL; + cmsPipelineFree(Lut); + return NULL; + } } // Lut was not found, try to create a matrix-shaper @@ -551,7 +557,7 @@ _cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data; CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR; - _cmsSetInterpolationRoutine(CLUT ->Params); + _cmsSetInterpolationRoutine(Lut->ContextID, CLUT ->Params); } } } @@ -609,54 +615,58 @@ cmsTagSignature tagFloat = PCS2DeviceFloat[Intent]; cmsContext ContextID = cmsGetProfileContextID(hProfile); - if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + if (Intent != -1) { - // Floating point LUT are always V4 - return _cmsReadFloatOutputTag(hProfile, tagFloat); - } + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence + + // Floating point LUT are always V4 + return _cmsReadFloatOutputTag(hProfile, tagFloat); + } - // Revert to perceptual if no tag is found - if (!cmsIsTag(hProfile, tag16)) { - tag16 = PCS2Device16[0]; - } + // Revert to perceptual if no tag is found + if (!cmsIsTag(hProfile, tag16)) { + tag16 = PCS2Device16[0]; + } - if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - - // Check profile version and LUT type. Do the necessary adjustments if needed + if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table? - // First read the tag - cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); - if (Lut == NULL) return NULL; + // Check profile version and LUT type. Do the necessary adjustments if needed - // After reading it, we have info about the original type - OriginalType = _cmsGetTagTrueType(hProfile, tag16); + // First read the tag + cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16); + if (Lut == NULL) return NULL; - // The profile owns the Lut, so we need to copy it - Lut = cmsPipelineDup(Lut); - if (Lut == NULL) return NULL; + // After reading it, we have info about the original type + OriginalType = _cmsGetTagTrueType(hProfile, tag16); - // Now it is time for a controversial stuff. I found that for 3D LUTS using - // Lab used as indexer space, trilinear interpolation should be used - if (cmsGetPCS(hProfile) == cmsSigLabData) - ChangeInterpolationToTrilinear(Lut); + // The profile owns the Lut, so we need to copy it + Lut = cmsPipelineDup(Lut); + if (Lut == NULL) return NULL; - // We need to adjust data only for Lab and Lut16 type - if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) - return Lut; + // Now it is time for a controversial stuff. I found that for 3D LUTS using + // Lab used as indexer space, trilinear interpolation should be used + if (cmsGetPCS(hProfile) == cmsSigLabData) + ChangeInterpolationToTrilinear(Lut); - // Add a matrix for conversion V4 to V2 Lab PCS - if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) - goto Error; + // We need to adjust data only for Lab and Lut16 type + if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) + return Lut; - // If the output is Lab, add also a conversion at the end - if (cmsGetColorSpace(hProfile) == cmsSigLabData) - if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + // Add a matrix for conversion V4 to V2 Lab PCS + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) goto Error; - return Lut; + // If the output is Lab, add also a conversion at the end + if (cmsGetColorSpace(hProfile) == cmsSigLabData) + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; + + return Lut; Error: - cmsPipelineFree(Lut); - return NULL; + cmsPipelineFree(Lut); + return NULL; + } } // Lut not found, try to create a matrix-shaper @@ -782,7 +792,7 @@ // Now it is time for a controversial stuff. I found that for 3D LUTS using // Lab used as indexer space, trilinear interpolation should be used - if (cmsGetColorSpace(hProfile) == cmsSigLabData) + if (cmsGetPCS(hProfile) == cmsSigLabData) ChangeInterpolationToTrilinear(Lut); // After reading it, we have info about the original type @@ -793,12 +803,12 @@ // Here it is possible to get Lab on both sides - if (cmsGetPCS(hProfile) == cmsSigLabData) { + if (cmsGetColorSpace(hProfile) == cmsSigLabData) { if(!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) goto Error2; } - if (cmsGetColorSpace(hProfile) == cmsSigLabData) { + if (cmsGetPCS(hProfile) == cmsSigLabData) { if(!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) goto Error2; } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsopt.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsopt.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsopt.c Wed Jul 05 20:01:50 2017 +0200 @@ -542,11 +542,13 @@ cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]); if (InversePostLin == NULL) { - WhiteOut[i] = 0; - continue; + WhiteOut[i] = WhitePointOut[i]; + + } else { + + WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); + cmsFreeToneCurve(InversePostLin); } - WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]); - cmsFreeToneCurve(InversePostLin); } } else { @@ -1666,44 +1668,102 @@ }; // The linked list head -static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization; +_cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginOptimizationList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsOptimizationPluginChunkType newHead = { NULL }; + _cmsOptimizationCollection* entry; + _cmsOptimizationCollection* Anterior = NULL; + _cmsOptimizationPluginChunkType* head = (_cmsOptimizationPluginChunkType*) src->chunks[OptimizationPlugin]; + + _cmsAssert(ctx != NULL); + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->OptimizationCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsOptimizationCollection *newEntry = ( _cmsOptimizationCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsOptimizationCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.OptimizationCollection == NULL) + newHead.OptimizationCollection = newEntry; + } + + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsOptimizationPluginChunkType)); +} + +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginOptimizationList(ctx, src); + } + else { + static _cmsOptimizationPluginChunkType OptimizationPluginChunkType = { NULL }; + ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx ->MemPool, &OptimizationPluginChunkType, sizeof(_cmsOptimizationPluginChunkType)); + } +} + // Register new ways to optimize -cmsBool _cmsRegisterOptimizationPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationCollection* fl; if (Data == NULL) { - OptimizationCollection = DefaultOptimization; + ctx->OptimizationCollection = NULL; return TRUE; } // Optimizer callback is required if (Plugin ->OptimizePtr == NULL) return FALSE; - fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(id, sizeof(_cmsOptimizationCollection)); + fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsOptimizationCollection)); if (fl == NULL) return FALSE; // Copy the parameters fl ->OptimizePtr = Plugin ->OptimizePtr; // Keep linked list - fl ->Next = OptimizationCollection; - OptimizationCollection = fl; + fl ->Next = ctx->OptimizationCollection; + + // Set the head + ctx ->OptimizationCollection = fl; // All is ok return TRUE; } // The entry point for LUT optimization -cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, +cmsBool _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** PtrLut, int Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { + _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationCollection* Opts; cmsBool AnySuccess = FALSE; @@ -1733,8 +1793,8 @@ if (*dwFlags & cmsFLAGS_NOOPTIMIZE) return FALSE; - // Try built-in optimizations and plug-in - for (Opts = OptimizationCollection; + // Try plug-in optimizations + for (Opts = ctx->OptimizationCollection; Opts != NULL; Opts = Opts ->Next) { @@ -1745,6 +1805,17 @@ } } + // Try built-in optimizations + for (Opts = DefaultOptimization; + Opts != NULL; + Opts = Opts ->Next) { + + if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) { + + return TRUE; + } + } + // Only simple optimizations succeeded return AnySuccess; } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmspack.c --- a/jdk/src/java.desktop/share/native/liblcms/cmspack.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmspack.c Wed Jul 05 20:01:50 2017 +0200 @@ -883,6 +883,42 @@ } } +// This is a conversion of XYZ float to 16 bits +static +cmsUInt8Number* UnrollXYZFloatTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + if (T_PLANAR(info -> InputFormat)) { + + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + cmsCIEXYZ XYZ; + + XYZ.X = Pt[0]; + XYZ.Y = Pt[Stride]; + XYZ.Z = Pt[Stride*2]; + cmsFloat2XYZEncoded(wIn, &XYZ); + + return accum + sizeof(cmsFloat32Number); + + } + + else { + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + cmsCIEXYZ XYZ; + + XYZ.X = Pt[0]; + XYZ.Y = Pt[1]; + XYZ.Z = Pt[2]; + cmsFloat2XYZEncoded(wIn, &XYZ); + + accum += 3 * sizeof(cmsFloat32Number) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat32Number); + + return accum; + } +} + // Check if space is marked as ink cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type) { @@ -2334,6 +2370,39 @@ } static +cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + if (T_PLANAR(Info -> OutputFormat)) { + + cmsCIEXYZ XYZ; + cmsFloat32Number* Out = (cmsFloat32Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); + + Out[0] = (cmsFloat32Number) XYZ.X; + Out[Stride] = (cmsFloat32Number) XYZ.Y; + Out[Stride*2] = (cmsFloat32Number) XYZ.Z; + + return output + sizeof(cmsFloat32Number); + + } + else { + + cmsCIEXYZ XYZ; + cmsFloat32Number* Out = (cmsFloat32Number*) output; + cmsXYZEncoded2Float(&XYZ, wOut); + + Out[0] = (cmsFloat32Number) XYZ.X; + Out[1] = (cmsFloat32Number) XYZ.Y; + Out[2] = (cmsFloat32Number) XYZ.Z; + + return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number)); + } +} + +static cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, @@ -2893,6 +2962,7 @@ { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleTo16}, { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleTo16}, { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatTo16}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatTo16}, { TYPE_GRAY_DBL, 0, UnrollDouble1Chan}, { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR| ANYSWAP|ANYEXTRA|ANYSPACE, UnrollDoubleTo16}, @@ -3027,6 +3097,7 @@ { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFrom16}, { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFrom16}, + { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFrom16}, { FLOAT_SH(1)|BYTES_SH(0), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16}, @@ -3182,40 +3253,98 @@ } cmsFormattersFactoryList; -static cmsFormattersFactoryList* FactoryList = NULL; +_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupFormatterFactoryList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsFormattersPluginChunkType newHead = { NULL }; + cmsFormattersFactoryList* entry; + cmsFormattersFactoryList* Anterior = NULL; + _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin]; + + _cmsAssert(head != NULL); + + // Walk the list copying all nodes + for (entry = head->FactoryList; + entry != NULL; + entry = entry ->Next) { + + cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.FactoryList == NULL) + newHead.FactoryList = newEntry; + } + + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType)); +} + +// The interpolation plug-in memory chunk allocator/dup +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsAssert(ctx != NULL); + + if (src != NULL) { + + // Duplicate the LIST + DupFormatterFactoryList(ctx, src); + } + else { + static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL }; + ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType)); + } +} + // Formatters management -cmsBool _cmsRegisterFormattersPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data) { + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data; cmsFormattersFactoryList* fl ; - // Reset + // Reset to built-in defaults if (Data == NULL) { - FactoryList = NULL; + ctx ->FactoryList = NULL; return TRUE; } - fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(id, sizeof(cmsFormattersFactoryList)); + fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList)); if (fl == NULL) return FALSE; fl ->Factory = Plugin ->FormattersFactory; - fl ->Next = FactoryList; - FactoryList = fl; + fl ->Next = ctx -> FactoryList; + ctx ->FactoryList = fl; return TRUE; } -cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 +cmsFormatter _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 cmsFormatterDirection Dir, cmsUInt32Number dwFlags) { + _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin); cmsFormattersFactoryList* f; - for (f = FactoryList; f != NULL; f = f ->Next) { + for (f =ctx->FactoryList; f != NULL; f = f ->Next) { cmsFormatter fn = f ->Factory(Type, Dir, dwFlags); if (fn.Fmt16 != NULL) return fn; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsplugin.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c Wed Jul 05 20:01:50 2017 +0200 @@ -544,22 +544,31 @@ // Plugin memory management ------------------------------------------------------------------------------------------------- -static _cmsSubAllocator* PluginPool = NULL; - // Specialized malloc for plug-ins, that is freed upon exit. -void* _cmsPluginMalloc(cmsContext id, cmsUInt32Number size) +void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size) { - if (PluginPool == NULL) - PluginPool = _cmsCreateSubAlloc(id, 4*1024); + struct _cmsContext_struct* ctx = _cmsGetContext(ContextID); + + if (ctx ->MemPool == NULL) { + + if (ContextID == NULL) { - return _cmsSubAlloc(PluginPool, size); + ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024); + } + else { + cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context"); + return NULL; + } + } + + return _cmsSubAlloc(ctx->MemPool, size); } // Main plug-in dispatcher cmsBool CMSEXPORT cmsPlugin(void* Plug_in) { - return cmsPluginTHR(NULL, Plug_in); + return cmsPluginTHR(NULL, Plug_in); } cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) @@ -571,12 +580,12 @@ Plugin = Plugin -> Next) { if (Plugin -> Magic != cmsPluginMagicNumber) { - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); return FALSE; } if (Plugin ->ExpectedVersion > LCMS_VERSION) { - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", Plugin ->ExpectedVersion, LCMS_VERSION); return FALSE; } @@ -584,11 +593,11 @@ switch (Plugin -> Type) { case cmsPluginMemHandlerSig: - if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE; + if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE; break; case cmsPluginInterpolationSig: - if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE; + if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE; break; case cmsPluginTagTypeSig: @@ -623,8 +632,12 @@ if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE; break; + case cmsPluginMutexSig: + if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE; + break; + default: - cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); + cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); return FALSE; } } @@ -637,19 +650,337 @@ // Revert all plug-ins to default void CMSEXPORT cmsUnregisterPlugins(void) { - _cmsRegisterMemHandlerPlugin(NULL); - _cmsRegisterInterpPlugin(NULL); - _cmsRegisterTagTypePlugin(NULL, NULL); - _cmsRegisterTagPlugin(NULL, NULL); - _cmsRegisterFormattersPlugin(NULL, NULL); - _cmsRegisterRenderingIntentPlugin(NULL, NULL); - _cmsRegisterParametricCurvesPlugin(NULL, NULL); - _cmsRegisterMultiProcessElementPlugin(NULL, NULL); - _cmsRegisterOptimizationPlugin(NULL, NULL); - _cmsRegisterTransformPlugin(NULL, NULL); + cmsUnregisterPluginsTHR(NULL); +} + + +// The Global storage for system context. This is the one and only global variable +// pointers structure. All global vars are referenced here. +static struct _cmsContext_struct globalContext = { + + NULL, // Not in the linked list + NULL, // No suballocator + { + NULL, // UserPtr, + &_cmsLogErrorChunk, // Logger, + &_cmsAlarmCodesChunk, // AlarmCodes, + &_cmsAdaptationStateChunk, // AdaptationState, + &_cmsMemPluginChunk, // MemPlugin, + &_cmsInterpPluginChunk, // InterpPlugin, + &_cmsCurvesPluginChunk, // CurvesPlugin, + &_cmsFormattersPluginChunk, // FormattersPlugin, + &_cmsTagTypePluginChunk, // TagTypePlugin, + &_cmsTagPluginChunk, // TagPlugin, + &_cmsIntentsPluginChunk, // IntentPlugin, + &_cmsMPETypePluginChunk, // MPEPlugin, + &_cmsOptimizationPluginChunk, // OptimizationPlugin, + &_cmsTransformPluginChunk, // TransformPlugin, + &_cmsMutexPluginChunk // MutexPlugin + }, + + { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0 +}; + + +// The context pool (linked list head) +static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER; +static struct _cmsContext_struct* _cmsContextPoolHead = NULL; + +// Internal, get associated pointer, with guessing. Never returns NULL. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID) +{ + struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID; + struct _cmsContext_struct* ctx; + + + // On 0, use global settings + if (id == NULL) + return &globalContext; + + // Search + for (ctx = _cmsContextPoolHead; + ctx != NULL; + ctx = ctx ->Next) { + + // Found it? + if (id == ctx) + return ctx; // New-style context, + } + + return &globalContext; +} + + +// Internal: get the memory area associanted with each context client +// Returns the block assigned to the specific zone. +void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) +{ + struct _cmsContext_struct* ctx; + void *ptr; + + if (mc < 0 || mc >= MemoryClientMax) { + cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client"); + return NULL; + } + + ctx = _cmsGetContext(ContextID); + ptr = ctx ->chunks[mc]; + + if (ptr != NULL) + return ptr; + + // A null ptr means no special settings for that context, and this + // reverts to Context0 globals + return globalContext.chunks[mc]; +} + + +// This function returns the given context its default pristine state, +// as no plug-ins were declared. There is no way to unregister a single +// plug-in, as a single call to cmsPluginTHR() function may register +// many different plug-ins simultaneously, then there is no way to +// identify which plug-in to unregister. +void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) +{ + _cmsRegisterMemHandlerPlugin(ContextID, NULL); + _cmsRegisterInterpPlugin(ContextID, NULL); + _cmsRegisterTagTypePlugin(ContextID, NULL); + _cmsRegisterTagPlugin(ContextID, NULL); + _cmsRegisterFormattersPlugin(ContextID, NULL); + _cmsRegisterRenderingIntentPlugin(ContextID, NULL); + _cmsRegisterParametricCurvesPlugin(ContextID, NULL); + _cmsRegisterMultiProcessElementPlugin(ContextID, NULL); + _cmsRegisterOptimizationPlugin(ContextID, NULL); + _cmsRegisterTransformPlugin(ContextID, NULL); + _cmsRegisterMutexPlugin(ContextID, NULL); +} + + +// Returns the memory manager plug-in, if any, from the Plug-in bundle +static +cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle) +{ + cmsPluginBase* Plugin; + + for (Plugin = (cmsPluginBase*) PluginBundle; + Plugin != NULL; + Plugin = Plugin -> Next) { + + if (Plugin -> Magic == cmsPluginMagicNumber && + Plugin -> ExpectedVersion <= LCMS_VERSION && + Plugin -> Type == cmsPluginMemHandlerSig) { + + // Found! + return (cmsPluginMemHandler*) Plugin; + } + } + + // Nope, revert to defaults + return NULL; +} + + +// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) +{ + struct _cmsContext_struct* ctx; + struct _cmsContext_struct fakeContext; + + _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager); + + fakeContext.chunks[UserPtr] = UserData; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + // Create the context structure. + ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened! + + // Init the structure and the memory manager + memset(ctx, 0, sizeof(struct _cmsContext_struct)); + + // Keep memory manager + memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk)); + + // Maintain the linked list (with proper locking) + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + ctx ->Next = _cmsContextPoolHead; + _cmsContextPoolHead = ctx; + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + ctx ->chunks[UserPtr] = UserData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + // Now we can allocate the pool by using default memory manager + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers + if (ctx ->MemPool == NULL) { - if (PluginPool != NULL) - _cmsSubAllocDestroy(PluginPool); + cmsDeleteContext(ctx); + return NULL; + } + + _cmsAllocLogErrorChunk(ctx, NULL); + _cmsAllocAlarmCodesChunk(ctx, NULL); + _cmsAllocAdaptationStateChunk(ctx, NULL); + _cmsAllocMemPluginChunk(ctx, NULL); + _cmsAllocInterpPluginChunk(ctx, NULL); + _cmsAllocCurvesPluginChunk(ctx, NULL); + _cmsAllocFormattersPluginChunk(ctx, NULL); + _cmsAllocTagTypePluginChunk(ctx, NULL); + _cmsAllocMPETypePluginChunk(ctx, NULL); + _cmsAllocTagPluginChunk(ctx, NULL); + _cmsAllocIntentsPluginChunk(ctx, NULL); + _cmsAllocOptimizationPluginChunk(ctx, NULL); + _cmsAllocTransformPluginChunk(ctx, NULL); + _cmsAllocMutexPluginChunk(ctx, NULL); + + // Setup the plug-ins + if (!cmsPluginTHR(ctx, Plugin)) { + + cmsDeleteContext(ctx); + return NULL; + } + + return (cmsContext) ctx; +} + +// Duplicates a context with all associated plug-ins. +// Caller may specify an optional pointer to user-defined +// data that will be forwarded to plug-ins and logger. +cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) +{ + int i; + struct _cmsContext_struct* ctx; + const struct _cmsContext_struct* src = _cmsGetContext(ContextID); + + void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr]; + + + ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct)); + if (ctx == NULL) + return NULL; // Something very wrong happened + + // Setup default memory allocators + memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + // Maintain the linked list + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + ctx ->Next = _cmsContextPoolHead; + _cmsContextPoolHead = ctx; + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + ctx ->chunks[UserPtr] = userData; + ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager; + + ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); + if (ctx ->MemPool == NULL) { + + cmsDeleteContext(ctx); + return NULL; + } + + // Allocate all required chunks. + _cmsAllocLogErrorChunk(ctx, src); + _cmsAllocAlarmCodesChunk(ctx, src); + _cmsAllocAdaptationStateChunk(ctx, src); + _cmsAllocMemPluginChunk(ctx, src); + _cmsAllocInterpPluginChunk(ctx, src); + _cmsAllocCurvesPluginChunk(ctx, src); + _cmsAllocFormattersPluginChunk(ctx, src); + _cmsAllocTagTypePluginChunk(ctx, src); + _cmsAllocMPETypePluginChunk(ctx, src); + _cmsAllocTagPluginChunk(ctx, src); + _cmsAllocIntentsPluginChunk(ctx, src); + _cmsAllocOptimizationPluginChunk(ctx, src); + _cmsAllocTransformPluginChunk(ctx, src); + _cmsAllocMutexPluginChunk(ctx, src); + + // Make sure no one failed + for (i=Logger; i < MemoryClientMax; i++) { - PluginPool = NULL; + if (src ->chunks[i] == NULL) { + cmsDeleteContext((cmsContext) ctx); + return NULL; + } + } + + return (cmsContext) ctx; +} + + + +static +struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id) +{ + struct _cmsContext_struct* prev; + + // Search for previous + for (prev = _cmsContextPoolHead; + prev != NULL; + prev = prev ->Next) + { + if (prev ->Next == id) + return prev; + } + + return NULL; // List is empty or only one element! } + +// Frees any resources associated with the given context, +// and destroys the context placeholder. +// The ContextID can no longer be used in any THR operation. +void CMSEXPORT cmsDeleteContext(cmsContext ContextID) +{ + if (ContextID != NULL) { + + struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID; + struct _cmsContext_struct fakeContext; + struct _cmsContext_struct* prev; + + memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); + + fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr]; + fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager; + + // Get rid of plugins + cmsUnregisterPluginsTHR(ContextID); + + // Since all memory is allocated in the private pool, all what we need to do is destroy the pool + if (ctx -> MemPool != NULL) + _cmsSubAllocDestroy(ctx ->MemPool); + ctx -> MemPool = NULL; + + // Maintain list + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + if (_cmsContextPoolHead == ctx) { + + _cmsContextPoolHead = ctx->Next; + } + else { + + // Search for previous + for (prev = _cmsContextPoolHead; + prev != NULL; + prev = prev ->Next) + { + if (prev -> Next == ctx) { + prev -> Next = ctx ->Next; + break; + } + } + } + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + + // free the memory block itself + _cmsFree(&fakeContext, ctx); + } +} + +// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation +void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID) +{ + return _cmsContextGetClientChunk(ContextID, UserPtr); +} + + diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsps2.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsps2.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsps2.c Wed Jul 05 20:01:50 2017 +0200 @@ -942,7 +942,7 @@ if (DeviceLink == NULL) return 0; dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); + _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); cmsPipelineFree(DeviceLink); @@ -1359,7 +1359,7 @@ // We need a CLUT dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); + _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "/ColorRenderingType 1\n"); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmstypes.c --- a/jdk/src/java.desktop/share/native/liblcms/cmstypes.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmstypes.c Wed Jul 05 20:01:50 2017 +0200 @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -61,7 +61,7 @@ // are no profiles holding them. The programmer can also extend this list by defining his own types // by using the appropiate plug-in. There are three types of plug ins regarding that. First type // allows to define new tags using any existing type. Next plug-in type allows to define new types -// and the third one is very specific: allows to extend the number of elements in the multiprofile +// and the third one is very specific: allows to extend the number of elements in the multiprocessing // elements special type. //-------------------------------------------------------------------------------------------------- @@ -89,54 +89,49 @@ // Helper macro to define a MPE handler. Callbacks do have a fixed naming convention #define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 } -// Register a new type handler. This routine is shared between normal types and MPE +// Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head static -cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount) +cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos) { cmsPluginTagType* Plugin = (cmsPluginTagType*) Data; - _cmsTagTypeLinkedList *pt, *Anterior = NULL; + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos); + _cmsTagTypeLinkedList *pt; // Calling the function with NULL as plug-in would unregister the plug in. if (Data == NULL) { - LinkedList[DefaultListCount-1].Next = NULL; + // There is no need to set free the memory, as pool is destroyed as a whole. + ctx ->TagTypes = NULL; return TRUE; } - pt = Anterior = LinkedList; - while (pt != NULL) { - - if (Plugin->Handler.Signature == pt -> Handler.Signature) { - pt ->Handler = Plugin ->Handler; // Replace old behaviour. - // Note that since no memory is allocated, unregister does not - // reset this action. - return TRUE; - } - - Anterior = pt; - pt = pt ->Next; - } - - // Registering happens in plug-in memory pool + // Registering happens in plug-in memory pool. pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList)); if (pt == NULL) return FALSE; pt ->Handler = Plugin ->Handler; - pt ->Next = NULL; - - if (Anterior) - Anterior -> Next = pt; + pt ->Next = ctx ->TagTypes; + + ctx ->TagTypes = pt; return TRUE; } -// Return handler for a given type or NULL if not found. Shared between normal types and MPE +// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons +// made by plug-ins and then the built-in defaults. static -cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList) +cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList) { _cmsTagTypeLinkedList* pt; - for (pt = LinkedList; + for (pt = PluginLinkedList; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Handler.Signature) return &pt ->Handler; + } + + for (pt = DefaultLinkedList; pt != NULL; pt = pt ->Next) { @@ -163,6 +158,7 @@ return TRUE; } +// Auxiliar to read an array of wchar_t static cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) { @@ -777,6 +773,8 @@ // Create memory Text = (char*) _cmsMalloc(self ->ContextID, size); + if (Text == NULL) return FALSE; + cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size); // Write it, including separator @@ -1783,7 +1781,6 @@ if (!_cmsReadUInt8Number(io, NULL)) goto Error; // Do some checking - if (InputChannels > cmsMAXCHANNELS) goto Error; if (OutputChannels > cmsMAXCHANNELS) goto Error; @@ -1824,9 +1821,16 @@ if (T == NULL) goto Error; Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize); - if (Temp == NULL) goto Error; - - if (io ->Read(io, Temp, nTabSize, 1) != 1) goto Error; + if (Temp == NULL) { + _cmsFree(self ->ContextID, T); + goto Error; + } + + if (io ->Read(io, Temp, nTabSize, 1) != 1) { + _cmsFree(self ->ContextID, T); + _cmsFree(self ->ContextID, Temp); + goto Error; + } for (i = 0; i < nTabSize; i++) { @@ -2371,27 +2375,30 @@ // Precision can be 1 or 2 bytes if (Precision == 1) { - cmsUInt8Number v; + cmsUInt8Number v; for (i=0; i < Data ->nEntries; i++) { - if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; - Data ->Tab.T[i] = FROM_8_TO_16(v); + if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; + Data ->Tab.T[i] = FROM_8_TO_16(v); } } else if (Precision == 2) { - if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL; - } - else { - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); - return NULL; - } - - - return CLUT; + if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) { + cmsStageFree(CLUT); + return NULL; + } + } + else { + cmsStageFree(CLUT); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); + return NULL; + } + + return CLUT; } static @@ -4374,7 +4381,7 @@ {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL }, }; -#define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList)) +_cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL }; static cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, @@ -4387,6 +4394,8 @@ cmsTagTypeHandler* TypeHandler; cmsUInt32Number nItems; cmsPipeline *NewLUT = (cmsPipeline *) Cargo; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); + // Take signature and channels for each element. if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE; @@ -4395,7 +4404,7 @@ if (!_cmsReadUInt32Number(io, NULL)) return FALSE; // Read diverse MPE types - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes); if (TypeHandler == NULL) { char String[5]; @@ -4472,6 +4481,7 @@ cmsPipeline* Lut = (cmsPipeline*) Ptr; cmsStage* Elem = Lut ->Elements; cmsTagTypeHandler* TypeHandler; + _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); @@ -4505,7 +4515,7 @@ ElementSig = Elem ->Type; - TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes); + TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes); if (TypeHandler == NULL) { char String[5]; @@ -5125,7 +5135,7 @@ } else { - rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); + rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); } if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS); @@ -5282,24 +5292,95 @@ {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } }; -#define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList)) + +_cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL }; + + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagTypeList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src, + int loc) +{ + _cmsTagTypePluginChunkType newHead = { NULL }; + _cmsTagTypeLinkedList* entry; + _cmsTagTypeLinkedList* Anterior = NULL; + _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc]; + + // Walk the list copying all nodes + for (entry = head->TagTypes; + entry != NULL; + entry = entry ->Next) { + + _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TagTypes == NULL) + newHead.TagTypes = newEntry; + } + + ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType)); +} + + +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, TagTypePlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } +} + +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Duplicate the LIST + DupTagTypeList(ctx, src, MPEPlugin); + } + else { + static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; + ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); + } + +} + // Both kind of plug-ins share same structure cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data) { - return RegisterTypesPlugin(id, Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT); + return RegisterTypesPlugin(id, Data, TagTypePlugin); } cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data) { - return RegisterTypesPlugin(id, Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT); + return RegisterTypesPlugin(id, Data,MPEPlugin); } // Wrapper for tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig) -{ - return GetHandler(sig, SupportedTagTypes); +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig) +{ + _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin); + + return GetHandler(sig, ctx->TagTypes, SupportedTagTypes); } // ******************************************************************************** @@ -5414,48 +5495,94 @@ cmsSigDeviceSettingsTag ==> Deprecated, useless */ -#define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList)) + +_cmsTagPluginChunkType _cmsTagPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupTagList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsTagPluginChunkType newHead = { NULL }; + _cmsTagLinkedList* entry; + _cmsTagLinkedList* Anterior = NULL; + _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin]; + + // Walk the list copying all nodes + for (entry = head->Tag; + entry != NULL; + entry = entry ->Next) { + + _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.Tag == NULL) + newHead.Tag = newEntry; + } + + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType)); +} + +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + DupTagList(ctx, src); + } + else { + static _cmsTagPluginChunkType TagPluginChunk = { NULL }; + ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType)); + } + +} cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) { cmsPluginTag* Plugin = (cmsPluginTag*) Data; - _cmsTagLinkedList *pt, *Anterior; - + _cmsTagLinkedList *pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin); if (Data == NULL) { - SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL; + TagPluginChunk->Tag = NULL; return TRUE; } - pt = Anterior = SupportedTags; - while (pt != NULL) { - - if (Plugin->Signature == pt -> Signature) { - pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour - return TRUE; - } - - Anterior = pt; - pt = pt ->Next; - } - pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList)); if (pt == NULL) return FALSE; pt ->Signature = Plugin ->Signature; pt ->Descriptor = Plugin ->Descriptor; - pt ->Next = NULL; - - if (Anterior != NULL) Anterior -> Next = pt; + pt ->Next = TagPluginChunk ->Tag; + + TagPluginChunk ->Tag = pt; return TRUE; } // Return a descriptor for a given tag or NULL -cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig) +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig) { _cmsTagLinkedList* pt; + _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin); + + for (pt = TagPluginChunk->Tag; + pt != NULL; + pt = pt ->Next) { + + if (sig == pt -> Signature) return &pt ->Descriptor; + } for (pt = SupportedTags; pt != NULL; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsvirt.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsvirt.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsvirt.c Wed Jul 05 20:01:50 2017 +0200 @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1019,7 +1019,7 @@ static const cmsAllowedLUT AllowedLUTTypes[] = { - { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}}, { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, @@ -1150,7 +1150,7 @@ if (AllowedLUT == NULL) { // Try to optimize - _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); } @@ -1159,7 +1159,7 @@ if (AllowedLUT == NULL) { dwFlags |= cmsFLAGS_FORCE_CLUT; - _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); + _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); // Put identity curves if needed if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c --- a/jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c Wed Jul 05 20:01:50 2017 +0200 @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/cmsxform.c --- a/jdk/src/java.desktop/share/native/liblcms/cmsxform.c Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsxform.c Wed Jul 05 20:01:50 2017 +0200 @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -58,44 +58,120 @@ // Transformations stuff // ----------------------------------------------------------------------- -// Alarm codes for 16-bit transformations, because the fixed range of containers there are -// no values left to mark out of gamut. volatile is C99 per 6.2.5 -static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS] = { 0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static volatile cmsFloat64Number GlobalAdaptationState = 1; +#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0 + +// The Context0 observer adaptation state. +_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + +// Init and duplicate observer adaptation state +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE }; + void* from; + + if (src != NULL) { + from = src ->chunks[AdaptationStateContext]; + } + else { + from = &AdaptationStateChunk; + } + + ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType)); +} + + +// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all +// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states. +cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d) +{ + cmsFloat64Number prev; + _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext); + + // Get previous value for return + prev = ptr ->AdaptationState; + + // Set the value if d is positive or zero + if (d >= 0.0) { + + ptr ->AdaptationState = d; + } + + // Always return previous value + return prev; +} + // The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d) { - cmsFloat64Number OldVal = GlobalAdaptationState; - - if (d >= 0) - GlobalAdaptationState = d; - - return OldVal; + return cmsSetAdaptationStateTHR(NULL, d); } -// Alarm codes are always global -void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) +// ----------------------------------------------------------------------- + +// Alarm codes for 16-bit transformations, because the fixed range of containers there are +// no values left to mark out of gamut. + +#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + +// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be +// encoded in 16 bits. +void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) { - int i; + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); + + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen + + memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes)); +} +// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context. +// Values are meant to be encoded in 16 bits. +void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS]) +{ + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext); + + _cmsAssert(ContextAlarmCodes != NULL); // Can't happen + + memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes)); +} + +void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]) +{ _cmsAssert(NewAlarm != NULL); - for (i=0; i < cmsMAXCHANNELS; i++) - Alarm[i] = NewAlarm[i]; + cmsSetAlarmCodesTHR(NULL, NewAlarm); } -// You can get the codes cas well void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS]) { - int i; + _cmsAssert(OldAlarm != NULL); + cmsGetAlarmCodesTHR(NULL, OldAlarm); +} + - _cmsAssert(OldAlarm != NULL); +// Init and duplicate alarm codes +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE }; + void* from; - for (i=0; i < cmsMAXCHANNELS; i++) - OldAlarm[i] = Alarm[i]; + if (src != NULL) { + from = src ->chunks[AlarmCodesContext]; + } + else { + from = &AlarmCodesChunk; + } + + ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType)); } +// ----------------------------------------------------------------------- + // Get rid of transform resources void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) { @@ -202,6 +278,30 @@ } } + +static +void NullFloatXFORM(_cmsTRANSFORM* p, + const void* in, + void* out, + cmsUInt32Number Size, + cmsUInt32Number Stride) +{ + cmsUInt8Number* accum; + cmsUInt8Number* output; + cmsFloat32Number fIn[cmsMAXCHANNELS]; + cmsUInt32Number i, n; + + accum = (cmsUInt8Number*) in; + output = (cmsUInt8Number*) out; + n = Size; + + for (i=0; i < n; i++) { + + accum = p -> FromInputFloat(p, fIn, accum, Stride); + output = p -> ToOutputFloat(p, fIn, output, Stride); + } +} + // 16 bit precision ----------------------------------------------------------------------------------------------------------- // Null transformation, only applies formatters. No caché @@ -252,7 +352,7 @@ } -// Auxiliar: Handle precalculated gamut check +// Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical. static void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, const cmsUInt16Number wIn[], @@ -264,9 +364,12 @@ if (wOutOfGamut >= 1) { cmsUInt16Number i; + _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext); - for (i=0; i < p ->Lut->OutputChannels; i++) - wOut[i] = Alarm[i]; + for (i=0; i < p ->Lut->OutputChannels; i++) { + + wOut[i] = ContextAlarmCodes ->AlarmCodes[i]; + } } else p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); @@ -393,34 +496,86 @@ } _cmsTransformCollection; // The linked list head -static _cmsTransformCollection* TransformCollection = NULL; +_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL }; + + +// Duplicates the zone of memory used by the plug-in in the new context +static +void DupPluginTransformList(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + _cmsTransformPluginChunkType newHead = { NULL }; + _cmsTransformCollection* entry; + _cmsTransformCollection* Anterior = NULL; + _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin]; + + // Walk the list copying all nodes + for (entry = head->TransformCollection; + entry != NULL; + entry = entry ->Next) { + + _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection)); + + if (newEntry == NULL) + return; + + // We want to keep the linked list order, so this is a little bit tricky + newEntry -> Next = NULL; + if (Anterior) + Anterior -> Next = newEntry; + + Anterior = newEntry; + + if (newHead.TransformCollection == NULL) + newHead.TransformCollection = newEntry; + } + + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType)); +} + +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src) +{ + if (src != NULL) { + + // Copy all linked list + DupPluginTransformList(ctx, src); + } + else { + static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL }; + ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType)); + } +} + + // Register new ways to transform -cmsBool _cmsRegisterTransformPlugin(cmsContext id, cmsPluginBase* Data) +cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data) { cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; _cmsTransformCollection* fl; + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin); - if (Data == NULL) { + if (Data == NULL) { // Free the chain. Memory is safely freed at exit - TransformCollection = NULL; + ctx->TransformCollection = NULL; return TRUE; } // Factory callback is required - if (Plugin ->Factory == NULL) return FALSE; + if (Plugin ->Factory == NULL) return FALSE; - fl = (_cmsTransformCollection*) _cmsPluginMalloc(id, sizeof(_cmsTransformCollection)); + fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection)); if (fl == NULL) return FALSE; - // Copy the parameters + // Copy the parameters fl ->Factory = Plugin ->Factory; // Keep linked list - fl ->Next = TransformCollection; - TransformCollection = fl; + fl ->Next = ctx->TransformCollection; + ctx->TransformCollection = fl; // All is ok return TRUE; @@ -463,6 +618,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { + _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin); _cmsTransformCollection* Plugin; // Allocate needed memory @@ -473,7 +629,7 @@ p ->Lut = lut; // Let's see if any plug-in want to do the transform by itself - for (Plugin = TransformCollection; + for (Plugin = ctx ->TransformCollection; Plugin != NULL; Plugin = Plugin ->Next) { @@ -493,10 +649,10 @@ // Fill the formatters just in case the optimized routine is interested. // No error is thrown if the formatter doesn't exist. It is up to the optimization // factory to decide what to do in those cases. - p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; return p; } @@ -504,14 +660,14 @@ // Not suitable for the transform plug-in, let's check the pipeline plug-in if (p ->Lut != NULL) - _cmsOptimizePipeline(&p->Lut, Intent, InputFormat, OutputFormat, dwFlags); + _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags); // Check whatever this is a true floating point transform if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) { // Get formatter function always return a valid union, but the contents of this union may be NULL. - p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { @@ -521,8 +677,15 @@ return NULL; } - // Float transforms don't use caché, always are non-NULL - p ->xform = FloatXFORM; + if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { + + p ->xform = NullFloatXFORM; + } + else { + // Float transforms don't use caché, always are non-NULL + p ->xform = FloatXFORM; + } + } else { @@ -534,8 +697,8 @@ int BytesPerPixelInput; - p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; if (p ->FromInput == NULL || p ->ToOutput == NULL) { @@ -727,6 +890,7 @@ // Check channel count if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) || (cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) { + cmsPipelineFree(Lut); cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted"); return NULL; } @@ -829,7 +993,7 @@ for (i=0; i < nProfiles; i++) { BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE; Intents[i] = Intent; - AdaptationStates[i] = GlobalAdaptationState; + AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1); } @@ -909,7 +1073,7 @@ Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent; BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0; - Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState; + Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1); if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK))) return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags); @@ -984,8 +1148,8 @@ return FALSE; } - FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; if (FromInput == NULL || ToOutput == NULL) { diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/lcms2.h --- a/jdk/src/java.desktop/share/native/liblcms/lcms2.h Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/lcms2.h Wed Jul 05 20:01:50 2017 +0200 @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2013 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -52,7 +52,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.5 +// Version 2.6 // #ifndef _lcms2_H @@ -84,6 +84,9 @@ // Uncomment to get rid of the tables for "half" float support // #define CMS_NO_HALF_SUPPORT 1 +// Uncomment to get rid of pthreads/windows dependency +// #define CMS_NO_PTHREADS 1 + // ********** End of configuration toggles ****************************** // Needed for streams @@ -101,7 +104,7 @@ #endif // Version/release -#define LCMS_VERSION 2050 +#define LCMS_VERSION 2060 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -202,28 +205,42 @@ // Try to detect big endian platforms. This list can be endless, so only some checks are performed over here. // you can pass this toggle to the compiler by using -DCMS_USE_BIG_ENDIAN or something similar -#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) -# define CMS_USE_BIG_ENDIAN 1 -#endif - -#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc) +#if defined(__sgi__) || defined(__sgi) || defined(sparc) # define CMS_USE_BIG_ENDIAN 1 #endif -#if defined(__ppc__) || defined(__s390__) || defined(__s390x__) +#if defined(__s390__) || defined(__s390x__) # define CMS_USE_BIG_ENDIAN 1 #endif -#ifdef TARGET_CPU_PPC -# if TARGET_CPU_PPC +# ifdef TARGET_CPU_PPC +# if TARGET_CPU_PPC +# define CMS_USE_BIG_ENDIAN 1 +# endif +# endif + +#if defined(__powerpc__) || defined(__ppc__) || defined(TARGET_CPU_PPC) # define CMS_USE_BIG_ENDIAN 1 -# endif +# if defined (__GNUC__) && defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) +# if __BYTE_ORDER == __LITTLE_ENDIAN +// // Don't use big endian for PowerPC little endian mode +# undef CMS_USE_BIG_ENDIAN +# endif +# endif +#endif + +// WORDS_BIGENDIAN takes precedence +#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN) +# define CMS_USE_BIG_ENDIAN 1 #endif #ifdef macintosh # ifdef __BIG_ENDIAN__ # define CMS_USE_BIG_ENDIAN 1 # endif +# ifdef __LITTLE_ENDIAN__ +# undef CMS_USE_BIG_ENDIAN +# endif #endif // Calling convention -- this is hardly platform and compiler dependent @@ -249,6 +266,14 @@ # define CMSAPI #endif +#ifdef HasTHREADS +# if HasTHREADS == 1 +# undef CMS_NO_PTHREADS +# else +# define CMS_NO_PTHREADS 1 +# endif +#endif + // Some common definitions #define cmsMAX_PATH 256 @@ -642,7 +667,6 @@ // Little CMS specific typedefs -typedef void* cmsContext; // Context identifier for multithreaded environments typedef void* cmsHANDLE ; // Generic handle typedef void* cmsHPROFILE; // Opaque typedefs to hide internals typedef void* cmsHTRANSFORM; @@ -1012,11 +1036,25 @@ CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2); CMSAPI long int CMSEXPORT cmsfilelength(FILE* f); -// Plug-In registering --------------------------------------------------------------------------------------------------- + +// Context handling -------------------------------------------------------------------------------------------------------- + +// Each context holds its owns globals and its own plug-ins. There is a global context with the id = 0 for lecacy compatibility +// though using the global context is not recomended. Proper context handling makes lcms more thread-safe. + +typedef struct _cmsContext_struct* cmsContext; + +CMSAPI cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData); +CMSAPI void CMSEXPORT cmsDeleteContext(cmsContext ContexID); +CMSAPI cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData); +CMSAPI void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID); + +// Plug-In registering -------------------------------------------------------------------------------------------------- CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin); CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin); CMSAPI void CMSEXPORT cmsUnregisterPlugins(void); +CMSAPI void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID); // Error logging ---------------------------------------------------------------------------------------------------------- @@ -1053,6 +1091,7 @@ // Allows user to set any specific logger CMSAPI void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn); +CMSAPI void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn); // Conversions -------------------------------------------------------------------------------------------------------------- @@ -1514,6 +1553,7 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void * MemPtr, cmsUInt32Number dwSize); CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void * MemPtr, cmsUInt32Number dwSize); CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io); +CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write); CMSAPI cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile); CMSAPI cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName); @@ -1604,6 +1644,7 @@ // Call with NULL as parameters to get the intent count CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions); // Flags @@ -1715,11 +1756,22 @@ cmsUInt32Number Stride); -CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); + +CMSAPI void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, + const cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); +CMSAPI void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]); + + + // Adaptation state for absolute colorimetric intent CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d); +CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d); + + // Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/lcms2_internal.h --- a/jdk/src/java.desktop/share/native/liblcms/lcms2_internal.h Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/lcms2_internal.h Wed Jul 05 20:01:50 2017 +0200 @@ -30,7 +30,7 @@ // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2014 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -193,16 +193,171 @@ return _cmsQuickFloorWord(d); } -// Plug-In registering --------------------------------------------------------------- + +// Pthread support -------------------------------------------------------------------- +#ifndef CMS_NO_PTHREADS + +// This is the threading support. Unfortunately, it has to be platform-dependent because +// windows does not support pthreads. + +#ifdef CMS_IS_WINDOWS_ + +#define WIN32_LEAN_AND_MEAN 1 +#include + + +// From: http://locklessinc.com/articles/pthreads_on_windows/ +// The pthreads API has an initialization macro that has no correspondence to anything in +// the windows API. By investigating the internal definition of the critical section type, +// one may work out how to initialize one without calling InitializeCriticalSection(). +// The trick here is that InitializeCriticalSection() is not allowed to fail. It tries +// to allocate a critical section debug object, but if no memory is available, it sets +// the pointer to a specific value. (One would expect that value to be NULL, but it is +// actually (void *)-1 for some reason.) Thus we can use this special value for that +// pointer, and the critical section code will work. + +// The other important part of the critical section type to initialize is the number +// of waiters. This controls whether or not the mutex is locked. Fortunately, this +// part of the critical section is unlikely to change. Apparently, many programs +// already test critical sections to see if they are locked using this value, so +// Microsoft felt that it was necessary to keep it set at -1 for an unlocked critical +// section, even when they changed the underlying algorithm to be more scalable. +// The final parts of the critical section object are unimportant, and can be set +// to zero for their defaults. This yields an initialization macro: + +typedef CRITICAL_SECTION _cmsMutex; + +#define CMS_MUTEX_INITIALIZER {(void*) -1,-1,0,0,0,0} + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + EnterCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + LeaveCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + InitializeCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + DeleteCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + EnterCriticalSection(m); + return 0; +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + LeaveCriticalSection(m); + return 0; +} + +#else + +// Rest of the wide world +#include + +#define CMS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +typedef pthread_mutex_t _cmsMutex; + + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + return pthread_mutex_lock(m); +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + return pthread_mutex_unlock(m); +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + return pthread_mutex_init(m, NULL); +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + return pthread_mutex_destroy(m); +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + return pthread_mutex_lock(m); +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + return pthread_mutex_unlock(m); +} + +#endif +#else + +#define CMS_MUTEX_INITIALIZER 0 +typedef int _cmsMutex; + + +cmsINLINE int _cmsLockPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} + +cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m) +{ + return 0; + cmsUNUSED_PARAMETER(m); +} +#endif + +// Plug-In registration --------------------------------------------------------------- // Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once. void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size); // Memory management -cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Interpolation -cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Parametric curves cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin); @@ -228,9 +383,12 @@ // Transform cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin); +// Mutex +cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + // --------------------------------------------------------------------------------------------------------- -// Suballocators. Those are blocks of memory that is freed at the end on whole block. +// Suballocators. typedef struct _cmsSubAllocator_chunk_st { cmsUInt8Number* Block; @@ -253,9 +411,264 @@ _cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial); void _cmsSubAllocDestroy(_cmsSubAllocator* s); void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size); +void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size); // ---------------------------------------------------------------------------------- +// The context clients. +typedef enum { + + UserPtr, // User-defined pointer + Logger, + AlarmCodesContext, + AdaptationStateContext, + MemPlugin, + InterpPlugin, + CurvesPlugin, + FormattersPlugin, + TagTypePlugin, + TagPlugin, + IntentPlugin, + MPEPlugin, + OptimizationPlugin, + TransformPlugin, + MutexPlugin, + + // Last in list + MemoryClientMax + +} _cmsMemoryClient; + + +// Container for memory management plug-in. +typedef struct { + + _cmsMallocFnPtrType MallocPtr; + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; + +} _cmsMemPluginChunkType; + +// Copy memory management function pointers from plug-in to chunk, taking care of missing routines +void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr); + +// Internal structure for context +struct _cmsContext_struct { + + struct _cmsContext_struct* Next; // Points to next context in the new style + _cmsSubAllocator* MemPool; // The memory pool that stores context data + + void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator. + // If NULL, then it reverts to global Context0 + + _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overriden +}; + +// Returns a pointer to a valid context structure, including the global one if id is zero. +// Verifies the magic number. +struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID); + +// Returns the block assigned to the specific zone. +void* _cmsContextGetClientChunk(cmsContext id, _cmsMemoryClient mc); + + +// Chunks of context memory by plug-in client ------------------------------------------------------- + +// Those structures encapsulates all variables needed by the several context clients (mostly plug-ins) + +// Container for error logger -- not a plug-in +typedef struct { + + cmsLogErrorHandlerFunction LogErrorHandler; // Set to NULL for Context0 fallback + +} _cmsLogErrorChunkType; + +// The global Context0 storage for error logger +extern _cmsLogErrorChunkType _cmsLogErrorChunk; + +// Allocate and init error logger container. +void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for alarm codes -- not a plug-in +typedef struct { + + cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]; + +} _cmsAlarmCodesChunkType; + +// The global Context0 storage for alarm codes +extern _cmsAlarmCodesChunkType _cmsAlarmCodesChunk; + +// Allocate and init alarm codes container. +void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for adaptation state -- not a plug-in +typedef struct { + + cmsFloat64Number AdaptationState; + +} _cmsAdaptationStateChunkType; + +// The global Context0 storage for adaptation state +extern _cmsAdaptationStateChunkType _cmsAdaptationStateChunk; + +// Allocate and init adaptation state container. +void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + + +// The global Context0 storage for memory management +extern _cmsMemPluginChunkType _cmsMemPluginChunk; + +// Allocate and init memory management container. +void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for interpolation plug-in +typedef struct { + + cmsInterpFnFactory Interpolators; + +} _cmsInterpPluginChunkType; + +// The global Context0 storage for interpolation plug-in +extern _cmsInterpPluginChunkType _cmsInterpPluginChunk; + +// Allocate and init interpolation container. +void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for parametric curves plug-in +typedef struct { + + struct _cmsParametricCurvesCollection_st* ParametricCurves; + +} _cmsCurvesPluginChunkType; + +// The global Context0 storage for tone curves plug-in +extern _cmsCurvesPluginChunkType _cmsCurvesPluginChunk; + +// Allocate and init parametric curves container. +void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for formatters plug-in +typedef struct { + + struct _cms_formatters_factory_list* FactoryList; + +} _cmsFormattersPluginChunkType; + +// The global Context0 storage for formatters plug-in +extern _cmsFormattersPluginChunkType _cmsFormattersPluginChunk; + +// Allocate and init formatters container. +void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// This chunk type is shared by TagType plug-in and MPE Plug-in +typedef struct { + + struct _cmsTagTypeLinkedList_st* TagTypes; + +} _cmsTagTypePluginChunkType; + + +// The global Context0 storage for tag types plug-in +extern _cmsTagTypePluginChunkType _cmsTagTypePluginChunk; + + +// The global Context0 storage for mult process elements plug-in +extern _cmsTagTypePluginChunkType _cmsMPETypePluginChunk; + +// Allocate and init Tag types container. +void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Allocate and init MPE container. +void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); +// Container for tag plug-in +typedef struct { + + struct _cmsTagLinkedList_st* Tag; + +} _cmsTagPluginChunkType; + + +// The global Context0 storage for tag plug-in +extern _cmsTagPluginChunkType _cmsTagPluginChunk; + +// Allocate and init Tag container. +void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for intents plug-in +typedef struct { + + struct _cms_intents_list* Intents; + +} _cmsIntentsPluginChunkType; + + +// The global Context0 storage for intents plug-in +extern _cmsIntentsPluginChunkType _cmsIntentsPluginChunk; + +// Allocate and init intents container. +void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for optimization plug-in +typedef struct { + + struct _cmsOptimizationCollection_st* OptimizationCollection; + +} _cmsOptimizationPluginChunkType; + + +// The global Context0 storage for optimizers plug-in +extern _cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk; + +// Allocate and init optimizers container. +void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for transform plug-in +typedef struct { + + struct _cmsTransformCollection_st* TransformCollection; + +} _cmsTransformPluginChunkType; + +// The global Context0 storage for full-transform replacement plug-in +extern _cmsTransformPluginChunkType _cmsTransformPluginChunk; + +// Allocate and init transform container. +void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// Container for mutex plug-in +typedef struct { + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} _cmsMutexPluginChunkType; + +// The global Context0 storage for mutex plug-in +extern _cmsMutexPluginChunkType _cmsMutexPluginChunk; + +// Allocate and init mutex container. +void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, + const struct _cmsContext_struct* src); + +// ---------------------------------------------------------------------------------- // MLU internal representation typedef struct { @@ -347,10 +760,14 @@ cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked void * TagPtrs[MAX_TABLE_TAG]; cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types - // depending on profile version, so we keep track of the // type handler for each tag in the list. + // depending on profile version, so we keep track of the + // type handler for each tag in the list. // Special cmsBool IsWrite; + // Keep a mutex for cmsReadTag -- Note that this only works if the user includes a mutex plugin + void * UsrMutex; + } _cmsICCPROFILE; // IO helpers for profiles @@ -359,9 +776,9 @@ int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks); // Tag types -cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig); +cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig); cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig); -cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig); +cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig); // Error logging --------------------------------------------------------------------------------------------------------- @@ -372,7 +789,7 @@ cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); void _cmsFreeInterpParams(cmsInterpParams* p); -cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p); +cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p); // Curves ---------------------------------------------------------------------------------------------------------------- @@ -503,7 +920,8 @@ cmsUInt16Number **Black, cmsUInt32Number *nOutputs); -cmsBool _cmsOptimizePipeline(cmsPipeline** Lut, +cmsBool _cmsOptimizePipeline(cmsContext ContextID, + cmsPipeline** Lut, int Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, @@ -528,7 +946,8 @@ cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type); cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type); -cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 +cmsFormatter _cmsGetFormatter(cmsContext ContextID, + cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 cmsFormatterDirection Dir, cmsUInt32Number dwFlags); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/share/native/liblcms/lcms2_plugin.h --- a/jdk/src/java.desktop/share/native/liblcms/lcms2_plugin.h Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/share/native/liblcms/lcms2_plugin.h Wed Jul 05 20:01:50 2017 +0200 @@ -231,6 +231,7 @@ #define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH' #define cmsPluginOptimizationSig 0x6F707448 // 'optH' #define cmsPluginTransformSig 0x7A666D48 // 'xfmH' +#define cmsPluginMutexSig 0x6D747A48 // 'mtxH' typedef struct _cmsPluginBaseStruct { @@ -247,19 +248,28 @@ //---------------------------------------------------------------------------------------------------------- // Memory handler. Each new plug-in type replaces current behaviour + +typedef void* (* _cmsMallocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void (* _cmsFreeFnPtrType)(cmsContext ContextID, void *Ptr); +typedef void* (* _cmsReallocFnPtrType)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + +typedef void* (* _cmsMalloZerocFnPtrType)(cmsContext ContextID, cmsUInt32Number size); +typedef void* (* _cmsCallocFnPtrType)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); +typedef void* (* _cmsDupFnPtrType)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + typedef struct { cmsPluginBase base; // Required - void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size); - void (* FreePtr)(cmsContext ContextID, void *Ptr); - void * (* ReallocPtr)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize); + _cmsMallocFnPtrType MallocPtr; + _cmsFreeFnPtrType FreePtr; + _cmsReallocFnPtrType ReallocPtr; // Optional - void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size); - void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size); - void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size); + _cmsMalloZerocFnPtrType MallocZeroPtr; + _cmsCallocFnPtrType CallocPtr; + _cmsDupFnPtrType DupPtr; } cmsPluginMemHandler; @@ -622,6 +632,29 @@ } cmsPluginTransform; +//---------------------------------------------------------------------------------------------------------- +// Mutex + +typedef void* (* _cmsCreateMutexFnPtrType)(cmsContext ContextID); +typedef void (* _cmsDestroyMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef cmsBool (* _cmsLockMutexFnPtrType)(cmsContext ContextID, void* mtx); +typedef void (* _cmsUnlockMutexFnPtrType)(cmsContext ContextID, void* mtx); + +typedef struct { + cmsPluginBase base; + + _cmsCreateMutexFnPtrType CreateMutexPtr; + _cmsDestroyMutexFnPtrType DestroyMutexPtr; + _cmsLockMutexFnPtrType LockMutexPtr; + _cmsUnlockMutexFnPtrType UnlockMutexPtr; + +} cmsPluginMutex; + +CMSAPI void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID); +CMSAPI void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx); +CMSAPI cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx); +CMSAPI void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx); + #ifndef CMS_USE_CPP_API # ifdef __cplusplus diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java Wed Jul 05 20:01:50 2017 +0200 @@ -55,7 +55,6 @@ */ private final static int AWT_MULTICLICK_SMUDGE = 4; // ButtonXXX events stuff - static int rbutton = 0; static int lastX = 0, lastY = 0; static long lastTime = 0; static long lastButton = 0; @@ -632,23 +631,6 @@ return res; } - /** - * Returns true if this event is disabled and shouldn't be passed to Java. - * Default implementation returns false for all events. - */ - static int getRightButtonNumber() { - if (rbutton == 0) { // not initialized yet - XToolkit.awtLock(); - try { - rbutton = XlibWrapper.XGetPointerMapping(XToolkit.getDisplay(), XlibWrapper.ibuffer, 3); - } - finally { - XToolkit.awtUnlock(); - } - } - return rbutton; - } - static int getMouseMovementSmudge() { //TODO: It's possible to read corresponding settings return AWT_MULTICLICK_SMUDGE; @@ -716,11 +698,7 @@ /* Check for popup trigger !! */ - if (lbutton == getRightButtonNumber() || lbutton > 2) { - popupTrigger = true; - } else { - popupTrigger = false; - } + popupTrigger = (lbutton == 3); } button = XConstants.buttons[lbutton - 1]; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/unix/classes/sun/awt/datatransfer/flavormap.properties --- a/jdk/src/java.desktop/unix/classes/sun/awt/datatransfer/flavormap.properties Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -# -# This properties file is used to initialize the default -# java.awt.datatransfer.SystemFlavorMap. It contains the X11 platform-specific, -# default mappings between common X11 selection atoms and platform-independent -# MIME type strings, which will be converted into -# java.awt.datatransfer.DataFlavors. -# -# The standard format is: -# -# =,, ... -# -# should be a string identifier that the native platform will -# recognize as a valid data format. should specify both a MIME -# primary type and a MIME subtype separated by a '/'. The MIME type may include -# parameters, where each parameter is a key/value pair separated by '=', and -# where each parameter to the MIME type is separated by a ';'. -# -# Because SystemFlavorMap implements FlavorTable, developers are free to -# duplicate DataFlavor values and set multiple values for a single native by -# separating them with ",". If a mapping contains a duplicate key or value, -# earlier mappings which included this key or value will be preferred. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", and which support the charset parameter, should specify the exact -# format in which the native platform expects the data. The "charset" -# parameter specifies the char to byte encoding, the "eoln" parameter -# specifies the end-of-line marker, and the "terminators" parameter specifies -# the number of terminating NUL bytes. Note that "eoln" and "terminators" -# are not standardized MIME type parameters. They are specific to this file -# format ONLY. They will not appear in any of the DataFlavors returned by the -# SystemFlavorMap at the Java level. -# -# If the "charset" parameter is omitted, or has zero length, the platform -# default encoding is assumed. If the "eoln" parameter is omitted, or has -# zero length, "\n" is assumed. If the "terminators" parameter is omitted, -# or has a value less than zero, zero is assumed. -# -# Upon initialization, the data transfer subsystem will record the specified -# details of the native text format, but the default SystemFlavorMap will -# present a large set of synthesized DataFlavors which map, in both -# directions, to the native. After receiving data from the application in one -# of the synthetic DataFlavors, the data transfer subsystem will transform -# the data stream into the format specified in this file before passing the -# transformed stream to the native system. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", but which do not support the charset parameter, will be treated as -# opaque, 8-bit data. They will not undergo any transformation process, and -# any "charset", "eoln", or "terminators" parameters specified in this file -# will be ignored. -# -# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of -# text flavors which support the charset parameter. - -UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 - -# The COMPOUND_TEXT support for inter-client text transfer is disabled by -# default. The reason is that many native applications prefer this format over -# other native text formats, but are unable to decode the textual data in this -# format properly. This results in java-to-native text transfer failures. -# To enable the COMPOUND_TEXT support for this JRE installation uncomment -# the line below. - -# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 - -TEXT=text/plain;eoln="\n";terminators=0 -STRING=text/plain;charset=iso8859-1;eoln="\n";terminators=0 -FILE_NAME=application/x-java-file-list;class=java.util.List -text/uri-list=application/x-java-file-list;class=java.util.List -PNG=image/x-java-image;class=java.awt.Image -JFIF=image/x-java-image;class=java.awt.Image diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/unix/classes/sun/datatransfer/resources/flavormap.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.desktop/unix/classes/sun/datatransfer/resources/flavormap.properties Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,71 @@ +# +# This properties file is used to initialize the default +# java.awt.datatransfer.SystemFlavorMap. It contains the X11 platform-specific, +# default mappings between common X11 selection atoms and platform-independent +# MIME type strings, which will be converted into +# java.awt.datatransfer.DataFlavors. +# +# The standard format is: +# +# =,, ... +# +# should be a string identifier that the native platform will +# recognize as a valid data format. should specify both a MIME +# primary type and a MIME subtype separated by a '/'. The MIME type may include +# parameters, where each parameter is a key/value pair separated by '=', and +# where each parameter to the MIME type is separated by a ';'. +# +# Because SystemFlavorMap implements FlavorTable, developers are free to +# duplicate DataFlavor values and set multiple values for a single native by +# separating them with ",". If a mapping contains a duplicate key or value, +# earlier mappings which included this key or value will be preferred. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", and which support the charset parameter, should specify the exact +# format in which the native platform expects the data. The "charset" +# parameter specifies the char to byte encoding, the "eoln" parameter +# specifies the end-of-line marker, and the "terminators" parameter specifies +# the number of terminating NUL bytes. Note that "eoln" and "terminators" +# are not standardized MIME type parameters. They are specific to this file +# format ONLY. They will not appear in any of the DataFlavors returned by the +# SystemFlavorMap at the Java level. +# +# If the "charset" parameter is omitted, or has zero length, the platform +# default encoding is assumed. If the "eoln" parameter is omitted, or has +# zero length, "\n" is assumed. If the "terminators" parameter is omitted, +# or has a value less than zero, zero is assumed. +# +# Upon initialization, the data transfer subsystem will record the specified +# details of the native text format, but the default SystemFlavorMap will +# present a large set of synthesized DataFlavors which map, in both +# directions, to the native. After receiving data from the application in one +# of the synthetic DataFlavors, the data transfer subsystem will transform +# the data stream into the format specified in this file before passing the +# transformed stream to the native system. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", but which do not support the charset parameter, will be treated as +# opaque, 8-bit data. They will not undergo any transformation process, and +# any "charset", "eoln", or "terminators" parameters specified in this file +# will be ignored. +# +# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of +# text flavors which support the charset parameter. + +UTF8_STRING=text/plain;charset=UTF-8;eoln="\n";terminators=0 + +# The COMPOUND_TEXT support for inter-client text transfer is disabled by +# default. The reason is that many native applications prefer this format over +# other native text formats, but are unable to decode the textual data in this +# format properly. This results in java-to-native text transfer failures. +# To enable the COMPOUND_TEXT support for this JRE installation uncomment +# the line below. + +# COMPOUND_TEXT=text/plain;charset=x-compound-text;eoln="\n";terminators=0 + +TEXT=text/plain;eoln="\n";terminators=0 +STRING=text/plain;charset=iso8859-1;eoln="\n";terminators=0 +FILE_NAME=application/x-java-file-list;class=java.util.List +text/uri-list=application/x-java-file-list;class=java.util.List +PNG=image/x-java-image;class=java.awt.Image +JFIF=image/x-java-image;class=java.awt.Image diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSolidSrcPict.java --- a/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSolidSrcPict.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/xr/XRSolidSrcPict.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,12 +31,14 @@ XRSurfaceData srcPict; XRColor xrCol; - int curPixVal = -1; + int curPixVal; public XRSolidSrcPict(XRBackend con, int parentXid) { this.con = con; xrCol = new XRColor(); + curPixVal = 0xFF000000; + int solidPixmap = con.createPixmap(parentXid, 32, 1, 1); int solidSrcPictXID = con.createPicture(solidPixmap, XRUtils.PictStandardARGB32); con.setPictureRepeat(solidSrcPictXID, XRUtils.RepeatNormal); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/windows/classes/sun/awt/datatransfer/flavormap.properties --- a/jdk/src/java.desktop/windows/classes/sun/awt/datatransfer/flavormap.properties Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -# -# This properties file is used to initialize the default -# java.awt.datatransfer.SystemFlavorMap. It contains the Win32 platform- -# specific, default mappings between common Win32 Clipboard atoms and platform- -# independent MIME type strings, which will be converted into -# java.awt.datatransfer.DataFlavors. -# -# The standard format is: -# -# =,, ... -# -# should be a string identifier that the native platform will -# recognize as a valid data format. should specify both a MIME -# primary type and a MIME subtype separated by a '/'. The MIME type may include -# parameters, where each parameter is a key/value pair separated by '=', and -# where each parameter to the MIME type is separated by a ';'. -# -# Because SystemFlavorMap implements FlavorTable, developers are free to -# duplicate DataFlavor values and set multiple values for a single native by -# separating them with ",". If a mapping contains a duplicate key or value, -# earlier mappings which included this key or value will be preferred.# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", and which support the charset parameter, should specify the exact -# format in which the native platform expects the data. The "charset" -# parameter specifies the char to byte encoding, the "eoln" parameter -# specifies the end-of-line marker, and the "terminators" parameter specifies -# the number of terminating NUL bytes. Note that "eoln" and "terminators" -# are not standardized MIME type parameters. They are specific to this file -# format ONLY. They will not appear in any of the DataFlavors returned by the -# SystemFlavorMap at the Java level. -# -# If the "charset" parameter is omitted, or has zero length, the platform -# default encoding is assumed. If the "eoln" parameter is omitted, or has -# zero length, "\n" is assumed. If the "terminators" parameter is omitted, -# or has a value less than zero, zero is assumed. -# -# Upon initialization, the data transfer subsystem will record the specified -# details of the native text format, but the default SystemFlavorMap will -# present a large set of synthesized DataFlavors which map, in both -# directions, to the native. After receiving data from the application in one -# of the synthetic DataFlavors, the data transfer subsystem will transform -# the data stream into the format specified in this file before passing the -# transformed stream to the native system. -# -# Mappings whose values specify DataFlavors with primary MIME types of -# "text", but which do not support the charset parameter, will be treated as -# opaque, 8-bit data. They will not undergo any transformation process, and -# any "charset", "eoln", or "terminators" parameters specified in this file -# will be ignored. -# -# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of -# text flavors which support the charset parameter. - -UNICODE\ TEXT=text/plain;charset=utf-16le;eoln="\r\n";terminators=2 -TEXT=text/plain;eoln="\r\n";terminators=1 -HTML\ Format=text/html;charset=utf-8;eoln="\r\n";terminators=1 -Rich\ Text\ Format=text/rtf -HDROP=application/x-java-file-list;class=java.util.List -PNG=image/x-java-image;class=java.awt.Image -JFIF=image/x-java-image;class=java.awt.Image -DIB=image/x-java-image;class=java.awt.Image -ENHMETAFILE=image/x-java-image;class=java.awt.Image -METAFILEPICT=image/x-java-image;class=java.awt.Image -LOCALE=application/x-java-text-encoding;class="[B" -UniformResourceLocator=application/x-java-url;class=java.net.URL,\ - text/uri-list;eoln="\r\n";terminators=1,\ - text/plain;eoln="\r\n";terminators=1 -FileGroupDescriptorW=application/x-java-file-list;class=java.util.List -FileGroupDescriptor=application/x-java-file-list;class=java.util.List diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/windows/classes/sun/awt/windows/WBufferStrategy.java --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WBufferStrategy.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2002, 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 sun.awt.windows; - -import java.awt.Image; -import java.awt.Component; - -/** - * This sun-private class exists solely to get a handle to - * the back buffer associated with a Component. If that - * Component has a BufferStrategy with >1 buffer, then the - * Image subclass associated with that buffer will be returned. - * Note: the class is used by the JAWT3d. - */ -public final class WBufferStrategy { - - private static native void initIDs(Class componentClass); - - static { - initIDs(Component.class); - } - - public static native Image getDrawBuffer(Component comp); - -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/windows/classes/sun/datatransfer/resources/flavormap.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.desktop/windows/classes/sun/datatransfer/resources/flavormap.properties Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,69 @@ +# +# This properties file is used to initialize the default +# java.awt.datatransfer.SystemFlavorMap. It contains the Win32 platform- +# specific, default mappings between common Win32 Clipboard atoms and platform- +# independent MIME type strings, which will be converted into +# java.awt.datatransfer.DataFlavors. +# +# The standard format is: +# +# =,, ... +# +# should be a string identifier that the native platform will +# recognize as a valid data format. should specify both a MIME +# primary type and a MIME subtype separated by a '/'. The MIME type may include +# parameters, where each parameter is a key/value pair separated by '=', and +# where each parameter to the MIME type is separated by a ';'. +# +# Because SystemFlavorMap implements FlavorTable, developers are free to +# duplicate DataFlavor values and set multiple values for a single native by +# separating them with ",". If a mapping contains a duplicate key or value, +# earlier mappings which included this key or value will be preferred.# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", and which support the charset parameter, should specify the exact +# format in which the native platform expects the data. The "charset" +# parameter specifies the char to byte encoding, the "eoln" parameter +# specifies the end-of-line marker, and the "terminators" parameter specifies +# the number of terminating NUL bytes. Note that "eoln" and "terminators" +# are not standardized MIME type parameters. They are specific to this file +# format ONLY. They will not appear in any of the DataFlavors returned by the +# SystemFlavorMap at the Java level. +# +# If the "charset" parameter is omitted, or has zero length, the platform +# default encoding is assumed. If the "eoln" parameter is omitted, or has +# zero length, "\n" is assumed. If the "terminators" parameter is omitted, +# or has a value less than zero, zero is assumed. +# +# Upon initialization, the data transfer subsystem will record the specified +# details of the native text format, but the default SystemFlavorMap will +# present a large set of synthesized DataFlavors which map, in both +# directions, to the native. After receiving data from the application in one +# of the synthetic DataFlavors, the data transfer subsystem will transform +# the data stream into the format specified in this file before passing the +# transformed stream to the native system. +# +# Mappings whose values specify DataFlavors with primary MIME types of +# "text", but which do not support the charset parameter, will be treated as +# opaque, 8-bit data. They will not undergo any transformation process, and +# any "charset", "eoln", or "terminators" parameters specified in this file +# will be ignored. +# +# See java.awt.datatransfer.DataFlavor.selectBestTextFlavor for a list of +# text flavors which support the charset parameter. + +UNICODE\ TEXT=text/plain;charset=utf-16le;eoln="\r\n";terminators=2 +TEXT=text/plain;eoln="\r\n";terminators=1 +HTML\ Format=text/html;charset=utf-8;eoln="\r\n";terminators=1 +Rich\ Text\ Format=text/rtf +HDROP=application/x-java-file-list;class=java.util.List +PNG=image/x-java-image;class=java.awt.Image +JFIF=image/x-java-image;class=java.awt.Image +DIB=image/x-java-image;class=java.awt.Image +ENHMETAFILE=image/x-java-image;class=java.awt.Image +METAFILEPICT=image/x-java-image;class=java.awt.Image +LOCALE=application/x-java-text-encoding;class="[B" +UniformResourceLocator=application/x-java-url;class=java.net.URL,\ + text/uri-list;eoln="\r\n";terminators=1,\ + text/plain;eoln="\r\n";terminators=1 +FileGroupDescriptorW=application/x-java-file-list;class=java.util.List +FileGroupDescriptor=application/x-java-file-list;class=java.util.List diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/windows/native/libawt/sun/java2d/d3d/D3DPipeline.cpp --- a/jdk/src/java.desktop/windows/native/libawt/sun/java2d/d3d/D3DPipeline.cpp Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. - * 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 "D3DPipeline.h" - -BOOL APIENTRY DllMain( HANDLE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved) -{ - switch (ul_reason_for_call) { - case DLL_PROCESS_ATTACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.desktop/windows/native/libawt/sun/windows/WBufferStrategy.cpp --- a/jdk/src/java.desktop/windows/native/libawt/sun/windows/WBufferStrategy.cpp Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 "sun_awt_windows_WBufferStrategy.h" -#include "jni_util.h" - - -static jmethodID getBackBufferID; - -/* - * Class: sun_awt_windows_WBufferStrategy - * Method: initIDs - * Signature: (Ljava/lang/Class;)V - */ -JNIEXPORT void JNICALL -Java_sun_awt_windows_WBufferStrategy_initIDs(JNIEnv *env, jclass wbs, - jclass componentClass) -{ - getBackBufferID = env->GetMethodID(componentClass, "getBackBuffer", - "()Ljava/awt/Image;"); -} - -/** - * Native method of WBufferStrategy.java. Given a Component - * object, this method will find the back buffer associated - * with the Component's BufferStrategy and return a handle - * to it. - */ -extern "C" JNIEXPORT jobject JNICALL -Java_sun_awt_windows_WBufferStrategy_getDrawBuffer(JNIEnv *env, jclass wbs, - jobject component) -{ - if (!JNU_IsNull(env, getBackBufferID)) { - return env->CallObjectMethod(component, getBackBufferID); - } else { - return NULL; - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java --- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnector.java Wed Jul 05 20:01:50 2017 +0200 @@ -1335,66 +1335,94 @@ int maxNotifications, long timeout) throws IOException, ClassNotFoundException { - IOException org; + boolean retried = false; while (true) { // used for a successful re-connection + // or a transient network problem try { return connection.fetchNotifications(clientSequenceNumber, maxNotifications, - timeout); + timeout); // return normally } catch (IOException ioe) { - org = ioe; + // Examine the chain of exceptions to determine whether this + // is a deserialization issue. If so - we propagate the + // appropriate exception to the caller, who will then + // proceed with fetching notifications one by one + rethrowDeserializationException(ioe); - // inform of IOException try { communicatorAdmin.gotIOException(ioe); - - // The connection should be re-established. - continue; + // reconnection OK, back to "while" to do again } catch (IOException ee) { - // No more fetch, the Exception will be re-thrown. - break; - } // never reached - } // never reached - } + boolean toClose = false; - // specially treating for an UnmarshalException - if (org instanceof UnmarshalException) { - UnmarshalException ume = (UnmarshalException)org; - - if (ume.detail instanceof ClassNotFoundException) - throw (ClassNotFoundException) ume.detail; + synchronized (this) { + if (terminated) { + // the connection is closed. + throw ioe; + } else if (retried) { + toClose = true; + } + } - /* In Sun's RMI implementation, if a method return - contains an unserializable object, then we get - UnmarshalException wrapping WriteAbortedException - wrapping NotSerializableException. In that case we - extract the NotSerializableException so that our - caller can realize it should try to skip past the - notification that presumably caused it. It's not - certain that every other RMI implementation will - generate this exact exception sequence. If not, we - will not detect that the problem is due to an - unserializable object, and we will stop trying to - receive notifications from the server. It's not - clear we can do much better. */ - if (ume.detail instanceof WriteAbortedException) { - WriteAbortedException wae = - (WriteAbortedException) ume.detail; - if (wae.detail instanceof IOException) - throw (IOException) wae.detail; + if (toClose) { + // JDK-8049303 + // We received an IOException - but the communicatorAdmin + // did not close the connection - possibly because + // the original exception was raised by a transient network + // problem? + // We already know that this exception is not due to a deserialization + // issue as we already took care of that before involving the + // communicatorAdmin. Moreover - we already made one retry attempt + // at fetching the same batch of notifications - and the + // problem persisted. + // Since trying again doesn't seem to solve the issue, we will now + // close the connection. Doing otherwise might cause the + // NotifFetcher thread to die silently. + final Notification failedNotif = + new JMXConnectionNotification( + JMXConnectionNotification.FAILED, + this, + connectionId, + clientNotifSeqNo++, + "Failed to communicate with the server: " + ioe.toString(), + ioe); + + sendNotification(failedNotif); + + try { + close(true); + } catch (Exception e) { + // OK. + // We are closing + } + throw ioe; // the connection is closed here. + } else { + // JDK-8049303 possible transient network problem, + // let's try one more time + retried = true; + } + } } - } else if (org instanceof MarshalException) { + } + } + + private void rethrowDeserializationException(IOException ioe) + throws ClassNotFoundException, IOException { + // specially treating for an UnmarshalException + if (ioe instanceof UnmarshalException) { + throw ioe; // the fix of 6937053 made ClientNotifForwarder.fetchNotifs + // fetch one by one with UnmarshalException + } else if (ioe instanceof MarshalException) { // IIOP will throw MarshalException wrapping a NotSerializableException // when a server fails to serialize a response. - MarshalException me = (MarshalException)org; + MarshalException me = (MarshalException)ioe; if (me.detail instanceof NotSerializableException) { throw (NotSerializableException)me.detail; } } - // Not serialization problem, simply re-throw the orginal exception - throw org; + // Not serialization problem, return. } protected Integer addListenerForMBeanRemovedNotif() diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2009, 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 com.sun.security.jgss; - -/** - * Kerberos 5 AuthorizationData entry. - */ -@jdk.Exported -public final class AuthorizationDataEntry { - - private final int type; - private final byte[] data; - - /** - * Create an AuthorizationDataEntry object. - * @param type the ad-type - * @param data the ad-data, a copy of the data will be saved - * inside the object. - */ - public AuthorizationDataEntry(int type, byte[] data) { - this.type = type; - this.data = data.clone(); - } - - /** - * Get the ad-type field. - * @return ad-type - */ - public int getType() { - return type; - } - - /** - * Get a copy of the ad-data field. - * @return ad-data - */ - public byte[] getData() { - return data.clone(); - } - - public String toString() { - return "AuthorizationDataEntry: type="+type+", data=" + - data.length + " bytes:\n" + - new sun.misc.HexDumpEncoder().encodeBuffer(data); - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2009, 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 com.sun.security.jgss; - -import org.ietf.jgss.*; - -/** - * The extended GSSContext interface for supporting additional - * functionalities not defined by {@code org.ietf.jgss.GSSContext}, - * such as querying context-specific attributes. - */ -@jdk.Exported -public interface ExtendedGSSContext extends GSSContext { - /** - * Return the mechanism-specific attribute associated with {@code type}. - *

- * If there is a security manager, an {@link InquireSecContextPermission} - * with the name {@code type.mech} must be granted. Otherwise, this could - * result in a {@link SecurityException}.

- * - * Example: - *

-     *      GSSContext ctxt = m.createContext(...)
-     *      // Establishing the context
-     *      if (ctxt instanceof ExtendedGSSContext) {
-     *          ExtendedGSSContext ex = (ExtendedGSSContext)ctxt;
-     *          try {
-     *              Key key = (key)ex.inquireSecContext(
-     *                      InquireType.KRB5_GET_SESSION_KEY);
-     *              // read key info
-     *          } catch (GSSException gsse) {
-     *              // deal with exception
-     *          }
-     *      }
-     * 
- * @param type the type of the attribute requested - * @return the attribute, see the method documentation for details. - * @throws GSSException containing the following - * major error codes: - * {@link GSSException#BAD_MECH GSSException.BAD_MECH} if the mechanism - * does not support this method, - * {@link GSSException#UNAVAILABLE GSSException.UNAVAILABLE} if the - * type specified is not supported, - * {@link GSSException#NO_CONTEXT GSSException.NO_CONTEXT} if the - * security context is invalid, - * {@link GSSException#FAILURE GSSException.FAILURE} for other - * unspecified failures. - * @throws SecurityException if a security manager exists and a proper - * {@link InquireSecContextPermission} is not granted. - * @see InquireSecContextPermission - * @see InquireType - */ - public Object inquireSecContext(InquireType type) - throws GSSException; - - /** - * Requests that the delegation policy be respected. When a true value is - * requested, the underlying context would use the delegation policy - * defined by the environment as a hint to determine whether credentials - * delegation should be performed. This request can only be made on the - * context initiator's side and it has to be done prior to the first - * call to initSecContext. - *

- * When this flag is false, delegation will only be tried when the - * {@link GSSContext#requestCredDeleg(boolean) credentials delegation flag} - * is true. - *

- * When this flag is true but the - * {@link GSSContext#requestCredDeleg(boolean) credentials delegation flag} - * is false, delegation will be only tried if the delegation policy permits - * delegation. - *

- * When both this flag and the - * {@link GSSContext#requestCredDeleg(boolean) credentials delegation flag} - * are true, delegation will be always tried. However, if the delegation - * policy does not permit delegation, the value of - * {@link #getDelegPolicyState} will be false, even - * if delegation is performed successfully. - *

- * In any case, if the delegation is not successful, the value returned - * by {@link GSSContext#getCredDelegState()} is false, and the value - * returned by {@link #getDelegPolicyState()} is also false. - *

- * Not all mechanisms support delegation policy. Therefore, the - * application should check to see if the request was honored with the - * {@link #getDelegPolicyState() getDelegPolicyState} method. When - * delegation policy is not supported, requestDelegPolicy - * should return silently without throwing an exception. - *

- * Note: for the Kerberos 5 mechanism, the delegation policy is expressed - * through the OK-AS-DELEGATE flag in the service ticket. When it's true, - * the KDC permits delegation to the target server. In a cross-realm - * environment, in order for delegation be permitted, all cross-realm TGTs - * on the authentication path must also have the OK-AS-DELAGATE flags set. - * @param state true if the policy should be respected - * @throws GSSException containing the following - * major error codes: - * {@link GSSException#FAILURE GSSException.FAILURE} - */ - public void requestDelegPolicy(boolean state) throws GSSException; - - /** - * Returns the delegation policy response. Called after a security context - * is established. This method can be only called on the initiator's side. - * See {@link ExtendedGSSContext#requestDelegPolicy}. - * @return the delegation policy response - */ - public boolean getDelegPolicyState(); -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.security.jgss; - -import org.ietf.jgss.*; - -/** - * The extended GSSCredential interface for supporting additional - * functionalities not defined by {@code org.ietf.jgss.GSSCredential}. - * @since 1.8 - */ -@jdk.Exported -public interface ExtendedGSSCredential extends GSSCredential { - /** - * Impersonates a principal. In Kerberos, this can be implemented - * using the Microsoft S4U2self extension. - *

- * A {@link GSSException#NO_CRED GSSException.NO_CRED} will be thrown if the - * impersonation fails. A {@link GSSException#FAILURE GSSException.FAILURE} - * will be thrown if the impersonation method is not available to this - * credential object. - * @param name the name of the principal to impersonate - * @return a credential for that principal - * @throws GSSException containing the following - * major error codes: - * {@link GSSException#NO_CRED GSSException.NO_CRED} - * {@link GSSException#FAILURE GSSException.FAILURE} - */ - public GSSCredential impersonate(GSSName name) throws GSSException; -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/GSSUtil.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/GSSUtil.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2000, 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 com.sun.security.jgss; - -import javax.security.auth.Subject; -import org.ietf.jgss.GSSName; -import org.ietf.jgss.GSSCredential; - -/** - * GSS-API Utilities for using in conjunction with Sun Microsystem's - * implementation of Java GSS-API. - */ -@jdk.Exported -public class GSSUtil { - - /** - * Use this method to convert a GSSName and GSSCredential into a - * Subject. Typically this would be done by a server that wants to - * impersonate a client thread at the Java level by setting a client - * Subject in the current access control context. If the server is merely - * interested in using a principal based policy in its local JVM, then - * it only needs to provide the GSSName of the client. - * - * The elements from the GSSName are placed in the principals set of this - * Subject and those from the GSSCredential are placed in the private - * credentials set of the Subject. Any Kerberos specific elements that - * are added to the subject will be instances of the standard Kerberos - * implementation classes defined in javax.security.auth.kerberos. - * - * @return a Subject with the entries that contain elements from the - * given GSSName and GSSCredential. - * - * @param principals a GSSName containing one or more mechanism specific - * representations of the same entity. These mechanism specific - * representations will be populated in the returned Subject's principal - * set. - * - * @param credentials a GSSCredential containing one or more mechanism - * specific credentials for the same entity. These mechanism specific - * credentials will be populated in the returned Subject's private - * credential set. Passing in a value of null will imply that the private - * credential set should be left empty. - */ - public static Subject createSubject(GSSName principals, - GSSCredential credentials) { - - return sun.security.jgss.GSSUtil.getSubject(principals, - credentials); - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2009, 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 com.sun.security.jgss; - -import java.security.BasicPermission; - -/** - * This class is used to protect various attributes of an established - * GSS security context that can be accessed using the - * {@link com.sun.security.jgss.ExtendedGSSContext#inquireSecContext} - * method. - * - *

The target name is the {@link InquireType} allowed. - */ -@jdk.Exported -public final class InquireSecContextPermission extends BasicPermission { - private static final long serialVersionUID = -7131173349668647297L; - - /** - * Constructs a new {@code InquireSecContextPermission} object with - * the specified name. The name is the symbolic name of the - * {@link InquireType} allowed. - * - * @param name the {@link InquireType} allowed by this - * permission. "*" means all {@link InquireType}s are allowed. - * - * @throws NullPointerException if name is null. - * @throws IllegalArgumentException if name is empty. - */ - public InquireSecContextPermission(String name) { - super(name); - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireType.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireType.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2009, 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 com.sun.security.jgss; - -/** - * Attribute types that can be specified as an argument of - * {@link com.sun.security.jgss.ExtendedGSSContext#inquireSecContext} - */ -@jdk.Exported -public enum InquireType { - /** - * Attribute type for retrieving the session key of an established - * Kerberos 5 security context. The returned object is an instance of - * {@link java.security.Key}, which has the following properties: - *

    - *
  • Algorithm: enctype as a string, where - * enctype is defined in RFC 3961, section 8. - *
  • Format: "RAW" - *
  • Encoded form: the raw key bytes, not in any ASN.1 encoding - *
- * @deprecated as of 1.9, replaced by {@link #KRB5_GET_SESSION_KEY_EX} - * which returns an instance of - * {@link javax.security.auth.kerberos.EncryptionKey} - * that implements the {@link javax.crypto.SecretKey} interface and - * has similar methods with {@link javax.security.auth.kerberos.KerberosKey}. - */ - @Deprecated - KRB5_GET_SESSION_KEY, - /** - * Attribute type for retrieving the session key of an - * established Kerberos 5 security context. The return value is an - * instance of {@link javax.security.auth.kerberos.EncryptionKey}. - * - * @since 1.9 - */ - KRB5_GET_SESSION_KEY_EX, - /** - * Attribute type for retrieving the service ticket flags of an - * established Kerberos 5 security context. The returned object is - * a boolean array for the service ticket flags, which is long enough - * to contain all true bits. This means if the user wants to get the - * n'th bit but the length of the returned array is less than - * n, it is regarded as false. - */ - KRB5_GET_TKT_FLAGS, - /** - * Attribute type for retrieving the authorization data in the - * service ticket of an established Kerberos 5 security context. - * Only supported on the acceptor side. - */ - KRB5_GET_AUTHZ_DATA, - /** - * Attribute type for retrieving the authtime in the service ticket - * of an established Kerberos 5 security context. The returned object - * is a String object in the standard KerberosTime format defined in - * RFC 4120 Section 5.2.3. - */ - KRB5_GET_AUTHTIME, - /** - * Attribute type for retrieving the KRB_CRED message that an initiator - * is about to send to an acceptor. The return type is an instance of - * {@link javax.security.auth.kerberos.KerberosCredMessage}. - * - * @since 1.9 - */ - KRB5_GET_KRB_CRED, -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/package-info.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/package-info.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +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. - */ - -@jdk.Exported -package com.sun.security.jgss; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.security.sasl.gsskerb; - -import javax.security.sasl.*; -import com.sun.security.sasl.util.PolicyUtils; - -import java.util.Map; -import javax.security.auth.callback.CallbackHandler; - -/** - * Client/server factory for GSSAPI (Kerberos V5) SASL client/server mechs. - * See GssKrb5Client/GssKrb5Server for input requirements. - * - * @author Rosanna Lee - */ -public final class FactoryImpl implements SaslClientFactory, SaslServerFactory { - private static final String myMechs[] = { - "GSSAPI"}; - - private static final int mechPolicies[] = { - PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS|PolicyUtils.NOACTIVE - }; - - private static final int GSS_KERB_V5 = 0; - - public FactoryImpl() { - } - - public SaslClient createSaslClient(String[] mechs, - String authorizationId, - String protocol, - String serverName, - Map props, - CallbackHandler cbh) throws SaslException { - - for (int i = 0; i < mechs.length; i++) { - if (mechs[i].equals(myMechs[GSS_KERB_V5]) - && PolicyUtils.checkPolicy(mechPolicies[GSS_KERB_V5], props)) { - return new GssKrb5Client( - authorizationId, - protocol, - serverName, - props, - cbh); - } - } - return null; - }; - - public SaslServer createSaslServer(String mech, - String protocol, - String serverName, - Map props, - CallbackHandler cbh) throws SaslException { - if (mech.equals(myMechs[GSS_KERB_V5]) - && PolicyUtils.checkPolicy(mechPolicies[GSS_KERB_V5], props)) { - if (cbh == null) { - throw new SaslException( - "Callback handler with support for AuthorizeCallback required"); - } - return new GssKrb5Server( - protocol, - serverName, - props, - cbh); - } - return null; - }; - - public String[] getMechanismNames(Map props) { - return PolicyUtils.filterMechs(myMechs, mechPolicies, props); - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2003, 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 com.sun.security.sasl.gsskerb; - -import java.util.Locale; -import java.util.Map; -import java.util.logging.Level; -import javax.security.sasl.*; -import com.sun.security.sasl.util.AbstractSaslImpl; -import org.ietf.jgss.*; -import com.sun.security.jgss.ExtendedGSSContext; -import com.sun.security.jgss.InquireType; - -abstract class GssKrb5Base extends AbstractSaslImpl { - - private static final String KRB5_OID_STR = "1.2.840.113554.1.2.2"; - protected static Oid KRB5_OID; - protected static final byte[] EMPTY = new byte[0]; - - static { - try { - KRB5_OID = new Oid(KRB5_OID_STR); - } catch (GSSException ignore) {} - } - - protected GSSContext secCtx = null; - protected static final int JGSS_QOP = 0; // unrelated to SASL QOP mask - - protected GssKrb5Base(Map props, String className) - throws SaslException { - super(props, className); - } - - /** - * Retrieves this mechanism's name. - * - * @return The string "GSSAPI". - */ - public String getMechanismName() { - return "GSSAPI"; - } - - @Override - public Object getNegotiatedProperty(String propName) { - if (!completed) { - throw new IllegalStateException("Authentication incomplete"); - } - String xprefix = "com.sun.security.jgss.inquiretype."; - if (propName.startsWith(xprefix)) { - String type = propName.substring(xprefix.length()); - if (logger.isLoggable(Level.FINEST)) { - logger.logp(Level.FINE, "GssKrb5Base", - "getNegotiatedProperty", propName); - } - for (InquireType t: InquireType.values()) { - if (t.name().toLowerCase(Locale.US).equals(type)) { - try { - return ((ExtendedGSSContext)secCtx).inquireSecContext(t); - } catch (GSSException e) { - if (logger.isLoggable(Level.FINEST)) { - logger.log(Level.WARNING, "inquireSecContext error", e); - } - return null; - } - } - } - // No such InquireType. Although not likely to be defined - // as a property in a parent class, still try it. - } - return super.getNegotiatedProperty(propName); - } - - public byte[] unwrap(byte[] incoming, int start, int len) - throws SaslException { - if (!completed) { - throw new IllegalStateException("GSSAPI authentication not completed"); - } - - // integrity will be true if either privacy or integrity negotiated - if (!integrity) { - throw new IllegalStateException("No security layer negotiated"); - } - - try { - MessageProp msgProp = new MessageProp(JGSS_QOP, privacy); - byte[] answer = secCtx.unwrap(incoming, start, len, msgProp); - if (logger.isLoggable(Level.FINEST)) { - traceOutput(myClassName, "KRB501:Unwrap", "incoming: ", - incoming, start, len); - traceOutput(myClassName, "KRB502:Unwrap", "unwrapped: ", - answer, 0, answer.length); - } - return answer; - } catch (GSSException e) { - throw new SaslException("Problems unwrapping SASL buffer", e); - } - } - - public byte[] wrap(byte[] outgoing, int start, int len) throws SaslException { - if (!completed) { - throw new IllegalStateException("GSSAPI authentication not completed"); - } - - // integrity will be true if either privacy or integrity negotiated - if (!integrity) { - throw new IllegalStateException("No security layer negotiated"); - } - - // Generate GSS token - try { - MessageProp msgProp = new MessageProp(JGSS_QOP, privacy); - byte[] answer = secCtx.wrap(outgoing, start, len, msgProp); - if (logger.isLoggable(Level.FINEST)) { - traceOutput(myClassName, "KRB503:Wrap", "outgoing: ", - outgoing, start, len); - traceOutput(myClassName, "KRB504:Wrap", "wrapped: ", - answer, 0, answer.length); - } - return answer; - - } catch (GSSException e) { - throw new SaslException("Problem performing GSS wrap", e); - } - } - - public void dispose() throws SaslException { - if (secCtx != null) { - try { - secCtx.dispose(); - } catch (GSSException e) { - throw new SaslException("Problem disposing GSS context", e); - } - secCtx = null; - } - } - - protected void finalize() throws Throwable { - dispose(); - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,329 +0,0 @@ -/* - * Copyright (c) 2000, 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 com.sun.security.sasl.gsskerb; - -import java.io.IOException; -import java.util.Map; -import java.util.logging.Level; -import javax.security.sasl.*; - -// JAAS -import javax.security.auth.callback.CallbackHandler; - -// JGSS -import org.ietf.jgss.*; - -/** - * Implements the GSSAPI SASL client mechanism for Kerberos V5. - * (RFC 2222, - * draft-ietf-cat-sasl-gssapi-04.txt). - * It uses the Java Bindings for GSSAPI - * (RFC 2853) - * for getting GSSAPI/Kerberos V5 support. - * - * The client/server interactions are: - * C0: bind (GSSAPI, initial response) - * S0: sasl-bind-in-progress, challenge 1 (output of accept_sec_context or []) - * C1: bind (GSSAPI, response 1 (output of init_sec_context or [])) - * S1: sasl-bind-in-progress challenge 2 (security layer, server max recv size) - * C2: bind (GSSAPI, response 2 (security layer, client max recv size, authzid)) - * S2: bind success response - * - * Expects the client's credentials to be supplied from the - * javax.security.sasl.credentials property or from the thread's Subject. - * Otherwise the underlying KRB5 mech will attempt to acquire Kerberos creds - * by logging into Kerberos (via default TextCallbackHandler). - * These creds will be used for exchange with server. - * - * Required callbacks: none. - * - * Environment properties that affect behavior of implementation: - * - * javax.security.sasl.qop - * - quality of protection; list of auth, auth-int, auth-conf; default is "auth" - * javax.security.sasl.maxbuf - * - max receive buffer size; default is 65536 - * javax.security.sasl.sendmaxbuffer - * - max send buffer size; default is 65536; (min with server max recv size) - * - * javax.security.sasl.server.authentication - * - "true" means require mutual authentication; default is "false" - * - * javax.security.sasl.credentials - * - an {@link org.ietf.jgss.GSSCredential} used for delegated authentication. - * - * @author Rosanna Lee - */ - -final class GssKrb5Client extends GssKrb5Base implements SaslClient { - // ---------------- Constants ----------------- - private static final String MY_CLASS_NAME = GssKrb5Client.class.getName(); - - private boolean finalHandshake = false; - private boolean mutual = false; // default false - private byte[] authzID; - - /** - * Creates a SASL mechanism with client credentials that it needs - * to participate in GSS-API/Kerberos v5 authentication exchange - * with the server. - */ - GssKrb5Client(String authzID, String protocol, String serverName, - Map props, CallbackHandler cbh) throws SaslException { - - super(props, MY_CLASS_NAME); - - String service = protocol + "@" + serverName; - logger.log(Level.FINE, "KRB5CLNT01:Requesting service name: {0}", - service); - - try { - GSSManager mgr = GSSManager.getInstance(); - - // Create the name for the requested service entity for Krb5 mech - GSSName acceptorName = mgr.createName(service, - GSSName.NT_HOSTBASED_SERVICE, KRB5_OID); - - // Parse properties to check for supplied credentials - GSSCredential credentials = null; - if (props != null) { - Object prop = props.get(Sasl.CREDENTIALS); - if (prop != null && prop instanceof GSSCredential) { - credentials = (GSSCredential) prop; - logger.log(Level.FINE, - "KRB5CLNT01:Using the credentials supplied in " + - "javax.security.sasl.credentials"); - } - } - - // Create a context using credentials for Krb5 mech - secCtx = mgr.createContext(acceptorName, - KRB5_OID, /* mechanism */ - credentials, /* credentials */ - GSSContext.INDEFINITE_LIFETIME); - - // Request credential delegation when credentials have been supplied - if (credentials != null) { - secCtx.requestCredDeleg(true); - } - - // Parse properties to set desired context options - if (props != null) { - // Mutual authentication - String prop = (String)props.get(Sasl.SERVER_AUTH); - if (prop != null) { - mutual = "true".equalsIgnoreCase(prop); - } - } - secCtx.requestMutualAuth(mutual); - - // Always specify potential need for integrity and confidentiality - // Decision will be made during final handshake - secCtx.requestConf(true); - secCtx.requestInteg(true); - - } catch (GSSException e) { - throw new SaslException("Failure to initialize security context", e); - } - - if (authzID != null && authzID.length() > 0) { - try { - this.authzID = authzID.getBytes("UTF8"); - } catch (IOException e) { - throw new SaslException("Cannot encode authorization ID", e); - } - } - } - - public boolean hasInitialResponse() { - return true; - } - - /** - * Processes the challenge data. - * - * The server sends a challenge data using which the client must - * process using GSS_Init_sec_context. - * As per RFC 2222, when GSS_S_COMPLETE is returned, we do - * an extra handshake to determine the negotiated security protection - * and buffer sizes. - * - * @param challengeData A non-null byte array containing the - * challenge data from the server. - * @return A non-null byte array containing the response to be - * sent to the server. - */ - public byte[] evaluateChallenge(byte[] challengeData) throws SaslException { - if (completed) { - throw new IllegalStateException( - "GSSAPI authentication already complete"); - } - - if (finalHandshake) { - return doFinalHandshake(challengeData); - } else { - - // Security context not established yet; continue with init - - try { - byte[] gssOutToken = secCtx.initSecContext(challengeData, - 0, challengeData.length); - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "evaluteChallenge", - "KRB5CLNT02:Challenge: [raw]", challengeData); - traceOutput(MY_CLASS_NAME, "evaluateChallenge", - "KRB5CLNT03:Response: [after initSecCtx]", gssOutToken); - } - - if (secCtx.isEstablished()) { - finalHandshake = true; - if (gssOutToken == null) { - // RFC 2222 7.2.1: Client responds with no data - return EMPTY; - } - } - - return gssOutToken; - } catch (GSSException e) { - throw new SaslException("GSS initiate failed", e); - } - } - } - - private byte[] doFinalHandshake(byte[] challengeData) throws SaslException { - try { - // Security context already established. challengeData - // should contain security layers and server's maximum buffer size - - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "doFinalHandshake", - "KRB5CLNT04:Challenge [raw]:", challengeData); - } - - if (challengeData.length == 0) { - // Received S0, should return [] - return EMPTY; - } - - // Received S1 (security layer, server max recv size) - - byte[] gssOutToken = secCtx.unwrap(challengeData, 0, - challengeData.length, new MessageProp(0, false)); - - // First octet is a bit-mask specifying the protections - // supported by the server - if (logger.isLoggable(Level.FINE)) { - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "doFinalHandshake", - "KRB5CLNT05:Challenge [unwrapped]:", gssOutToken); - } - logger.log(Level.FINE, "KRB5CLNT06:Server protections: {0}", - gssOutToken[0]); - } - - // Client selects preferred protection - // qop is ordered list of qop values - byte selectedQop = findPreferredMask(gssOutToken[0], qop); - if (selectedQop == 0) { - throw new SaslException( - "No common protection layer between client and server"); - } - - if ((selectedQop&PRIVACY_PROTECTION) != 0) { - privacy = true; - integrity = true; - } else if ((selectedQop&INTEGRITY_ONLY_PROTECTION) != 0) { - integrity = true; - } - - // 2nd-4th octets specifies maximum buffer size expected by - // server (in network byte order) - int srvMaxBufSize = networkByteOrderToInt(gssOutToken, 1, 3); - - // Determine the max send buffer size based on what the - // server is able to receive and our specified max - sendMaxBufSize = (sendMaxBufSize == 0) ? srvMaxBufSize : - Math.min(sendMaxBufSize, srvMaxBufSize); - - // Update context to limit size of returned buffer - rawSendSize = secCtx.getWrapSizeLimit(JGSS_QOP, privacy, - sendMaxBufSize); - - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, -"KRB5CLNT07:Client max recv size: {0}; server max recv size: {1}; rawSendSize: {2}", - new Object[] {recvMaxBufSize, - srvMaxBufSize, - rawSendSize}); - } - - // Construct negotiated security layers and client's max - // receive buffer size and authzID - int len = 4; - if (authzID != null) { - len += authzID.length; - } - - byte[] gssInToken = new byte[len]; - gssInToken[0] = selectedQop; - - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, - "KRB5CLNT08:Selected protection: {0}; privacy: {1}; integrity: {2}", - new Object[]{selectedQop, - Boolean.valueOf(privacy), - Boolean.valueOf(integrity)}); - } - - intToNetworkByteOrder(recvMaxBufSize, gssInToken, 1, 3); - if (authzID != null) { - // copy authorization id - System.arraycopy(authzID, 0, gssInToken, 4, authzID.length); - logger.log(Level.FINE, "KRB5CLNT09:Authzid: {0}", authzID); - } - - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "doFinalHandshake", - "KRB5CLNT10:Response [raw]", gssInToken); - } - - gssOutToken = secCtx.wrap(gssInToken, - 0, gssInToken.length, - new MessageProp(0 /* qop */, false /* privacy */)); - - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "doFinalHandshake", - "KRB5CLNT11:Response [after wrap]", gssOutToken); - } - - completed = true; // server authenticated - - return gssOutToken; - } catch (GSSException e) { - throw new SaslException("Final handshake failed", e); - } - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java --- a/jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,365 +0,0 @@ -/* - * Copyright (c) 2000, 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 com.sun.security.sasl.gsskerb; - -import javax.security.sasl.*; -import java.io.*; -import java.util.Map; -import java.util.logging.Level; - -// JAAS -import javax.security.auth.callback.*; - -// JGSS -import org.ietf.jgss.*; - -/** - * Implements the GSSAPI SASL server mechanism for Kerberos V5. - * (RFC 2222, - * draft-ietf-cat-sasl-gssapi-00.txt). - * - * Expects thread's Subject to contain server's Kerberos credentials - * - If not, underlying KRB5 mech will attempt to acquire Kerberos creds - * by logging into Kerberos (via default TextCallbackHandler). - * - These creds will be used for exchange with client. - * - * Required callbacks: - * - AuthorizeCallback - * handler must verify that authid/authzids are allowed and set - * authorized ID to be the canonicalized authzid (if applicable). - * - * Environment properties that affect behavior of implementation: - * - * javax.security.sasl.qop - * - quality of protection; list of auth, auth-int, auth-conf; default is "auth" - * javax.security.sasl.maxbuf - * - max receive buffer size; default is 65536 - * javax.security.sasl.sendmaxbuffer - * - max send buffer size; default is 65536; (min with client max recv size) - * - * @author Rosanna Lee - */ -final class GssKrb5Server extends GssKrb5Base implements SaslServer { - private static final String MY_CLASS_NAME = GssKrb5Server.class.getName(); - - private int handshakeStage = 0; - private String peer; - private String me; - private String authzid; - private CallbackHandler cbh; - - // When serverName is null, the server will be unbound. We need to save and - // check the protocol name after the context is established. This value - // will be null if serverName is not null. - private final String protocolSaved; - /** - * Creates a SASL mechanism with server credentials that it needs - * to participate in GSS-API/Kerberos v5 authentication exchange - * with the client. - */ - GssKrb5Server(String protocol, String serverName, - Map props, CallbackHandler cbh) throws SaslException { - - super(props, MY_CLASS_NAME); - - this.cbh = cbh; - - String service; - if (serverName == null) { - protocolSaved = protocol; - service = null; - } else { - protocolSaved = null; - service = protocol + "@" + serverName; - } - - logger.log(Level.FINE, "KRB5SRV01:Using service name: {0}", service); - - try { - GSSManager mgr = GSSManager.getInstance(); - - // Create the name for the requested service entity for Krb5 mech - GSSName serviceName = service == null ? null: - mgr.createName(service, GSSName.NT_HOSTBASED_SERVICE, KRB5_OID); - - GSSCredential cred = mgr.createCredential(serviceName, - GSSCredential.INDEFINITE_LIFETIME, - KRB5_OID, GSSCredential.ACCEPT_ONLY); - - // Create a context using the server's credentials - secCtx = mgr.createContext(cred); - - if ((allQop&INTEGRITY_ONLY_PROTECTION) != 0) { - // Might need integrity - secCtx.requestInteg(true); - } - - if ((allQop&PRIVACY_PROTECTION) != 0) { - // Might need privacy - secCtx.requestConf(true); - } - } catch (GSSException e) { - throw new SaslException("Failure to initialize security context", e); - } - logger.log(Level.FINE, "KRB5SRV02:Initialization complete"); - } - - - /** - * Processes the response data. - * - * The client sends response data to which the server must - * process using GSS_accept_sec_context. - * As per RFC 2222, the GSS authenication completes (GSS_S_COMPLETE) - * we do an extra hand shake to determine the negotiated security protection - * and buffer sizes. - * - * @param responseData A non-null but possible empty byte array containing the - * response data from the client. - * @return A non-null byte array containing the challenge to be - * sent to the client, or null when no more data is to be sent. - */ - public byte[] evaluateResponse(byte[] responseData) throws SaslException { - if (completed) { - throw new SaslException( - "SASL authentication already complete"); - } - - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "evaluateResponse", - "KRB5SRV03:Response [raw]:", responseData); - } - - switch (handshakeStage) { - case 1: - return doHandshake1(responseData); - - case 2: - return doHandshake2(responseData); - - default: - // Security context not established yet; continue with accept - - try { - byte[] gssOutToken = secCtx.acceptSecContext(responseData, - 0, responseData.length); - - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "evaluateResponse", - "KRB5SRV04:Challenge: [after acceptSecCtx]", gssOutToken); - } - - if (secCtx.isEstablished()) { - handshakeStage = 1; - - peer = secCtx.getSrcName().toString(); - me = secCtx.getTargName().toString(); - - logger.log(Level.FINE, - "KRB5SRV05:Peer name is : {0}, my name is : {1}", - new Object[]{peer, me}); - - // me might take the form of proto@host or proto/host - if (protocolSaved != null && - !protocolSaved.equalsIgnoreCase(me.split("[/@]")[0])) { - throw new SaslException( - "GSS context targ name protocol error: " + me); - } - - if (gssOutToken == null) { - return doHandshake1(EMPTY); - } - } - - return gssOutToken; - } catch (GSSException e) { - throw new SaslException("GSS initiate failed", e); - } - } - } - - private byte[] doHandshake1(byte[] responseData) throws SaslException { - try { - // Security context already established. responseData - // should contain no data - if (responseData != null && responseData.length > 0) { - throw new SaslException( - "Handshake expecting no response data from server"); - } - - // Construct 4 octets of data: - // First octet contains bitmask specifying protections supported - // 2nd-4th octets contains max receive buffer of server - - byte[] gssInToken = new byte[4]; - gssInToken[0] = allQop; - intToNetworkByteOrder(recvMaxBufSize, gssInToken, 1, 3); - - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, - "KRB5SRV06:Supported protections: {0}; recv max buf size: {1}", - new Object[]{allQop, - recvMaxBufSize}); - } - - handshakeStage = 2; // progress to next stage - - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "doHandshake1", - "KRB5SRV07:Challenge [raw]", gssInToken); - } - - byte[] gssOutToken = secCtx.wrap(gssInToken, 0, gssInToken.length, - new MessageProp(0 /* gop */, false /* privacy */)); - - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "doHandshake1", - "KRB5SRV08:Challenge [after wrap]", gssOutToken); - } - return gssOutToken; - - } catch (GSSException e) { - throw new SaslException("Problem wrapping handshake1", e); - } - } - - private byte[] doHandshake2(byte[] responseData) throws SaslException { - try { - // Expecting 4 octets from client selected protection - // and client's receive buffer size - byte[] gssOutToken = secCtx.unwrap(responseData, 0, - responseData.length, new MessageProp(0, false)); - - if (logger.isLoggable(Level.FINER)) { - traceOutput(MY_CLASS_NAME, "doHandshake2", - "KRB5SRV09:Response [after unwrap]", gssOutToken); - } - - // First octet is a bit-mask specifying the selected protection - byte selectedQop = gssOutToken[0]; - if ((selectedQop&allQop) == 0) { - throw new SaslException("Client selected unsupported protection: " - + selectedQop); - } - if ((selectedQop&PRIVACY_PROTECTION) != 0) { - privacy = true; - integrity = true; - } else if ((selectedQop&INTEGRITY_ONLY_PROTECTION) != 0) { - integrity = true; - } - - // 2nd-4th octets specifies maximum buffer size expected by - // client (in network byte order). This is the server's send - // buffer maximum. - int clntMaxBufSize = networkByteOrderToInt(gssOutToken, 1, 3); - - // Determine the max send buffer size based on what the - // client is able to receive and our specified max - sendMaxBufSize = (sendMaxBufSize == 0) ? clntMaxBufSize : - Math.min(sendMaxBufSize, clntMaxBufSize); - - // Update context to limit size of returned buffer - rawSendSize = secCtx.getWrapSizeLimit(JGSS_QOP, privacy, - sendMaxBufSize); - - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, - "KRB5SRV10:Selected protection: {0}; privacy: {1}; integrity: {2}", - new Object[]{selectedQop, - Boolean.valueOf(privacy), - Boolean.valueOf(integrity)}); - logger.log(Level.FINE, -"KRB5SRV11:Client max recv size: {0}; server max send size: {1}; rawSendSize: {2}", - new Object[] {clntMaxBufSize, - sendMaxBufSize, - rawSendSize}); - } - - // Get authorization identity, if any - if (gssOutToken.length > 4) { - try { - authzid = new String(gssOutToken, 4, - gssOutToken.length - 4, "UTF-8"); - } catch (UnsupportedEncodingException uee) { - throw new SaslException ("Cannot decode authzid", uee); - } - } else { - authzid = peer; - } - logger.log(Level.FINE, "KRB5SRV12:Authzid: {0}", authzid); - - AuthorizeCallback acb = new AuthorizeCallback(peer, authzid); - - // In Kerberos, realm is embedded in peer name - cbh.handle(new Callback[] {acb}); - if (acb.isAuthorized()) { - authzid = acb.getAuthorizedID(); - completed = true; - } else { - // Authorization failed - throw new SaslException(peer + - " is not authorized to connect as " + authzid); - } - - return null; - } catch (GSSException e) { - throw new SaslException("Final handshake step failed", e); - } catch (IOException e) { - throw new SaslException("Problem with callback handler", e); - } catch (UnsupportedCallbackException e) { - throw new SaslException("Problem with callback handler", e); - } - } - - public String getAuthorizationID() { - if (completed) { - return authzid; - } else { - throw new IllegalStateException("Authentication incomplete"); - } - } - - public Object getNegotiatedProperty(String propName) { - if (!completed) { - throw new IllegalStateException("Authentication incomplete"); - } - - Object result; - switch (propName) { - case Sasl.BOUND_SERVER_NAME: - try { - // me might take the form of proto@host or proto/host - result = me.split("[/@]")[1]; - } catch (Exception e) { - result = null; - } - break; - default: - result = super.getNegotiatedProperty(propName); - } - return result; - } -} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java --- a/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java Wed Jul 05 20:01:50 2017 +0200 @@ -25,7 +25,6 @@ package org.ietf.jgss; -import sun.security.jgss.spi.*; import java.io.InputStream; import java.io.OutputStream; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSName.java --- a/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSName.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.security.jgss/share/classes/org/ietf/jgss/GSSName.java Wed Jul 05 20:01:50 2017 +0200 @@ -25,10 +25,6 @@ package org.ietf.jgss; -import sun.security.jgss.spi.*; -import java.util.Vector; -import java.util.Enumeration; - /** * This interface encapsulates a single GSS-API principal entity. The * application obtains an implementation of this interface diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java --- a/jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.security.jgss/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java Wed Jul 05 20:01:50 2017 +0200 @@ -25,7 +25,6 @@ package sun.net.www.protocol.http.spnego; -import com.sun.security.jgss.ExtendedGSSContext; import java.io.IOException; import org.ietf.jgss.GSSContext; @@ -36,6 +35,7 @@ import sun.net.www.protocol.http.HttpCallerInfo; import sun.net.www.protocol.http.Negotiator; import sun.security.jgss.GSSManagerImpl; +import sun.security.jgss.GSSContextImpl; import sun.security.jgss.GSSUtil; import sun.security.jgss.HttpCaller; @@ -102,8 +102,8 @@ GSSContext.DEFAULT_LIFETIME); // Always respect delegation policy in HTTP/SPNEGO. - if (context instanceof ExtendedGSSContext) { - ((ExtendedGSSContext)context).requestDelegPolicy(true); + if (context instanceof GSSContextImpl) { + ((GSSContextImpl)context).requestDelegPolicy(true); } oneToken = context.initSecContext(new byte[0], 0, 0); } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSContextImpl.java --- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSContextImpl.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSContextImpl.java Wed Jul 05 20:01:50 2017 +0200 @@ -33,7 +33,8 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import com.sun.security.jgss.*; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; /** * This class represents the JGSS security context and its associated @@ -87,10 +88,10 @@ * per-message operations are returned in an instance of the MessageProp * class, which is used as an argument in these calls. */ -class GSSContextImpl implements ExtendedGSSContext { +public class GSSContextImpl implements GSSContext { - private final GSSManagerImpl gssManager; - private final boolean initiator; + private GSSManagerImpl gssManager; + private boolean initiator; // private flags for the context state private static final int PRE_INIT = 1; @@ -122,6 +123,22 @@ private boolean reqAnonState = false; private boolean reqDelegPolicyState = false; + public GSSContextImpl() { + // Useless + } + + // Used by new ExtendedGSSContext.ExtendedGSSContextImpl(ctxt) + protected GSSContextImpl(GSSContextImpl src) { + for (Field f: GSSContextImpl.class.getDeclaredFields()) { + if (!Modifier.isStatic(f.getModifiers())) { + try { + f.set(this, f.get(src)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } /** * Creates a GSSContextImp on the context initiator's side. */ @@ -613,7 +630,7 @@ "No mechanism context yet!"); GSSCredentialSpi delCredElement = mechCtxt.getDelegCred(); return (delCredElement == null ? - null : new GSSCredentialImpl(gssManager, delCredElement)); + null : GSSManagerImpl.wrap(new GSSCredentialImpl(gssManager, delCredElement))); } public boolean isInitiator() throws GSSException { @@ -633,25 +650,18 @@ // ExtendedGSSContext methods: - @Override - public Object inquireSecContext(InquireType type) throws GSSException { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - security.checkPermission(new InquireSecContextPermission(type.toString())); - } + public Object inquireSecContext(String type) throws GSSException { if (mechCtxt == null) { throw new GSSException(GSSException.NO_CONTEXT); } return mechCtxt.inquireSecContext(type); } - @Override public void requestDelegPolicy(boolean state) throws GSSException { if (mechCtxt == null && initiator) reqDelegPolicyState = state; } - @Override public boolean getDelegPolicyState() { if (mechCtxt != null) return mechCtxt.getDelegPolicyState(); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java --- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java Wed Jul 05 20:01:50 2017 +0200 @@ -27,11 +27,11 @@ import org.ietf.jgss.*; import sun.security.jgss.spi.*; + import java.util.*; -import com.sun.security.jgss.*; import sun.security.jgss.spnego.SpNegoCredElement; -public class GSSCredentialImpl implements ExtendedGSSCredential { +public class GSSCredentialImpl implements GSSCredential { private GSSManagerImpl gssManager = null; private boolean destroyed = false; @@ -47,6 +47,18 @@ // XXX Optimization for single mech usage private GSSCredentialSpi tempCred = null; + public GSSCredentialImpl() { + // Useless + } + + // Used by new ExtendedGSSCredential.ExtendedGSSCredentialImpl(cred) + protected GSSCredentialImpl(GSSCredentialImpl src) { + this.gssManager = src.gssManager; + this.destroyed = src.destroyed; + this.hashtable = src.hashtable; + this.tempCred = src.tempCred; + } + GSSCredentialImpl(GSSManagerImpl gssManager, int usage) throws GSSException { this(gssManager, null, GSSCredential.DEFAULT_LIFETIME, @@ -140,7 +152,7 @@ ((GSSNameImpl)name).getElement(mech)); GSSCredentialSpi cred = tempCred.impersonate(nameElement); return (cred == null ? - null : new GSSCredentialImpl(gssManager, cred)); + null : GSSManagerImpl.wrap(new GSSCredentialImpl(gssManager, cred))); } public GSSName getName() throws GSSException { diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java --- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java Wed Jul 05 20:01:50 2017 +0200 @@ -145,35 +145,35 @@ public GSSCredential createCredential(int usage) throws GSSException { - return new GSSCredentialImpl(this, usage); + return wrap(new GSSCredentialImpl(this, usage)); } public GSSCredential createCredential(GSSName aName, int lifetime, Oid mech, int usage) throws GSSException { - return new GSSCredentialImpl(this, aName, lifetime, mech, usage); + return wrap(new GSSCredentialImpl(this, aName, lifetime, mech, usage)); } public GSSCredential createCredential(GSSName aName, int lifetime, Oid mechs[], int usage) throws GSSException { - return new GSSCredentialImpl(this, aName, lifetime, mechs, usage); + return wrap(new GSSCredentialImpl(this, aName, lifetime, mechs, usage)); } public GSSContext createContext(GSSName peer, Oid mech, GSSCredential myCred, int lifetime) throws GSSException { - return new GSSContextImpl(this, peer, mech, myCred, lifetime); + return wrap(new GSSContextImpl(this, peer, mech, myCred, lifetime)); } public GSSContext createContext(GSSCredential myCred) throws GSSException { - return new GSSContextImpl(this, myCred); + return wrap(new GSSContextImpl(this, myCred)); } public GSSContext createContext(byte[] interProcessToken) throws GSSException { - return new GSSContextImpl(this, interProcessToken); + return wrap(new GSSContextImpl(this, interProcessToken)); } public void addProviderAtFront(Provider p, Oid mech) @@ -257,4 +257,20 @@ } return result; } + + static { + // Load the extended JGSS interfaces if exist + try { + Class.forName("com.sun.security.jgss.Extender"); + } catch (Exception e) { + } + } + + static GSSCredential wrap(GSSCredentialImpl cred) { + return sun.security.jgss.JgssExtender.getExtender().wrap(cred); + } + + static GSSContext wrap(GSSContextImpl ctxt) { + return sun.security.jgss.JgssExtender.getExtender().wrap(ctxt); + } } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/sun/security/jgss/JgssExtender.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/JgssExtender.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.jgss; + +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSCredential; + +/** + * The extending point of basic JGSS-API. + *

+ * If a module wants to extend basic JGSS-API classes, it should extends this + * class and register itself as "the extender" using the setExtender method. + * When various GSSManager.createXXX methods are called, they will call + * "the extender"'s wrap methods to create objects of extended types + * instead of basic types. + *

+ * We have only one extension now defined in com.sun.security.jgss, and the + * registering process is triggered in {@link GSSManagerImpl} by calling + * Class.forName("com.sun.security.jgss.Extender"). Only GSSContext + * and GSSCredential are extended now. + *

+ * The setExtender method should be called before any JGSS call. + */ +public class JgssExtender { + + // "The extender" + private static volatile JgssExtender theOne = new JgssExtender(); + + /** + * Gets "the extender". GSSManager calls this method so that it can + * wrap basic objects into extended objects. + * @return the extender + */ + public static JgssExtender getExtender() { + return theOne; + } + + /** + * Set "the extender" so that GSSManager can create extended objects. + */ + protected static void setExtender(JgssExtender theOne) { + JgssExtender.theOne = theOne; + } + + /** + * Wraps a plain GSSCredential object into an extended type. + */ + public GSSCredential wrap(GSSCredential cred) { + return cred; + } + + /** + * Wraps a plain GSSContext object into an extended type. + */ + public GSSContext wrap(GSSContext ctxt) { + return ctxt; + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java --- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java Wed Jul 05 20:01:50 2017 +0200 @@ -25,7 +25,6 @@ package sun.security.jgss.krb5; -import com.sun.security.jgss.AuthorizationDataEntry; import org.ietf.jgss.*; import java.io.InputStream; import java.io.IOException; @@ -152,17 +151,7 @@ new KerberosTime(apReq.getCreds().getAuthTime()).toString()); context.setTktFlags(apReq.getCreds().getFlags()); AuthorizationData ad = apReq.getCreds().getAuthzData(); - if (ad == null) { - context.setAuthzData(null); - } else { - AuthorizationDataEntry[] authzData = - new AuthorizationDataEntry[ad.count()]; - for (int i=0; iA thin wrapper around a millisecond value that allows @@ -42,6 +44,8 @@ */ public class Date extends java.util.Date { + private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + /** * Constructs a Date object initialized with the given * year, month, and day. @@ -108,31 +112,27 @@ * JDBC date escape format (yyyy-[m]m-[d]d) */ public static Date valueOf(String s) { + if (s == null) { + throw new java.lang.IllegalArgumentException(); + } final int YEAR_LENGTH = 4; final int MONTH_LENGTH = 2; final int DAY_LENGTH = 2; final int MAX_MONTH = 12; final int MAX_DAY = 31; - int firstDash; - int secondDash; Date d = null; - if (s == null) { - throw new java.lang.IllegalArgumentException(); - } - firstDash = s.indexOf('-'); - secondDash = s.indexOf('-', firstDash + 1); + int firstDash = s.indexOf('-'); + int secondDash = s.indexOf('-', firstDash + 1); + int len = s.length(); - if ((firstDash > 0) && (secondDash > 0) && (secondDash < s.length() - 1)) { - String yyyy = s.substring(0, firstDash); - String mm = s.substring(firstDash + 1, secondDash); - String dd = s.substring(secondDash + 1); - if (yyyy.length() == YEAR_LENGTH && - (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) && - (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) { - int year = Integer.parseInt(yyyy); - int month = Integer.parseInt(mm); - int day = Integer.parseInt(dd); + if ((firstDash > 0) && (secondDash > 0) && (secondDash < len - 1)) { + if (firstDash == YEAR_LENGTH && + (secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1) && + (len - secondDash > 1 && len - secondDash <= DAY_LENGTH + 1)) { + int year = Integer.parseInt(s, 0, firstDash, 10); + int month = Integer.parseInt(s, firstDash + 1, secondDash, 10); + int day = Integer.parseInt(s, secondDash + 1, len, 10); if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) { d = new Date(year - 1900, month - 1, day); @@ -159,17 +159,34 @@ int month = super.getMonth() + 1; int day = super.getDate(); - char buf[] = "2000-00-00".toCharArray(); - buf[0] = Character.forDigit(year/1000,10); - buf[1] = Character.forDigit((year/100)%10,10); - buf[2] = Character.forDigit((year/10)%10,10); - buf[3] = Character.forDigit(year%10,10); - buf[5] = Character.forDigit(month/10,10); - buf[6] = Character.forDigit(month%10,10); - buf[8] = Character.forDigit(day/10,10); - buf[9] = Character.forDigit(day%10,10); + char buf[] = new char[10]; + formatDecimalInt(year, buf, 0, 4); + buf[4] = '-'; + Date.formatDecimalInt(month, buf, 5, 2); + buf[7] = '-'; + Date.formatDecimalInt(day, buf, 8, 2); + + return jla.newStringUnsafe(buf); + } - return new String(buf); + /** + * Formats an unsigned integer into a char array in decimal output format. + * Numbers will be zero-padded or truncated if the string representation + * of the integer is smaller than or exceeds len, respectively. + * + * Should consider moving this to Integer and expose it through + * JavaLangAccess similar to Integer::formatUnsignedInt + * @param val Value to convert + * @param buf Array containing converted value + * @param offset Starting pos in buf + * @param len length of output value + */ + static void formatDecimalInt(int val, char[] buf, int offset, int len) { + int charPos = offset + len; + do { + buf[--charPos] = (char)('0' + (val % 10)); + val /= 10; + } while (charPos > offset); } // Override all the time operations inherited from java.util.Date; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.sql/share/classes/java/sql/Time.java --- a/jdk/src/java.sql/share/classes/java/sql/Time.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.sql/share/classes/java/sql/Time.java Wed Jul 05 20:01:50 2017 +0200 @@ -27,6 +27,8 @@ import java.time.Instant; import java.time.LocalTime; +import sun.misc.SharedSecrets; +import sun.misc.JavaLangAccess; /** *

A thin wrapper around the java.util.Date class that allows the JDBC @@ -39,6 +41,8 @@ */ public class Time extends java.util.Date { + private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + /** * Constructs a Time object initialized with the * given values for the hour, minute, and second. @@ -90,22 +94,19 @@ * @return a corresponding Time object */ public static Time valueOf(String s) { + if (s == null) throw new java.lang.IllegalArgumentException(); + int hour; int minute; int second; - int firstColon; - int secondColon; - - if (s == null) throw new java.lang.IllegalArgumentException(); - - firstColon = s.indexOf(':'); - secondColon = s.indexOf(':', firstColon+1); - if ((firstColon > 0) & (secondColon > 0) & - (secondColon < s.length()-1)) { - hour = Integer.parseInt(s.substring(0, firstColon)); - minute = - Integer.parseInt(s.substring(firstColon+1, secondColon)); - second = Integer.parseInt(s.substring(secondColon+1)); + int firstColon = s.indexOf(':'); + int secondColon = s.indexOf(':', firstColon + 1); + int len = s.length(); + if (firstColon > 0 && secondColon > 0 && + secondColon < len - 1) { + hour = Integer.parseInt(s, 0, firstColon, 10); + minute = Integer.parseInt(s, firstColon + 1, secondColon, 10); + second = Integer.parseInt(s, secondColon + 1, len, 10); } else { throw new java.lang.IllegalArgumentException(); } @@ -123,26 +124,15 @@ int hour = super.getHours(); int minute = super.getMinutes(); int second = super.getSeconds(); - String hourString; - String minuteString; - String secondString; - if (hour < 10) { - hourString = "0" + hour; - } else { - hourString = Integer.toString(hour); - } - if (minute < 10) { - minuteString = "0" + minute; - } else { - minuteString = Integer.toString(minute); - } - if (second < 10) { - secondString = "0" + second; - } else { - secondString = Integer.toString(second); - } - return (hourString + ":" + minuteString + ":" + secondString); + char[] buf = new char[8]; + Date.formatDecimalInt(hour, buf, 0, 2); + buf[2] = ':'; + Date.formatDecimalInt(minute, buf, 3, 2); + buf[5] = ':'; + Date.formatDecimalInt(second, buf, 6, 2); + + return jla.newStringUnsafe(buf); } // Override all the date operations inherited from java.util.Date; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/java.sql/share/classes/java/sql/Timestamp.java --- a/jdk/src/java.sql/share/classes/java/sql/Timestamp.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/java.sql/share/classes/java/sql/Timestamp.java Wed Jul 05 20:01:50 2017 +0200 @@ -27,7 +27,8 @@ import java.time.Instant; import java.time.LocalDateTime; -import java.util.StringTokenizer; +import sun.misc.SharedSecrets; +import sun.misc.JavaLangAccess; /** *

A thin wrapper around java.util.Date that allows @@ -71,6 +72,8 @@ */ public class Timestamp extends java.util.Date { + private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + /** * Constructs a Timestamp object initialized * with the given values. @@ -171,9 +174,6 @@ final int DAY_LENGTH = 2; final int MAX_MONTH = 12; final int MAX_DAY = 31; - String date_s; - String time_s; - String nanos_s; int year = 0; int month = 0; int day = 0; @@ -184,49 +184,38 @@ int firstDash; int secondDash; int dividingSpace; - int firstColon = 0; - int secondColon = 0; - int period = 0; + int firstColon; + int secondColon; + int period; String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]"; - String zeros = "000000000"; - String delimiterDate = "-"; - String delimiterTime = ":"; if (s == null) throw new java.lang.IllegalArgumentException("null string"); // Split the string into date and time components s = s.trim(); dividingSpace = s.indexOf(' '); - if (dividingSpace > 0) { - date_s = s.substring(0,dividingSpace); - time_s = s.substring(dividingSpace+1); - } else { + if (dividingSpace < 0) { throw new java.lang.IllegalArgumentException(formatError); } // Parse the date - firstDash = date_s.indexOf('-'); - secondDash = date_s.indexOf('-', firstDash+1); + firstDash = s.indexOf('-'); + secondDash = s.indexOf('-', firstDash+1); // Parse the time - if (time_s == null) - throw new java.lang.IllegalArgumentException(formatError); - firstColon = time_s.indexOf(':'); - secondColon = time_s.indexOf(':', firstColon+1); - period = time_s.indexOf('.', secondColon+1); + firstColon = s.indexOf(':', dividingSpace + 1); + secondColon = s.indexOf(':', firstColon + 1); + period = s.indexOf('.', secondColon + 1); // Convert the date boolean parsedDate = false; - if ((firstDash > 0) && (secondDash > 0) && (secondDash < date_s.length() - 1)) { - String yyyy = date_s.substring(0, firstDash); - String mm = date_s.substring(firstDash + 1, secondDash); - String dd = date_s.substring(secondDash + 1); - if (yyyy.length() == YEAR_LENGTH && - (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) && - (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) { - year = Integer.parseInt(yyyy); - month = Integer.parseInt(mm); - day = Integer.parseInt(dd); + if (firstDash > 0 && secondDash > 0 && secondDash < dividingSpace - 1) { + if (firstDash == YEAR_LENGTH && + (secondDash - firstDash > 1 && secondDash - firstDash <= MONTH_LENGTH + 1) && + (dividingSpace - secondDash > 1 && dividingSpace - secondDash <= DAY_LENGTH + 1)) { + year = Integer.parseInt(s, 0, firstDash, 10); + month = Integer.parseInt(s, firstDash + 1, secondDash, 10); + day = Integer.parseInt(s, secondDash + 1, dividingSpace, 10); if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) { parsedDate = true; @@ -238,25 +227,27 @@ } // Convert the time; default missing nanos - if ((firstColon > 0) & (secondColon > 0) & - (secondColon < time_s.length()-1)) { - hour = Integer.parseInt(time_s.substring(0, firstColon)); - minute = - Integer.parseInt(time_s.substring(firstColon+1, secondColon)); - if ((period > 0) & (period < time_s.length()-1)) { - second = - Integer.parseInt(time_s.substring(secondColon+1, period)); - nanos_s = time_s.substring(period+1); - if (nanos_s.length() > 9) + int len = s.length(); + if (firstColon > 0 && secondColon > 0 && secondColon < len - 1) { + hour = Integer.parseInt(s, dividingSpace + 1, firstColon, 10); + minute = Integer.parseInt(s, firstColon + 1, secondColon, 10); + if (period > 0 && period < len - 1) { + second = Integer.parseInt(s, secondColon + 1, period, 10); + int nanoPrecision = len - (period + 1); + if (nanoPrecision > 9) throw new java.lang.IllegalArgumentException(formatError); - if (!Character.isDigit(nanos_s.charAt(0))) + if (!Character.isDigit(s.charAt(period + 1))) throw new java.lang.IllegalArgumentException(formatError); - nanos_s = nanos_s + zeros.substring(0,9-nanos_s.length()); - a_nanos = Integer.parseInt(nanos_s); + int tmpNanos = Integer.parseInt(s, period + 1, len, 10); + while (nanoPrecision < 9) { + tmpNanos *= 10; + nanoPrecision++; + } + a_nanos = tmpNanos; } else if (period > 0) { throw new java.lang.IllegalArgumentException(formatError); } else { - second = Integer.parseInt(time_s.substring(secondColon+1)); + second = Integer.parseInt(s, secondColon + 1, len, 10); } } else { throw new java.lang.IllegalArgumentException(formatError); @@ -274,95 +265,53 @@ * yyyy-mm-dd hh:mm:ss.fffffffff format */ @SuppressWarnings("deprecation") - public String toString () { - + public String toString() { int year = super.getYear() + 1900; int month = super.getMonth() + 1; int day = super.getDate(); int hour = super.getHours(); int minute = super.getMinutes(); int second = super.getSeconds(); - String yearString; - String monthString; - String dayString; - String hourString; - String minuteString; - String secondString; - String nanosString; - String zeros = "000000000"; - String yearZeros = "0000"; - StringBuffer timestampBuf; - if (year < 1000) { - // Add leading zeros - yearString = "" + year; - yearString = yearZeros.substring(0, (4-yearString.length())) + - yearString; - } else { - yearString = "" + year; - } - if (month < 10) { - monthString = "0" + month; - } else { - monthString = Integer.toString(month); - } - if (day < 10) { - dayString = "0" + day; + int trailingZeros = 0; + int tmpNanos = nanos; + if (tmpNanos == 0) { + trailingZeros = 8; } else { - dayString = Integer.toString(day); - } - if (hour < 10) { - hourString = "0" + hour; - } else { - hourString = Integer.toString(hour); - } - if (minute < 10) { - minuteString = "0" + minute; - } else { - minuteString = Integer.toString(minute); - } - if (second < 10) { - secondString = "0" + second; - } else { - secondString = Integer.toString(second); - } - if (nanos == 0) { - nanosString = "0"; - } else { - nanosString = Integer.toString(nanos); - - // Add leading zeros - nanosString = zeros.substring(0, (9-nanosString.length())) + - nanosString; - - // Truncate trailing zeros - char[] nanosChar = new char[nanosString.length()]; - nanosString.getChars(0, nanosString.length(), nanosChar, 0); - int truncIndex = 8; - while (nanosChar[truncIndex] == '0') { - truncIndex--; + while (tmpNanos % 10 == 0) { + tmpNanos /= 10; + trailingZeros++; } - - nanosString = new String(nanosChar, 0, truncIndex + 1); } - // do a string buffer here instead. - timestampBuf = new StringBuffer(20+nanosString.length()); - timestampBuf.append(yearString); - timestampBuf.append("-"); - timestampBuf.append(monthString); - timestampBuf.append("-"); - timestampBuf.append(dayString); - timestampBuf.append(" "); - timestampBuf.append(hourString); - timestampBuf.append(":"); - timestampBuf.append(minuteString); - timestampBuf.append(":"); - timestampBuf.append(secondString); - timestampBuf.append("."); - timestampBuf.append(nanosString); + // 8058429: To comply with current JCK tests, we need to deal with year + // being any number between 0 and 292278995 + int count = 10000; + int yearSize = 4; + do { + if (year < count) { + break; + } + yearSize++; + count *= 10; + } while (count < 1000000000); - return (timestampBuf.toString()); + char[] buf = new char[25 + yearSize - trailingZeros]; + Date.formatDecimalInt(year, buf, 0, yearSize); + buf[yearSize] = '-'; + Date.formatDecimalInt(month, buf, yearSize + 1, 2); + buf[yearSize + 3] = '-'; + Date.formatDecimalInt(day, buf, yearSize + 4, 2); + buf[yearSize + 6] = ' '; + Date.formatDecimalInt(hour, buf, yearSize + 7, 2); + buf[yearSize + 9] = ':'; + Date.formatDecimalInt(minute, buf, yearSize + 10, 2); + buf[yearSize + 12] = ':'; + Date.formatDecimalInt(second, buf, yearSize + 13, 2); + buf[yearSize + 15] = '.'; + Date.formatDecimalInt(tmpNanos, buf, yearSize + 16, 9 - trailingZeros); + + return jla.newStringUnsafe(buf); } /** diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo --- a/jdk/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/src/jdk.localedata/META-INF/cldrdata-services/sun.util.locale.provider.LocaleDataMetaInfo Wed Jul 05 20:01:50 2017 +0200 @@ -1,1 +1,1 @@ -sun.util.cldr.CLDRLocaleDataMetaInfo +sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009, 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 com.sun.security.jgss; + +/** + * Kerberos 5 AuthorizationData entry. + */ +@jdk.Exported +public final class AuthorizationDataEntry { + + private final int type; + private final byte[] data; + + /** + * Create an AuthorizationDataEntry object. + * @param type the ad-type + * @param data the ad-data, a copy of the data will be saved + * inside the object. + */ + public AuthorizationDataEntry(int type, byte[] data) { + this.type = type; + this.data = data.clone(); + } + + /** + * Get the ad-type field. + * @return ad-type + */ + public int getType() { + return type; + } + + /** + * Get a copy of the ad-data field. + * @return ad-data + */ + public byte[] getData() { + return data.clone(); + } + + public String toString() { + return "AuthorizationDataEntry: type="+type+", data=" + + data.length + " bytes:\n" + + new sun.misc.HexDumpEncoder().encodeBuffer(data); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2009, 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 com.sun.security.jgss; + +import org.ietf.jgss.*; +import sun.security.jgss.GSSContextImpl; +import sun.security.krb5.internal.AuthorizationData; + +/** + * The extended GSSContext interface for supporting additional + * functionalities not defined by {@code org.ietf.jgss.GSSContext}, + * such as querying context-specific attributes. + */ +@jdk.Exported +public interface ExtendedGSSContext extends GSSContext { + + // The impl is almost identical to GSSContextImpl with only 2 differences: + // 1. It implements the extended interface + // 2. It translates result to data types here in inquireSecContext + static class ExtendedGSSContextImpl extends GSSContextImpl + implements ExtendedGSSContext { + + public ExtendedGSSContextImpl(GSSContextImpl old) { + super(old); + } + + @Override + public Object inquireSecContext(InquireType type) throws GSSException { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission( + new InquireSecContextPermission(type.toString())); + } + Object output = super.inquireSecContext(type.name()); + if (output != null) { + if (type == InquireType.KRB5_GET_AUTHZ_DATA) { + AuthorizationData ad = (AuthorizationData) output; + AuthorizationDataEntry[] authzData = + new AuthorizationDataEntry[ad.count()]; + for (int i = 0; i < ad.count(); i++) { + authzData[i] = new AuthorizationDataEntry( + ad.item(i).adType, ad.item(i).adData); + } + output = authzData; + } + } + return output; + } + } + + /** + * Return the mechanism-specific attribute associated with {@code type}. + *

+ * If there is a security manager, an {@link InquireSecContextPermission} + * with the name {@code type.mech} must be granted. Otherwise, this could + * result in a {@link SecurityException}. + *

+ * Example: + *

+     *      GSSContext ctxt = m.createContext(...)
+     *      // Establishing the context
+     *      if (ctxt instanceof ExtendedGSSContext) {
+     *          ExtendedGSSContext ex = (ExtendedGSSContext)ctxt;
+     *          try {
+     *              Key key = (key)ex.inquireSecContext(
+     *                      InquireType.KRB5_GET_SESSION_KEY);
+     *              // read key info
+     *          } catch (GSSException gsse) {
+     *              // deal with exception
+     *          }
+     *      }
+     * 
+ * @param type the type of the attribute requested + * @return the attribute, see the method documentation for details. + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#BAD_MECH GSSException.BAD_MECH} if the mechanism + * does not support this method, + * {@link GSSException#UNAVAILABLE GSSException.UNAVAILABLE} if the + * type specified is not supported, + * {@link GSSException#NO_CONTEXT GSSException.NO_CONTEXT} if the + * security context is invalid, + * {@link GSSException#FAILURE GSSException.FAILURE} for other + * unspecified failures. + * @throws SecurityException if a security manager exists and a proper + * {@link InquireSecContextPermission} is not granted. + * @see InquireSecContextPermission + * @see InquireType + */ + public Object inquireSecContext(InquireType type) + throws GSSException; + + /** + * Requests that the delegation policy be respected. When a true value is + * requested, the underlying context would use the delegation policy + * defined by the environment as a hint to determine whether credentials + * delegation should be performed. This request can only be made on the + * context initiator's side and it has to be done prior to the first + * call to initSecContext. + *

+ * When this flag is false, delegation will only be tried when the + * {@link GSSContext#requestCredDeleg(boolean) credentials delegation flag} + * is true. + *

+ * When this flag is true but the + * {@link GSSContext#requestCredDeleg(boolean) credentials delegation flag} + * is false, delegation will be only tried if the delegation policy permits + * delegation. + *

+ * When both this flag and the + * {@link GSSContext#requestCredDeleg(boolean) credentials delegation flag} + * are true, delegation will be always tried. However, if the delegation + * policy does not permit delegation, the value of + * {@link #getDelegPolicyState} will be false, even + * if delegation is performed successfully. + *

+ * In any case, if the delegation is not successful, the value returned + * by {@link GSSContext#getCredDelegState()} is false, and the value + * returned by {@link #getDelegPolicyState()} is also false. + *

+ * Not all mechanisms support delegation policy. Therefore, the + * application should check to see if the request was honored with the + * {@link #getDelegPolicyState() getDelegPolicyState} method. When + * delegation policy is not supported, requestDelegPolicy + * should return silently without throwing an exception. + *

+ * Note: for the Kerberos 5 mechanism, the delegation policy is expressed + * through the OK-AS-DELEGATE flag in the service ticket. When it's true, + * the KDC permits delegation to the target server. In a cross-realm + * environment, in order for delegation be permitted, all cross-realm TGTs + * on the authentication path must also have the OK-AS-DELAGATE flags set. + * @param state true if the policy should be respected + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public void requestDelegPolicy(boolean state) throws GSSException; + + /** + * Returns the delegation policy response. Called after a security context + * is established. This method can be only called on the initiator's side. + * See {@link ExtendedGSSContext#requestDelegPolicy}. + * @return the delegation policy response + */ + public boolean getDelegPolicyState(); +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.jgss; + +import org.ietf.jgss.*; +import sun.security.jgss.GSSCredentialImpl; + +/** + * The extended GSSCredential interface for supporting additional + * functionalities not defined by {@code org.ietf.jgss.GSSCredential}. + * @since 1.8 + */ +@jdk.Exported +public interface ExtendedGSSCredential extends GSSCredential { + + static class ExtendedGSSCredentialImpl extends GSSCredentialImpl + implements ExtendedGSSCredential { + + public ExtendedGSSCredentialImpl(GSSCredentialImpl old) { + super(old); + } + } + + /** + * Impersonates a principal. In Kerberos, this can be implemented + * using the Microsoft S4U2self extension. + *

+ * A {@link GSSException#NO_CRED GSSException.NO_CRED} will be thrown if the + * impersonation fails. A {@link GSSException#FAILURE GSSException.FAILURE} + * will be thrown if the impersonation method is not available to this + * credential object. + * @param name the name of the principal to impersonate + * @return a credential for that principal + * @throws GSSException containing the following + * major error codes: + * {@link GSSException#NO_CRED GSSException.NO_CRED} + * {@link GSSException#FAILURE GSSException.FAILURE} + */ + public GSSCredential impersonate(GSSName name) throws GSSException; +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/Extender.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/Extender.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,56 @@ +/* + * 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. + */ + +package com.sun.security.jgss; + +import org.ietf.jgss.GSSContext; +import org.ietf.jgss.GSSCredential; +import sun.security.jgss.GSSContextImpl; +import sun.security.jgss.GSSCredentialImpl; +import sun.security.jgss.JgssExtender; + +// The com.sun.security.jgss extension to JGSS-API +class Extender extends JgssExtender { + + static { + JgssExtender.setExtender(new Extender()); + } + + public GSSCredential wrap(GSSCredential cred) { + if (cred instanceof ExtendedGSSCredential.ExtendedGSSCredentialImpl) { + return cred; + } else { + return new ExtendedGSSCredential.ExtendedGSSCredentialImpl((GSSCredentialImpl)cred); + } + } + + public GSSContext wrap(GSSContext ctxt) { + if (ctxt instanceof ExtendedGSSContext.ExtendedGSSContextImpl) { + return ctxt; + } else { + return new ExtendedGSSContext.ExtendedGSSContextImpl((GSSContextImpl)ctxt); + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/GSSUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/GSSUtil.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000, 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 com.sun.security.jgss; + +import javax.security.auth.Subject; +import org.ietf.jgss.GSSName; +import org.ietf.jgss.GSSCredential; + +/** + * GSS-API Utilities for using in conjunction with Sun Microsystem's + * implementation of Java GSS-API. + */ +@jdk.Exported +public class GSSUtil { + + /** + * Use this method to convert a GSSName and GSSCredential into a + * Subject. Typically this would be done by a server that wants to + * impersonate a client thread at the Java level by setting a client + * Subject in the current access control context. If the server is merely + * interested in using a principal based policy in its local JVM, then + * it only needs to provide the GSSName of the client. + * + * The elements from the GSSName are placed in the principals set of this + * Subject and those from the GSSCredential are placed in the private + * credentials set of the Subject. Any Kerberos specific elements that + * are added to the subject will be instances of the standard Kerberos + * implementation classes defined in javax.security.auth.kerberos. + * + * @return a Subject with the entries that contain elements from the + * given GSSName and GSSCredential. + * + * @param principals a GSSName containing one or more mechanism specific + * representations of the same entity. These mechanism specific + * representations will be populated in the returned Subject's principal + * set. + * + * @param credentials a GSSCredential containing one or more mechanism + * specific credentials for the same entity. These mechanism specific + * credentials will be populated in the returned Subject's private + * credential set. Passing in a value of null will imply that the private + * credential set should be left empty. + */ + public static Subject createSubject(GSSName principals, + GSSCredential credentials) { + + return sun.security.jgss.GSSUtil.getSubject(principals, + credentials); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2009, 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 com.sun.security.jgss; + +import java.security.BasicPermission; + +/** + * This class is used to protect various attributes of an established + * GSS security context that can be accessed using the + * {@link com.sun.security.jgss.ExtendedGSSContext#inquireSecContext} + * method. + * + *

The target name is the {@link InquireType} allowed. + */ +@jdk.Exported +public final class InquireSecContextPermission extends BasicPermission { + private static final long serialVersionUID = -7131173349668647297L; + + /** + * Constructs a new {@code InquireSecContextPermission} object with + * the specified name. The name is the symbolic name of the + * {@link InquireType} allowed. + * + * @param name the {@link InquireType} allowed by this + * permission. "*" means all {@link InquireType}s are allowed. + * + * @throws NullPointerException if name is null. + * @throws IllegalArgumentException if name is empty. + */ + public InquireSecContextPermission(String name) { + super(name); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/InquireType.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2009, 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 com.sun.security.jgss; + +/** + * Attribute types that can be specified as an argument of + * {@link com.sun.security.jgss.ExtendedGSSContext#inquireSecContext} + */ +@jdk.Exported +public enum InquireType { + /** + * Attribute type for retrieving the session key of an established + * Kerberos 5 security context. The returned object is an instance of + * {@link java.security.Key}, which has the following properties: + *

    + *
  • Algorithm: enctype as a string, where + * enctype is defined in RFC 3961, section 8. + *
  • Format: "RAW" + *
  • Encoded form: the raw key bytes, not in any ASN.1 encoding + *
+ * @deprecated as of 1.9, replaced by {@link #KRB5_GET_SESSION_KEY_EX} + * which returns an instance of + * {@link javax.security.auth.kerberos.EncryptionKey} + * that implements the {@link javax.crypto.SecretKey} interface and + * has similar methods with {@link javax.security.auth.kerberos.KerberosKey}. + */ + @Deprecated + KRB5_GET_SESSION_KEY, + /** + * Attribute type for retrieving the session key of an + * established Kerberos 5 security context. The return value is an + * instance of {@link javax.security.auth.kerberos.EncryptionKey}. + * + * @since 1.9 + */ + KRB5_GET_SESSION_KEY_EX, + /** + * Attribute type for retrieving the service ticket flags of an + * established Kerberos 5 security context. The returned object is + * a boolean array for the service ticket flags, which is long enough + * to contain all true bits. This means if the user wants to get the + * n'th bit but the length of the returned array is less than + * n, it is regarded as false. + */ + KRB5_GET_TKT_FLAGS, + /** + * Attribute type for retrieving the authorization data in the + * service ticket of an established Kerberos 5 security context. + * Only supported on the acceptor side. + */ + KRB5_GET_AUTHZ_DATA, + /** + * Attribute type for retrieving the authtime in the service ticket + * of an established Kerberos 5 security context. The returned object + * is a String object in the standard KerberosTime format defined in + * RFC 4120 Section 5.2.3. + */ + KRB5_GET_AUTHTIME, + /** + * Attribute type for retrieving the KRB_CRED message that an initiator + * is about to send to an acceptor. The return type is an instance of + * {@link javax.security.auth.kerberos.KerberosCredMessage}. + * + * @since 1.9 + */ + KRB5_GET_KRB_CRED, +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/jgss/package-info.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,27 @@ +/* + * 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. + */ + +@jdk.Exported +package com.sun.security.jgss; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.security.sasl.gsskerb; + +import javax.security.sasl.*; +import com.sun.security.sasl.util.PolicyUtils; + +import java.util.Map; +import javax.security.auth.callback.CallbackHandler; + +/** + * Client/server factory for GSSAPI (Kerberos V5) SASL client/server mechs. + * See GssKrb5Client/GssKrb5Server for input requirements. + * + * @author Rosanna Lee + */ +public final class FactoryImpl implements SaslClientFactory, SaslServerFactory { + private static final String myMechs[] = { + "GSSAPI"}; + + private static final int mechPolicies[] = { + PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS|PolicyUtils.NOACTIVE + }; + + private static final int GSS_KERB_V5 = 0; + + public FactoryImpl() { + } + + public SaslClient createSaslClient(String[] mechs, + String authorizationId, + String protocol, + String serverName, + Map props, + CallbackHandler cbh) throws SaslException { + + for (int i = 0; i < mechs.length; i++) { + if (mechs[i].equals(myMechs[GSS_KERB_V5]) + && PolicyUtils.checkPolicy(mechPolicies[GSS_KERB_V5], props)) { + return new GssKrb5Client( + authorizationId, + protocol, + serverName, + props, + cbh); + } + } + return null; + }; + + public SaslServer createSaslServer(String mech, + String protocol, + String serverName, + Map props, + CallbackHandler cbh) throws SaslException { + if (mech.equals(myMechs[GSS_KERB_V5]) + && PolicyUtils.checkPolicy(mechPolicies[GSS_KERB_V5], props)) { + if (cbh == null) { + throw new SaslException( + "Callback handler with support for AuthorizeCallback required"); + } + return new GssKrb5Server( + protocol, + serverName, + props, + cbh); + } + return null; + }; + + public String[] getMechanismNames(Map props) { + return PolicyUtils.filterMechs(myMechs, mechPolicies, props); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003, 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 com.sun.security.sasl.gsskerb; + +import java.util.Locale; +import java.util.Map; +import java.util.logging.Level; +import javax.security.sasl.*; +import com.sun.security.sasl.util.AbstractSaslImpl; +import org.ietf.jgss.*; +import com.sun.security.jgss.ExtendedGSSContext; +import com.sun.security.jgss.InquireType; + +abstract class GssKrb5Base extends AbstractSaslImpl { + + private static final String KRB5_OID_STR = "1.2.840.113554.1.2.2"; + protected static Oid KRB5_OID; + protected static final byte[] EMPTY = new byte[0]; + + static { + try { + KRB5_OID = new Oid(KRB5_OID_STR); + } catch (GSSException ignore) {} + } + + protected GSSContext secCtx = null; + protected static final int JGSS_QOP = 0; // unrelated to SASL QOP mask + + protected GssKrb5Base(Map props, String className) + throws SaslException { + super(props, className); + } + + /** + * Retrieves this mechanism's name. + * + * @return The string "GSSAPI". + */ + public String getMechanismName() { + return "GSSAPI"; + } + + @Override + public Object getNegotiatedProperty(String propName) { + if (!completed) { + throw new IllegalStateException("Authentication incomplete"); + } + String xprefix = "com.sun.security.jgss.inquiretype."; + if (propName.startsWith(xprefix)) { + String type = propName.substring(xprefix.length()); + if (logger.isLoggable(Level.FINEST)) { + logger.logp(Level.FINE, "GssKrb5Base", + "getNegotiatedProperty", propName); + } + for (InquireType t: InquireType.values()) { + if (t.name().toLowerCase(Locale.US).equals(type)) { + try { + return ((ExtendedGSSContext)secCtx).inquireSecContext(t); + } catch (GSSException e) { + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.WARNING, "inquireSecContext error", e); + } + return null; + } + } + } + // No such InquireType. Although not likely to be defined + // as a property in a parent class, still try it. + } + return super.getNegotiatedProperty(propName); + } + + public byte[] unwrap(byte[] incoming, int start, int len) + throws SaslException { + if (!completed) { + throw new IllegalStateException("GSSAPI authentication not completed"); + } + + // integrity will be true if either privacy or integrity negotiated + if (!integrity) { + throw new IllegalStateException("No security layer negotiated"); + } + + try { + MessageProp msgProp = new MessageProp(JGSS_QOP, privacy); + byte[] answer = secCtx.unwrap(incoming, start, len, msgProp); + if (logger.isLoggable(Level.FINEST)) { + traceOutput(myClassName, "KRB501:Unwrap", "incoming: ", + incoming, start, len); + traceOutput(myClassName, "KRB502:Unwrap", "unwrapped: ", + answer, 0, answer.length); + } + return answer; + } catch (GSSException e) { + throw new SaslException("Problems unwrapping SASL buffer", e); + } + } + + public byte[] wrap(byte[] outgoing, int start, int len) throws SaslException { + if (!completed) { + throw new IllegalStateException("GSSAPI authentication not completed"); + } + + // integrity will be true if either privacy or integrity negotiated + if (!integrity) { + throw new IllegalStateException("No security layer negotiated"); + } + + // Generate GSS token + try { + MessageProp msgProp = new MessageProp(JGSS_QOP, privacy); + byte[] answer = secCtx.wrap(outgoing, start, len, msgProp); + if (logger.isLoggable(Level.FINEST)) { + traceOutput(myClassName, "KRB503:Wrap", "outgoing: ", + outgoing, start, len); + traceOutput(myClassName, "KRB504:Wrap", "wrapped: ", + answer, 0, answer.length); + } + return answer; + + } catch (GSSException e) { + throw new SaslException("Problem performing GSS wrap", e); + } + } + + public void dispose() throws SaslException { + if (secCtx != null) { + try { + secCtx.dispose(); + } catch (GSSException e) { + throw new SaslException("Problem disposing GSS context", e); + } + secCtx = null; + } + } + + protected void finalize() throws Throwable { + dispose(); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2000, 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 com.sun.security.sasl.gsskerb; + +import java.io.IOException; +import java.util.Map; +import java.util.logging.Level; +import javax.security.sasl.*; + +// JAAS +import javax.security.auth.callback.CallbackHandler; + +// JGSS +import org.ietf.jgss.*; + +/** + * Implements the GSSAPI SASL client mechanism for Kerberos V5. + * (RFC 2222, + * draft-ietf-cat-sasl-gssapi-04.txt). + * It uses the Java Bindings for GSSAPI + * (RFC 2853) + * for getting GSSAPI/Kerberos V5 support. + * + * The client/server interactions are: + * C0: bind (GSSAPI, initial response) + * S0: sasl-bind-in-progress, challenge 1 (output of accept_sec_context or []) + * C1: bind (GSSAPI, response 1 (output of init_sec_context or [])) + * S1: sasl-bind-in-progress challenge 2 (security layer, server max recv size) + * C2: bind (GSSAPI, response 2 (security layer, client max recv size, authzid)) + * S2: bind success response + * + * Expects the client's credentials to be supplied from the + * javax.security.sasl.credentials property or from the thread's Subject. + * Otherwise the underlying KRB5 mech will attempt to acquire Kerberos creds + * by logging into Kerberos (via default TextCallbackHandler). + * These creds will be used for exchange with server. + * + * Required callbacks: none. + * + * Environment properties that affect behavior of implementation: + * + * javax.security.sasl.qop + * - quality of protection; list of auth, auth-int, auth-conf; default is "auth" + * javax.security.sasl.maxbuf + * - max receive buffer size; default is 65536 + * javax.security.sasl.sendmaxbuffer + * - max send buffer size; default is 65536; (min with server max recv size) + * + * javax.security.sasl.server.authentication + * - "true" means require mutual authentication; default is "false" + * + * javax.security.sasl.credentials + * - an {@link org.ietf.jgss.GSSCredential} used for delegated authentication. + * + * @author Rosanna Lee + */ + +final class GssKrb5Client extends GssKrb5Base implements SaslClient { + // ---------------- Constants ----------------- + private static final String MY_CLASS_NAME = GssKrb5Client.class.getName(); + + private boolean finalHandshake = false; + private boolean mutual = false; // default false + private byte[] authzID; + + /** + * Creates a SASL mechanism with client credentials that it needs + * to participate in GSS-API/Kerberos v5 authentication exchange + * with the server. + */ + GssKrb5Client(String authzID, String protocol, String serverName, + Map props, CallbackHandler cbh) throws SaslException { + + super(props, MY_CLASS_NAME); + + String service = protocol + "@" + serverName; + logger.log(Level.FINE, "KRB5CLNT01:Requesting service name: {0}", + service); + + try { + GSSManager mgr = GSSManager.getInstance(); + + // Create the name for the requested service entity for Krb5 mech + GSSName acceptorName = mgr.createName(service, + GSSName.NT_HOSTBASED_SERVICE, KRB5_OID); + + // Parse properties to check for supplied credentials + GSSCredential credentials = null; + if (props != null) { + Object prop = props.get(Sasl.CREDENTIALS); + if (prop != null && prop instanceof GSSCredential) { + credentials = (GSSCredential) prop; + logger.log(Level.FINE, + "KRB5CLNT01:Using the credentials supplied in " + + "javax.security.sasl.credentials"); + } + } + + // Create a context using credentials for Krb5 mech + secCtx = mgr.createContext(acceptorName, + KRB5_OID, /* mechanism */ + credentials, /* credentials */ + GSSContext.INDEFINITE_LIFETIME); + + // Request credential delegation when credentials have been supplied + if (credentials != null) { + secCtx.requestCredDeleg(true); + } + + // Parse properties to set desired context options + if (props != null) { + // Mutual authentication + String prop = (String)props.get(Sasl.SERVER_AUTH); + if (prop != null) { + mutual = "true".equalsIgnoreCase(prop); + } + } + secCtx.requestMutualAuth(mutual); + + // Always specify potential need for integrity and confidentiality + // Decision will be made during final handshake + secCtx.requestConf(true); + secCtx.requestInteg(true); + + } catch (GSSException e) { + throw new SaslException("Failure to initialize security context", e); + } + + if (authzID != null && authzID.length() > 0) { + try { + this.authzID = authzID.getBytes("UTF8"); + } catch (IOException e) { + throw new SaslException("Cannot encode authorization ID", e); + } + } + } + + public boolean hasInitialResponse() { + return true; + } + + /** + * Processes the challenge data. + * + * The server sends a challenge data using which the client must + * process using GSS_Init_sec_context. + * As per RFC 2222, when GSS_S_COMPLETE is returned, we do + * an extra handshake to determine the negotiated security protection + * and buffer sizes. + * + * @param challengeData A non-null byte array containing the + * challenge data from the server. + * @return A non-null byte array containing the response to be + * sent to the server. + */ + public byte[] evaluateChallenge(byte[] challengeData) throws SaslException { + if (completed) { + throw new IllegalStateException( + "GSSAPI authentication already complete"); + } + + if (finalHandshake) { + return doFinalHandshake(challengeData); + } else { + + // Security context not established yet; continue with init + + try { + byte[] gssOutToken = secCtx.initSecContext(challengeData, + 0, challengeData.length); + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "evaluteChallenge", + "KRB5CLNT02:Challenge: [raw]", challengeData); + traceOutput(MY_CLASS_NAME, "evaluateChallenge", + "KRB5CLNT03:Response: [after initSecCtx]", gssOutToken); + } + + if (secCtx.isEstablished()) { + finalHandshake = true; + if (gssOutToken == null) { + // RFC 2222 7.2.1: Client responds with no data + return EMPTY; + } + } + + return gssOutToken; + } catch (GSSException e) { + throw new SaslException("GSS initiate failed", e); + } + } + } + + private byte[] doFinalHandshake(byte[] challengeData) throws SaslException { + try { + // Security context already established. challengeData + // should contain security layers and server's maximum buffer size + + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "doFinalHandshake", + "KRB5CLNT04:Challenge [raw]:", challengeData); + } + + if (challengeData.length == 0) { + // Received S0, should return [] + return EMPTY; + } + + // Received S1 (security layer, server max recv size) + + byte[] gssOutToken = secCtx.unwrap(challengeData, 0, + challengeData.length, new MessageProp(0, false)); + + // First octet is a bit-mask specifying the protections + // supported by the server + if (logger.isLoggable(Level.FINE)) { + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "doFinalHandshake", + "KRB5CLNT05:Challenge [unwrapped]:", gssOutToken); + } + logger.log(Level.FINE, "KRB5CLNT06:Server protections: {0}", + gssOutToken[0]); + } + + // Client selects preferred protection + // qop is ordered list of qop values + byte selectedQop = findPreferredMask(gssOutToken[0], qop); + if (selectedQop == 0) { + throw new SaslException( + "No common protection layer between client and server"); + } + + if ((selectedQop&PRIVACY_PROTECTION) != 0) { + privacy = true; + integrity = true; + } else if ((selectedQop&INTEGRITY_ONLY_PROTECTION) != 0) { + integrity = true; + } + + // 2nd-4th octets specifies maximum buffer size expected by + // server (in network byte order) + int srvMaxBufSize = networkByteOrderToInt(gssOutToken, 1, 3); + + // Determine the max send buffer size based on what the + // server is able to receive and our specified max + sendMaxBufSize = (sendMaxBufSize == 0) ? srvMaxBufSize : + Math.min(sendMaxBufSize, srvMaxBufSize); + + // Update context to limit size of returned buffer + rawSendSize = secCtx.getWrapSizeLimit(JGSS_QOP, privacy, + sendMaxBufSize); + + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, +"KRB5CLNT07:Client max recv size: {0}; server max recv size: {1}; rawSendSize: {2}", + new Object[] {recvMaxBufSize, + srvMaxBufSize, + rawSendSize}); + } + + // Construct negotiated security layers and client's max + // receive buffer size and authzID + int len = 4; + if (authzID != null) { + len += authzID.length; + } + + byte[] gssInToken = new byte[len]; + gssInToken[0] = selectedQop; + + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, + "KRB5CLNT08:Selected protection: {0}; privacy: {1}; integrity: {2}", + new Object[]{selectedQop, + Boolean.valueOf(privacy), + Boolean.valueOf(integrity)}); + } + + intToNetworkByteOrder(recvMaxBufSize, gssInToken, 1, 3); + if (authzID != null) { + // copy authorization id + System.arraycopy(authzID, 0, gssInToken, 4, authzID.length); + logger.log(Level.FINE, "KRB5CLNT09:Authzid: {0}", authzID); + } + + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "doFinalHandshake", + "KRB5CLNT10:Response [raw]", gssInToken); + } + + gssOutToken = secCtx.wrap(gssInToken, + 0, gssInToken.length, + new MessageProp(0 /* qop */, false /* privacy */)); + + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "doFinalHandshake", + "KRB5CLNT11:Response [after wrap]", gssOutToken); + } + + completed = true; // server authenticated + + return gssOutToken; + } catch (GSSException e) { + throw new SaslException("Final handshake failed", e); + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2000, 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 com.sun.security.sasl.gsskerb; + +import javax.security.sasl.*; +import java.io.*; +import java.util.Map; +import java.util.logging.Level; + +// JAAS +import javax.security.auth.callback.*; + +// JGSS +import org.ietf.jgss.*; + +/** + * Implements the GSSAPI SASL server mechanism for Kerberos V5. + * (RFC 2222, + * draft-ietf-cat-sasl-gssapi-00.txt). + * + * Expects thread's Subject to contain server's Kerberos credentials + * - If not, underlying KRB5 mech will attempt to acquire Kerberos creds + * by logging into Kerberos (via default TextCallbackHandler). + * - These creds will be used for exchange with client. + * + * Required callbacks: + * - AuthorizeCallback + * handler must verify that authid/authzids are allowed and set + * authorized ID to be the canonicalized authzid (if applicable). + * + * Environment properties that affect behavior of implementation: + * + * javax.security.sasl.qop + * - quality of protection; list of auth, auth-int, auth-conf; default is "auth" + * javax.security.sasl.maxbuf + * - max receive buffer size; default is 65536 + * javax.security.sasl.sendmaxbuffer + * - max send buffer size; default is 65536; (min with client max recv size) + * + * @author Rosanna Lee + */ +final class GssKrb5Server extends GssKrb5Base implements SaslServer { + private static final String MY_CLASS_NAME = GssKrb5Server.class.getName(); + + private int handshakeStage = 0; + private String peer; + private String me; + private String authzid; + private CallbackHandler cbh; + + // When serverName is null, the server will be unbound. We need to save and + // check the protocol name after the context is established. This value + // will be null if serverName is not null. + private final String protocolSaved; + /** + * Creates a SASL mechanism with server credentials that it needs + * to participate in GSS-API/Kerberos v5 authentication exchange + * with the client. + */ + GssKrb5Server(String protocol, String serverName, + Map props, CallbackHandler cbh) throws SaslException { + + super(props, MY_CLASS_NAME); + + this.cbh = cbh; + + String service; + if (serverName == null) { + protocolSaved = protocol; + service = null; + } else { + protocolSaved = null; + service = protocol + "@" + serverName; + } + + logger.log(Level.FINE, "KRB5SRV01:Using service name: {0}", service); + + try { + GSSManager mgr = GSSManager.getInstance(); + + // Create the name for the requested service entity for Krb5 mech + GSSName serviceName = service == null ? null: + mgr.createName(service, GSSName.NT_HOSTBASED_SERVICE, KRB5_OID); + + GSSCredential cred = mgr.createCredential(serviceName, + GSSCredential.INDEFINITE_LIFETIME, + KRB5_OID, GSSCredential.ACCEPT_ONLY); + + // Create a context using the server's credentials + secCtx = mgr.createContext(cred); + + if ((allQop&INTEGRITY_ONLY_PROTECTION) != 0) { + // Might need integrity + secCtx.requestInteg(true); + } + + if ((allQop&PRIVACY_PROTECTION) != 0) { + // Might need privacy + secCtx.requestConf(true); + } + } catch (GSSException e) { + throw new SaslException("Failure to initialize security context", e); + } + logger.log(Level.FINE, "KRB5SRV02:Initialization complete"); + } + + + /** + * Processes the response data. + * + * The client sends response data to which the server must + * process using GSS_accept_sec_context. + * As per RFC 2222, the GSS authenication completes (GSS_S_COMPLETE) + * we do an extra hand shake to determine the negotiated security protection + * and buffer sizes. + * + * @param responseData A non-null but possible empty byte array containing the + * response data from the client. + * @return A non-null byte array containing the challenge to be + * sent to the client, or null when no more data is to be sent. + */ + public byte[] evaluateResponse(byte[] responseData) throws SaslException { + if (completed) { + throw new SaslException( + "SASL authentication already complete"); + } + + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "evaluateResponse", + "KRB5SRV03:Response [raw]:", responseData); + } + + switch (handshakeStage) { + case 1: + return doHandshake1(responseData); + + case 2: + return doHandshake2(responseData); + + default: + // Security context not established yet; continue with accept + + try { + byte[] gssOutToken = secCtx.acceptSecContext(responseData, + 0, responseData.length); + + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "evaluateResponse", + "KRB5SRV04:Challenge: [after acceptSecCtx]", gssOutToken); + } + + if (secCtx.isEstablished()) { + handshakeStage = 1; + + peer = secCtx.getSrcName().toString(); + me = secCtx.getTargName().toString(); + + logger.log(Level.FINE, + "KRB5SRV05:Peer name is : {0}, my name is : {1}", + new Object[]{peer, me}); + + // me might take the form of proto@host or proto/host + if (protocolSaved != null && + !protocolSaved.equalsIgnoreCase(me.split("[/@]")[0])) { + throw new SaslException( + "GSS context targ name protocol error: " + me); + } + + if (gssOutToken == null) { + return doHandshake1(EMPTY); + } + } + + return gssOutToken; + } catch (GSSException e) { + throw new SaslException("GSS initiate failed", e); + } + } + } + + private byte[] doHandshake1(byte[] responseData) throws SaslException { + try { + // Security context already established. responseData + // should contain no data + if (responseData != null && responseData.length > 0) { + throw new SaslException( + "Handshake expecting no response data from server"); + } + + // Construct 4 octets of data: + // First octet contains bitmask specifying protections supported + // 2nd-4th octets contains max receive buffer of server + + byte[] gssInToken = new byte[4]; + gssInToken[0] = allQop; + intToNetworkByteOrder(recvMaxBufSize, gssInToken, 1, 3); + + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, + "KRB5SRV06:Supported protections: {0}; recv max buf size: {1}", + new Object[]{allQop, + recvMaxBufSize}); + } + + handshakeStage = 2; // progress to next stage + + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "doHandshake1", + "KRB5SRV07:Challenge [raw]", gssInToken); + } + + byte[] gssOutToken = secCtx.wrap(gssInToken, 0, gssInToken.length, + new MessageProp(0 /* gop */, false /* privacy */)); + + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "doHandshake1", + "KRB5SRV08:Challenge [after wrap]", gssOutToken); + } + return gssOutToken; + + } catch (GSSException e) { + throw new SaslException("Problem wrapping handshake1", e); + } + } + + private byte[] doHandshake2(byte[] responseData) throws SaslException { + try { + // Expecting 4 octets from client selected protection + // and client's receive buffer size + byte[] gssOutToken = secCtx.unwrap(responseData, 0, + responseData.length, new MessageProp(0, false)); + + if (logger.isLoggable(Level.FINER)) { + traceOutput(MY_CLASS_NAME, "doHandshake2", + "KRB5SRV09:Response [after unwrap]", gssOutToken); + } + + // First octet is a bit-mask specifying the selected protection + byte selectedQop = gssOutToken[0]; + if ((selectedQop&allQop) == 0) { + throw new SaslException("Client selected unsupported protection: " + + selectedQop); + } + if ((selectedQop&PRIVACY_PROTECTION) != 0) { + privacy = true; + integrity = true; + } else if ((selectedQop&INTEGRITY_ONLY_PROTECTION) != 0) { + integrity = true; + } + + // 2nd-4th octets specifies maximum buffer size expected by + // client (in network byte order). This is the server's send + // buffer maximum. + int clntMaxBufSize = networkByteOrderToInt(gssOutToken, 1, 3); + + // Determine the max send buffer size based on what the + // client is able to receive and our specified max + sendMaxBufSize = (sendMaxBufSize == 0) ? clntMaxBufSize : + Math.min(sendMaxBufSize, clntMaxBufSize); + + // Update context to limit size of returned buffer + rawSendSize = secCtx.getWrapSizeLimit(JGSS_QOP, privacy, + sendMaxBufSize); + + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, + "KRB5SRV10:Selected protection: {0}; privacy: {1}; integrity: {2}", + new Object[]{selectedQop, + Boolean.valueOf(privacy), + Boolean.valueOf(integrity)}); + logger.log(Level.FINE, +"KRB5SRV11:Client max recv size: {0}; server max send size: {1}; rawSendSize: {2}", + new Object[] {clntMaxBufSize, + sendMaxBufSize, + rawSendSize}); + } + + // Get authorization identity, if any + if (gssOutToken.length > 4) { + try { + authzid = new String(gssOutToken, 4, + gssOutToken.length - 4, "UTF-8"); + } catch (UnsupportedEncodingException uee) { + throw new SaslException ("Cannot decode authzid", uee); + } + } else { + authzid = peer; + } + logger.log(Level.FINE, "KRB5SRV12:Authzid: {0}", authzid); + + AuthorizeCallback acb = new AuthorizeCallback(peer, authzid); + + // In Kerberos, realm is embedded in peer name + cbh.handle(new Callback[] {acb}); + if (acb.isAuthorized()) { + authzid = acb.getAuthorizedID(); + completed = true; + } else { + // Authorization failed + throw new SaslException(peer + + " is not authorized to connect as " + authzid); + } + + return null; + } catch (GSSException e) { + throw new SaslException("Final handshake step failed", e); + } catch (IOException e) { + throw new SaslException("Problem with callback handler", e); + } catch (UnsupportedCallbackException e) { + throw new SaslException("Problem with callback handler", e); + } + } + + public String getAuthorizationID() { + if (completed) { + return authzid; + } else { + throw new IllegalStateException("Authentication incomplete"); + } + } + + public Object getNegotiatedProperty(String propName) { + if (!completed) { + throw new IllegalStateException("Authentication incomplete"); + } + + Object result; + switch (propName) { + case Sasl.BOUND_SERVER_NAME: + try { + // me might take the form of proto@host or proto/host + result = me.split("[/@]")[1]; + } catch (Exception e) { + result = null; + } + break; + default: + result = super.getNegotiatedProperty(propName); + } + return result; + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/ProblemList.txt Wed Jul 05 20:01:50 2017 +0200 @@ -139,9 +139,6 @@ com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java aix-all javax/management/MBeanServer/OldMBeanServerTest.java aix-all -# 8050115 -javax/management/monitor/GaugeMonitorDeadlockTest.java generic-all - ############################################################################ # jdk_math diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/TEST.ROOT --- a/jdk/test/TEST.ROOT Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/TEST.ROOT Wed Jul 05 20:01:50 2017 +0200 @@ -8,7 +8,7 @@ othervm.dirs=java/awt java/beans javax/accessibility javax/imageio javax/sound javax/print javax/management com/sun/awt sun/awt sun/java2d sun/pisces # Tests that cannot run concurrently -exclusiveAccess.dirs=java/rmi/Naming java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi +exclusiveAccess.dirs=java/rmi/Naming java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi java/util/stream # Group definitions groups=TEST.groups [closed/TEST.groups] diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/awt/Graphics2D/WhiteTextColorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Graphics2D/WhiteTextColorTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; +import java.awt.image.*; +import javax.swing.*; + +/** + * @test + * @bug 8056009 + * @summary tests whether Graphics.setColor-calls with Color.white are ignored directly + * after pipeline initialization for a certain set of operations. + * @author ceisserer + */ +public class WhiteTextColorTest extends Frame { + public static volatile boolean success = false; + + public WhiteTextColorTest() { + Image dstImg = getGraphicsConfiguration() + .createCompatibleVolatileImage(30, 20); + Graphics g = dstImg.getGraphics(); + + g.setColor(Color.BLACK); + g.fillRect(0, 0, dstImg.getWidth(null), dstImg.getHeight(null)); + g.setColor(Color.WHITE); + g.drawString("Test", 0, 15); + + BufferedImage readBackImg = new BufferedImage(dstImg.getWidth(null), + dstImg.getHeight(null), BufferedImage.TYPE_INT_RGB); + readBackImg.getGraphics().drawImage(dstImg, 0, 0, null); + + for (int x = 0; x < readBackImg.getWidth(); x++) { + for (int y = 0; y < readBackImg.getHeight(); y++) { + int pixel = readBackImg.getRGB(x, y); + + // In case a single white pixel is found, the + // setColor(Color.WHITE) + // call before was not ignored and the bug is not present + if (pixel == 0xFFFFFFFF) { + return; + } + } + } + + throw new RuntimeException("Test Failed"); + } + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + new WhiteTextColorTest(); + } + }); + } +} + diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/awt/Window/setLocRelativeTo/SetLocationRelativeToTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Window/setLocRelativeTo/SetLocationRelativeToTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; +import java.util.ArrayList; +import javax.swing.*; + +/* +@test +@summary Toplevel should be correctly positioned as relative to a component: + so that their centers coincide + or, if the component is hidden, centered on the screen. +@bug 8036915 +@library ../../../../lib/testlibrary +@build ExtendedRobot +@run main/timeout=1200 SetLocationRelativeToTest +*/ + +public class SetLocationRelativeToTest { + private static int delay = 500; + private static boolean testEverything = false;// NB: change this to true to test everything + java.util.List awtToplevels = new ArrayList(); + java.util.List swingToplevels = new ArrayList(); + java.util.List allToplevels = new ArrayList(); + java.util.List awtComponents = new ArrayList(); + java.util.List swingComponents = new ArrayList(); + java.util.List allComponents = new ArrayList(); + Label placeholder = new Label(); + JLabel jplaceholder = new JLabel(); + JFrame jcontainer; + public SetLocationRelativeToTest() { + Frame frame = new Frame("Frame"); + frame.setSize(200,100); + Frame uframe = new Frame("U.Frame"); + uframe.setUndecorated(true); + uframe.setSize(200,100); + Window window = new Window(frame); + window.setSize(200,100); + Dialog dialog = new Dialog(frame, "Dialog"); + dialog.setSize(200,100); + awtToplevels.add(frame); + awtToplevels.add(uframe); + awtToplevels.add(window); + awtToplevels.add(dialog); + + awtComponents.add(new TextArea("Am a TextArea")); + awtComponents.add(new TextField("Am a TextField")); + awtComponents.add(new Button("Press")); + awtComponents.add(new Label("Label")); + Choice aChoice = new Choice(); + aChoice.add("One"); + aChoice.add("Two"); + awtComponents.add(aChoice); + awtComponents.add(new Canvas()); + awtComponents.add(new List(4)); + awtComponents.add(new Checkbox("Me CheckBox")); + awtComponents.add(new Scrollbar()); + + swingComponents.add(new JTextArea("Am a JTextArea")); + swingComponents.add(new JTextField("Am a JTextField")); + swingComponents.add(new JButton("Press")); + swingComponents.add(new JLabel("JLabel")); + JComboBox jcombo = new JComboBox(); + swingComponents.add(jcombo); + swingComponents.add(new JPanel()); + swingComponents.add(new JList()); + swingComponents.add(new JCheckBox("Me JCheckBox")); + swingComponents.add(new JScrollBar()); + } + + public static void main(String args[]) { + SetLocationRelativeToTest test = new SetLocationRelativeToTest(); + test.doAWTTest(true); + test.doAWTTest(false); + try { + test.doSwingTest(true); + test.doSwingTest(false); + }catch(InterruptedException ie) { + ie.printStackTrace(); + }catch(java.lang.reflect.InvocationTargetException ite) { + ite.printStackTrace(); + throw new RuntimeException("InvocationTarget?"); + } + return; + } + + // In regular testing, we select just few components to test + // randomly. If full testing required, select many ("all"). + void selectObjectsToTest(boolean doSwing) { + allToplevels.clear(); + allComponents.clear(); + if(testEverything) { + allToplevels.addAll(0, awtToplevels); + allComponents.addAll(0, awtComponents); + if(doSwing) { + allToplevels.addAll(allToplevels.size(), swingToplevels); + allComponents.addAll(allComponents.size(), swingComponents); + } + }else{ + //select a random of each + int i = (int)(java.lang.Math.random()*awtToplevels.size()); + allToplevels.add(awtToplevels.get(i)); + i = (int)(java.lang.Math.random()*awtComponents.size()); + allComponents.add(awtComponents.get(i)); + if(doSwing) { + i = (int)(java.lang.Math.random()*swingToplevels.size()); + allToplevels.add(swingToplevels.get(i)); + i = (int)(java.lang.Math.random()*swingComponents.size()); + allComponents.add(swingComponents.get(i)); + } + } + } + + // create Frame, add an AWT component to it, + // hide it (or not) and position a new toplevel + // relativeTo + void doAWTTest(boolean isHidden) { + boolean res; + ExtendedRobot robot; + try { + robot = new ExtendedRobot(); + }catch(Exception ex) { + ex.printStackTrace(); + throw new RuntimeException("Failed: "+ex.getMessage()); + } + Frame container = new Frame("Frame"); + container.setBounds(100,100,300,300); + container.setLayout(new GridLayout(3,1)); + container.add(placeholder); + container.setVisible(true); + selectObjectsToTest(false); + for(Component c: allComponents) { + placeholder.setText((isHidden ? "Hidden: " : "Below is ")+ c.getClass().getName()); + c.setVisible(true); + container.add(c); + container.doLayout(); + if(isHidden) { + c.setVisible(false); + } + robot.waitForIdle(delay); + for(Window w: allToplevels) { + w.setLocationRelativeTo(c); + w.setVisible(true); + robot.waitForIdle(delay); + res = compareLocations(w, c, robot); + System.out.println(c.getClass().getName()+" \t: "+w.getClass().getName()+ + ((w instanceof Frame) && (((Frame)w).isUndecorated()) ? " undec\t\t:" : "\t\t:")+" "+ + (res ? "" : "Failed")); + if(!res) { + throw new RuntimeException("Test failed."); + } + w.dispose(); + } + container.remove(c); + robot.waitForIdle(delay); + } + container.dispose(); + } + + // Create JFrame, add an AWT or Swing component to it, + // hide it (or not) and position a new toplevel + // relativeTo + void doSwingTest(boolean isHidden) throws InterruptedException, + java.lang.reflect.InvocationTargetException { + boolean res; + ExtendedRobot robot; + try { + robot = new ExtendedRobot(); + }catch(Exception ex) { + ex.printStackTrace(); + throw new RuntimeException("Failed: "+ex.getMessage()); + } + + EventQueue.invokeAndWait( () -> { + JFrame jframe = new JFrame("jframe"); + jframe.setSize(200,100); + swingToplevels.add(jframe); + JFrame ujframe = new JFrame("ujframe"); + ujframe.setSize(200,100); + ujframe.setUndecorated(true); + swingToplevels.add(ujframe); + JWindow jwin = new JWindow(); + jwin.setSize(200,100); + swingToplevels.add(jwin); + JDialog jdia = new JDialog((Frame)null, "JDialog"); + jdia.setSize(200,100); + swingToplevels.add(jdia); + jcontainer = new JFrame("JFrame"); + jcontainer.setBounds(100,100,300,300); + jcontainer.setLayout(new GridLayout(3,1)); + jcontainer.add(jplaceholder); + jcontainer.setVisible(true); + selectObjectsToTest(true); + }); + robot.waitForIdle(delay); + + for(Component c: allComponents) { + EventQueue.invokeAndWait( () -> { + jplaceholder.setText((isHidden ? "Hidden: " : "Below is: ")+ c.getClass().getName()); + c.setVisible(true); + jcontainer.add(c); + jcontainer.doLayout(); + if(isHidden) { + c.setVisible(false); + } + }); + robot.waitForIdle(delay); + for(Window w: allToplevels) { + EventQueue.invokeAndWait( () -> { + w.setLocationRelativeTo(c); + w.setVisible(true); + }); + robot.waitForIdle(delay); + res = compareLocations(w, c, robot); + System.out.println(c.getClass().getName()+" \t: "+w.getClass().getName()+ + ((w instanceof Frame) && (((Frame)w).isUndecorated()) ? " undec\t\t:" : "\t\t:")+" "+ + (res ? "" : "Failed")); + EventQueue.invokeAndWait( () -> { + w.dispose(); + }); + robot.waitForIdle(); + if(!res) { + throw new RuntimeException("Test failed."); + } + } + EventQueue.invokeAndWait( () -> { + jcontainer.remove(c); + }); + robot.waitForIdle(delay); + } + EventQueue.invokeAndWait( () -> { + jcontainer.dispose(); + }); + } + + // Check, finally, if w either is concentric with c + // or sits in the center of the screen (if c is hidden) + boolean compareLocations(final Window w, final Component c, ExtendedRobot robot) { + final Point pc = new Point(); + final Point pw = new Point(); + try { + EventQueue.invokeAndWait( () -> { + pw.setLocation(w.getLocationOnScreen()); + pw.translate(w.getWidth()/2, w.getHeight()/2); + if(!c.isVisible()) { + Rectangle screenRect = w.getGraphicsConfiguration().getBounds(); + pc.setLocation(screenRect.x+screenRect.width/2, + screenRect.y+screenRect.height/2); + }else{ + pc.setLocation(c.getLocationOnScreen()); + pc.translate(c.getWidth()/2, c.getHeight()/2); + } + }); + } catch(InterruptedException ie) { + throw new RuntimeException("Interrupted"); + } catch(java.lang.reflect.InvocationTargetException ite) { + ite.printStackTrace(); + throw new RuntimeException("InvocationTarget?"); + } + robot.waitForIdle(delay); + // Compare with 1 tolerance to forgive possible rounding errors + if(pc.x - pw.x > 1 || + pc.x - pw.x < -1 || + pc.y - pw.y > 1 || + pc.y - pw.y < -1 ) { + System.out.println("Center of "+(c.isVisible() ? "Component:" : "screen:")+pc); + System.out.println("Center of Window:"+pw); + System.out.println("Centers of "+w+" and "+c+" do not coincide"); + return false; + } + return true; + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/awt/font/GlyphVector/GlyphVectorOutline.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/font/GlyphVector/GlyphVectorOutline.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 Google Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineBreakMeasurer; +import java.awt.font.TextAttribute; +import java.awt.font.TextLayout; +import java.awt.image.BufferedImage; +import java.io.File; +import java.text.AttributedString; + +import javax.imageio.ImageIO; + +/** + * Manual test for: + * JDK-8057986: freetype code to get glyph outline does not handle initial control point properly + * + * Manual repro recipe: + * (cd test/java/awt/font/GlyphVector/ && javac GlyphVectorOutline.java && wget -q -O/tmp/msgothic.ttc https://browserlinux-jp.googlecode.com/files/msgothic.ttc && java GlyphVectorOutline /tmp/msgothic.ttc /tmp/katakana.png) + * + * Then examine the two rendered Japanese characters in the png file. + * + * Renders text to a PNG by + * 1. using the native Graphics2D#drawGlyphVector implementation + * 2. filling in the result of GlyphVector#getOutline + * + * Should be the same but is different for some CJK characters + * (e.g. Katakana character \u30AF). + * + * @author ikopylov@google.com (Igor Kopylov) + */ +public class GlyphVectorOutline { + public static void main(String[] args) throws Exception { + if (args.length != 2) { + throw new Error("Usage: java GlyphVectorOutline fontfile outputfile"); + } + writeImage(new File(args[0]), + new File(args[1]), + "\u30AF"); + } + + public static void writeImage(File fontFile, File outputFile, String value) throws Exception { + BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); + Graphics2D g = image.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, image.getWidth(), image.getHeight()); + g.setColor(Color.BLACK); + + Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile); + font = font.deriveFont(Font.PLAIN, 72f); + FontRenderContext frc = new FontRenderContext(null, false, false); + GlyphVector gv = font.createGlyphVector(frc, value); + g.drawGlyphVector(gv, 10, 80); + g.fill(gv.getOutline(10, 180)); + ImageIO.write(image, "png", outputFile); + } + + private static void drawString(Graphics2D g, Font font, String value, float x, float y) { + AttributedString str = new AttributedString(value); + str.addAttribute(TextAttribute.FOREGROUND, Color.BLACK); + str.addAttribute(TextAttribute.FONT, font); + FontRenderContext frc = new FontRenderContext(null, true, true); + TextLayout layout = new LineBreakMeasurer(str.getIterator(), frc).nextLayout(Integer.MAX_VALUE); + layout.draw(g, x, y); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/lang/invoke/LFCaching/LFCachingTestCase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/LFCaching/LFCachingTestCase.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.InvocationTargetException; + +/** + * Abstract class for lambda forms caching testing. + * + * @author kshefov + */ +public abstract class LFCachingTestCase extends LambdaFormTestCase { + + /** + * Constructor for lambda forms caching test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + protected LFCachingTestCase(TestMethods testMethod) { + super(testMethod); + } + + /** + * Checks that the lambda forms of the two adapter method handles adapter1 + * and adapter2 are the same. + * + * @param adapter1 First method handle. + * @param adapter2 Second method handle. + */ + public void checkLFCaching(MethodHandle adapter1, MethodHandle adapter2) { + try { + + if (!adapter1.type().equals(adapter2.type())) { + throw new Error("TESTBUG: Types of the two method handles are not the same"); + } + + Object lambdaForm0 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter1); + Object lambdaForm1 = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter2); + + if (lambdaForm0 == null || lambdaForm1 == null) { + throw new Error("Unexpected error: One or both lambda forms of the method handles are null"); + } + + if (lambdaForm0 != lambdaForm1) { + System.err.println("Lambda form 0 toString is:"); + System.err.println(lambdaForm0); + System.err.println("Lambda form 1 toString is:"); + System.err.println(lambdaForm1); + throw new AssertionError("Error: Lambda forms of the two method handles" + + " are not the same. LF cahing does not work"); + } + } catch (IllegalAccessException | IllegalArgumentException | + SecurityException | InvocationTargetException ex) { + throw new Error("Unexpected exception: ", ex); + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/LFCaching/LFGarbageCollectedTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test LFGarbageCollectedTest + * @bug 8046703 + * @summary Test verifies that lambda forms are garbage collected + * @author kshefov + * @ignore 8057020 + * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @build TestMethods + * @build LambdaFormTestCase + * @build LFGarbageCollectedTest + * @run main/othervm/timeout=600 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true -DtestLimit=150 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI LFGarbageCollectedTest + */ + +import java.lang.invoke.MethodHandle; +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Map; + +/** + * Lambda forms garbage collection test class. + */ +public final class LFGarbageCollectedTest extends LambdaFormTestCase { + + /** + * Constructor for a lambda forms garbage collection test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + public LFGarbageCollectedTest(TestMethods testMethod) { + super(testMethod); + } + + @Override + public void doTest() { + try { + Map data = getTestMethod().getTestCaseData(); + MethodHandle adapter; + try { + adapter = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE); + } catch (NoSuchMethodException ex) { + throw new Error("Unexpected exception: ", ex); + } + Object lambdaForm = LambdaFormTestCase.INTERNAL_FORM.invoke(adapter); + if (lambdaForm == null) { + throw new Error("Unexpected error: Lambda form of the method handle is null"); + } + ReferenceQueue rq = new ReferenceQueue(); + PhantomReference ph = new PhantomReference(lambdaForm, rq); + lambdaForm = null; + data = null; + adapter = null; + for (int i = 0; i < 1000 && !ph.isEnqueued(); i++) { + System.gc(); + } + if (!ph.isEnqueued()) { + throw new AssertionError("Error: Lambda form is not garbage collected"); + } + } catch (IllegalAccessException | IllegalArgumentException | + InvocationTargetException ex) { + throw new Error("Unexpected exception: ", ex); + } + } + + /** + * Main routine for lambda forms garbage collection test. + * + * @param args Accepts no arguments. + */ + public static void main(String[] args) { + // The "identity" and "constant" methods should be removed from this test, + // because their lambda forms are stored in a static filed and are not GC'ed. + // There can be only 5 such LFs for each method, so no memory leak happens. + EnumSet testMethods = EnumSet.complementOf(EnumSet.of(TestMethods.IDENTITY, TestMethods.CONSTANT)); + LambdaFormTestCase.runTests(LFGarbageCollectedTest::new, testMethods); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test LFMultiThreadCachingTest + * @bug 8046703 + * @summary Test verifies that lambda forms are cached when run with multiple threads + * @author kshefov + * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @build TestMethods + * @build LambdaFormTestCase + * @build LFCachingTestCase + * @build LFMultiThreadCachingTest + * @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFMultiThreadCachingTest + */ + +import java.lang.invoke.MethodHandle; +import java.util.EnumSet; +import java.util.Map; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; + +/** + * Multiple threaded lambda forms caching test class. + */ +public final class LFMultiThreadCachingTest extends LFCachingTestCase { + private static final TestMethods.Kind[] KINDS; + static { + EnumSet set = EnumSet.complementOf(EnumSet.of(TestMethods.Kind.EXCEPT)); + KINDS = set.toArray(new TestMethods.Kind[set.size()]); + if (KINDS.length < 2) { + throw new Error("TESTBUG: KINDS.length[" + KINDS.length + "] should be at least 2"); + } + } + private static final int CORES = Math.max(KINDS.length, Runtime.getRuntime().availableProcessors()); + + /** + * Constructor a for multiple threaded lambda forms caching test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + public LFMultiThreadCachingTest(TestMethods testMethod) { + super(testMethod); + } + + @Override + public void doTest() { + Map data = getTestMethod().getTestCaseData(); + ConcurrentLinkedQueue adapters = new ConcurrentLinkedQueue<>(); + CyclicBarrier begin = new CyclicBarrier(CORES); + CountDownLatch end = new CountDownLatch(CORES); + for (int i = 0; i < CORES; ++i) { + TestMethods.Kind kind = KINDS[i % KINDS.length]; + new Thread(() -> { + try { + begin.await(); + adapters.add(getTestMethod().getTestCaseMH(data, kind)); + } catch (InterruptedException | BrokenBarrierException | IllegalAccessException | NoSuchMethodException ex) { + throw new Error("Unexpected exception: ", ex); + } finally { + end.countDown(); + } + }).start(); + } + try { + end.await(); + } catch (InterruptedException ex) { + throw new Error("Unexpected exception: ", ex); + } + if (adapters.size() < CORES) { + throw new Error("adapters size[" + adapters.size() + "] is less than " + CORES); + } + MethodHandle prev = adapters.poll(); + for (MethodHandle current : adapters) { + checkLFCaching(prev, current); + prev = current; + } + } + + /** + * Main routine for multiple threaded lambda forms caching test. + * + * @param args Accepts no arguments. + */ + public static void main(String[] args) { + LambdaFormTestCase.runTests(LFMultiThreadCachingTest::new, EnumSet.allOf(TestMethods.class)); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test LFSingleThreadCachingTest + * @bug 8046703 + * @summary Test verifies that lambda forms are cached when run with single thread + * @author kshefov + * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @build TestMethods + * @build LambdaFormTestCase + * @build LFCachingTestCase + * @build LFSingleThreadCachingTest + * @run main/othervm/timeout=300 -Djava.lang.invoke.MethodHandle.USE_LF_EDITOR=true LFSingleThreadCachingTest + */ + +import java.lang.invoke.MethodHandle; +import java.util.EnumSet; +import java.util.Map; + +/** + * Single threaded lambda forms caching test class. + */ +public final class LFSingleThreadCachingTest extends LFCachingTestCase { + + /** + * Constructor for a single threaded lambda forms caching test case. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class that + * returns a {@code j.l.i.MethodHandle} instance. + */ + public LFSingleThreadCachingTest(TestMethods testMethod) { + super(testMethod); + } + + @Override + public void doTest() { + MethodHandle adapter1; + MethodHandle adapter2; + Map data = getTestMethod().getTestCaseData(); + try { + adapter1 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.ONE); + adapter2 = getTestMethod().getTestCaseMH(data, TestMethods.Kind.TWO); + } catch (NoSuchMethodException | IllegalAccessException ex) { + throw new Error("Unexpected exception: ", ex); + } + checkLFCaching(adapter1, adapter2); + } + + /** + * Main routine for single threaded lambda forms caching test. + * + * @param args Accepts no arguments. + */ + public static void main(String[] args) { + LambdaFormTestCase.runTests(LFSingleThreadCachingTest::new, EnumSet.allOf(TestMethods.class)); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/lang/invoke/LFCaching/LambdaFormTestCase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/LFCaching/LambdaFormTestCase.java Wed Jul 05 20:01:50 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.oracle.testlibrary.jsr292.Helper; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.function.Function; + +/** + * Lambda forms caching test case class. Contains all necessary test routines to + * test lambda forms caching in method handles returned by methods of + * MethodHandles class. + * + * @author kshefov + */ +public abstract class LambdaFormTestCase { + + private final static String METHOD_HANDLE_CLASS_NAME = "java.lang.invoke.MethodHandle"; + private final static String INTERNAL_FORM_METHOD_NAME = "internalForm"; + + /** + * Reflection link to {@code j.l.i.MethodHandle.internalForm} method. It is + * used to get a lambda form from a method handle. + */ + protected final static Method INTERNAL_FORM; + + static { + try { + Class mhClass = Class.forName(METHOD_HANDLE_CLASS_NAME); + INTERNAL_FORM = mhClass.getDeclaredMethod(INTERNAL_FORM_METHOD_NAME); + INTERNAL_FORM.setAccessible(true); + } catch (Exception ex) { + throw new Error("Unexpected exception: ", ex); + } + } + + private final TestMethods testMethod; + + /** + * Test case constructor. Generates test cases with random method types for + * given methods form {@code j.l.i.MethodHandles} class. + * + * @param testMethod A method from {@code j.l.i.MethodHandles} class which + * returns a {@code j.l.i.MethodHandle}. + */ + protected LambdaFormTestCase(TestMethods testMethod) { + this.testMethod = testMethod; + } + + public TestMethods getTestMethod() { + return testMethod; + } + + /** + * Routine that executes a test case. + */ + public abstract void doTest(); + + /** + * Runs a number of test cases defined by the size of testCases list. + * + * @param ctor constructor of LambdaFormCachingTest or its child classes + * object. + * @param testMethods list of test methods + */ + public static void runTests(Function ctor, Collection testMethods) { + boolean passed = true; + int testCounter = 0; + int failCounter = 0; + long iterations = Math.max(1, Helper.TEST_LIMIT / testMethods.size()); + for (long i = 0; i < iterations; i++) { + System.err.println(String.format("Iteration %d:", i)); + for (TestMethods testMethod : testMethods) { + LambdaFormTestCase testCase = ctor.apply(testMethod); + try { + System.err.printf("Tested LF caching feature with MethodHandles.%s method.%n", + testCase.getTestMethod().name); + testCase.doTest(); + System.err.println("PASSED"); + } catch (Throwable t) { + t.printStackTrace(); + System.err.println("FAILED"); + passed = false; + failCounter++; + } + testCounter++; + } + } + if (!passed) { + throw new Error(String.format("%d of %d test cases FAILED! %n" + + "Rerun the test with the same \"-Dseed=\" option as in the log file!", + failCounter, testCounter)); + } else { + System.err.println(String.format("All %d test cases PASSED!", testCounter)); + } + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/lang/invoke/LFCaching/TestMethods.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/LFCaching/TestMethods.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,698 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.oracle.testlibrary.jsr292.Helper; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Enumeration containing information about methods from + * {@code j.l.i.MethodHandles} class that are used for testing lambda forms + * caching. + * + * @author kshefov + */ +public enum TestMethods { + + FOLD_ARGUMENTS("foldArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + Class combinerReturnType; + if (realArity == 0) { + combinerReturnType = void.class; + } else { + combinerReturnType = Helper.RNG.nextBoolean() ? void.class : mtTarget.parameterType(0); + } + data.put("combinerReturnType", combinerReturnType); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class combinerReturnType = (Class) data.get("combinerReturnType"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + Class rType = mtTarget.returnType(); + int combListStart = (combinerReturnType == void.class) ? 0 : 1; + if (modifierMHArgNum < combListStart) { + modifierMHArgNum = combListStart; + } + MethodHandle combiner = TestMethods.methodHandleGenerator(combinerReturnType, + mtTarget.parameterList().subList(combListStart, + modifierMHArgNum), kind); + return MethodHandles.foldArguments(target, combiner); + } + }, + DROP_ARGUMENTS("dropArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int dropArgsPos = Helper.RNG.nextInt(realArity + 1); + data.put("dropArgsPos", dropArgsPos); + MethodType mtDropArgs = TestMethods.randomMethodTypeGenerator( + Helper.RNG.nextInt(Helper.MAX_ARITY - realArity)); + data.put("mtDropArgs", mtDropArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtDropArgs = (MethodType) data.get("mtDropArgs"); + int dropArgsPos = (int) data.get("dropArgsPos"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + int mtTgtSlotsCount = TestMethods.argSlotsCount(mtTarget); + int mtDASlotsCount = TestMethods.argSlotsCount(mtDropArgs); + List> fakeParList; + if (mtTgtSlotsCount + mtDASlotsCount > Helper.MAX_ARITY - 1) { + fakeParList = TestMethods.reduceArgListToSlotsCount(mtDropArgs.parameterList(), + Helper.MAX_ARITY - mtTgtSlotsCount - 1); + } else { + fakeParList = mtDropArgs.parameterList(); + } + return MethodHandles.dropArguments(target, dropArgsPos, fakeParList); + } + }, + EXPLICIT_CAST_ARGUMENTS("explicitCastArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + MethodType mtExcplCastArgs = TestMethods.randomMethodTypeGenerator(realArity); + if (mtTarget.returnType() == void.class) { + mtExcplCastArgs = MethodType.methodType(void.class, + mtExcplCastArgs.parameterArray()); + } + if (mtExcplCastArgs.returnType() == void.class) { + mtExcplCastArgs = MethodType.methodType(mtTarget.returnType(), + mtExcplCastArgs.parameterArray()); + } + data.put("mtExcplCastArgs", mtExcplCastArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtExcplCastArgs = (MethodType) data.get("mtExcplCastArgs"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + return MethodHandles.explicitCastArguments(target, mtExcplCastArgs); + } + }, + FILTER_ARGUMENTS("filterArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int filterArgsPos = Helper.RNG.nextInt(realArity + 1); + data.put("filterArgsPos", filterArgsPos); + int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos); + data.put("filtersArgsArrayLength", filtersArgsArrayLength); + MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength); + data.put("mtFilter", mtFilter); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtFilter = (MethodType) data.get("mtFilter"); + int filterArgsPos = (int) data.get("filterArgsPos"); + int filtersArgsArrayLength = (int) data.get("filtersArgsArrayLength"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + MethodHandle[] filters = new MethodHandle[filtersArgsArrayLength]; + for (int i = 0; i < filtersArgsArrayLength; i++) { + filters[i] = TestMethods.filterGenerator(mtFilter.parameterType(i), + mtTarget.parameterType(filterArgsPos + i), kind); + } + return MethodHandles.filterArguments(target, filterArgsPos, filters); + } + }, + FILTER_RETURN_VALUE("filterReturnValue") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int filterArgsPos = Helper.RNG.nextInt(realArity + 1); + int filtersArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - filterArgsPos); + MethodType mtFilter = TestMethods.randomMethodTypeGenerator(filtersArgsArrayLength); + data.put("mtFilter", mtFilter); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtFilter = (MethodType) data.get("mtFilter"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + MethodHandle filter = TestMethods.filterGenerator(mtTarget.returnType(), + mtFilter.returnType(), kind); + return MethodHandles.filterReturnValue(target, filter); + } + }, + INSERT_ARGUMENTS("insertArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int insertArgsPos = Helper.RNG.nextInt(realArity + 1); + data.put("insertArgsPos", insertArgsPos); + int insertArgsArrayLength = Helper.RNG.nextInt(realArity + 1 - insertArgsPos); + MethodType mtInsertArgs = MethodType.methodType(void.class, mtTarget.parameterList() + .subList(insertArgsPos, insertArgsPos + insertArgsArrayLength)); + data.put("mtInsertArgs", mtInsertArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtInsertArgs = (MethodType) data.get("mtInsertArgs"); + int insertArgsPos = (int) data.get("insertArgsPos"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + Object[] insertList = Helper.randomArgs(mtInsertArgs.parameterList()); + return MethodHandles.insertArguments(target, insertArgsPos, insertList); + } + }, + PERMUTE_ARGUMENTS("permuteArguments") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY / 2); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int[] permuteArgsReorderArray = new int[realArity]; + int mtParmuteArgsNum = Helper.RNG.nextInt(Helper.MAX_ARITY); + mtParmuteArgsNum = mtParmuteArgsNum == 0 ? 1 : mtParmuteArgsNum; + MethodType mtPermuteArgs = TestMethods.randomMethodTypeGenerator(mtParmuteArgsNum); + mtTarget = mtTarget.changeReturnType(mtPermuteArgs.returnType()); + for (int i = 0; i < realArity; i++) { + int mtPermuteArgsParNum = Helper.RNG.nextInt(mtPermuteArgs.parameterCount()); + permuteArgsReorderArray[i] = mtPermuteArgsParNum; + mtTarget = mtTarget.changeParameterType( + i, mtPermuteArgs.parameterType(mtPermuteArgsParNum)); + } + data.put("mtTarget", mtTarget); + data.put("permuteArgsReorderArray", permuteArgsReorderArray); + data.put("mtPermuteArgs", mtPermuteArgs); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + MethodType mtPermuteArgs = (MethodType) data.get("mtPermuteArgs"); + int[] permuteArgsReorderArray = (int[]) data.get("permuteArgsReorderArray"); + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), kind); + return MethodHandles.permuteArguments(target, mtPermuteArgs, permuteArgsReorderArray); + } + }, + THROW_EXCEPTION("throwException") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + return MethodHandles.throwException(rType, Exception.class + ); + } + }, + GUARD_WITH_TEST("guardWithTest") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + TestMethods.Kind targetKind; + TestMethods.Kind fallbackKind; + if (kind.equals(TestMethods.Kind.ONE)) { + targetKind = TestMethods.Kind.ONE; + fallbackKind = TestMethods.Kind.TWO; + } else { + targetKind = TestMethods.Kind.TWO; + fallbackKind = TestMethods.Kind.ONE; + } + MethodHandle target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), targetKind); + MethodHandle fallback = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), fallbackKind); + MethodHandle test = TestMethods.methodHandleGenerator(boolean.class, + mtTarget.parameterList().subList(0, modifierMHArgNum), kind); + return MethodHandles.guardWithTest(test, target, fallback); + } + }, + CATCH_EXCEPTION("catchException") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + MethodHandle target; + if (kind.equals(TestMethods.Kind.ONE)) { + target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), TestMethods.Kind.ONE); + } else { + target = TestMethods.methodHandleGenerator(mtTarget.returnType(), + mtTarget.parameterList(), TestMethods.Kind.EXCEPT); + } + List> handlerParamList = new ArrayList<>(mtTarget.parameterCount() + 1); + handlerParamList.add(Exception.class); + handlerParamList.addAll(mtTarget.parameterList().subList(0, modifierMHArgNum)); + MethodHandle handler = TestMethods.methodHandleGenerator( + mtTarget.returnType(), handlerParamList, TestMethods.Kind.TWO); + return MethodHandles.catchException(target, Exception.class, handler); + } + }, + INVOKER("invoker") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + return MethodHandles.invoker(mtTarget); + } + }, + EXACT_INVOKER("exactInvoker") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + return MethodHandles.exactInvoker(mtTarget); + } + }, + SPREAD_INVOKER("spreadInvoker") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + // Arity after reducing because of long and double take 2 slots. + int realArity = mtTarget.parameterCount(); + int modifierMHArgNum = Helper.RNG.nextInt(realArity + 1); + data.put("modifierMHArgNum", modifierMHArgNum); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + int modifierMHArgNum = (int) data.get("modifierMHArgNum"); + return MethodHandles.spreadInvoker(mtTarget, modifierMHArgNum); + } + }, + ARRAY_ELEMENT_GETTER("arrayElementGetter") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + return MethodHandles.arrayElementGetter(Array.newInstance(rType, 2).getClass()); + } + }, + ARRAY_ELEMENT_SETTER("arrayElementSetter") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + return MethodHandles.arrayElementSetter(Array.newInstance(rType, 2).getClass()); + } + }, + CONSTANT("constant") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + if (rType.equals(boolean.class)) { + // There should be the same return values because for default values there are special "zero" forms + return MethodHandles.constant(rType, true); + } else { + return MethodHandles.constant(rType, kind.getValue(rType)); + } + } + }, + IDENTITY("identity") { + @Override + public Map getTestCaseData() { + Map data = new HashMap<>(); + int desiredArity = Helper.RNG.nextInt(Helper.MAX_ARITY); + MethodType mtTarget = TestMethods.randomMethodTypeGenerator(desiredArity); + data.put("mtTarget", mtTarget); + return data; + } + + @Override + protected MethodHandle getMH(Map data, TestMethods.Kind kind) { + MethodType mtTarget = (MethodType) data.get("mtTarget"); + Class rType = mtTarget.returnType(); + if (rType == void.class) { + rType = Object.class; + } + return MethodHandles.identity(rType); + } + }; + + /** + * Test method's name. + */ + public final String name; + + private TestMethods(String name) { + this.name = name; + } + + protected MethodHandle getMH(Map data, TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + throw new UnsupportedOperationException("TESTBUG: getMH method is not implemented for test method " + this); + } + + /** + * Creates an adapter method handle depending on a test method from + * MethodHandles class. Adapter is what is returned by the test method. This + * method is able to create two kinds of adapters, their type will be the + * same, but return values are different. + * + * @param data a Map containing data to create a method handle, can be + * obtained by {@link #getTestCaseData} method + * @param kind defines whether adapter ONE or adapter TWO will be + * initialized. Should be equal to TestMethods.Kind.ONE or + * TestMethods.Kind.TWO + * @return Method handle adapter that behaves according to + * TestMethods.Kind.ONE or TestMethods.Kind.TWO + * @throws java.lang.NoSuchMethodException + * @throws java.lang.IllegalAccessException + */ + public MethodHandle getTestCaseMH(Map data, TestMethods.Kind kind) + throws NoSuchMethodException, IllegalAccessException { + if (data == null) { + throw new Error(String.format("TESTBUG: Data for test method %s is not prepared", + this.name)); + } + if (!kind.equals(TestMethods.Kind.ONE) && !kind.equals(TestMethods.Kind.TWO)) { + throw new IllegalArgumentException("TESTBUG: Wrong \"kind\" (" + kind + + ") arg to getTestCaseMH function." + + " Should be Kind.ONE or Kind.TWO"); + } + return getMH(data, kind); + } + + /** + * Returns a data Map needed for {@link #getTestCaseMH} method. + * + * @return data Map needed for {@link #getTestCaseMH} method + */ + public Map getTestCaseData() { + throw new UnsupportedOperationException( + "TESTBUG: getTestCaseData method is not implemented for test method " + this); + } + + /** + * Enumeration used in methodHandleGenerator to define whether a MH returned + * by this method returns "2" in different type representations, "4", or + * throw an Exception. + */ + public static enum Kind { + + ONE(2), + TWO(4), + EXCEPT(0); + + private final int value; + + private Object getValue(Class cl) { + return Helper.castToWrapper(value, cl); + } + + private MethodHandle getBasicMH(Class rType) throws NoSuchMethodException, IllegalAccessException { + MethodHandle result = null; + switch (this) { + case ONE: + case TWO: + if (rType.equals(void.class)) { + result = MethodHandles.lookup().findVirtual(Kind.class, "returnVoid", MethodType.methodType(void.class)); + result = MethodHandles.insertArguments(result, 0, this); + } else { + result = MethodHandles.constant(rType, getValue(rType)); + } + break; + case EXCEPT: + result = MethodHandles.throwException(rType, Exception.class); + result = MethodHandles.insertArguments(result, 0, new Exception()); + break; + } + return result; + } + + private void returnVoid() { + } + + private Kind(int value) { + this.value = value; + } + } + + /** + * Routine used to obtain a randomly generated method type. + * + * @param arity Arity of returned method type. + * @return MethodType generated randomly. + */ + private static MethodType randomMethodTypeGenerator(int arity) { + final Class[] CLASSES = { + Object.class, + int.class, + boolean.class, + byte.class, + short.class, + char.class, + long.class, + float.class, + double.class + }; + if (arity > Helper.MAX_ARITY) { + throw new IllegalArgumentException( + String.format("Arity should not exceed %d!", Helper.MAX_ARITY)); + } + List> list = Helper.randomClasses(CLASSES, arity); + list = Helper.getParams(list, false, arity); + int i = Helper.RNG.nextInt(CLASSES.length + 1); + Class rtype = i == CLASSES.length ? void.class : CLASSES[i]; + return MethodType.methodType(rtype, list); + } + + /** + * Routine used to obtain a method handles of a given type an kind (return + * value). + * + * @param returnType Type of MH return value. + * @param argTypes Types of MH args. + * @param kind Defines whether the obtained MH returns "1" or "2". + * @return Method handle of the given type. + * @throws NoSuchMethodException + * @throws IllegalAccessException + */ + private static MethodHandle methodHandleGenerator(Class returnType, + List> argTypes, TestMethods.Kind kind) + throws NoSuchMethodException, IllegalAccessException { + MethodHandle result; + result = kind.getBasicMH(returnType); + return Helper.addTrailingArgs(result, argTypes.size(), argTypes); + } + + /** + * Routine that generates filter method handles to test + * MethodHandles.filterArguments method. + * + * @param inputType Filter's argument type. + * @param returnType Filter's return type. + * @param kind Filter's return value definer. + * @return A filter method handle, that takes one argument. + * @throws NoSuchMethodException + * @throws IllegalAccessException + */ + private static MethodHandle filterGenerator(Class inputType, Class returnType, + TestMethods.Kind kind) throws NoSuchMethodException, IllegalAccessException { + MethodHandle tmpMH = kind.getBasicMH(returnType); + if (inputType.equals(void.class)) { + return tmpMH; + } + ArrayList> inputTypeList = new ArrayList<>(1); + inputTypeList.add(inputType); + return Helper.addTrailingArgs(tmpMH, 1, inputTypeList); + } + + private static int argSlotsCount(MethodType mt) { + int result = 0; + for (Class cl : mt.parameterArray()) { + if (cl.equals(long.class) || cl.equals(double.class)) { + result += 2; + } else { + result++; + } + } + return result; + } + + private static List> reduceArgListToSlotsCount(List> list, + int desiredSlotCount) { + List> result = new ArrayList<>(desiredSlotCount); + int count = 0; + for (Class cl : list) { + if (count >= desiredSlotCount) { + break; + } + if (cl.equals(long.class) || cl.equals(double.class)) { + count += 2; + } else { + count++; + } + result.add(cl); + } + return result; + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java --- a/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -42,6 +42,7 @@ public class CatchExceptionTest { private static final List> ARGS_CLASSES; protected static final int MAX_ARITY = Helper.MAX_ARITY - 1; + static { Class classes[] = { Object.class, @@ -52,11 +53,8 @@ double[].class, String.class, }; - List> list = new ArrayList<>(MAX_ARITY); - for (int i = 0; i < MAX_ARITY; ++i) { - list.add(classes[Helper.RNG.nextInt(classes.length)]); - } - ARGS_CLASSES = Collections.unmodifiableList(list); + ARGS_CLASSES = Collections.unmodifiableList( + Helper.randomClasses(classes, MAX_ARITY)); } private final TestCase testCase; @@ -66,7 +64,6 @@ private int dropped; private MethodHandle thrower; - public CatchExceptionTest(TestCase testCase, final boolean isVararg, final int argsCount, final int catchDrops) { this.testCase = testCase; @@ -107,37 +104,7 @@ } private List> getThrowerParams(boolean isVararg, int argsCount) { - boolean unmodifiable = true; - List> classes; - classes = ARGS_CLASSES.subList(0, - Math.min(argsCount, (MAX_ARITY / 2) - 1)); - int extra = 0; - if (argsCount >= MAX_ARITY / 2) { - classes = new ArrayList<>(classes); - unmodifiable = false; - extra = (int) classes.stream().filter(Helper::isDoubleCost).count(); - int i = classes.size(); - while (classes.size() + extra < argsCount) { - Class aClass = ARGS_CLASSES.get(i); - if (Helper.isDoubleCost(aClass)) { - ++extra; - if (classes.size() + extra >= argsCount) { - break; - } - } - classes.add(aClass); - } - } - if (isVararg && classes.size() > 0) { - if (unmodifiable) { - classes = new ArrayList<>(classes); - } - int last = classes.size() - 1; - Class aClass = classes.get(classes.size() - 1); - aClass = Array.newInstance(aClass, 2).getClass(); - classes.set(last, aClass); - } - return classes; + return Helper.getParams(ARGS_CLASSES, isVararg, argsCount); } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/lang/invoke/lambda/LUtils.java --- a/jdk/test/java/lang/invoke/lambda/LUtils.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/java/lang/invoke/lambda/LUtils.java Wed Jul 05 20:01:50 2017 +0200 @@ -37,8 +37,6 @@ * support infrastructure to invoke a java class from the command line */ class LUtils { - static final sun.tools.jar.Main jarTool = - new sun.tools.jar.Main(System.out, System.err, "jar-tool"); static final com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main(); static final File cwd = new File(".").getAbsoluteFile(); @@ -49,6 +47,10 @@ static final File JAVA_BIN_FILE = new File(JAVAHOME, "bin"); static final File JAVA_CMD = new File(JAVA_BIN_FILE, isWindows ? "java.exe" : "java"); + static final File JAR_BIN_FILE = + new File(new File(JAVAHOME).getParentFile(), "bin"); + static final File JAR_CMD = new File(JAR_BIN_FILE, + isWindows ? "jar.exe" : "jar"); protected LUtils() { } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java --- a/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -67,12 +67,17 @@ compile(javacArgs); File jarFile = new File("foo.jar"); String[] jargs = {"cvf", jarFile.getName(), doprivClass.getName()}; - jarTool.run(jargs); + TestResult tr = doExec(JAR_CMD.getAbsolutePath(), + "cvf", jarFile.getName(), + doprivClass.getName()); + if (tr.exitValue != 0){ + throw new RuntimeException(tr.toString()); + } doprivJava.delete(); doprivClass.delete(); - TestResult tr = doExec(JAVA_CMD.getAbsolutePath(), - "-Xbootclasspath/p:foo.jar", - "-cp", ".", "Bar"); + tr = doExec(JAVA_CMD.getAbsolutePath(), + "-Xbootclasspath/p:foo.jar", + "-cp", ".", "Bar"); tr.assertZero("testDoPrivileged fails"); barJava.delete(); barClass.delete(); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/math/BigDecimal/ZeroScalingTests.java --- a/jdk/test/java/math/BigDecimal/ZeroScalingTests.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/java/math/BigDecimal/ZeroScalingTests.java Wed Jul 05 20:01:50 2017 +0200 @@ -23,8 +23,10 @@ /* * @test - * @bug 4902952 4905407 4916149 - * @summary Tests that the scale of zero is propagated properly and has the proper effect. + * @bug 4902952 4905407 4916149 8057793 + * @summary Tests that the scale of zero is propagated properly and has the + * proper effect and that setting the scale to zero does not mutate the + * BigDecimal. * @author Joseph D. Darcy */ @@ -445,6 +447,16 @@ return failures; } + static int setScaleDoesNotMutateTest() { + BigDecimal total = new BigDecimal("258815507198903607775511093103396443816569106750031264155319238473795838680758514810110764742309284477206138527975952150289602995045050194333030191178778772026538699925775139201970526695485362661420908248887297829319881475178467494779683293036572059595504702727301324759997409522995072582369210284334718757260859794972695026582432867589093687280300148141501712013226636373167978223780290547640482160818746599330924736802844173226042389174403401903999447463440670236056324929325189403433689" + + ".426167432065785331444814035799717606745777287606858873045971898862329763544687891847664736523584843544347118836628373041412918374550458884706686730726101338872517021688769782894793734049819222924171842793485919753186993388451909096042127903835765393729547730953942175461146061715108701615615142134282261293656760570061554783195726716403304101469782303957325142638493327692352838806741611887655695029948975509680496573999174402058593454203190963443179532640446352828089016874853634851387762579319853267317320515941105912189838719919259277721994880193541634872882180184303434360412344059435559680494807415573269199203376126242271766939666939316648575065702750502798973418978204972336924254702551350654650573582614211506856383897692911422458286912085339575875324832979140870119455620532272318122103640233069115700020760625493816902806241630788230268031695140687964931377988962507263990468276009750998066442971308866347136022907166625330623130307555914930120150437900510530537258665172619821272937026713977709974434967165159545592482710663639966781678268622620229577009317698254134914742098420792313931843709810905414336383757407675429663714210967924767434203021205270369316797752411974617662200898086335322218191674846795163102021505555508444216708745911194321674887527227200297039471799580744303346354057273540730643842091810899490590914195225087593013834388801018488174855060306804024894292757613618190472234110859436472645203753139820658279559340251226992556744343475086923568365637919479462424794554522865559888240039662899509652221329892034706445253487898044421278283079233226845124525434586324657471286953226255430662125870993375281512713207125720748163498642795960457639954616530163959004770092547297392499137383176609646505351001304840762905826237024982330597805063521162285806541220110524989649256399233792799406995068469271941269511818994954109392839548141262324660472253632382325038836831429045617036015122388070240133760858500132713255407855625837956886349324981003917084922808187223285051144454915441134217743066575863563572152133978905444998209075763950909784148142018992367290485890072303179512881131769414783097454103103347826517701720263541869335631166977965013552647906729408522950996105479525445916501155305220090853891226367184989434453290788068397817927893708837722255115237672194162924260945492012622891770365546831236789867922136747819364833843397165107825773447549885351449899330007200651144003961228091210630807333236718793283427788965479074476288255387824982443633190938302785760754436525586544523339170400053128503337395428393881357669568532722167493096151221381017320147344991331421789379785964440840684363041795410525097564979585773948558651896834067324427900848255265001498890329859444233861478388742393060996236783742654761350763876989363052609107226398858310051497856931093693697981165801539060516895227818925342535261227134364063673285588256280386915163875872231395348293505967057794409379709079685798908660258077792158532257603211711587587586356431658240229896344639704"); + if (total.setScale(0, RoundingMode.DOWN).equals(total.setScale(0, RoundingMode.DOWN))) { + return 0; + } else { + return 1; + } + } + public static void main(String argv[]) { int failures = 0; @@ -455,6 +467,7 @@ failures += setScaleTests(); failures += toEngineeringStringTests(); failures += ulpTests(); + failures += setScaleDoesNotMutateTest(); if (failures > 0 ) { throw new RuntimeException("Incurred " + failures + " failures" + diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/math/BigInteger/BigIntegerTest.java --- a/jdk/test/java/math/BigInteger/BigIntegerTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/java/math/BigInteger/BigIntegerTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -71,6 +71,7 @@ static final int BITS_TOOM_COOK_SQUARE = 6912; static final int BITS_SCHOENHAGE_BASE = 640; static final int BITS_BURNIKEL_ZIEGLER = 2560; + static final int BITS_BURNIKEL_ZIEGLER_OFFSET = 1280; static final int ORDER_SMALL = 60; static final int ORDER_MEDIUM = 100; @@ -288,19 +289,19 @@ * where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if * {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then * {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}. The test - * ensures that {@code v} is just under the B-Z threshold and that {@code w} - * and {@code z} are both over the threshold. This implies that {@code u/v} - * uses the standard division algorithm and {@code w/z} uses the B-Z - * algorithm. The results of the two algorithms are then compared using the - * observation described in the foregoing and if they are not equal a - * failure is logged. + * ensures that {@code v} is just under the B-Z threshold, that {@code z} is + * over the threshold and {@code w} is much larger than {@code z}. This + * implies that {@code u/v} uses the standard division algorithm and + * {@code w/z} uses the B-Z algorithm. The results of the two algorithms + * are then compared using the observation described in the foregoing and + * if they are not equal a failure is logged. */ public static void divideLarge() { int failCount = 0; - BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER - 33); + BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 33); for (int i=0; i) () -> null, acc, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test2() { + AccessController.doPrivileged( + (PrivilegedAction) () -> null, acc, p1, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test3() { + AccessController.doPrivilegedWithCombiner( + (PrivilegedAction) () -> null, acc, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test4() { + AccessController.doPrivilegedWithCombiner( + (PrivilegedAction) () -> null, acc, p1, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test5() throws PrivilegedActionException { + AccessController.doPrivileged( + (PrivilegedExceptionAction) () -> null, + acc, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test6() throws PrivilegedActionException { + AccessController.doPrivileged( + (PrivilegedExceptionAction) () -> null, + acc, p1, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test7() throws PrivilegedActionException { + AccessController.doPrivilegedWithCombiner( + (PrivilegedExceptionAction) () -> null, + acc, null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void test8() throws PrivilegedActionException { + AccessController.doPrivilegedWithCombiner( + (PrivilegedExceptionAction) () -> null, + acc, p1, null); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/security/AccessController/LimitedDoPrivilegedWithThread.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/AccessController/LimitedDoPrivilegedWithThread.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013,2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8050281 + * @summary Test limited doprivileged action with trhead calls. + * @run main/othervm/policy=policy LimitedDoPrivilegedWithThread + */ +import java.io.FilePermission; +import java.security.AccessControlContext; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; +import java.util.PropertyPermission; + +public class LimitedDoPrivilegedWithThread { + + private static final Permission PROPERTYPERM + = new PropertyPermission("user.name", "read"); + private static final Permission FILEPERM + = new FilePermission("*", "read"); + private static final AccessControlContext ACC + = new AccessControlContext( + new ProtectionDomain[]{new ProtectionDomain(null, null)}); + + public static void main(String args[]) { + //parent thread without any permission + AccessController.doPrivileged( + (PrivilegedAction) () -> { + Thread ct = new Thread( + new ChildThread(PROPERTYPERM, FILEPERM)); + ct.start(); + try { + ct.join(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + ie.printStackTrace(); + throw new RuntimeException("Unexpected InterruptedException"); + } + return null; + }, ACC); + } +} + +class ChildThread implements Runnable { + + private final Permission P1; + private final Permission P2; + private boolean catchACE = false; + + public ChildThread(Permission p1, Permission p2) { + this.P1 = p1; + this.P2 = p2; + } + + @Override + public void run() { + //Verified that child thread has permission p1, + runTest(null, P1, false, 1); + //Verified that child thread inherits parent thread's access control context + AccessControlContext childAcc = AccessController.getContext(); + runTest(childAcc, P1, true, 2); + //Verified that we can give permision p2 to limit the "privilege" of the + //class calling doprivileged action, stack walk will continue + runTest(null, P2, true, 3); + + } + + public void runTest(AccessControlContext acc, Permission perm, + boolean expectACE, int id) { + + AccessController.doPrivileged( + (PrivilegedAction) () -> { + try { + AccessController.getContext().checkPermission(P1); + } catch (AccessControlException ace) { + catchACE = true; + } + if (catchACE ^ expectACE) { + throw new RuntimeException("test" + id + " failed"); + } + return null; + }, acc, perm); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/security/AccessController/policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/AccessController/policy Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,4 @@ +grant{ + permission java.util.PropertyPermission "user.name", "read"; + permission java.io.FilePermission "*", "read"; +}; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/sql/test/sql/TimestampTests.java --- a/jdk/test/java/sql/test/sql/TimestampTests.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/java/sql/test/sql/TimestampTests.java Wed Jul 05 20:01:50 2017 +0200 @@ -27,14 +27,40 @@ import java.sql.Timestamp; import java.time.Instant; import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.Calendar; +import java.util.TimeZone; import static org.testng.Assert.*; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import util.BaseTest; public class TimestampTests extends BaseTest { + private static TimeZone defaultTimeZone = null; + + /* + * Need to set and use a custom TimeZone which does not + * observe daylight savings time for this test. + */ + @BeforeClass + public static void setUpClass() throws Exception { + defaultTimeZone = TimeZone.getDefault(); + TimeZone tzone = TimeZone.getTimeZone("GMT+01"); + assertFalse(tzone.observesDaylightTime()); + TimeZone.setDefault(tzone); + } + + /* + * Conservatively reset the default time zone after test. + */ + @AfterClass + public static void tearDownClass() throws Exception { + TimeZone.setDefault(defaultTimeZone); + } + /* * Validate an IllegalArgumentException is thrown for an invalid Timestamp */ @@ -610,6 +636,12 @@ "Error with Nanos"); } + @Test(dataProvider = "validTimestampLongValues") + public void test52(long value, String ts) { + Timestamp ts1 = new Timestamp(value); + assertEquals(ts1.toString(), ts, "ts1.toString() != ts"); + } + /* * DataProvider used to provide Timestamps which are not valid and are used * to validate that an IllegalArgumentException will be thrown from the @@ -678,6 +710,40 @@ }; } + @DataProvider(name = "validTimestampLongValues") + private Object[][] validTimestampLongValues() { + return new Object[][]{ + {1L, "1970-01-01 01:00:00.001"}, + {-3600*1000L - 1, "1969-12-31 23:59:59.999"}, + {-(20000L*365*24*60*60*1000), "18018-08-28 01:00:00.0"}, + {Timestamp.valueOf("1961-08-30 11:22:33").getTime(), "1961-08-30 11:22:33.0"}, + {Timestamp.valueOf("1961-08-30 11:22:33.54321000").getTime(), "1961-08-30 11:22:33.543"}, // nanoprecision lost + {new Timestamp(114, 10, 10, 10, 10, 10, 100000000).getTime(), "2014-11-10 10:10:10.1"}, + {new Timestamp(0, 10, 10, 10, 10, 10, 100000).getTime(), "1900-11-10 10:10:10.0"}, // nanoprecision lost + {new Date(114, 10, 10).getTime(), "2014-11-10 00:00:00.0"}, + {new Date(0, 10, 10).getTime(), "1900-11-10 00:00:00.0"}, + {LocalDateTime.of(1960, 10, 10, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) + .toInstant().toEpochMilli(), "1960-10-10 19:10:10.0"}, + + // millisecond timestamps wraps around at year 1, so Long.MIN_VALUE looks similar + // Long.MAX_VALUE, while actually representing 292278994 BCE + {Long.MIN_VALUE, "292278994-08-17 08:12:55.192"}, + {Long.MAX_VALUE + 1, "292278994-08-17 08:12:55.192"}, + {Long.MAX_VALUE, "292278994-08-17 08:12:55.807"}, + {Long.MIN_VALUE - 1, "292278994-08-17 08:12:55.807"}, + + // wrap around point near 0001-01-01, test that we never get a negative year: + {-(1970L*365*24*60*60*1000), "0001-04-25 01:00:00.0"}, + {-(1970L*365*24*60*60*1000 + 115*24*60*60*1000L), "0001-12-31 01:00:00.0"}, + {-(1970L*365*24*60*60*1000 + 115*24*60*60*1000L - 23*60*60*1000L), "0001-01-01 00:00:00.0"}, + + {LocalDateTime.of(0, 1, 1, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) + .toInstant().toEpochMilli() - 2*24*60*60*1000L, "0001-01-01 19:03:08.0"}, // 1 BCE + {LocalDateTime.of(0, 1, 1, 10, 10, 10, 50000).atZone(ZoneId.of("America/Los_Angeles")) + .toInstant().toEpochMilli() - 3*24*60*60*1000L, "0002-12-31 19:03:08.0"} // 2 BCE + }; + } + /* * DataProvider used to provide Timestamp and Nanos values in order to * validate that the correct Nanos value is generated from the specified diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/java/util/zip/DataDescriptorSignatureMissing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/zip/DataDescriptorSignatureMissing.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,147 @@ +/* + * Copyright 2012 Google, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8056934 + * @summary Check ability to read zip files created by python zipfile + * implementation, which fails to write optional (but recommended) data + * descriptor signatures. Repro scenario is a Java -> Python -> Java round trip: + * - ZipOutputStream creates zip file with DEFLATED entries and data + * descriptors with optional signature "PK0x0708". + * - Python reads those entries, preserving the 0x08 flag byte + * - Python outputs those entries with data descriptors lacking the + * optional signature. + * - ZipInputStream cannot handle the missing signature + * + * No way to adapt the technique in this test to get a ZIP64 zip file + * without data descriptors was found. + * + * @ignore This test has brittle dependencies on an external working python. + */ + +import java.io.*; +import java.util.zip.*; + +public class DataDescriptorSignatureMissing { + void printStream(InputStream is) throws IOException { + Reader r = new InputStreamReader(is); + StringBuilder sb = new StringBuilder(); + char[] buf = new char[1024]; + int n; + while ((n = r.read(buf)) > 0) { + sb.append(buf, 0, n); + } + System.out.print(sb); + } + + int entryCount(File zipFile) throws IOException { + try (FileInputStream fis = new FileInputStream(zipFile); + ZipInputStream zis = new ZipInputStream(fis)) { + for (int count = 0;; count++) + if (zis.getNextEntry() == null) + return count; + } + } + + void test(String[] args) throws Throwable { + if (! new File("/usr/bin/python").canExecute()) + return; + + // Create a java zip file with DEFLATED entries and data + // descriptors with signatures. + final File in = new File("in.zip"); + final File out = new File("out.zip"); + final int count = 3; + try (FileOutputStream fos = new FileOutputStream(in); + ZipOutputStream zos = new ZipOutputStream(fos)) { + for (int i = 0; i < count; i++) { + ZipEntry ze = new ZipEntry("hello.python" + i); + ze.setMethod(ZipEntry.DEFLATED); + zos.putNextEntry(ze); + zos.write(new byte[10]); + zos.closeEntry(); + } + } + + // Copy the zip file using python's zipfile module + String[] python_program_lines = { + "import os", + "import zipfile", + "input_zip = zipfile.ZipFile('in.zip', mode='r')", + "output_zip = zipfile.ZipFile('out.zip', mode='w')", + "count08 = 0", + "for input_info in input_zip.infolist():", + " output_info = input_info", + " if output_info.flag_bits & 0x08 == 0x08:", + " count08 += 1", + " output_zip.writestr(output_info, input_zip.read(input_info))", + "output_zip.close()", + "if count08 == 0:", + " raise ValueError('Expected to see entries with 0x08 flag_bits set')", + }; + StringBuilder python_program_builder = new StringBuilder(); + for (String line : python_program_lines) + python_program_builder.append(line).append('\n'); + String python_program = python_program_builder.toString(); + String[] cmdline = { "/usr/bin/python", "-c", python_program }; + ProcessBuilder pb = new ProcessBuilder(cmdline); + pb.redirectErrorStream(true); + Process p = pb.start(); + printStream(p.getInputStream()); + p.waitFor(); + equal(p.exitValue(), 0); + + File pythonZipFile = new File("out.zip"); + check(pythonZipFile.exists()); + + equal(entryCount(in), + entryCount(out)); + + // We expect out to be identical to in, except for the removal of + // the optional data descriptor signatures. + final int SIG_LENGTH = 4; // length of a zip signature - PKxx + equal(in.length(), + out.length() + SIG_LENGTH * count); + + in.delete(); + out.delete(); + } + + //--------------------- Infrastructure --------------------------- + volatile int passed = 0, failed = 0; + void pass() {passed++;} + void fail() {failed++; Thread.dumpStack();} + void fail(String msg) {System.err.println(msg); fail();} + void unexpected(Throwable t) {failed++; t.printStackTrace();} + void check(boolean cond) {if (cond) pass(); else fail();} + void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + new DataDescriptorSignatureMissing().instanceMain(args);} + public void instanceMain(String[] args) throws Throwable { + try {test(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/management/monitor/AttributeArbitraryDataTypeTest.java --- a/jdk/test/javax/management/monitor/AttributeArbitraryDataTypeTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/javax/management/monitor/AttributeArbitraryDataTypeTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -58,9 +58,9 @@ public class AttributeArbitraryDataTypeTest implements NotificationListener { // Flag to notify that a message has been received - private boolean counterMessageReceived = false; - private boolean gaugeMessageReceived = false; - private boolean stringMessageReceived = false; + private volatile boolean counterMessageReceived = false; + private volatile boolean gaugeMessageReceived = false; + private volatile boolean stringMessageReceived = false; // Match enum public enum Match { do_not_match_0, @@ -195,21 +195,33 @@ " has reached or exceeded the threshold"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - counterMessageReceived = true; + + synchronized (this) { + counterMessageReceived = true; + notifyAll(); + } } else if (type.equals(MonitorNotification. THRESHOLD_HIGH_VALUE_EXCEEDED)) { echo("\t\t" + n.getObservedAttribute() + " has reached or exceeded the high threshold"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - gaugeMessageReceived = true; + + synchronized (this) { + gaugeMessageReceived = true; + notifyAll(); + } } else if (type.equals(MonitorNotification. STRING_TO_COMPARE_VALUE_MATCHED)) { echo("\t\t" + n.getObservedAttribute() + " matches the string-to-compare value"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - stringMessageReceived = true; + + synchronized (this) { + stringMessageReceived = true; + notifyAll(); + } } else { echo("\t\tSkipping notification of type: " + type); } @@ -358,6 +370,17 @@ // Check if notification was received // + synchronized (this) { + while (!counterMessageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } if (counterMessageReceived) { echo("\tOK: CounterMonitor notification received"); } else { @@ -525,6 +548,17 @@ // Check if notification was received // + synchronized (this) { + while (!gaugeMessageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } if (gaugeMessageReceived) { echo("\tOK: GaugeMonitor notification received"); } else { @@ -680,6 +714,17 @@ // Check if notification was received // + synchronized (this) { + while (!stringMessageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } if (stringMessageReceived) { echo("\tOK: StringMonitor notification received"); } else { diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/management/monitor/CounterMonitorTest.java --- a/jdk/test/javax/management/monitor/CounterMonitorTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/javax/management/monitor/CounterMonitorTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -43,9 +43,6 @@ // modulus number private Number modulus = new Integer(7); - // offset number - private int offset = 0; - // difference mode flag private boolean differenceModeFlag = true; @@ -58,9 +55,6 @@ // counter values private int[] values = new int[] {4, 6, 9, 11}; - // time to wait for notification (in seconds) - private int timeout = 5; - // flag to notify that a message has been received private volatile boolean messageReceived = false; @@ -92,8 +86,9 @@ echo("\t\t" + n.getObservedAttribute() + " has reached or exceeded the threshold"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); - messageReceived = true; + synchronized (this) { + messageReceived = true; notifyAll(); } } else { @@ -205,22 +200,17 @@ } /* - * Wait until timeout reached + * Wait messageReceived to be true */ - void doWait() { - for (int i = 0; i < timeout; i++) { - echo("\tdoWait: Waiting for " + timeout + " seconds. " + - "i = " + i + ", messageReceived = " + messageReceived); - if (messageReceived) { + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); break; } - try { - synchronized (this) { - wait(1000); - } - } catch (InterruptedException e) { - // OK: Ignore... - } } } diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java --- a/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/javax/management/monitor/GaugeMonitorDeadlockTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -36,8 +36,9 @@ */ import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; import java.util.concurrent.atomic.AtomicInteger; -import javax.management.Attribute; import javax.management.JMX; import javax.management.MBeanServer; import javax.management.Notification; @@ -47,10 +48,16 @@ import javax.management.monitor.GaugeMonitorMBean; public class GaugeMonitorDeadlockTest { + private static enum When {IN_GET_ATTRIBUTE, IN_NOTIFY}; + private static long checkingTime; public static void main(String[] args) throws Exception { if (args.length != 1) throw new Exception("Arg should be test number"); + double factor = Double.parseDouble(System.getProperty("test.timeout.factor", "1.0")); + checkingTime = (long)factor*1000; + System.out.println("=== checkingTime = " + checkingTime + "ms"); + int testNo = Integer.parseInt(args[0]) - 1; TestCase test = testCases[testNo]; System.out.println("Test: " + test.getDescription()); @@ -58,8 +65,6 @@ System.out.println("Test passed"); } - private static enum When {IN_GET_ATTRIBUTE, IN_NOTIFY}; - private static abstract class TestCase { TestCase(String description, When when) { this.description = description; @@ -98,16 +103,29 @@ monitorProxy.setNotifyLow(true); monitorProxy.start(); + System.out.println("=== Waiting observedProxy.getGetCount() to be " + + "changed, presumable deadlock if timeout?"); final int initGetCount = observedProxy.getGetCount(); - int getCount = initGetCount; - for (int i = 0; i < 2000; i++) { // 2000 * 10 = 20 seconds - getCount = observedProxy.getGetCount(); - if (getCount != initGetCount) - break; - Thread.sleep(10); + long checkedTime = System.currentTimeMillis(); + long nowTime; + ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); + while (observedProxy.getGetCount() == initGetCount) { + Thread.sleep(100); + + nowTime = System.currentTimeMillis(); + if (nowTime - checkedTime >= checkingTime) { + System.out.println("=== Checking deadlocked ..."); + if (threadMXBean.findDeadlockedThreads() != null) { + for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) { + System.out.println(info); + } + throw new Error("Found deadlocked threads: " + + threadMXBean.findDeadlockedThreads().length); + } + checkedTime = System.currentTimeMillis(); + } } - if (getCount <= initGetCount) - throw new Exception("Test failed: presumable deadlock"); + // This won't show up as a deadlock in CTRL-\ or in // ThreadMXBean.findDeadlockedThreads(), because they don't // see that thread A is waiting for thread B (B.join()), and @@ -117,13 +135,13 @@ // so if we want to test notify behaviour we can trigger by // exceeding the threshold. if (when == When.IN_NOTIFY) { + final Thread testedThread = new Thread(sensitiveThing); final AtomicInteger notifCount = new AtomicInteger(); final NotificationListener listener = new NotificationListener() { public void handleNotification(Notification n, Object h) { - Thread t = new Thread(sensitiveThing); - t.start(); + testedThread.start(); try { - t.join(); + testedThread.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } @@ -132,12 +150,36 @@ }; mbs.addNotificationListener(monitorName, listener, null, null); observedProxy.setThing(1000); - for (int i = 0; i < 2000 && notifCount.get() == 0; i++) - Thread.sleep(10); - if (notifCount.get() == 0) - throw new Exception("Test failed: presumable deadlock"); + System.out.println("=== Waiting notifications, presumable " + + "deadlock if timeout?"); + long startTime = System.currentTimeMillis(); + checkedTime = startTime; + while (notifCount.get() == 0) { + Thread.sleep(100); + + nowTime = System.currentTimeMillis(); + if (nowTime - checkedTime >= checkingTime) { + System.out.println("=== Checking the thread state ..."); + if (testedThread.isAlive()) { + System.out.println("=== Waiting testedThread to die " + + "after " + (nowTime - startTime) + "ms"); + + ThreadInfo tinfo = threadMXBean.getThreadInfo(testedThread.getId()); + if (Thread.State.BLOCKED.equals(tinfo.getThreadState())) { + for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) { + System.out.println(info); + } + } else { + System.out.println(tinfo); + } + } else { + System.out.println("=== The testedThread is dead as wished, " + + "the test must be passed soon."); + } + checkedTime = System.currentTimeMillis(); + } + } } - } abstract void doSensitiveThing(GaugeMonitorMBean monitorProxy, diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/management/monitor/NonComparableAttributeValueTest.java --- a/jdk/test/javax/management/monitor/NonComparableAttributeValueTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/javax/management/monitor/NonComparableAttributeValueTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -39,7 +39,7 @@ public class NonComparableAttributeValueTest implements NotificationListener { // Flag to notify that a message has been received - private boolean messageReceived = false; + private volatile boolean messageReceived = false; // MBean class public class ObservedObject implements ObservedObjectMBean { @@ -69,7 +69,11 @@ echo("\t\t" + n.getObservedAttribute() + " is null"); echo("\t\tDerived Gauge = " + n.getDerivedGauge()); echo("\t\tTrigger = " + n.getTrigger()); - messageReceived = true; + + synchronized (this) { + messageReceived = true; + notifyAll(); + } } else { echo("\t\tSkipping notification of type: " + type); } @@ -134,12 +138,9 @@ echo(">>> START the CounterMonitor"); counterMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: CounterMonitor notification received"); } else { @@ -212,12 +213,9 @@ echo(">>> START the GaugeMonitor"); gaugeMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: GaugeMonitor notification received"); } else { @@ -289,12 +287,9 @@ echo(">>> START the StringMonitor"); stringMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: StringMonitor notification received"); } else { @@ -334,6 +329,21 @@ } /* + * Wait messageReceived to be true + */ + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } + + /* * Standalone entry point. * * Run the test and report to stdout. diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/management/monitor/ReflectionExceptionTest.java --- a/jdk/test/javax/management/monitor/ReflectionExceptionTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/javax/management/monitor/ReflectionExceptionTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -87,7 +87,11 @@ echo("\tObservedAttribute: " + mn.getObservedAttribute()); echo("\tDerivedGauge: " + mn.getDerivedGauge()); echo("\tTrigger: " + mn.getTrigger()); - messageReceived = true; + + synchronized (this) { + messageReceived = true; + notifyAll(); + } } } } @@ -135,12 +139,9 @@ echo(">>> START the CounterMonitor"); counterMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: CounterMonitor got RUNTIME_ERROR notification!"); } else { @@ -203,12 +204,9 @@ echo(">>> START the GaugeMonitor"); gaugeMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: GaugeMonitor got RUNTIME_ERROR notification!"); } else { @@ -270,12 +268,9 @@ echo(">>> START the StringMonitor"); stringMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: StringMonitor got RUNTIME_ERROR notification!"); } else { @@ -349,8 +344,23 @@ } } + /* + * Wait messageReceived to be true + */ + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } + // Flag to notify that a message has been received - private boolean messageReceived = false; + private volatile boolean messageReceived = false; private MBeanServer server; private ObjectName obsObjName; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/management/monitor/RuntimeExceptionTest.java --- a/jdk/test/javax/management/monitor/RuntimeExceptionTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/javax/management/monitor/RuntimeExceptionTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -86,7 +86,11 @@ echo("\tObservedAttribute: " + mn.getObservedAttribute()); echo("\tDerivedGauge: " + mn.getDerivedGauge()); echo("\tTrigger: " + mn.getTrigger()); - messageReceived = true; + + synchronized (this) { + messageReceived = true; + notifyAll(); + } } } } @@ -134,12 +138,9 @@ echo(">>> START the CounterMonitor"); counterMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: CounterMonitor got RUNTIME_ERROR notification!"); } else { @@ -202,12 +203,9 @@ echo(">>> START the GaugeMonitor"); gaugeMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: GaugeMonitor got RUNTIME_ERROR notification!"); } else { @@ -269,12 +267,9 @@ echo(">>> START the StringMonitor"); stringMonitor.start(); - // Wait for granularity period (multiplied by 2 for sure) - // - Thread.sleep(granularityperiod * 2); - // Check if notification was received // + doWait(); if (messageReceived) { echo("\tOK: StringMonitor got RUNTIME_ERROR notification!"); } else { @@ -347,8 +342,23 @@ } } + /* + * Wait messageReceived to be true + */ + synchronized void doWait() { + while (!messageReceived) { + try { + wait(); + } catch (InterruptedException e) { + System.err.println("Got unexpected exception: " + e); + e.printStackTrace(); + break; + } + } + } + // Flag to notify that a message has been received - private boolean messageReceived = false; + private volatile boolean messageReceived = false; private MBeanServer server; private ObjectName obsObjName; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/Common.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/Common.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.*; +import java.awt.geom.Area; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.security.SecureRandom; + +public abstract class Common { + + ExtendedRobot robot; + Class windowClass; + JFrame background; + BufferedImage foreground; + Window window; + volatile boolean gradientBackgroundEnabled = false; + volatile int gradientWidth = 255; + volatile int gradientHeight = 255; + + float opacity = 1.0f; + float perPixelTranslucency = 1.0f; + static Color BG_COLOR = Color.BLUE; + static Color FG_COLOR = Color.RED; + static final int delay = 1000; + static final SecureRandom random = new SecureRandom(); + static final int dl = 100; + static final Class[] WINDOWS_TO_TEST = { JWindow.class, JFrame.class, JDialog.class }; + + volatile int clicked; + + public Common(Class windowClass, float opacity, float perPixelTranslucency, boolean gradient) throws Exception { + this.gradientBackgroundEnabled = gradient; + this.perPixelTranslucency = perPixelTranslucency; + this.opacity = opacity; + robot = new ExtendedRobot(); + this.windowClass = windowClass; + EventQueue.invokeAndWait(this::initBackgroundFrame); + EventQueue.invokeAndWait(this::initGUI); + } + + public Common(Class windowClass) throws Exception { + this(windowClass, 1.0f, 1.0f, false); + } + + public Common(Class windowClass, boolean gradient) throws Exception { + this(windowClass, 1.0f, 1.0f, gradient); + } + + public abstract void doTest() throws Exception; + + public void dispose() { + window.dispose(); + background.dispose(); + } + + public void applyShape() {}; + + public void applyDynamicShape() { + final Area a = new Area(); + Dimension size = window.getSize(); + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 3; y++) { + a.add(new Area(new Rectangle2D.Double( + x * size.getWidth() / 17*6, y * size.getHeight() / 17*6, + size.getWidth() / 17*5, size.getHeight() / 17*5))); + } + } + window.setShape(a); + } + + public BufferedImage getForegroundWindow() throws Exception { + final BufferedImage f[] = new BufferedImage[1]; + EventQueue.invokeAndWait( () -> { + f[0] = new BufferedImage(window.getWidth(), + window.getHeight(), BufferedImage.TYPE_INT_RGB); + window.printAll(f[0].createGraphics()); + }); + robot.waitForIdle(delay); + return f[0]; + } + + public static boolean checkTranslucencyMode(GraphicsDevice.WindowTranslucency mode) { + + if (!GraphicsEnvironment + .getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .isWindowTranslucencySupported(mode)){ + System.out.println(mode+" translucency mode isn't supported"); + return false; + } else { + return true; + } + + } + + public void applyAppDragNResizeSupport() { + MouseAdapter m = new MouseAdapter() { + + private Point dragOrigin = null; + private Dimension origSize = null; + private Point origLoc = null; + private boolean left = false; + private boolean top = false; + private boolean bottom = false; + private boolean right = false; + + public void mousePressed(MouseEvent e) { + dragOrigin = e.getLocationOnScreen(); + origSize = window.getSize(); + origLoc = window.getLocationOnScreen(); + right = (origLoc.x + window.getWidth() - dragOrigin.x) < 5; + left = !right && dragOrigin.x - origLoc.x < 5; + bottom = (origLoc.y + window.getHeight() - dragOrigin.y) < 5; + top = !bottom && dragOrigin.y - origLoc.y < 5; + } + + public void mouseReleased(MouseEvent e) { resize(e); } + public void mouseDragged(MouseEvent e) { resize(e); } + + void resize(MouseEvent e) { + Point dragDelta = e.getLocationOnScreen(); + dragDelta.translate(-dragOrigin.x, -dragOrigin.y); + Point newLoc = new Point(origLoc); + newLoc.translate(dragDelta.x, dragDelta.y); + Dimension newSize = new Dimension(origSize); + if (left || right) { + newSize.width += right ? dragDelta.x : -dragDelta.x; + } + if (top || bottom) { + newSize.height += bottom ? dragDelta.y : -dragDelta.y; + } + if (right || (top || bottom) && !left) { + newLoc.x = origLoc.x; + } + if (bottom || (left || right) && !top) { + newLoc.y = origLoc.y; + } + window.setBounds(newLoc.x, newLoc.y, newSize.width, newSize.height); + } + }; + for (Component comp : window.getComponents()) { + comp.addMouseListener(m); + comp.addMouseMotionListener(m); + } + + window.addMouseListener(m); + window.addMouseMotionListener(m); + } + + public void checkTranslucentShape() throws Exception { + foreground = getForegroundWindow(); + Point[] points = new Point[4]; + + Dimension size = window.getSize(); + Point location = window.getLocationOnScreen(); + + points[0] = new Point(20, 20); + points[1] = new Point(20, size.height-20); + points[2] = new Point(size.width-20, 20); + points[3] = new Point(size.width-20, size.height-20); + + for (Point p : points){ + p.translate(location.x, location.y); + Color actual = robot.getPixelColor(p.x, p.y); + if (actual.equals(BG_COLOR)|| actual.equals(FG_COLOR)) + throw new RuntimeException("Error in point "+p+": "+actual+" equals to foreground or background color"); + else + System.out.println("OK with foreground point "+p); + } + } + + public void checkDynamicShape() throws Exception { + Point[] points = new Point[4]; + + Dimension size = window.getSize(); + + int blockSizeX = (int) (size.getWidth() / 17); + int blockSizeY = (int) (size.getHeight() / 17); + + // background + points[0] = new Point((int) (blockSizeX * 5.5), (int) (blockSizeY * 5.5)); + points[1] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5)); + points[2] = new Point((int) (blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5)); + points[3] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (blockSizeY * 5.5)); + checkShape(points, true); + + // foreground + if (opacity < 1.0f){ + checkTranslucentShape(); + } else { + points[0] = new Point(3 * blockSizeX, 3 * blockSizeY); + points[1] = new Point(14 * blockSizeX, 14 * blockSizeY); + points[2] = new Point(3 * blockSizeX, 14 * blockSizeY); + points[3] = new Point(14 * blockSizeX, 3 * blockSizeY); + checkShape(points, false); + } + } + + public void checkShape(Point[] points, boolean areBackgroundPoints) throws Exception { + + Point location = window.getLocationOnScreen(); + + for (Point p : points) { + p.translate(location.x, location.y); + Color pixel = robot.getPixelColor(p.x, p.y); + if (areBackgroundPoints) { + if (pixel.getRed() != 0 + || pixel.getGreen() != 0 ) + throw new RuntimeException("Background point " + p + + " color " + pixel + + " does not equal to background color " + BG_COLOR); + else + System.out.println("OK with background point " + p); + } else { + if (pixel.equals(BG_COLOR)) + throw new RuntimeException("Foreground point " + p + + " color " + pixel + + " equals to background color " + BG_COLOR); + else + System.out.println("OK with foreground point " + p); + } + } + } + + public void initBackgroundFrame() { + background = new JFrame(); + background.setUndecorated(true); + background.getContentPane().setBackground(BG_COLOR); + background.setSize(500, 500); + background.setLocation(dl, dl); + background.setVisible(true); + } + + public void initGUI() { + Container contentPane; + if (windowClass.equals(Frame.class)) { + window = new JFrame(); + ((JFrame) window).setUndecorated(true); + contentPane = ((JFrame) window).getContentPane(); + } else if (windowClass.equals(Dialog.class)) { + window = new JDialog(background); + ((JDialog) window).setUndecorated(true); + contentPane = ((JDialog) window).getContentPane(); + } else { + window = new JWindow(background); + contentPane = ((JWindow) window).getContentPane(); + } + + if (perPixelTranslucency < 1.0f) { + contentPane.setBackground(colorWithOpacity(FG_COLOR, perPixelTranslucency)); + window.setBackground(colorWithOpacity(FG_COLOR, perPixelTranslucency)); + } else { + contentPane.setBackground(FG_COLOR); + window.setBackground(FG_COLOR); + } + + window.setLocation(2 * dl, 2 * dl); + window.setSize(255, 255); + window.setPreferredSize(new Dimension(255, 255)); + createSwingComponents(); + if (opacity < 1.0f) + window.setOpacity(opacity); + + window.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + applyShape(); + } + }); + applyShape(); + window.setVisible(true); + applyAppDragNResizeSupport(); + window.toFront(); + } + + public void createSwingComponents() { + Container contentPane; + if (gradientBackgroundEnabled) { + JPanel jPanel = new JPanel() { + @Override + protected void paintComponent(Graphics g) { + if (g instanceof Graphics2D) { + Color background = Color.RED; + Paint p = new GradientPaint(0.0f, 0.0f, colorWithOpacity(background, 0), + 0.0f, gradientHeight - 3, colorWithOpacity(background, 1), true); + Graphics2D g2d = (Graphics2D) g; + g2d.setPaint(p); + g2d.fillRect(0, 3, gradientWidth, gradientHeight - 3); + } else { + super.paintComponent(g); + } + } + }; + jPanel.setBorder(new EmptyBorder(15, 5, 5, 5)); + jPanel.setOpaque(false); + + contentPane = jPanel; + + RootPaneContainer.class.cast(window).setContentPane(contentPane); + } else { + contentPane = RootPaneContainer.class.cast(window).getContentPane(); + } + contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); + + JButton button = new JButton("JButton"); + window.add(button); + + JTextArea textArea = new JTextArea("JTextArea"); + window.add(textArea); + + JCheckBox checkbox = new JCheckBox("JCheckBox"); + checkbox.setOpaque(false); + window.add(checkbox); + + JComboBox comboBox = new JComboBox(new String[]{"JComboBox", "Some item"}); + window.add(comboBox); + + JLabel label = new JLabel("JLabel"); + window.add(label); + + JTextField textField = new JTextField("JTextField"); + window.add(textField); + + JPanel panel = new JPanel(); + panel.setOpaque(false); + window.add(panel); + + JComboBox comboBox2 = new JComboBox(new String[]{"JComboBox2", "Another item"}); + window.add(comboBox2); + + JRadioButton radioButton = new JRadioButton("JRadioButton"); + radioButton.setOpaque(false); + window.add(radioButton); + } + + Color colorWithOpacity(Color color, float opacity) { + return new Color(color.getColorSpace(), color.getColorComponents(null), opacity); + } + + public void checkTranslucent() throws Exception { + checkTranslucentShape(); + + // Drag + Point location = window.getLocationOnScreen(); + robot.dragAndDrop(location.x + 30, location.y + 5, location.x + dl + random.nextInt(dl), location.y + random.nextInt(dl)); + robot.waitForIdle(delay); + checkTranslucentShape(); + + // Resize + location = window.getLocationOnScreen(); + robot.dragAndDrop(location.x + 4, location.y + 4, location.x + random.nextInt(2*dl)-dl, location.y + random.nextInt(2*dl)-dl); + robot.waitForIdle(delay); + checkTranslucentShape(); + + EventQueue.invokeAndWait(this::dispose); + } + + public void checkDynamic() throws Exception { + checkDynamicShape(); + + // Drag + Point location = window.getLocationOnScreen(); + robot.dragAndDrop(location.x + 30, location.y + 5, location.x + dl + random.nextInt(dl), location.y + random.nextInt(dl)); + robot.waitForIdle(delay); + checkDynamicShape(); + + // Resize + location = window.getLocationOnScreen(); + robot.dragAndDrop(location.x + 4, location.y + 4, location.x + random.nextInt(2*dl)-dl, location.y + random.nextInt(2*dl)-dl); + robot.waitForIdle(delay); + checkDynamicShape(); + + EventQueue.invokeAndWait(this::dispose); + } + + void checkClick(int x, int y, int flag) throws Exception { + + System.out.println("Trying to click point " + x + ", " + y + ", looking for " + flag + " flag to trigger."); + + clicked = 0; + robot.mouseMove(x, y); + robot.click(); + + for (int i = 0; i < 100; i++) + if ((clicked & (1 << flag)) == 0) + robot.delay(50); + else + break; + + if ((clicked & (1 << flag)) == 0) + throw new RuntimeException("FAIL: Flag " + flag + " is not triggered for point " + x + ", " + y + "!"); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucent.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @summary Check if a per-pixel translucent window is dragged and resized + * by mouse correctly. + * Test Description: Check if PERPIXEL_TRANSLUCENT translucency type is supported + * on the current platform. Proceed if they are supported. Create a window + * with some components in it, make window undecorated, apply translucent + * background of 0.5. Drag and resize the window using AWT Robot and verify + * that translucency is correctly applied with pixels checking. Make the + * window appear on top of a known background. Repeat this for JWindow, + * JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT translucency type is supported, the + * window should appear with the translucency. Only window background + * should be translucent, all the controls should be opaque. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main PerPixelTranslucent + */ + +public class PerPixelTranslucent extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new PerPixelTranslucent(windowClass).doTest(); + } + + public PerPixelTranslucent(Class windowClass) throws Exception { + super(windowClass, 1.0f, 0.5f, false); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkTranslucent(); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentCanvas.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentCanvas.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; +import javax.swing.*; +import java.awt.image.BufferedImage; + +/* + * @test + * @summary Check if a per-pixel translucent window shows up with correct translucency + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main PerPixelTranslucentCanvas + */ + +public class PerPixelTranslucentCanvas extends Common { + + JPanel center; + Color OVAL_COLOR = Color.BLUE; + + public static void main(String[] ignored) throws Exception { + FG_COLOR = new Color(200, 0, 0, 100); + BG_COLOR = Color.GREEN; + for (Class windowClass: WINDOWS_TO_TEST) + new PerPixelTranslucentCanvas(windowClass).doTest(); + } + + public PerPixelTranslucentCanvas(Class windowClass) throws Exception { + super(windowClass); + } + + @Override + public void createSwingComponents() { + Container contentPane = RootPaneContainer.class.cast(window).getContentPane(); + BorderLayout bl = new BorderLayout(10, 10); + contentPane.setLayout(bl); + + JLabel label = new JLabel("North", new ImageIcon( + new BufferedImage(30, 30, BufferedImage.TYPE_INT_RGB)), SwingConstants.CENTER); + contentPane.add(label, BorderLayout.NORTH); + + JButton button = new JButton("West"); + contentPane.add(button, BorderLayout.WEST); + + center = new JPanel() { + @Override + public void paint(Graphics g) { + g.setColor(OVAL_COLOR); + g.fillOval(0, 0, getWidth(), getHeight()); + } + }; + contentPane.add(center, BorderLayout.CENTER); + + JTextField jTextField = new JTextField("South"); + contentPane.add(jTextField, BorderLayout.SOUTH); + } + + @Override + public void doTest() throws Exception { + robot.waitForIdle(delay); + + Rectangle bounds = center.getBounds(); + Point loc = center.getLocationOnScreen(); + + final int x = loc.x + bounds.width / 2; + final int y = loc.y + bounds.height / 2; + + Color color = robot.getPixelColor(x, y); + if (OVAL_COLOR.getRGB() != color.getRGB()) + throw new RuntimeException("bounds = " + bounds + "\n" + + "loc = " + loc + "\n" + + "background loc = " + background.getX() + ", " + background.getY() + "\n" + + "so middle point over background is " + (x - background.getX()) + ", " + (y - background.getY()) + "\n" + + "Oval is not opaque in the middle point (" + x + ", " + y + ", " + color + ")"); + + color = robot.getPixelColor(loc.x - 5, loc.y - 5); + if (FG_COLOR.getRGB() == color.getRGB()) + throw new RuntimeException("Background is not translucent (" + color + ")"); + + EventQueue.invokeAndWait(this::dispose); + robot.waitForIdle(); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentGradient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentGradient.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @bug 8032644 + * @summary Check if a per-pixel translucent window is dragged and resized by + * mouse correctly + * Test Description: Check if PERPIXEL_TRANSLUCENT translucency type is supported + * on the current platform. Proceed if they are supported. Create a window + * with some components in it, make window undecorated, apply translucent + * background of 0 and have a gradient painted as background from + * fully-transparent to fully-opaque in componentResized listener. Drag and + * resize the window using AWT Robot and verify that translucency is + * correctly applied with pixels checking. Make the window appear on top of + * a known background. Repeat this for JWindow, JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT translucency type is supported, + * the window should appear as specified with the translucency. Only window + * background should be translucent, all the controls should be opaque. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main PerPixelTranslucentGradient + */ + +public class PerPixelTranslucentGradient extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new PerPixelTranslucentGradient(windowClass).doTest(); + } + + public PerPixelTranslucentGradient(Class windowClass) throws Exception { + super(windowClass, 1.0f, 0f, true); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkTranslucent(); + } + + @Override + public void applyShape() { + gradientWidth = window.getWidth(); + gradientHeight = window.getHeight(); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentSwing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/PerPixelTranslucentSwing.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import java.awt.*; + +/* + * @test + * @summary Check if a per-pixel translucent window shows only the area having + * opaque pixels + * Test Description: Check if PERPIXEL_TRANSLUCENT Translucency type is supported + * on the current platform. Proceed if it is supported. Create a swing window + * with some swing components in it and a transparent background (alpha 0.0). + * Bring this window on top of a known background. Do this test for JFrame, + * JWindow and JDialog + * Expected Result: Only the components present in the window must be shown. Other + * areas of the window must be transparent so that the background shows + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main PerPixelTranslucentSwing + */ + +public class PerPixelTranslucentSwing extends Common { + + JButton north; + + public static void main(String[] ignored) throws Exception { + FG_COLOR = new Color(200, 0, 0, 0); + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new PerPixelTranslucentSwing(windowClass).doTest(); + } + + public PerPixelTranslucentSwing(Class windowClass) throws Exception { + super(windowClass); + } + + @Override + public void createSwingComponents() { + Container contentPane = RootPaneContainer.class.cast(window).getContentPane(); + BorderLayout bl = new BorderLayout(10, 5); + contentPane.setLayout(bl); + + north = new JButton("North"); + contentPane.add(north, BorderLayout.NORTH); + + JList center = new JList(new String[] {"Center"}); + contentPane.add(center, BorderLayout.CENTER); + + JTextField south = new JTextField("South"); + contentPane.add(south, BorderLayout.SOUTH); + + window.pack(); + window.setVisible(true); + + north.requestFocus(); + } + + @Override + public void doTest() throws Exception { + robot.waitForIdle(delay); + + // Check for background translucency + Rectangle bounds = north.getBounds(); + Point loc = north.getLocationOnScreen(); + + Color color = robot.getPixelColor(loc.x + bounds.width / 2, loc.y + bounds.height + 3); + System.out.println(color); + if (FG_COLOR.getRGB() == color.getRGB()) + throw new RuntimeException("Background is not translucent (" + color + ")"); + + EventQueue.invokeAndWait(this::dispose); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/SetShapeAndClickSwing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/SetShapeAndClickSwing.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; + +/* + * @test + * @summary Check if a window set with shape clips the contents + * Test Description: Check if PERPIXEL_TRANSPARENT translucency type is supported + * by the current platform. Proceed if it is supported. Apply different types + * of shapes on a Window which contains some awt components. Shape should be + * applied in such a way that some components are partially clipped off. Check + * if the components appear only partially and events work correctly for those + * components - i.e. events occur only on the areas which appear and do not + * occur on the clipped off areas. Events should be checked by clicking on the + * visible and clipped regions. Repeat this for Window, Dialog and Frame. + * Expected Result: If PERPIXEL_TRANSPARENT translucency type is supported, clicking + * on clipped region should deliver the event to the background (it should be + * another Window behind the test window) + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main SetShapeAndClickSwing + */ + +public class SetShapeAndClickSwing extends Common { + + Component south, center, north; + + public static void main(String[] args) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new SetShapeAndClickSwing(windowClass).doTest(); + } + + public SetShapeAndClickSwing(Class windowClass) throws Exception { + super(windowClass); + } + + @Override + public void initBackgroundFrame() { + super.initBackgroundFrame(); + background.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + clicked |= 1 << 0; + } + }); + } + + @Override + public void createSwingComponents() { + window.setSize(200,200); + window.setLayout(new BorderLayout()); + + south = new JLabel("South"); + south.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + clicked |= 1 << 3; + } + }); + window.add(south, BorderLayout.SOUTH); + + center = new JList(); + center.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + clicked |= 1 << 2; + } + }); + window.add(center, BorderLayout.CENTER); + + north = new JTextField("North"); + north.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + clicked |= 1 << 1; + } + }); + window.add(north, BorderLayout.NORTH); + } + + @Override + public void doTest() throws Exception { + + robot.waitForIdle(); + + Point wls = window.getLocationOnScreen(); + Point ls; + int y; + ls = north.getLocationOnScreen(); + checkClick(ls.x + north.getWidth() / 3, ls.y + north.getHeight() / 2, 1); + + ls = center.getLocationOnScreen(); + checkClick(ls.x + center.getWidth() * 3 / 4, ls.y + center.getHeight() * 3 / 4, 2); + + ls = south.getLocationOnScreen(); + checkClick(ls.x + south.getWidth() * 2 / 3, ls.y + south.getHeight() / 2, 3); + + ls = center.getLocationOnScreen(); + checkClick(ls.x + center.getWidth() / 4, ls.y + center.getHeight() / 4, 2); + + ls = north.getLocationOnScreen(); + y = ls.y + north.getHeight() / 2; + checkClick(wls.x + 200 - (y - wls.y), y, 0); + + EventQueue.invokeAndWait(window::toFront); + robot.waitForIdle(); + + ls = center.getLocationOnScreen(); + y = ls.y + center.getHeight() / 2; + checkClick(wls.x + 200 - (y - wls.y), y, 0); + + EventQueue.invokeAndWait(window::toFront); + robot.waitForIdle(); + + ls = south.getLocationOnScreen(); + y = ls.y + south.getHeight() / 2; + checkClick(wls.x + 200 - (y - wls.y), y, 0); + + EventQueue.invokeAndWait(window::dispose); + EventQueue.invokeAndWait(background::dispose); + + robot.waitForIdle(); + } + + @Override + public void applyShape() { + Area shape = new Area(new Rectangle2D.Float(0, 0, 200, 200)); + GeneralPath gp; + gp = new GeneralPath(); + gp.moveTo(190, 0); + gp.lineTo(200, 0); + gp.lineTo(200, 10); + gp.lineTo(10, 200); + gp.lineTo(0, 200); + gp.lineTo(0, 190); + gp.closePath(); + shape.subtract(new Area(gp)); + + window.setShape(shape); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedPerPixelTranslucentGradient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedPerPixelTranslucentGradient.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @bug 7043845 + * @summary Check if shaped and per-pixel translucent window is dragged and + * resized by mouse correctly. + * Test Description: Check if PERPIXEL_TRANSLUCENT and PERPIXEL_TRANSPARENT + * translucency types are supported on the current platform. Proceed if + * they are supported. Create a window with some components in it, make + * window undecorated, apply shape in componentResized listener. The shape + * should match the window size; apply translucent background of 0 and have + * a gradient painted as background from fully-transparent to fully-opaque + * in componentResized listener. Drag and resize the window using AWT Robot + * and verify that shape and translucency are correctly applied with pixels + * checking. Make the window appear on top of a known background. Repeat + * this for JWindow, JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT and PERPIXEL_TRANSPARENT translucency + * types are supported, the window should appear as specified with the + * expected shape and translucency. Window background should have + * translucent gradient in parts that are not clipped by shape, all the + * controls should be opaque. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main ShapedPerPixelTranslucentGradient + */ + +public class ShapedPerPixelTranslucentGradient extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT) + && checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new ShapedPerPixelTranslucentGradient(windowClass).doTest(); + } + + public ShapedPerPixelTranslucentGradient(Class windowClass) throws Exception { + super(windowClass, 1.0f, 0f, true); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkDynamic(); + } + + @Override + public void applyShape() { + applyDynamicShape(); + gradientWidth = window.getWidth(); + gradientHeight = window.getHeight(); + } + +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedTranslucentPerPixelTranslucentGradient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedTranslucentPerPixelTranslucentGradient.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @summary Check if shaped, translucent and per-pixel translucent window is + * dragged and resized by mouse correctly. + * Test Description: Check if PERPIXEL_TRANSLUCENT, TRANSLUCENT and + * PERPIXEL_TRANSPARENT translucency types are supported on the current + * platform. Proceed if they are supported. Create a window with some + * components in it, make window undecorated, apply shape in componentResized + * listener. The shape should match the window size; apply opacity of 0.7, + * apply translucent background of 0 and have a gradient painted as + * background from fully-transparent to fully-opaque in componentResized + * listener. Drag and resize the window using AWT Robot and verify that + * shape and translucency are correctly applied with pixels checking. Make + * the window appear on top of a known background. Repeat this for JWindow, + * JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT, TRANSLUCENT and PERPIXEL_TRANSPARENT + * translucency types are supported, the window should appear as specified + * with the expected shape and translucency. Window background should have + * translucent gradient in parts that are not clipped by shape, all the + * controls should be equally translucent. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main ShapedTranslucentPerPixelTranslucentGradient + */ + +public class ShapedTranslucentPerPixelTranslucentGradient extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT) + && checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT) + && checkTranslucencyMode(GraphicsDevice.WindowTranslucency.TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new ShapedTranslucentPerPixelTranslucentGradient(windowClass).doTest(); + } + + public ShapedTranslucentPerPixelTranslucentGradient(Class windowClass) throws Exception { + super(windowClass, 0.7f, 0f, true); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkDynamic(); + } + + @Override + public void applyShape() { + applyDynamicShape(); + gradientWidth = window.getWidth(); + gradientHeight = window.getHeight(); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentJComboBox.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentJComboBox.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 8024627 + * @summary Check if a JComboBox present in a window set with opacity less than + * 1.0 shows a translucent drop down + * Test Description: Check if TRANSLUCENT translucency type is supported on the + * current platform. Proceed if supported. Show a window which contains an + * JComboBox and set with opacity less than 1.0. Another Window having a canvas + * component drawn with an image can be used as the background for the test + * window. Click on the ComboBox to show the drop down. Check if the drop down + * appears translucent. Repeat this for JWindow, JDialog and JFrame + * Expected Result: If TRANSLUCENT Translucency type is supported, the drop down + * should appear translucent. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main TranslucentJComboBox + */ + +public class TranslucentJComboBox extends Common { + + JComponent south; + JComponent center; + JPanel north; + volatile boolean southClicked = false; + + public static void main(String[] args) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new TranslucentJComboBox(windowClass).doTest(); + } + + public TranslucentJComboBox(Class windowClass) throws Exception { + super(windowClass, 0.3f, 1.0f, false); + } + + @Override + public void initBackgroundFrame() { + super.initBackgroundFrame(); + } + + @Override + public void createSwingComponents() { + Container contentPane = RootPaneContainer.class.cast(window).getContentPane(); + window.setLayout(new BorderLayout()); + + north = new JPanel(); + contentPane.add(north, BorderLayout.NORTH); + + center = new JList(new String [] { "Center" }); + contentPane.add(center, BorderLayout.CENTER); + + JComboBox jComboBox = new JComboBox(); + for(int i = 0; i < 20; i++) { + jComboBox.addItem("item " + i); + } + south = jComboBox; + + south.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + southClicked = true; + } + }); + contentPane.add(south, BorderLayout.SOUTH); + } + + + @Override + public void doTest() throws Exception { + robot.waitForIdle(delay); + // Make window an active + Point ls = north.getLocationOnScreen(); + robot.mouseMove(ls.x + north.getWidth()/2, ls.y + north.getHeight()/2); + robot.click(); + + // Invoke list + ls = south.getLocationOnScreen(); + + Point p1 = new Point( + (int) (ls.x + south.getWidth() * 0.75), + ls.y + south.getHeight() * 3); + + Point p2 = new Point( + (int) (ls.x + south.getWidth() * 0.75), + ls.y - south.getHeight() * 2); + + Color c1 = robot.getPixelColor(p1.x, p1.y); + Color c2 = robot.getPixelColor(p2.x, p2.y); + + int x = ls.x + south.getWidth()/2; + int y = ls.y + south.getHeight()/2; + + System.out.println("Trying to click point "+x+", "+y+ + ", looking for flag to trigger."); + + robot.mouseMove(x, y); + robot.waitForIdle(delay); + robot.click(); + robot.waitForIdle(delay); + + if (!southClicked) + throw new RuntimeException("Flag is not triggered for point "+x+", "+y+"!"); + + robot.waitForIdle(); + + Color c1b = robot.getPixelColor(p1.x, p1.y); + Color c2b = robot.getPixelColor(p2.x, p2.y); + + if (!c1.equals(c1b) && !south.getBackground().equals(c1b)) + throw new RuntimeException( + "Check for opaque drop down failed at point " + p1 + + ". Before click: " + c1 + ", after click: " + c1b + + ", expected is " + south.getBackground()); + + if (!c2.equals(c2b) && !south.getBackground().equals(c2b)) + throw new RuntimeException( + "Check for opaque drop down failed at point " + p2 + + ". Before click: " + c2 + ", after click: " + c2b + + ", expected is " + south.getBackground()); + + EventQueue.invokeAndWait(this::dispose); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentPerPixelTranslucentGradient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentPerPixelTranslucentGradient.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +/* + * @test + * @summary Check if a per-pixel translucent and translucent window is dragged + * and resized by mouse correctly + * Test Description: Check if PERPIXEL_TRANSLUCENT and TRANSLUCENT translucency + * types are supported on the current platform. Proceed if they are supported. + * Create a window with some components in it, make window undecorated, apply + * opacity of 0.7, apply translucent background of 0 and have a gradient + * painted as background from fully-transparent to fully-opaque in + * componentResized listener. Drag and resize the window using AWT Robot and + * verify that translucency is correctly applied with pixels checking. Make + * the window appear on top of a known background. Repeat this for specified + * JWindow, JDialog, JFrame. + * Expected Result: If PERPIXEL_TRANSLUCENT and TRANSLUCENT translucency types + * are supported, the window should appear as specified with the translucency. + * Both window background and all the controls should be translucent but + * background should have a gradient in translucency while controls - not. + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main TranslucentPerPixelTranslucentGradient + */ + +public class TranslucentPerPixelTranslucentGradient extends Common { + + public static void main(String[] ignored) throws Exception { + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT) + && checkTranslucencyMode(GraphicsDevice.WindowTranslucency.TRANSLUCENT)) + for (Class windowClass: WINDOWS_TO_TEST) + new TranslucentPerPixelTranslucentGradient(windowClass).doTest(); + } + + public TranslucentPerPixelTranslucentGradient(Class windowClass) throws Exception { + super(windowClass, 0.7f, 0f, true); + } + + public void doTest() throws Exception { + robot.waitForIdle(delay); + checkTranslucent(); + } + + @Override + public void applyShape() { + gradientWidth = window.getWidth(); + gradientHeight = window.getHeight(); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentWindowClickSwing.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentWindowClickSwing.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @summary Check if swing components present in a window set with opacity less + * than 1.0 appears translucent + * Test Description: Check if TRANSLUCENT Translucency type is supported for the + * current platform. Proceed if supported. Show a window containing some swing + * components and set it with opacity less than 1.0. Check if the swing components + * appear translucent and check if events trigger correctly for the components + * Expected Result: If TRANSLUCENT Translucency type is supported, the components + * should appear translucent showing the background. They should trigger events + * correctly + * @author mrkam + * @library ../../../../lib/testlibrary + * @build Common ExtendedRobot + * @run main TranslucentWindowClickSwing + */ + +public class TranslucentWindowClickSwing extends Common { + + private Component south; + private Component center; + private Component north; + + public static void main(String[] args) throws Exception{ + if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.TRANSLUCENT)) + new TranslucentWindowClickSwing(JWindow.class).doTest(); + } + + public TranslucentWindowClickSwing(Class windowClass) throws Exception { + super(windowClass, 0.2f, 1.0f, false); + } + + @Override + public void createSwingComponents() { + south = new JButton("South"); + south.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { clicked |= 1 << 2; } + }); + window.add(south, BorderLayout.SOUTH); + + center = new JList(); + center.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { clicked |= 1 << 1; } + }); + window.add(center, BorderLayout.CENTER); + + north = new JTextField("North"); + north.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { clicked |= 1 << 0; } + }); + window.add(north, BorderLayout.NORTH); + } + + @Override + public void doTest() throws Exception { + Point ls; + robot.waitForIdle(); + + ls = north.getLocationOnScreen(); + checkClick(ls.x + north.getWidth() / 3, ls.y + north.getHeight() / 2, 0); + + ls = center.getLocationOnScreen(); + checkClick(ls.x + center.getWidth() / 4, ls.y + center.getHeight() / 4, 1); + + ls = center.getLocationOnScreen(); + checkClick(ls.x + center.getWidth() * 3 / 4, ls.y + center.getHeight() * 3 / 4, 1); + + ls = south.getLocationOnScreen(); + checkClick(ls.x + south.getWidth() * 2 / 3, ls.y + south.getHeight() / 2, 2); + + EventQueue.invokeAndWait(this::dispose); + robot.waitForIdle(); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java --- a/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java Wed Jul 05 20:01:50 2017 +0200 @@ -52,7 +52,7 @@ public static final long TEST_LIMIT; static { String str = System.getProperty("testLimit"); - TEST_LIMIT = str != null ? Long.parseUnsignedLong(str) : 2_000L; + TEST_LIMIT = str != null ? Long.parseUnsignedLong(str) : 2000L; System.out.printf("-DtestLimit=%d%n", TEST_LIMIT); } @@ -116,6 +116,48 @@ return size <= lag ? null : calledLog.get(size - lag - 1); } + public static List> randomClasses(Class[] classes, int size) { + List> result = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + result.add(classes[RNG.nextInt(classes.length)]); + } + return result; + } + + public static List> getParams(List> classes, + boolean isVararg, int argsCount) { + boolean unmodifiable = true; + List> result = classes.subList(0, + Math.min(argsCount, (MAX_ARITY / 2) - 1)); + int extra = 0; + if (argsCount >= MAX_ARITY / 2) { + result = new ArrayList<>(result); + unmodifiable = false; + extra = (int) result.stream().filter(Helper::isDoubleCost).count(); + int i = result.size(); + while (result.size() + extra < argsCount) { + Class aClass = classes.get(i); + if (Helper.isDoubleCost(aClass)) { + ++extra; + if (result.size() + extra >= argsCount) { + break; + } + } + result.add(aClass); + } + } + if (isVararg && result.size() > 0) { + if (unmodifiable) { + result = new ArrayList<>(result); + } + int last = result.size() - 1; + Class aClass = result.get(last); + aClass = Array.newInstance(aClass, 2).getClass(); + result.set(last, aClass); + } + return result; + } + public static MethodHandle addTrailingArgs(MethodHandle target, int nargs, List> classes) { int targetLen = target.type().parameterCount(); @@ -230,7 +272,7 @@ return randomArgs(params.toArray(new Class[params.size()])); } - private static Object castToWrapper(Object value, Class dst) { + public static Object castToWrapper(Object value, Class dst) { Object wrap = null; if (value instanceof Number) { wrap = castToWrapperOrNull(((Number) value).longValue(), dst); @@ -268,7 +310,7 @@ if (dst == byte.class || dst == Byte.class) { return (byte) (value); } - if (dst == boolean.class || dst == boolean.class) { + if (dst == boolean.class || dst == Boolean.class) { return ((value % 29) & 1) == 0; } return null; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/sun/java2d/OpenGL/DrawHugeImageTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/java2d/OpenGL/DrawHugeImageTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 8040617 + * @summary Test verifies that an attempt to get an accelerated copy of + * a huge buffered image does not result in an OOME. + * + * @run main DrawHugeImageTest + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.awt.image.VolatileImage; + +public class DrawHugeImageTest { + // we have to render the BI source several times in order + // to get an accelerated copy to be used. + static { + System.setProperty("sun.java2d.accthreshold", "1"); + } + private static final int max_rendering_count = 5; + + private static final Color srcColor = Color.red; + private static final Color dstColor = Color.blue; + + public static void main(String[] args) { + BufferedImage src = createSrc(); + + VolatileImage dst = createDst(); + System.out.println("Dst: " + dst); + boolean status; + int count = max_rendering_count; + + do { + System.out.println("render image: " + (max_rendering_count - count)); + status = render(src, dst); + + } while (status && count-- > 0); + + if (!status || count > 0) { + throw new RuntimeException("Test failed: " + count); + } + } + + private static boolean render(BufferedImage src, VolatileImage dst) { + int cnt = 5; + do { + Graphics2D g = dst.createGraphics(); + g.setColor(dstColor); + g.fillRect(0, 0, dst.getWidth(), dst.getHeight()); + g.drawImage(src, 0, 0, null); + g.dispose(); + } while (dst.contentsLost() && (--cnt > 0)); + + if (cnt == 0) { + System.err.println("Test failed: unable to render to volatile destination"); + return false; + } + + BufferedImage s = dst.getSnapshot(); + + return s.getRGB(1,1) == srcColor.getRGB(); + } + + private static BufferedImage createSrc() { + final int w = 20000; + final int h = 5; + + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); + Graphics2D g = img.createGraphics(); + g.setColor(srcColor); + g.fillRect(0, 0, w, h); + g.dispose(); + + return img; + } + + private static VolatileImage createDst() { + GraphicsConfiguration gc = + GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); + + return gc.createCompatibleVolatileImage(200, 200); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/sun/security/krb5/auto/Context.java --- a/jdk/test/sun/security/krb5/auto/Context.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/sun/security/krb5/auto/Context.java Wed Jul 05 20:01:50 2017 +0200 @@ -22,15 +22,14 @@ */ import com.sun.security.auth.module.Krb5LoginModule; -import java.security.Key; + +import java.lang.reflect.Method; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Arrays; -import java.util.Base64; import java.util.HashMap; import java.util.Map; import javax.security.auth.Subject; -import javax.security.auth.kerberos.KerberosCredMessage; import javax.security.auth.kerberos.KerberosKey; import javax.security.auth.kerberos.KerberosTicket; import javax.security.auth.login.LoginContext; @@ -41,10 +40,6 @@ import org.ietf.jgss.GSSName; import org.ietf.jgss.MessageProp; import org.ietf.jgss.Oid; -import com.sun.security.jgss.ExtendedGSSContext; -import com.sun.security.jgss.InquireType; -import com.sun.security.jgss.AuthorizationDataEntry; -import com.sun.security.jgss.ExtendedGSSCredential; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.security.Principal; @@ -78,7 +73,7 @@ public class Context { private Subject s; - private ExtendedGSSContext x; + private GSSContext x; private String name; private GSSCredential cred; // see static method delegated(). @@ -143,7 +138,6 @@ /** * Logins with username/password as an existing Subject. The * same subject can be used multiple times to simulate multiple logins. - * @param s existing subject */ public static Context fromUserPass(Subject s, String user, char[] pass, boolean storeKey) throws Exception { @@ -222,7 +216,7 @@ @Override public byte[] run(Context me, byte[] dummy) throws Exception { GSSManager m = GSSManager.getInstance(); - me.x = (ExtendedGSSContext)m.createContext( + me.x = m.createContext( target.indexOf('@') < 0 ? m.createName(target, null) : m.createName(target, GSSName.NT_HOSTBASED_SERVICE), @@ -267,7 +261,7 @@ asInitiator? GSSCredential.INITIATE_AND_ACCEPT: GSSCredential.ACCEPT_ONLY); - me.x = (ExtendedGSSContext)m.createContext(me.cred); + me.x = m.createContext(me.cred); return null; } }, null); @@ -285,7 +279,7 @@ * * @return the GSSContext object */ - public ExtendedGSSContext x() { + public GSSContext x() { return x; } @@ -339,7 +333,7 @@ */ public void status() throws Exception { System.out.println("STATUS OF " + name.toUpperCase()); - try { + if (x != null) { StringBuffer sb = new StringBuffer(); if (x.getAnonymityState()) { sb.append("anon, "); @@ -362,19 +356,15 @@ if (x.getSequenceDetState()) { sb.append("seq det, "); } - if (x instanceof ExtendedGSSContext) { - if (((ExtendedGSSContext)x).getDelegPolicyState()) { - sb.append("deleg policy, "); - } + System.out.println(" Context status of " + name + ": " + sb.toString()); + if (x.isProtReady() || x.isEstablished()) { + System.out.println(" " + x.getSrcName() + " -> " + x.getTargName()); } - System.out.println("Context status of " + name + ": " + sb.toString()); - System.out.println(x.getSrcName() + " -> " + x.getTargName()); - } catch (Exception e) { - ;// Don't care } + xstatus(); if (s != null) { System.out.println("====== START SUBJECT CONTENT ====="); - for (Principal p: s.getPrincipals()) { + for (Principal p : s.getPrincipals()) { System.out.println(" Principal: " + p); } for (Object o : s.getPublicCredentials()) { @@ -405,51 +395,42 @@ } System.out.println("====== END SUBJECT CONTENT ====="); } - if (x != null && x instanceof ExtendedGSSContext) { - if (x.isEstablished()) { - ExtendedGSSContext ex = (ExtendedGSSContext)x; - Key k = (Key)ex.inquireSecContext( - InquireType.KRB5_GET_SESSION_KEY); - if (k == null) { - throw new Exception("(Old) Session key cannot be null"); - } - System.out.println("(Old) Session key is: " + k); - Key k2 = (Key)ex.inquireSecContext( - InquireType.KRB5_GET_SESSION_KEY_EX); - if (k2 == null) { - throw new Exception("Session key cannot be null"); - } - System.out.println("Session key is: " + k); - boolean[] flags = (boolean[])ex.inquireSecContext( - InquireType.KRB5_GET_TKT_FLAGS); - if (flags == null) { - throw new Exception("Ticket flags cannot be null"); + } + + public void xstatus() throws Exception { + System.out.println(" Extended context status:"); + if (x != null) { + try { + Class clazz = Class.forName("com.sun.security.jgss.ExtendedGSSContext"); + if (clazz.isAssignableFrom(x.getClass())) { + if (clazz.getMethod("getDelegPolicyState").invoke(x) == Boolean.TRUE) { + System.out.println(" deleg policy"); + } + if (x.isEstablished()) { + Class inqType = Class.forName("com.sun.security.jgss.InquireType"); + Method inqMethod = clazz.getMethod("inquireSecContext", inqType); + for (Object o : inqType.getEnumConstants()) { + System.out.println(" " + o + ":"); + try { + System.out.println(" " + inqMethod.invoke(x, o)); + } catch (Exception e) { + System.out.println(e.getCause()); + } + } + } } - System.out.println("Ticket flags is: " + Arrays.toString(flags)); - String authTime = (String)ex.inquireSecContext( - InquireType.KRB5_GET_AUTHTIME); - if (authTime == null) { - throw new Exception("Auth time cannot be null"); - } - System.out.println("AuthTime is: " + authTime); - if (!x.isInitiator()) { - AuthorizationDataEntry[] ad = (AuthorizationDataEntry[])ex.inquireSecContext( - InquireType.KRB5_GET_AUTHZ_DATA); - System.out.println("AuthzData is: " + Arrays.toString(ad)); + } catch (ClassNotFoundException cnfe) { + System.out.println(" -- ExtendedGSSContext not available"); + } + } + if (cred != null) { + try { + Class clazz2 = Class.forName("com.sun.security.jgss.ExtendedGSSCredential"); + if (!clazz2.isAssignableFrom(cred.getClass())) { + throw new Exception("cred is not extended"); } - try { - KerberosCredMessage tok = (KerberosCredMessage)ex.inquireSecContext( - InquireType.KRB5_GET_KRB_CRED); - System.out.println("KRB_CRED is " + - (tok == null?"not ":"") + "available"); - if (tok != null) { - System.out.println("From " + tok.getSender() + " to " - + tok.getRecipient()); - System.out.println(Base64.getEncoder().encodeToString(tok.getEncoded())); - } - } catch (Exception e) { - System.out.println("KRB_CRED is not available: " + e); - } + } catch (ClassNotFoundException cnfe) { + System.out.println(" -- ExtendedGSSCredential not available"); } } } @@ -591,7 +572,10 @@ if (Context.this.cred == null) { Context.this.cred = m.createCredential(GSSCredential.INITIATE_ONLY); } - return ((ExtendedGSSCredential)Context.this.cred).impersonate(other); + return (GSSCredential) + Class.forName("com.sun.security.jgss.ExtendedGSSCredential") + .getMethod("impersonate", GSSName.class) + .invoke(Context.this.cred, other); } }); Context out = new Context(); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/sun/security/krb5/auto/NewInquireTypes.java --- a/jdk/test/sun/security/krb5/auto/NewInquireTypes.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/sun/security/krb5/auto/NewInquireTypes.java Wed Jul 05 20:01:50 2017 +0200 @@ -29,6 +29,7 @@ * @run main/othervm NewInquireTypes */ +import com.sun.security.jgss.ExtendedGSSContext; import com.sun.security.jgss.InquireType; import sun.security.jgss.GSSUtil; import sun.security.krb5.internal.KRBCred; @@ -52,10 +53,12 @@ Context.handshake(c, s); + ExtendedGSSContext ctxt = (ExtendedGSSContext)c.x(); EncryptionKey key = (EncryptionKey) - c.x().inquireSecContext(InquireType.KRB5_GET_SESSION_KEY_EX); + ctxt.inquireSecContext(InquireType.KRB5_GET_SESSION_KEY_EX); KerberosCredMessage cred = (KerberosCredMessage) - c.x().inquireSecContext(InquireType.KRB5_GET_KRB_CRED); + ctxt.inquireSecContext(InquireType.KRB5_GET_KRB_CRED); + c.status(); // Confirm the KRB_CRED message is encrypted with the session key. new KRBCred(cred.getEncoded()).encPart.decrypt( diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/sun/security/krb5/auto/OkAsDelegate.java --- a/jdk/test/sun/security/krb5/auto/OkAsDelegate.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/sun/security/krb5/auto/OkAsDelegate.java Wed Jul 05 20:01:50 2017 +0200 @@ -48,6 +48,7 @@ * @summary Support OK-AS-DELEGATE flag */ import com.sun.security.jgss.ExtendedGSSContext; +import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSException; import org.ietf.jgss.Oid; @@ -102,7 +103,7 @@ cx.requestCredDeleg(requestDelegState); cx.requestDelegPolicy(requestDelegPolicyState); s.startAsServer(mech); - ExtendedGSSContext sx = (ExtendedGSSContext)s.x(); + GSSContext sx = s.x(); Context.handshake(c, s); diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/sun/security/krb5/auto/OkAsDelegateXRealm.java --- a/jdk/test/sun/security/krb5/auto/OkAsDelegateXRealm.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/sun/security/krb5/auto/OkAsDelegateXRealm.java Wed Jul 05 20:01:50 2017 +0200 @@ -42,6 +42,8 @@ import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; + +import com.sun.security.jgss.ExtendedGSSContext; import org.ietf.jgss.GSSException; import sun.security.jgss.GSSUtil; import sun.security.krb5.Config; @@ -129,7 +131,7 @@ for (int i=0; i<2; i++) { c.startAsClient("host@host.r3.local", GSSUtil.GSS_KRB5_MECH_OID); s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); - c.x().requestDelegPolicy(true); + ((ExtendedGSSContext)c.x()).requestDelegPolicy(true); Context.handshake(c, s); boolean succeed = true; diff -r 89a653341cf2 -r 1b1ec4291abc jdk/test/sun/security/krb5/auto/SSL.java --- a/jdk/test/sun/security/krb5/auto/SSL.java Wed Jul 05 20:01:05 2017 +0200 +++ b/jdk/test/sun/security/krb5/auto/SSL.java Wed Jul 05 20:01:50 2017 +0200 @@ -186,13 +186,13 @@ // Client checks "initiate", then server gets the name // and checks "accept". Second connection resume. if (!permChecks.equals("IA")) { - throw new Exception(); + throw new Exception(permChecks); } } else { // For bound, JAAS checks "accept" once. Server checks again, // client then checks "initiate". Second connection resume. if (!permChecks.equals("AAI")) { - throw new Exception(); + throw new Exception(permChecks); } } } diff -r 89a653341cf2 -r 1b1ec4291abc langtools/.hgtags --- a/langtools/.hgtags Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/.hgtags Wed Jul 05 20:01:50 2017 +0200 @@ -273,3 +273,4 @@ 016786f793149135ab6b23c71087c1ca12691d77 jdk9-b28 13705e2ddeb20a78e066595a1709e61f257189e9 jdk9-b29 ef5427c13e1e741c457a2ed868e3b6d6bf717754 jdk9-b30 +0046d55383a9d873ffbc7253d7c5e28ab98c5bea jdk9-b31 diff -r 89a653341cf2 -r 1b1ec4291abc langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Wed Jul 05 20:01:50 2017 +0200 @@ -358,11 +358,9 @@ for (Type aLowerBound : from.getBounds(InferenceBound.LOWER)) { for (Type anotherLowerBound : from.getBounds(InferenceBound.LOWER)) { if (aLowerBound != anotherLowerBound && - commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) { - /* self comment check if any lower bound may be and undetVar, - * in that case the result of this call may be a false positive. - * Should this be restricted to non free types? - */ + !inferenceContext.free(aLowerBound) && + !inferenceContext.free(anotherLowerBound) && + commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) { return generateReferenceToTargetConstraint(tree, from, to, resultInfo, inferenceContext); } diff -r 89a653341cf2 -r 1b1ec4291abc langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Wed Jul 05 20:01:50 2017 +0200 @@ -397,20 +397,19 @@ Content htmlComment = new Comment(configuration.getText("doclet.New_Page")); Content head = new HtmlTree(HtmlTag.HEAD); head.addContent(getGeneratedBy(!configuration.notimestamp)); - if (configuration.charset.length() > 0) { - Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, - configuration.charset); - head.addContent(meta); - } head.addContent(getTitle()); + Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, + (configuration.charset.length() > 0) ? + configuration.charset : HtmlConstants.HTML_DEFAULT_CHARSET); + head.addContent(meta); if (!configuration.notimestamp) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - Content meta = HtmlTree.META("date", dateFormat.format(new Date())); + meta = HtmlTree.META("date", dateFormat.format(new Date())); head.addContent(meta); } if (metakeywords != null) { for (String metakeyword : metakeywords) { - Content meta = HtmlTree.META("keywords", metakeyword); + meta = HtmlTree.META("keywords", metakeyword); head.addContent(meta); } } diff -r 89a653341cf2 -r 1b1ec4291abc langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java Wed Jul 05 20:01:50 2017 +0200 @@ -90,8 +90,7 @@ * {@inheritDoc} */ public Content getPackageHeader(String heading) { - String pkgName = packageDoc.name(); - Content bodyTree = getBody(true, getWindowTitle(pkgName)); + Content bodyTree = getBody(true, getWindowTitle(utils.getPackageName(packageDoc))); addTop(bodyTree); addNavLinks(true, bodyTree); HtmlTree div = new HtmlTree(HtmlTag.DIV); diff -r 89a653341cf2 -r 1b1ec4291abc langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ProfilePackageWriterImpl.java --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ProfilePackageWriterImpl.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/ProfilePackageWriterImpl.java Wed Jul 05 20:01:50 2017 +0200 @@ -103,8 +103,7 @@ * {@inheritDoc} */ public Content getPackageHeader(String heading) { - String pkgName = packageDoc.name(); - Content bodyTree = getBody(true, getWindowTitle(pkgName)); + Content bodyTree = getBody(true, getWindowTitle(utils.getPackageName(packageDoc))); addTop(bodyTree); addNavLinks(true, bodyTree); HtmlTree div = new HtmlTree(HtmlTag.DIV); diff -r 89a653341cf2 -r 1b1ec4291abc langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlConstants.java Wed Jul 05 20:01:50 2017 +0200 @@ -220,4 +220,9 @@ * Html tag for the member heading. */ public static final HtmlTag MEMBER_HEADING = HtmlTag.H4; + + /** + * Default charset for HTML. + */ + public static final String HTML_DEFAULT_CHARSET = "utf-8"; } diff -r 89a653341cf2 -r 1b1ec4291abc langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java Wed Jul 05 20:01:50 2017 +0200 @@ -311,13 +311,12 @@ Content htmlComment = new Comment(configuration.getText("doclet.New_Page")); Content head = new HtmlTree(HtmlTag.HEAD); head.addContent(getGeneratedBy(!noTimeStamp)); - if (configuration.charset.length() > 0) { - Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, - configuration.charset); - head.addContent(meta); - } Content windowTitle = HtmlTree.TITLE(new StringContent(title)); head.addContent(windowTitle); + Content meta = HtmlTree.META("Content-Type", CONTENT_TYPE, + (configuration.charset.length() > 0) ? + configuration.charset : HtmlConstants.HTML_DEFAULT_CHARSET); + head.addContent(meta); head.addContent(getFramesetJavaScript()); Content htmlTree = HtmlTree.HTML(configuration.getLocale().getLanguage(), head, frameset); diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/com/sun/javadoc/testCharset/TestCharset.java --- a/langtools/test/com/sun/javadoc/testCharset/TestCharset.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/com/sun/javadoc/testCharset/TestCharset.java Wed Jul 05 20:01:50 2017 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 7052170 + * @bug 7052170 8047745 * @summary Run a test on -charset to make sure the charset gets generated as a * part of the meta tag. * @author Bhavesh Patel @@ -42,19 +42,32 @@ @Test void test() { javadoc("-d", "out", - "-charset", "UTF-8", + "-charset", "ISO-8859-1", "-sourcepath", testSrc, "pkg"); checkExit(Exit.OK); checkOutput("index.html", true, - ""); + ""); checkOutput("pkg/Foo.html", true, - ""); + ""); checkOutput("index.html", false, - ""); + ""); checkOutput("pkg/Foo.html", false, - ""); + ""); + } + + @Test + void test1() { + javadoc("-d", "out-1", + "-sourcepath", testSrc, + "pkg"); + checkExit(Exit.OK); + + checkOutput("index.html", true, + ""); + checkOutput("pkg/Foo.html", true, + ""); } } diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/com/sun/javadoc/testUnnamedPackage/TestUnnamedPackage.java --- a/langtools/test/com/sun/javadoc/testUnnamedPackage/TestUnnamedPackage.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/com/sun/javadoc/testUnnamedPackage/TestUnnamedPackage.java Wed Jul 05 20:01:50 2017 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 4904075 4774450 5015144 + * @bug 4904075 4774450 5015144 8043698 * @summary Reference unnamed package as "Unnamed", not empty string. * Generate a package summary for the unnamed package. * @author jamieh @@ -51,6 +51,9 @@ "This is a package comment for the unnamed package.", "This is a class in the unnamed package."); + checkOutput("package-summary.html", true, + "<Unnamed>"); + checkOutput("package-tree.html", true, "

Hierarchy For Package <Unnamed>

"); diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/Parens1.java --- a/langtools/test/tools/javac/Parens1.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/tools/javac/Parens1.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,33 +1,10 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 + * @test /nodynamiccopyright/ * @bug 4391330 * @summary compiler accepted (Integer).toString(123) * @author gafter * - * @compile/fail Parens1.java + * @compile/fail/ref=Parens1.out -XDrawDiagnostics Parens1.java */ class Parens1 { diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/Parens1.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/Parens1.out Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,2 @@ +Parens1.java:12:20: compiler.err.illegal.start.of.type +1 error diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/Parens2.java --- a/langtools/test/tools/javac/Parens2.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/tools/javac/Parens2.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,33 +1,10 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 + * @test /nodynamiccopyright/ * @bug 4408036 * @summary Compiler accepted "(i=2);" as a valid expession statement. * @author gafter * - * @compile/fail Parens2.java + * @compile/fail/ref=Parens2.out -XDrawDiagnostics Parens2.java */ class Parens2 { diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/Parens2.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/Parens2.out Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,2 @@ +Parens2.java:13:9: compiler.err.not.stmt +1 error diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/Parens3.java --- a/langtools/test/tools/javac/Parens3.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/tools/javac/Parens3.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,33 +1,10 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 + * @test /nodynamiccopyright/ * @bug 4394546 * @summary get no err msg if label wrapped in parentheses * @author gafter * - * @compile/fail Parens3.java + * @compile/fail/ref=Parens3.out -XDrawDiagnostics Parens3.java */ class Parens3 { diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/Parens3.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/Parens3.out Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,3 @@ +Parens3.java:12:5: compiler.err.not.stmt +Parens3.java:12:10: compiler.err.expected: ';' +2 errors diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/Parens4.java --- a/langtools/test/tools/javac/Parens4.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/tools/javac/Parens4.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,33 +1,10 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. - * 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 + * @test /nodynamiccopyright/ * @bug 4933317 * @summary javac accepts parens in package names * @author gafter * - * @compile/fail Parens4.java + * @compile/fail/ref=Parens4.out -XDrawDiagnostics Parens4.java */ class Parens4 { diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/Parens4.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/Parens4.out Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,2 @@ +Parens4.java:12:16: compiler.err.illegal.start.of.type +1 error diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/ParseConditional.java --- a/langtools/test/tools/javac/ParseConditional.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/tools/javac/ParseConditional.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,34 +1,11 @@ /* - * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved. - * 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 + * @test /nodynamiccopyright/ * @bug 4092958 * @summary The compiler was too permissive in its parsing of conditional * expressions. * @author turnidge * - * @compile/fail ParseConditional.java + * @compile/fail/ref=ParseConditional.out -XDrawDiagnostics ParseConditional.java */ public class ParseConditional { @@ -38,6 +15,11 @@ int b = 2; int c = 3; int d = 4; - a = condition ? b = c : c = d; // Should get a parse error. + // The following line should give an error because the conditional ?: operator + // is higher priority than the final assignment operator, between c and d. + // As such, the correct parsing is: + // a = (condition ? b = c : c) = d; + // and it is illegal to try and assign to the value of the conditional expression. + a = condition ? b = c : c = d; } } diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/ParseConditional.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/ParseConditional.out Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,2 @@ +ParseConditional.java:23:23: compiler.err.unexpected.type: kindname.variable, kindname.value +1 error diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/StoreClass.java --- a/langtools/test/tools/javac/StoreClass.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/tools/javac/StoreClass.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,33 +1,10 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. - * 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 + * @test /nodynamiccopyright/ * @bug 4350352 * @summary InternalError: store unsupported: com.sun.tools.javac.v8.comp.Items * @author gafter * - * @compile/fail StoreClass.java + * @compile/fail/ref=StoreClass.out -XDrawDiagnostics StoreClass.java */ class StoreClass { diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/StoreClass.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/StoreClass.out Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,3 @@ +StoreClass.java:12:19: compiler.err.cant.assign.val.to.final.var: class +StoreClass.java:13:12: compiler.err.cant.assign.val.to.final.var: class +2 errors diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/SwitchScope.java --- a/langtools/test/tools/javac/SwitchScope.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/tools/javac/SwitchScope.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,33 +1,10 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * 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 + * @test /nodynamiccopyright/ * @bug 4725650 * @summary Restrict scope of local classes in switch-block-group * @author gafter * - * @compile/fail SwitchScope.java + * @compile/fail/ref=SwitchScope.out -XDrawDiagnostics SwitchScope.java */ public class SwitchScope { diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/SwitchScope.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/SwitchScope.out Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,2 @@ +SwitchScope.java:22:28: compiler.err.cant.resolve.location: kindname.class, Local, , , (compiler.misc.location: kindname.class, SwitchScope, null) +1 error diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/SynthName2.java --- a/langtools/test/tools/javac/SynthName2.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/tools/javac/SynthName2.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,38 +1,15 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. - * 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 + * @test /nodynamiccopyright/ * @bug 4462714 * @summary using of synthetic names in local class causes ClassFormatError * @author gafter * - * @compile/fail SynthName2.java + * @compile/fail/ref=SynthName2.out -XDrawDiagnostics SynthName2.java */ import java.io.PrintStream; -class SynthName1 { +class SynthName2 { public static void main(String args[]) { run(args, System.out); } diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/SynthName2.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/SynthName2.out Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,4 @@ +SynthName2.java:33:9: compiler.err.synthetic.name.conflict: val$zzz, InnClass +SynthName2.java:34:17: compiler.err.synthetic.name.conflict: val$prm1, InnClass +SynthName2.java:35:17: compiler.err.synthetic.name.conflict: val$zzz, InnClass +3 errors diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/T6234077.java --- a/langtools/test/tools/javac/T6234077.java Wed Jul 05 20:01:05 2017 +0200 +++ b/langtools/test/tools/javac/T6234077.java Wed Jul 05 20:01:50 2017 +0200 @@ -1,30 +1,7 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * 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 /nodynamiccopyright/ + * @bug 6234077 + * @compile/fail/ref=T6234077.out -XDrawDiagnostics T6234077.java */ -/* - * @test - * @bug 6234077 - * @compile/fail T6234077.java - */ -@Deprecated /** @deprecated */ public class Foo { } diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/T6234077.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/T6234077.out Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,2 @@ +T6234077.java:7:8: compiler.err.class.public.should.be.in.file: Foo +1 error diff -r 89a653341cf2 -r 1b1ec4291abc langtools/test/tools/javac/generics/inference/8055963/T8055963.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/generics/inference/8055963/T8055963.java Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/** + * @test + * @bug 8055963 + * @summary Inference failure with nested invocation + * @compile T8055963.java + */ +class T8055963 { + + static class C {} + + T choose(T first, T second) { return null; } + + void test() { + C cs = choose(new C(), new C<>()); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc make/HotspotWrapper.gmk --- a/make/HotspotWrapper.gmk Wed Jul 05 20:01:05 2017 +0200 +++ b/make/HotspotWrapper.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -42,7 +42,7 @@ # not doing it breaks builds on msys. $(HOTSPOT_OUTPUTDIR)/_hotspot.timestamp: $(HOTSPOT_FILES) @$(MKDIR) -p $(HOTSPOT_OUTPUTDIR) - @($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) -j1 $(HOTSPOT_MAKE_ARGS) SPEC=$(HOTSPOT_SPEC) BASE_SPEC=$(BASE_SPEC)) + @($(CD) $(HOTSPOT_TOPDIR)/make && $(MAKE) $(HOTSPOT_MAKE_ARGS) SPEC=$(HOTSPOT_SPEC) BASE_SPEC=$(BASE_SPEC)) $(TOUCH) $@ hotspot: $(HOTSPOT_OUTPUTDIR)/_hotspot.timestamp diff -r 89a653341cf2 -r 1b1ec4291abc make/Main.gmk --- a/make/Main.gmk Wed Jul 05 20:01:05 2017 +0200 +++ b/make/Main.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -298,7 +298,9 @@ # Verification targets verify-modules: + @$(call TargetEnter) +($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f CheckModules.gmk) + @$(call TargetExit) ALL_TARGETS += verify-modules @@ -400,7 +402,7 @@ main-jars: java.security.jgss-libs endif - images: jars demos samples exploded-image source-tips + images: jars demos samples exploded-image verify-modules source-tips bootcycle-images: images @@ -476,7 +478,7 @@ ################################################################################ -all: images docs verify-modules +all: images docs default: exploded-image ALL_TARGETS += default all @@ -491,7 +493,7 @@ # file. CLEAN_COMPONENTS += langtools corba hotspot jdk nashorn images \ - bootcycle-build docs docstemp test + bootcycle-build docs docstemp test make-support CLEAN_TARGETS := $(addprefix clean-, $(CLEAN_COMPONENTS)) # Remove everything, except the output from configure. diff -r 89a653341cf2 -r 1b1ec4291abc make/common/Modules.gmk --- a/make/common/Modules.gmk Wed Jul 05 20:01:05 2017 +0200 +++ b/make/common/Modules.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -26,6 +26,9 @@ ifndef _MODULES_GMK _MODULES_GMK := 1 +include JavaCompilation.gmk +include SetupJavaCompilers.gmk + ################################################################################ # Module list macros @@ -50,8 +53,32 @@ $(patsubst %,%/*/$(OPENJDK_TARGET_OS)/classes/*, $(ALL_TOP_SRC_DIRS)))))))))))) endef -MODULES_LIST_FILE := $(SRC_ROOT)/make/common/modules.list -MODULE_DEPS_MAKEFILE := $(OUTPUT_ROOT)/module-deps.gmk +# Find all modules with source for the target platform. +define FindAllModules + $(sort $(filter-out closed demo sample, $(notdir $(patsubst %/,%, $(dir \ + $(wildcard $(patsubst %, %/*/share, $(ALL_TOP_SRC_DIRS)) \ + $(patsubst %, %/*/$(OPENJDK_TARGET_OS), $(ALL_TOP_SRC_DIRS)) \ + $(patsubst %, %/*/$(OPENJDK_TARGET_OS_API_DIR), $(ALL_TOP_SRC_DIRS)))))))) +endef + +################################################################################ + +$(eval $(call SetupJavaCompilation,BUILD_GENMODULESLIST, \ + SETUP := BOOT_JAVAC, \ + SRC := $(JDK_TOPDIR)/make/src/classes, \ + INCLUDES := build/tools/module, \ + BIN := $(MAKESUPPORT_OUTPUTDIR)/bt_classes_moduleslist)) + +TOOL_GENMODULESLIST = $(JAVA_SMALL) \ + -cp "$(MAKESUPPORT_OUTPUTDIR)/bt_classes_moduleslist" \ + build.tools.module.GenModulesList + +MODULES_LIST_FILE := $(MAKESUPPORT_OUTPUTDIR)/modules.list +MODULE_DEPS_MAKEFILE := $(MAKESUPPORT_OUTPUTDIR)/module-deps.gmk + +$(MODULES_LIST_FILE): $(SRC_ROOT)/modules.xml \ + $(BUILD_GENMODULESLIST) + $(TOOL_GENMODULESLIST) -o $@ $(filter %.xml, $^) $(MODULE_DEPS_MAKEFILE): $(MODULES_LIST_FILE) $(CAT) $^ | $(SED) -e 's/^\([^:]*\):/DEPS_\1 :=/g' > $@ @@ -63,14 +90,6 @@ $(DEPS_$(strip $1)) endef -# Find all modules with source for the target platform. -define FindAllModules - $(sort $(filter-out closed demo sample, $(notdir $(patsubst %/,%, $(dir \ - $(wildcard $(patsubst %, %/*/share, $(ALL_TOP_SRC_DIRS)) \ - $(patsubst %, %/*/$(OPENJDK_TARGET_OS), $(ALL_TOP_SRC_DIRS)) \ - $(patsubst %, %/*/$(OPENJDK_TARGET_OS_API_DIR), $(ALL_TOP_SRC_DIRS)))))))) -endef - ################################################################################ # Hook to include the corresponding custom file, if present. diff -r 89a653341cf2 -r 1b1ec4291abc make/common/SetupJavaCompilers.gmk --- a/make/common/SetupJavaCompilers.gmk Wed Jul 05 20:01:05 2017 +0200 +++ b/make/common/SetupJavaCompilers.gmk Wed Jul 05 20:01:50 2017 +0200 @@ -34,6 +34,12 @@ # make JAVAC_WARNINGS="-Xlint:all -Xmaxwarns 10000" JAVAC_WARNINGS := -Xlint:all,-deprecation -Werror +# The BOOT_JAVAC setup uses the boot jdk compiler to compile the tools +# and the interim javac, to be run by the boot jdk. +$(eval $(call SetupJavaCompiler,BOOT_JAVAC, \ + JAVAC := $(JAVAC), \ + FLAGS := -XDignore.symbol.file=true -g -Xlint:all$(COMMA)-deprecation -Werror)) + # Any java code executed during a JDK build to build other parts of the JDK must be # executed by the bootstrap JDK (probably with -Xbootclasspath/p: ) and for this # purpose must be built with -target PREVIOUS for bootstrapping purposes, which diff -r 89a653341cf2 -r 1b1ec4291abc make/common/modules.list --- a/make/common/modules.list Wed Jul 05 20:01:05 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -java.base: -java.logging: java.base -java.security.sasl: java.logging java.base -java.naming: java.security.sasl java.base -java.security.acl: java.base -jdk.charsets: java.base -java.scripting: java.base -java.xml: java.base -java.sql: java.xml java.logging java.base -jdk.scripting.nashorn: java.scripting java.logging java.base -java.rmi: java.logging java.base -java.prefs: java.xml java.base -java.desktop: jdk.charsets java.prefs java.xml java.logging java.base -java.corba: java.naming java.rmi java.desktop java.logging java.base -java.compiler: java.logging java.base -jdk.compiler: java.compiler java.base -jdk.javadoc: java.compiler java.xml jdk.compiler java.base -jdk.rmic: java.corba jdk.compiler jdk.javadoc java.base -jdk.jvmstat: java.rmi java.base -jdk.attach: jdk.jvmstat java.base -jdk.jcmd: jdk.jvmstat jdk.attach java.base -jdk.jdi: jdk.attach java.base -jdk.hotspot.agent: java.rmi java.scripting java.desktop java.base jdk.jdi -jdk.hprof.agent: java.base -java.management: java.naming java.rmi java.logging java.base -jdk.jconsole: java.management jdk.jvmstat java.rmi jdk.attach java.desktop java.logging java.base -java.activation: java.desktop java.logging java.base -java.xml.bind: java.activation java.compiler java.xml java.desktop java.logging java.base -jdk.xml.bind: java.activation java.compiler java.xml.bind java.xml java.desktop java.logging jdk.compiler java.base -jdk.httpserver: java.logging java.base -java.annotations.common: java.base -java.xml.soap: java.activation java.xml.bind java.xml java.desktop java.logging java.base -java.xml.ws: java.activation java.management jdk.httpserver java.rmi java.annotations.common java.xml.bind java.xml java.desktop java.logging java.xml.soap java.base -jdk.xml.ws: jdk.xml.bind java.compiler java.rmi java.xml.ws java.xml.bind java.xml java.logging java.base -java.sql.rowset: java.naming java.sql java.xml java.logging java.base -java.instrument: java.base -java.security.jgss: java.naming java.security.sasl java.logging java.base -java.xml.crypto: java.xml java.logging java.base -jdk.localedata: java.base -jdk.crypto.ec: java.base -jdk.crypto.pkcs11: jdk.crypto.ec java.base -jdk.crypto.mscapi: java.base -jdk.naming.rmi: java.naming java.rmi java.base -jdk.zipfs: java.base -jdk.naming.dns: java.naming java.base -java.smartcardio: java.base -jdk.dev: jdk.xml.bind jdk.xml.ws java.scripting jdk.rmic java.xml jdk.compiler java.base -jdk.snmp: java.management java.security.acl java.logging java.base -jdk.jdwp.agent: java.base -jdk.security.auth: java.naming java.security.jgss java.base -jdk.sctp: java.base -jdk.runtime: java.desktop java.base -jdk.jfr: java.management java.xml java.base -jdk.deploy.osx: java.scripting java.desktop java.base diff -r 89a653341cf2 -r 1b1ec4291abc modules.xml --- a/modules.xml Wed Jul 05 20:01:05 2017 +0200 +++ b/modules.xml Wed Jul 05 20:01:50 2017 +0200 @@ -243,6 +243,7 @@ java.rmi java.security.jgss java.security.sasl + java.sql jdk.charsets jdk.deploy.osx jdk.dev @@ -250,6 +251,7 @@ jdk.jvmstat jdk.runtime jdk.security.auth + jdk.security.jgss sun.net.dns @@ -326,6 +328,7 @@ sun.security.internal.spec + jdk.crypto.mscapi jdk.crypto.pkcs11 jdk.crypto.ucrypto @@ -730,6 +733,10 @@ javax.swing.undo + + sun.awt + oracle.accessbridge +
java.instrument @@ -900,12 +907,7 @@ java.security.jgss java.base - java.logging java.naming - java.security.sasl - - com.sun.security.jgss - javax.security.auth.kerberos @@ -924,6 +926,14 @@ sun.security.krb5.internal.ktab jdk.security.auth + + sun.security.jgss + jdk.security.jgss + + + sun.security.krb5.internal + jdk.security.jgss + java.security.sasl @@ -934,7 +944,7 @@ com.sun.security.sasl.util - java.security.jgss + jdk.security.jgss @@ -1570,6 +1580,10 @@ + jdk.crypto.mscapi + java.base + + jdk.crypto.pkcs11 java.base jdk.crypto.ec @@ -1752,6 +1766,16 @@ + jdk.security.jgss + java.base + java.logging + java.security.jgss + java.security.sasl + + com.sun.security.jgss + + + jdk.xml.bind java.activation java.base diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/.hgtags --- a/nashorn/.hgtags Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/.hgtags Wed Jul 05 20:01:50 2017 +0200 @@ -264,3 +264,4 @@ 00c31e5eaf26f9b238165157b9d1c617b03abcb6 jdk9-b28 e541ebaf2ab7038333ad0c13f4decd327c26dd15 jdk9-b29 072dbed6c5d968a6b9e156c36cd8838b4ff86ea1 jdk9-b30 +77efdecfa2a5c28672b7c7dcc2d1b52dcb90d493 jdk9-b31 diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/README diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java Wed Jul 05 20:01:50 2017 +0200 @@ -231,7 +231,7 @@ if (symbol != null) { if (hasArguments() && symbol.isParam()) { symbol.setFieldIndex(paramCount++); - } else { + } else if (!isValidArrayIndex(getArrayIndex(tuple.key))) { symbol.setFieldIndex(fieldCount++); } } diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Jul 05 20:01:50 2017 +0200 @@ -439,8 +439,8 @@ // current ScriptContext to use - can be null. private ScriptContext scontext; - // associated Property object for "context" property. - private jdk.nashorn.internal.runtime.Property scontextProperty; + // current ScriptEngine associated - can be null. + private ScriptEngine engine; /** * Set the current script context @@ -448,7 +448,6 @@ */ public void setScriptContext(final ScriptContext scontext) { this.scontext = scontext; - scontextProperty.setValue(this, this, scontext, false); } // global constants for this global - they can be replaced with MethodHandle.constant until invalidated @@ -581,6 +580,7 @@ return; } + this.engine = engine; init(engine); } @@ -917,6 +917,13 @@ } } + switch (nameStr) { + case "context": + return sctxt; + case "engine": + return global.engine; + } + if (self == UNDEFINED) { // scope access and so throw ReferenceError throw referenceError(global, "not.defined", nameStr); @@ -1789,9 +1796,6 @@ } if (engine != null) { - final int NOT_ENUMERABLE_NOT_CONFIG = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE; - scontextProperty = addOwnProperty("context", NOT_ENUMERABLE_NOT_CONFIG, null); - addOwnProperty("engine", NOT_ENUMERABLE_NOT_CONFIG, engine); // default file name addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); // __noSuchProperty__ hook for ScriptContext search of missing variables diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Wed Jul 05 20:01:50 2017 +0200 @@ -54,6 +54,7 @@ import static jdk.nashorn.internal.parser.TokenType.TERNARY; import static jdk.nashorn.internal.parser.TokenType.WHILE; +import java.io.Serializable; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; @@ -2977,11 +2978,13 @@ * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer * for resuming parsing after skipping a function body. */ - private static class ParserState { + private static class ParserState implements Serializable { private final int position; private final int line; private final int linePosition; + private static final long serialVersionUID = -2382565130754093694L; + ParserState(final int position, final int line, final int linePosition) { this.position = position; this.line = line; diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Wed Jul 05 20:01:50 2017 +0200 @@ -119,7 +119,7 @@ * produce different boun method handles wrapping the same access mechanism * depending on callsite */ - private MethodHandle[] GETTER_CACHE = new MethodHandle[NOOF_TYPES]; + private transient MethodHandle[] GETTER_CACHE = new MethodHandle[NOOF_TYPES]; /** * Create a new accessor property. Factory method used by nasgen generated code. diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Wed Jul 05 20:01:50 2017 +0200 @@ -101,7 +101,7 @@ private final int slot; /** SwitchPoint that is invalidated when property is changed, optional */ - protected SwitchPoint changeCallback; + protected transient SwitchPoint changeCallback; private static final long serialVersionUID = 2099814273074501176L; diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Wed Jul 05 20:01:50 2017 +0200 @@ -568,9 +568,7 @@ for (final Property property : otherProperties) { // This method is only safe to use with non-slotted, native getter/setter properties assert property.getSlot() == -1; - if (isValidArrayIndex(getArrayIndex(property.getKey()))) { - newMap.setContainsArrayKeys(); - } + assert !(isValidArrayIndex(getArrayIndex(property.getKey()))); } return newMap; diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Wed Jul 05 20:01:50 2017 +0200 @@ -125,6 +125,15 @@ @Override public Comparison compareConversion(final Class sourceType, final Class targetType1, final Class targetType2) { + if (sourceType == ConsString.class) { + if (String.class == targetType1 || CharSequence.class == targetType1) { + return Comparison.TYPE_1_BETTER; + } + + if (String.class == targetType2 || CharSequence.class == targetType2) { + return Comparison.TYPE_2_BETTER; + } + } return linkerServices.compareConversion(sourceType, targetType1, targetType2); } } diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Wed Jul 05 20:01:50 2017 +0200 @@ -131,11 +131,16 @@ } return getInvocation(EMPTY_ELEM_GETTER, self, linkerServices, desc); case "setProp": - case "setElem": + case "setElem": { + final boolean strict = NashornCallSiteDescriptor.isStrict(desc); + if (strict) { + throw typeError("cant.set.property", getArgument(linkRequest), ScriptRuntime.safeToString(self)); + } if (desc.getOperand() != null) { return getInvocation(EMPTY_PROP_SETTER, self, linkerServices, desc); } return getInvocation(EMPTY_ELEM_SETTER, self, linkerServices, desc); + } default: break; } diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Jul 05 20:01:50 2017 +0200 @@ -92,7 +92,7 @@ # other wrong usages of property type.error.property.has.no.setter=Cannot set property "{0}" of {1} that has only a getter -type.error.cant.set.proto.to.non.object=Cannot set Object {0}'s __proto__ to be a non-object like {1} +type.error.cant.set.proto.to.non.object=Cannot set Object {0}''s __proto__ to be a non-object like {1} type.error.no.such.function={1} has no such function "{0}" type.error.no.such.java.class=No such Java class: {0} type.error.no.such.java.constructor=No such Java constructor: {0} @@ -125,10 +125,10 @@ type.error.cant.load.script=Cannot load script from {0} type.error.JSON.stringify.cyclic=JSON.stringify got a cyclic data structure type.error.cant.convert.string.to.char=Cannot convert string to character; its length must be exactly 1 -type.error.cant.convert.number.to.char=Cannot convert number to character; it's out of 0-65535 range +type.error.cant.convert.number.to.char=Cannot convert number to character; it is out of 0-65535 range type.error.cant.convert.to.java.string=Cannot convert object of type {0} to a Java argument of string type type.error.cant.convert.to.java.number=Cannot convert object of type {0} to a Java argument of number type -type.error.cant.convert.to.javascript.array=Can only convert Java arrays and lists to JavaScript arrays. Can't convert object of type {0}. +type.error.cant.convert.to.javascript.array=Can only convert Java arrays and lists to JavaScript arrays. Cannot convert object of type {0}. type.error.extend.expects.at.least.one.argument=Java.extend needs at least one argument. type.error.extend.expects.at.least.one.type.argument=Java.extend needs at least one type argument. type.error.extend.expects.java.types=Java.extend needs Java types as its arguments. @@ -141,10 +141,10 @@ type.error.extend.ERROR_FINAL_FINALIZER=Can not extend class because {0} has a final finalize method. type.error.no.constructor.matches.args=Can not construct {0} with the passed arguments; they do not match any of its constructor signatures. type.error.no.method.matches.args=Can not invoke method {0} with the passed arguments; they do not match any of its method signatures. -type.error.method.not.constructor=Java method {0} can't be used as a constructor. +type.error.method.not.constructor=Java method {0} cannot be used as a constructor. type.error.env.not.object=$ENV must be an Object. type.error.unsupported.java.to.type=Unsupported Java.to target type {0}. -type.error.constructor.requires.new=Constructor {0} requires 'new'. +type.error.constructor.requires.new=Constructor {0} requires "new". type.error.new.on.nonpublic.javatype=new cannot be used with non-public java type {0}. range.error.dataview.constructor.offset=Wrong offset or length in DataView constructor diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8043232.js --- a/nashorn/test/script/basic/JDK-8043232.js Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8043232.js Wed Jul 05 20:01:50 2017 +0200 @@ -29,14 +29,14 @@ */ // call explicit constructor -print(new (java.awt["Color(int,int,int)"])(255,0,255)); +print(new (java.lang["String(char[],int,int)"])(['a','b', 'c', 'd'], 1, 3)); // print the constructor itself -print(java.awt["Color(int,int,int)"]); +print(java.lang["String(char[],int,int)"]); // store constructor to call later -var Color = java.awt["Color(int,int,int)"]; +var Color = java.lang["String(char[],int,int)"]; // call stored constructor -print(new Color(33, 233, 2)) +print(new Color(['r','r', 'e', 'd'], 1, 3)) // check if default constructor works var obj = new (java.lang["Object()"])(); diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8043232.js.EXPECTED --- a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED Wed Jul 05 20:01:50 2017 +0200 @@ -1,14 +1,14 @@ -java.awt.Color[r=255,g=0,b=255] -[jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] -java.awt.Color[r=33,g=233,b=2] +bcd +[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] +red TypeError: No such Java class: java.lang.NonExistent TypeError: No such Java constructor: Object(String) TypeError: Java constructor signature invalid: Object()xxxxx TypeError: Java constructor signature invalid: Object( TypeError: Java constructor signature invalid: Object) -TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cant be used as a constructor. -TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cant be used as a constructor. -TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires new. +TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cannot be used as a constructor. +TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cannot be used as a constructor. +TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new". TypeError: No such Java constructor: Runnable() TypeError: No such Java constructor: Runnable(int) java.lang.InstantiationException: java.io.InputStream diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8049086.js --- a/nashorn/test/script/basic/JDK-8049086.js Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8049086.js Wed Jul 05 20:01:50 2017 +0200 @@ -58,7 +58,7 @@ // (a) Java methods (b) Java classes (as these respond to new) // (c) FunctionalInterface objects (d) JSObjects that are 'functions' -print("java.awt.Color is java function? " + Java.isJavaFunction(java.awt.Color)); +print("java.lang.String is java function? " + Java.isJavaFunction(java.lang.String)); print("java.lang.Runnable instance is java function? " + Java.isJavaFunction(new java.lang.Runnable(function() {}))); print("eval is java function? " + Java.isJavaFunction(eval)); diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8049086.js.EXPECTED --- a/nashorn/test/script/basic/JDK-8049086.js.EXPECTED Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8049086.js.EXPECTED Wed Jul 05 20:01:50 2017 +0200 @@ -13,7 +13,7 @@ Object is script object? true {} is script object? true /foo/ is script object? true -java.awt.Color is java function? true +java.lang.String is java function? true java.lang.Runnable instance is java function? true eval is java function? false println is java function? true diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8049242.js --- a/nashorn/test/script/basic/JDK-8049242.js Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8049242.js Wed Jul 05 20:01:50 2017 +0200 @@ -29,14 +29,14 @@ */ // call explicit constructor -print(new (Java.type("java.awt.Color")["(int,int,int)"])(255,0,255)); +print(new (Java.type("java.lang.String")["(char[],int,int)"])(['a', 'b', 'c'],0, 3)); // print the constructor itself -print(Java.type("java.awt.Color")["(int,int,int)"]); +print(Java.type("java.lang.String")["(char[],int,int)"]); // store constructor to call later -var Color = Java.type("java.awt.Color")["(int,int,int)"]; +var Color = Java.type("java.lang.String")["(char[],int,int)"]; // call stored constructor -print(new Color(33, 233, 2)) +print(new Color(['j', 'a', 'v', 'a'], 1, 3)) // check if default constructor works var obj = new (Java.type("java.lang.Object")["()"])(); diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8049242.js.EXPECTED --- a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED Wed Jul 05 20:01:50 2017 +0200 @@ -1,10 +1,10 @@ -java.awt.Color[r=255,g=0,b=255] -[jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] -java.awt.Color[r=33,g=233,b=2] +abc +[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] +ava TypeError: null is not a function TypeError: null is not a function TypeError: null is not a function -TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires new. +TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new". TypeError: null is not a function TypeError: null is not a function java.lang.InstantiationException: java.io.InputStream diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8056978.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8056978.js Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8056978: ClassCastException: cannot cast jdk.nashorn.internal.scripts.JO* + * + * @test + * @run + */ + +var obj1 = { + 'name': 'test name', + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5' +}; + +var obj2 = { + 'name': 'hello' +}; + +print(obj2['name']); +print(obj2.name); + diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8056978.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8056978.js.EXPECTED Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,2 @@ +hello +hello diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8058422.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8058422.js Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058422: Users should be able to overwrite "context" and "engine" variables + * + * @test + * @run + */ + +var m = new javax.script.ScriptEngineManager(); +var e = m.getEngineByName("nashorn"); +e.put("foo", "hello"); +var obj = e.eval("context.getAttribute('foo')"); +if (obj != "hello") { + fail("Expected 'obj' to be 'hello'"); +} + +e.put("context", "bar"); +if (e.eval("context") != "bar") { + fail("Expected 'context' to be 'bar'"); +} + +if (e.eval("foo") != "hello") { + fail("Expected 'foo' to be 'hello'"); +} + +if (e.eval("engine") != e) { + fail("'engine' is not evaluaed to current engine"); +} + +e.put("engine", "foobar"); +if (e.eval("engine") != "foobar") { + fail("'engine' is not evalued to 'foobar'"); +} diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8058545.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8058545.js Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058545: With strict mode, bean property assignment of a non-existent property should result in TypeError + * + * @test + * @run + */ + +'use strict'; +var File = Java.type("java.io.File"); +var f = new File("."); +try { + f.foo = 33; + fail("Should have thrown TypeError"); +} catch (e) { + if (! (e instanceof TypeError)) { + fail("Expected TypeError, got " + e); + } +} diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8058615.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8058615.js Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8058615: Overload resolution ambiguity involving ConsString + * + * @test + * @run + */ + +var strw = new java.io.StringWriter(); +var bufw = new java.io.BufferedWriter(strw); +var s = "hello "; +bufw.write(s + "world"); +bufw.close(); +print(strw.toString()); diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/script/basic/JDK-8058615.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8058615.js.EXPECTED Wed Jul 05 20:01:50 2017 +0200 @@ -0,0 +1,1 @@ +hello world diff -r 89a653341cf2 -r 1b1ec4291abc nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java Wed Jul 05 20:01:05 2017 +0200 +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java Wed Jul 05 20:01:50 2017 +0200 @@ -582,6 +582,60 @@ assertEquals(e.eval("x", newCtxt), 2); } + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void contextOverwriteTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = new SimpleBindings(); + b.put("context", "hello"); + b.put("foo", 32); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + e.setContext(newCtxt); + assertEquals(e.eval("context"), "hello"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void contextOverwriteInScriptTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + e.put("foo", 32); + + assertEquals(((Number)e.eval("foo")).intValue(), 32); + assertEquals(e.eval("context = 'bar'"), "bar"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void engineOverwriteTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final Bindings b = new SimpleBindings(); + b.put("engine", "hello"); + b.put("foo", 32); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + e.setContext(newCtxt); + assertEquals(e.eval("engine"), "hello"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + + // @bug 8058422: Users should be able to overwrite "context" and "engine" variables + @Test + public static void engineOverwriteInScriptTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + e.put("foo", 32); + + assertEquals(((Number)e.eval("foo")).intValue(), 32); + assertEquals(e.eval("engine = 'bar'"), "bar"); + assertEquals(((Number)e.eval("foo")).intValue(), 32); + } + // @bug 8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook @Test public static void testMegamorphicGetInGlobal() throws Exception {