OpenJDK / jdk / jdk12
changeset 26643:78599aa8d4f4
Merge
author | duke |
---|---|
date | Wed, 05 Jul 2017 20:01:33 +0200 |
parents | 559e6ee4a338 f9d078aa7a23 |
children | 92d153d19228 |
files | hotspot/test/runtime/RedefineFinalizer/RedefineFinalizer.java jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk jdk/src/java.desktop/macosx/classes/sun/awt/datatransfer/flavormap.properties jdk/src/java.desktop/unix/classes/sun/awt/datatransfer/flavormap.properties jdk/src/java.desktop/windows/classes/sun/awt/datatransfer/flavormap.properties jdk/src/java.desktop/windows/classes/sun/awt/windows/WBufferStrategy.java jdk/src/java.desktop/windows/native/libawt/sun/java2d/d3d/D3DPipeline.cpp jdk/src/java.desktop/windows/native/libawt/sun/windows/WBufferStrategy.cpp jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSContext.java jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/ExtendedGSSCredential.java jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/GSSUtil.java jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireSecContextPermission.java jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/InquireType.java jdk/src/java.security.jgss/share/classes/com/sun/security/jgss/package-info.java jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Base.java jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Client.java jdk/src/java.security.jgss/share/classes/com/sun/security/sasl/gsskerb/GssKrb5Server.java make/common/modules.list |
diffstat | 249 files changed, 11579 insertions(+), 4439 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags-top-repo Wed Sep 17 22:55:51 2014 -0700 +++ b/.hgtags-top-repo Wed Jul 05 20:01:33 2017 +0200 @@ -273,3 +273,4 @@ ea2f7981236f3812436958748ab3d26e80a35130 jdk9-b28 9e6581aeda388a23fbee021fc33e6aa152a60657 jdk9-b29 36e9bc875325813ac9c44ac0c617a463091fa9f5 jdk9-b30 +69a84c16d9c28e0e3d504b9c8766c24bafcd58f6 jdk9-b31
--- a/Makefile Wed Sep 17 22:55:51 2014 -0700 +++ b/Makefile Wed Jul 05 20:01:33 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)
--- a/common/autoconf/generated-configure.sh Wed Sep 17 22:55:51 2014 -0700 +++ b/common/autoconf/generated-configure.sh Wed Jul 05 20:01:33 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 )
--- a/common/autoconf/hotspot-spec.gmk.in Wed Sep 17 22:55:51 2014 -0700 +++ b/common/autoconf/hotspot-spec.gmk.in Wed Jul 05 20:01:33 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@
--- a/common/autoconf/jdk-options.m4 Wed Sep 17 22:55:51 2014 -0700 +++ b/common/autoconf/jdk-options.m4 Wed Jul 05 20:01:33 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 )
--- a/common/autoconf/spec.gmk.in Wed Sep 17 22:55:51 2014 -0700 +++ b/common/autoconf/spec.gmk.in Wed Jul 05 20:01:33 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
--- a/common/bin/unshuffle_list.txt Wed Sep 17 22:55:51 2014 -0700 +++ b/common/bin/unshuffle_list.txt Wed Jul 05 20:01:33 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
--- a/hotspot/.hgtags Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/.hgtags Wed Jul 05 20:01:33 2017 +0200 @@ -433,3 +433,4 @@ 657294869d7ff063e055f5492cab7ce5612ca851 jdk9-b28 deb29e92f68ace2808a36ecfa18c7d61dcb645bb jdk9-b29 5c722dffbc0f34eb8d903dca7b261e52248fa17e jdk9-b30 +9f7d155d28e519f3e4645dc21cf185c25f3176ed jdk9-b31
--- a/hotspot/agent/src/os/win32/windbg/sawindbg.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/agent/src/os/win32/windbg/sawindbg.cpp Wed Jul 05 20:01:33 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);
--- a/hotspot/make/Makefile Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/Makefile Wed Jul 05 20:01:33 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:
--- a/hotspot/make/aix/Makefile Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/aix/Makefile Wed Jul 05 20:01:33 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:
--- a/hotspot/make/aix/makefiles/buildtree.make Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/aix/makefiles/buildtree.make Wed Jul 05 20:01:33 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:
--- a/hotspot/make/aix/makefiles/top.make Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/aix/makefiles/top.make Wed Jul 05 20:01:33 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:
--- a/hotspot/make/bsd/Makefile Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/bsd/Makefile Wed Jul 05 20:01:33 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:
--- a/hotspot/make/bsd/makefiles/buildtree.make Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/bsd/makefiles/buildtree.make Wed Jul 05 20:01:33 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:
--- a/hotspot/make/bsd/makefiles/top.make Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/bsd/makefiles/top.make Wed Jul 05 20:01:33 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:
--- a/hotspot/make/bsd/makefiles/universal.gmk Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/bsd/makefiles/universal.gmk Wed Jul 05 20:01:33 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)
--- a/hotspot/make/linux/Makefile Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/linux/Makefile Wed Jul 05 20:01:33 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:
--- a/hotspot/make/linux/makefiles/buildtree.make Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/linux/makefiles/buildtree.make Wed Jul 05 20:01:33 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:
--- a/hotspot/make/linux/makefiles/top.make Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/linux/makefiles/top.make Wed Jul 05 20:01:33 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:
--- a/hotspot/make/solaris/Makefile Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/solaris/Makefile Wed Jul 05 20:01:33 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:
--- a/hotspot/make/solaris/makefiles/buildtree.make Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/solaris/makefiles/buildtree.make Wed Jul 05 20:01:33 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:
--- a/hotspot/make/solaris/makefiles/top.make Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/solaris/makefiles/top.make Wed Jul 05 20:01:33 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:
--- a/hotspot/make/solaris/makefiles/vm.make Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/make/solaris/makefiles/vm.make Wed Jul 05 20:01:33 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
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Jul 05 20:01:33 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");
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Jul 05 20:01:33 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() {
--- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp Wed Jul 05 20:01:33 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 } } }
--- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Wed Jul 05 20:01:33 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); }
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Jul 05 20:01:33 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 }
--- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 20:01:33 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);
--- a/hotspot/src/os/posix/vm/os_posix.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os/posix/vm/os_posix.cpp Wed Jul 05 20:01:33 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);
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 20:01:33 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
--- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 20:01:33 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); }
--- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Wed Jul 05 20:01:33 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; +}
--- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Wed Jul 05 20:01:33 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(); +}
--- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Wed Jul 05 20:01:33 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; +}
--- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Wed Jul 05 20:01:33 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; +}
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Wed Jul 05 20:01:33 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; +}
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Jul 05 20:01:33 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(); +}
--- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Wed Jul 05 20:01:33 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; +}
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Jul 05 20:01:33 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; +}
--- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Wed Jul 05 20:01:33 2017 +0200 @@ -28,10 +28,140 @@ #include "runtime/os.hpp" #include "vm_version_sparc.hpp" -# include <sys/auxv.h> -# include <sys/auxv_SPARC.h> -# include <sys/systeminfo.h> -# include <kstat.h> +#include <sys/auxv.h> +#include <sys/auxv_SPARC.h> +#include <sys/systeminfo.h> +#include <kstat.h> +#include <picl.h> + +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<int>(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<int>(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<UniqueValueVisitor*>(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; }
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 20:01:33 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(); +}
--- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Wed Jul 05 20:01:33 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(); +}
--- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Wed Jul 05 20:01:33 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) {
--- a/hotspot/src/share/vm/ci/ciEnv.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/ci/ciEnv.cpp Wed Jul 05 20:01:33 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");
--- a/hotspot/src/share/vm/classfile/classLoader.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 20:01:33 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();
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Jul 05 20:01:33 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
--- a/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp Wed Jul 05 20:01:33 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();
--- a/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp Wed Jul 05 20:01:33 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); };
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 20:01:33 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(); }
--- a/hotspot/src/share/vm/code/codeCache.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 20:01:33 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 "'",
--- a/hotspot/src/share/vm/code/codeCache.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 20:01:33 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(); }
--- a/hotspot/src/share/vm/code/compiledIC.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/code/compiledIC.cpp Wed Jul 05 20:01:33 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(); }
--- a/hotspot/src/share/vm/code/nmethod.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 20:01:33 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
--- a/hotspot/src/share/vm/code/nmethod.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/code/nmethod.hpp Wed Jul 05 20:01:33 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
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 20:01:33 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("<CompileTask compile_id=%d ", _compile_id); - tty->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;
--- a/hotspot/src/share/vm/compiler/compileBroker.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp Wed Jul 05 20:01:33 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;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Wed Jul 05 20:01:33 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
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Wed Jul 05 20:01:33 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; };
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CodeCacheRemSet.cpp Wed Jul 05 20:01:33 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<typename CB> - 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<typename CB> -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(); } }
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jul 05 20:01:33 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());
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 20:01:33 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*>* 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*>* 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*>* 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<Method*>* 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<PreviousVersionNode *>(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<Method*>* 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*>* method_refs = new (ResourceObj::C_HEAP, mtClass) - GrowableArray<Method*>(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<Method*>* 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*>* 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*>* 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<Method*>* 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<Method*>* 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()
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 20:01:33 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<PreviousVersionNode *>* _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<PreviousVersionNode *>* 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<Method*>* 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<mtClass> { - 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<Method*>* _prev_EMCP_methods; - -public: - PreviousVersionNode(ConstantPool* prev_constant_pool, - GrowableArray<Method*>* prev_EMCP_methods); - ~PreviousVersionNode(); - ConstantPool* prev_constant_pool() const { - return _prev_constant_pool; - } - GrowableArray<Method*>* prev_EMCP_methods() const { - return _prev_EMCP_methods; - } -}; - - -// Helper object for walking previous versions. -class PreviousVersionWalker : public StackObj { - private: - Thread* _thread; - GrowableArray<PreviousVersionNode *>* _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 <klass, method>
--- a/hotspot/src/share/vm/oops/method.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/oops/method.cpp Wed Jul 05 20:01:33 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); } }
--- a/hotspot/src/share/vm/oops/method.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/oops/method.hpp Wed Jul 05 20:01:33 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);
--- a/hotspot/src/share/vm/oops/methodCounters.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/oops/methodCounters.cpp Wed Jul 05 20:01:33 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 +} +
--- a/hotspot/src/share/vm/oops/methodCounters.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/oops/methodCounters.hpp Wed Jul 05 20:01:33 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; }
--- a/hotspot/src/share/vm/oops/methodData.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/oops/methodData.cpp Wed Jul 05 20:01:33 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
--- a/hotspot/src/share/vm/oops/methodData.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/oops/methodData.hpp Wed Jul 05 20:01:33 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; }
--- a/hotspot/src/share/vm/opto/compile.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/opto/compile.cpp Wed Jul 05 20:01:33 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); } // ============================================================================
--- a/hotspot/src/share/vm/opto/library_call.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 20:01:33 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 __
--- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp Wed Jul 05 20:01:33 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<Method*>* 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<Method*>* 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)",
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jul 05 20:01:33 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);
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Wed Jul 05 20:01:33 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
--- a/hotspot/src/share/vm/runtime/arguments.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/runtime/arguments.hpp Wed Jul 05 20:01:33 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);
--- a/hotspot/src/share/vm/runtime/globals.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 20:01:33 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") \ \
--- a/hotspot/src/share/vm/runtime/os.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 20:01:33 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));
--- a/hotspot/src/share/vm/runtime/os.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 20:01:33 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"
--- a/hotspot/src/share/vm/runtime/sweeper.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/runtime/sweeper.cpp Wed Jul 05 20:01:33 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
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Jul 05 20:01:33 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); +}
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Jul 05 20:01:33 2017 +0200 @@ -99,6 +99,9 @@ template(RotateGCLog) \ template(WhiteBoxOperation) \ template(ClassLoaderStatsOperation) \ + template(PrintCompileQueue) \ + template(PrintCodeList) \ + template(PrintCodeCache) \ class VM_Operation: public CHeapObj<mtInternal> { 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
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Jul 05 20:01:33 2017 +0200 @@ -60,6 +60,9 @@ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompileQueueDCmd>(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(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); +} +
--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Jul 05 20:01:33 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
--- a/hotspot/test/TEST.groups Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/test/TEST.groups Wed Jul 05 20:01:33 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 \
--- a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java Wed Jul 05 20:01:33 2017 +0200 @@ -22,7 +22,7 @@ */ /* - * @ignore 8027915 + * @ignore 8049864 * @test TestParallelHeapSizeFlags * @key gc * @bug 8006088
--- a/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/test/gc/arguments/TestUseCompressedOopsErgo.java Wed Jul 05 20:01:33 2017 +0200 @@ -22,7 +22,6 @@ */ /* - * @ignore 8025645 * @test TestUseCompressedOopsErgo * @key gc * @bug 8010722
--- a/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/test/gc/parallelScavenge/TestDynShrinkHeap.java Wed Jul 05 20:01:33 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/NMT/MallocTrackingVerify.java Wed Jul 05 20:01:33 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<MallocMemory> mallocd_memory = new ArrayList<MallocMemory>(); + 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 <pid> 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; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/NMT/UnsafeMallocLimit.java Wed Jul 05 20:01:33 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"); + } + } +}
--- a/hotspot/test/runtime/RedefineFinalizer/RedefineFinalizer.java Wed Sep 17 22:55:51 2014 -0700 +++ /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 - } - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineTests/RedefineFinalizer.java Wed Jul 05 20:01:33 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 + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/RedefineTests/RedefineRunningMethods.java Wed Jul 05 20:01:33 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(); + } + } +}
--- a/hotspot/test/runtime/SharedArchiveFile/ArchiveDoesNotExist.java Wed Sep 17 22:55:51 2014 -0700 +++ b/hotspot/test/runtime/SharedArchiveFile/ArchiveDoesNotExist.java Wed Jul 05 20:01:33 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); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/CodeCacheTest.java Wed Jul 05 20:01:33 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"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/CodelistTest.java Wed Jul 05 20:01:33 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.<init>()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("<init>")) { + continue; + } + if (methodPrintedInLogFormat.contains("<clinit>")) { + 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; + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/CompilerQueueTest.java Wed Jul 05 20:01:33 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); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/MethodIdentifierParser.java Wed Jul 05 20:01:33 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<Class<?>> list = new ArrayList<Class<?>>(); + 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); + } +}
--- a/jdk/.hgtags Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/.hgtags Wed Jul 05 20:01:33 2017 +0200 @@ -273,3 +273,4 @@ 1828f73b35cfe35e460e41fd6e087ab1f83e0621 jdk9-b28 2da27e8e2c865e154f0c2eb9009f011a44649b11 jdk9-b29 8d24fb4493f13d380a2adf62d444e1e5a4451f37 jdk9-b30 +71e99dae28f9791287b88d46e16a266b564f22be jdk9-b31
--- a/jdk/make/CreateJars.gmk Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/make/CreateJars.gmk Wed Jul 05 20:01:33 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), \
--- a/jdk/make/gensrc/Gensrc-java.base.gmk Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/make/gensrc/Gensrc-java.base.gmk Wed Jul 05 20:01:33 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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/gensrc/Gensrc-jdk.localedata.gmk Wed Jul 05 20:01:33 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
--- a/jdk/make/gensrc/GensrcCLDR.gmk Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/make/gensrc/GensrcCLDR.gmk Wed Jul 05 20:01:33 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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/gensrc/GensrcLocaleData.gmk Wed Jul 05 20:01:33 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) + +################################################################################
--- a/jdk/make/gensrc/GensrcLocaleDataMetaInfo.gmk Wed Sep 17 22:55:51 2014 -0700 +++ /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) - -################################################################################
--- a/jdk/make/lib/Awt2dLibraries.gmk Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/make/lib/Awt2dLibraries.gmk Wed Jul 05 20:01:33 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++
--- a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java Wed Jul 05 20:01:33 2017 +0200 @@ -143,8 +143,9 @@ @Override public void generateMetaInfo(Map<String, SortedSet<String>> 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");
--- a/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java Wed Jul 05 20:01:33 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<Module> modules = new HashSet<>(); for (; i < args.length; i++) { Path p = Paths.get(args[i]); - try (InputStream in = new BufferedInputStream(Files.newInputStream(p))) { - Set<Module> 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<Module> load(InputStream in) throws XMLStreamException, IOException { - Set<Module> modules = new HashSet<>(); - XMLInputFactory factory = XMLInputFactory.newInstance(); - XMLEventReader stream = factory.createXMLEventReader(in); - Module.Builder mb = null; - String modulename = null; - String pkg = null; - Set<String> 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<Module> 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<String> 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<Dependence> requires; - private final Map<String, Set<String>> exports; - private final Set<String> packages; - - private Module(String name, - Set<Dependence> requires, - Map<String, Set<String>> exports, - Set<String> 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<Dependence> requires() { - return requires; - } - - public Map<String, Set<String>> exports() { - return exports; - } - - public Set<String> 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<Dependence> requires = new HashSet<>(); - private final Map<String, Set<String>> exports = new HashMap<>(); - private final Set<String> 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<String> 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(); } }
--- /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:33 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 <output file> path-to-modules-xml"; + + private Set<Module> modules = new HashSet<>(); + private HashMap<String,Module> 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<Module> 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<Module> 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<String> AGGREGATORS = Arrays.asList(new String[] { + "java.se", "java.compact1", "java.compact2", + "java.compact3", "jdk.compact3"}); + + class TopoSorter { + final Deque<Module> result = new LinkedList<>(); + final Deque<Module> nodes = new LinkedList<>(); + + TopoSorter(Collection<Module> nodes) { + nodes.stream() + .forEach(m -> this.nodes.add(m)); + + sort(); + } + + public Iterable<Module> result() { + return result; + } + + private void sort() { + Deque<Module> visited = new LinkedList<>(); + Deque<Module> done = new LinkedList<>(); + Module node; + while ((node = nodes.poll()) != null) { + if (!visited.contains(node)) { + visit(node, visited, done); + } + } + } + + private void visit(Module m, Deque<Module> visited, Deque<Module> 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); + } + } +}
--- /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:33 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<Dependence> requires; + private final Map<String, Set<String>> exports; + private final Set<String> packages; + + private Module(String name, + Set<Dependence> requires, + Map<String, Set<String>> exports, + Set<String> 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<Dependence> requires() { + return requires; + } + + public Map<String, Set<String>> exports() { + return exports; + } + + public Set<String> 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<Dependence> requires = new HashSet<>(); + private final Map<String, Set<String>> exports = new HashMap<>(); + private final Set<String> 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<String> 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; + } + } +}
--- /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:33 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<Module> readModules(Path modulesXml) + throws XMLStreamException, IOException + { + Set<Module> modules = new HashSet<>(); + try (InputStream in = new BufferedInputStream(Files.newInputStream(modulesXml))) { + Set<Module> 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<Module> load(InputStream in) + throws XMLStreamException, IOException + { + Set<Module> modules = new HashSet<>(); + XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLEventReader stream = factory.createXMLEventReader(in); + Module.Builder mb = null; + String modulename = null; + String pkg = null; + Set<String> 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); + } +}
--- /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:33 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<Module> 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<Module> 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<String> 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(); + } +}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Jul 05 20:01:33 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;
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Jul 05 20:01:33 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();
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Jul 05 20:01:33 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<Class<?>> 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; }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Jul 05 20:01:33 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;
--- a/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.base/share/classes/java/math/MutableBigInteger.java Wed Jul 05 20:01:33 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; } }
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipInputStream.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.base/share/classes/java/util/zip/ZipInputStream.java Wed Jul 05 20:01:33 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);
--- a/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c Wed Jul 05 20:01:33 2017 +0200 @@ -34,6 +34,10 @@ #include <fcntl.h> #include <sys/uio.h> #include <unistd.h> +#if defined(__linux__) +#include <linux/fs.h> +#include <sys/ioctl.h> +#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; }
--- a/jdk/src/java.base/windows/native/libnet/NetworkInterface.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.base/windows/native/libnet/NetworkInterface.c Wed Jul 05 20:01:33 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; }
--- a/jdk/src/java.desktop/macosx/classes/sun/awt/datatransfer/flavormap.properties Wed Sep 17 22:55:51 2014 -0700 +++ /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: -# -# <native>=<MIME type>,<MIME type>, ... -# -# <native> should be a string identifier that the native platform will -# recognize as a valid data format. <MIME type> 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
--- /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:33 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: +# +# <native>=<MIME type>,<MIME type>, ... +# +# <native> should be a string identifier that the native platform will +# recognize as a valid data format. <MIME type> 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
--- a/jdk/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java Wed Jul 05 20:01:33 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(); } }
--- a/jdk/src/java.desktop/share/classes/javax/swing/JDesktopPane.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/classes/javax/swing/JDesktopPane.java Wed Jul 05 20:01:33 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 <code>JInternalFrame</code> objects and add them to the @@ -271,7 +272,7 @@ private static Collection<JInternalFrame> getAllFrames(Container parent) { int i, count; - Collection<JInternalFrame> results = new ArrayList<JInternalFrame>(); + Collection<JInternalFrame> results = new LinkedHashSet<>(); count = parent.getComponentCount(); for (i = 0; i < count; i++) { Component next = parent.getComponent(i);
--- a/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceDataProxy.java Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceDataProxy.java Wed Jul 05 20:01:33 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; }
--- a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Wed Jul 05 20:01:33 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; i<outline->n_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) {
--- a/jdk/src/java.desktop/share/native/liblcms/cmscam02.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmscam02.c Wed Jul 05 20:01:33 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]; } -
--- a/jdk/src/java.desktop/share/native/liblcms/cmscgats.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmscgats.c Wed Jul 05 20:01:33 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); } - } + } }
--- a/jdk/src/java.desktop/share/native/liblcms/cmscnvrt.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmscnvrt.c Wed Jul 05 20:01:33 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; }
--- a/jdk/src/java.desktop/share/native/liblcms/cmserr.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmserr.c Wed Jul 05 20:01:33 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); + } +}
--- a/jdk/src/java.desktop/share/native/liblcms/cmsgamma.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsgamma.c Wed Jul 05 20:01:33 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),
--- a/jdk/src/java.desktop/share/native/liblcms/cmsgmt.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsgmt.c Wed Jul 05 20:01:33 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);
--- a/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c Wed Jul 05 20:01:33 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;
--- a/jdk/src/java.desktop/share/native/liblcms/cmsio0.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsio0.c Wed Jul 05 20:01:33 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; }
--- a/jdk/src/java.desktop/share/native/liblcms/cmsio1.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsio1.c Wed Jul 05 20:01:33 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; }
--- a/jdk/src/java.desktop/share/native/liblcms/cmsopt.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsopt.c Wed Jul 05 20:01:33 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; }
--- a/jdk/src/java.desktop/share/native/liblcms/cmspack.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmspack.c Wed Jul 05 20:01:33 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;
--- a/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c Wed Sep 17 22:55:51 2014 -0700 +++ b/jdk/src/java.desktop/share/native/liblcms/cmsplugin.c Wed Jul 05 20:01:33 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)); +